检测多边形与纬度列表的自交点?

Detect self intersection of a polygon with list of latLng?

提问人:shanmkha 提问时间:11/2/2023 最后编辑:shanmkha 更新时间:11/3/2023 访问量:44

问:

我有一个坐标列表来绘制一个完美的多边形,该多边形不应该是自相交和闭合的多边形。我在 shift 中找到了这段代码,但我想要在 dart 中使用它,因为我在 flutter 中实现。

  1. 我想要这个完美的多边形
  2. 不是这个多边形

因此,当多边形类似于第一种情况时,代码应返回 --> true

在其他情况下,应返回 --> false。

我尝试了一些代码,但它效果不佳,我尝试了另一种代码,它在某些情况下有效(不确定在哪些情况下)。

因此,下面我更新了最小的可重复示例。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  const MyHomePage({
    Key? key,
    required this.title,
  }) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  List<LatLng> polygonLatLngs = [];
  Set<Polygon> _polygons = HashSet<Polygon>();
  Set<Marker> _markers = HashSet<Marker>();
  LatLng centerCamera = LatLng(13.621975344148467, 79.42180316886122);
  double? zoomCamera;
  BitmapDescriptor? errorMark;
  GoogleMapController? googleMapController;
  
  void _setPolygon() {
      final String polygonIdVal = 'polygon_id_$_polygonIdCounter';
      _polygons.add(Polygon(
        polygonId: PolygonId(polygonIdVal),
        points: polygonLatLngs,
        strokeWidth: 2,
        strokeColor: Colors.blueAccent,
        fillColor: Colors.transparent,
      ));
    }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: GoogleMap(
              myLocationButtonEnabled: false,
              myLocationEnabled: false,
              mapType: MapType.normal,
              padding: EdgeInsets.only(bottom: 160),
              initialCameraPosition: CameraPosition(
                target: centerCamera,
                zoom: 18,
              ),
              onMapCreated: (GoogleMapController controller) {
                googleMapController = controller;
              },
              gestureRecognizers: Set()
                ..add(Factory<PanGestureRecognizer>(
                    () => PanGestureRecognizer())),
              onTap: (latLng) {
                setState(() {
                  polygonLatLngs.add(latLng);
                  _setPolygon();
                  isIntersecting(polygonLatLngs);
                });
              },
              onCameraMove: (position) {
                centerCamera = position.target;
                zoomCamera = position.zoom;
              },
              markers: _markers,
              polygons: _polygons,
            ),
      ),
  
    );
  }
  
  LatLng? intersectionBetweenSegments(LatLng p0, LatLng p1, LatLng p2, LatLng p3){
    var denominator = (p3.longitude - p2.longitude) * (p1.latitude - p0.latitude) - (p3.latitude - p2.latitude) * (p1.longitude - p0.longitude);
    var ua = (p3.latitude - p2.latitude) * (p0.longitude - p2.longitude) - (p3.longitude - p2.longitude) * (p0.latitude - p2.latitude);
    var ub = (p1.latitude - p0.latitude) * (p0.longitude - p2.longitude) - (p0.longitude - p0.longitude) * (p0.latitude - p2.latitude);

    if(denominator < 0){
      ua = -ua;
      ub = -ub;
      denominator = -denominator;
    }

    if (ua >= 0.0 && ua <= denominator && ub >= 0.0 && ub <= denominator && denominator != 0){
      print("INTERSECT");
      return LatLng(p0.latitude + ua / denominator * (p1.latitude - p0.latitude), p0.longitude + ua / denominator * (p1.longitude - p0.longitude));
    }
    return null;
  }

  bool isIntersecting(List<LatLng> polygon) {
    LatLng? intersection;
    if(polygon.length > 2){
      final n = polygon.length - 1;

      for(var i =1; i < n; i++){
        for(var j=0; j < i-1; j++){
          intersection = intersectionBetweenSegments(polygon[i], polygon[i+1], polygon[j], polygon[j+1]);
          if (intersection != null){
            print("Error: Intersection @$intersection");
            placeErrorMarker(intersection);
            //alert user about intersection
            showDialog(
                context: context,
                barrierDismissible: false,
                builder: ((BuildContext context) {
                  return DialogBoxForErrorWithCb(
                    "Error",
                    "Station boundary should not be overlap",
                    onPress: () {
                      //remove last polyline and remove error mark on map
                   
                      setState(() {
                        polygonLatLngs.removeLast();
                        _markers.remove(_markers.firstWhere((Marker marker) => marker.markerId.value == 'error'));
                      });
                      popDialog(context);
                    },
                  );
                }));
            return true;
          }
        }
      }
    }
    return false;
  }

  void placeErrorMarker(LatLng intersection) {
    _markers.add(Marker( 
      markerId: MarkerId('error'),
      position: intersection, 
      anchor : const Offset(0.5, 0.5),
      infoWindow: InfoWindow( 
        title: 'Overlap Point',
        snippet: 'Boundary should not be overlap',
      ),
      icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed),
    ));
    Future.delayed(Duration(seconds: 1)).then((value) {
      googleMapController?.showMarkerInfoWindow(MarkerId('error'));
    });
  }
}

非常感谢您的帮助。

飞镖 谷歌地图 坐标 FlutterMap

评论

0赞 Yrll 11/3/2023
请提供一个最小的可重现示例,例如指向重现您的问题的示例 github 存储库的链接,我们可以尝试克隆和玩弄。
0赞 shanmkha 11/3/2023
对不起,现在我更新了我的代码,你能检查一下吗?
0赞 Yrll 11/7/2023
您添加的代码似乎不可重现,缺少一些方法/类,使其无法运行。

答: 暂无答案