arthur-e / Wicket

A modest library for moving between Well-Known Text (WKT) and various framework geometries
https://arthur-e.github.io/Wicket/
Other
586 stars 226 forks source link

MultiPolygon and MultiLineString does not work in Leaflet 1.0.2 #104

Open Searlon opened 7 years ago

Searlon commented 7 years ago

I'm upgrading my versions of Leaflet and Wkt to the latest versions: Old Leaflet version 0.7.5 -> New Leaflet version 1.0.2 Old Wkt version 1.3 -> New Wkt version 1.3.2

MultiPolygon and MultLineString shapes no longer work. I can no longer create the leaflet objects from Wkt or convert a leaflet object to Wkt. It looks like this is because Leaflet has changed how they construct these shapes. There are no longer unique constructors for these types (no L.MultiPolygon or L.MultiLineString), instead they are using L.Polygon and L.Polyline.

See this JSFiddle for a simple examples https://jsfiddle.net/6tt646oc/3/

arthur-e commented 7 years ago

It seems to me this was already reported in #95 and supposedly fixed by PR #98. Can you comment on how these this issue and its supposed fix compare?

Searlon commented 7 years ago

I'm not in a position where I can easily test that change right now. But looking at it I would think it will fix the problem when creating a MultiPolygon or MultiPolyline from a Wkt String. However I think you're still going to have a problem deconstructing a leaflet object. So going from a Leaflet Object that is a MultiPolygon or MultiPolyline to a Wkt string is going to error.

If you look at my example in JSFiddle and click the "Wkt from single geoJson" button, you'll notice the error states that tmp[0].equals is not a function in the following bit of code

`if (obj.constructor === L.Polyline || obj.constructor === L.polyline) { verts = []; tmp = obj.getLatLngs();

    if (!tmp[0].equals(tmp[tmp.length - 1])) {

        for (i = 0; i < tmp.length; i += 1) {
            verts.push({
                x: tmp[i].lng,
                y: tmp[i].lat
            });
        }

        return {
            type: 'linestring',
            components: verts
        };

    }
}`

This is because the Polyline LatLng object is not a flat array for a MultiPolyline.

arthur-e commented 7 years ago

@crash-dive Maybe you could take a look at this and create a pull request?

crash-dive commented 7 years ago

@arthur-e I am sorry to say we encountered this issue and tried to fix in Wicket but decided it was easier to write it ourselves because we had much simpler requirements such as not needing to support deconstruction of multipolygons or holes in the polygons.

What we ended up with is in TypeScript and attached. It is designed for a specific narrow circumstance so it does not convert everything.

    export class WKT
    {
        public ToPolygon(wkt: string, polygonOptions: L.PolylineOptions): L.Polygon
        {
            var latLongs = [];

            if (wkt.startsWith('POLYGON'))
            {
                //Single Polygon
                var polygon = wkt.replace('POLYGON', '')
                                 .trim()
                                 .slice(1, wkt.length) //Remove first (
                                 .slice(0, wkt.length - 1); //Remove last )

                latLongs.push(this.CreatePolygonArray(polygon));
            }
            else
            {
                //Multi Polygon
                var polygons = wkt.replace('MULTIPOLYGON', '')
                                  .trim()
                                  .slice(1, wkt.length) //Remove first (
                                  .slice(0, wkt.length - 1) //Remove last )
                                  .split(')),');

                for (var polygon of polygons)
                {
                    latLongs.push(this.CreatePolygonArray(polygon));
                }
            }

            return new L.Polygon(latLongs, polygonOptions);
        }

        private CreatePolygonArray (polygon: string): L.LatLng[][]
        {
            var polygonComponents = polygon.split('),').filter(this.RemoveEmptyStrings);
            var polyArray: L.LatLng[][] = [];

            for (var polygonComponent of polygonComponents)
            {
                polyArray.push(this.CreatePolygonCordArray(polygonComponent));
            }
            return polyArray;
        }

        private CreatePolygonCordArray (polygonComponent: string): L.LatLng[]
        {
            var cordArray: L.LatLng[] = [];
            var cords = polygonComponent.trim()
                                        .replace(/\(|\)/g,'') //Removes ( & ) from the string g makes it apply to all instances not just the first
                                        .split(',')
                                        .filter(this.RemoveEmptyStrings)

            for (var cord of cords)
            {
                var latLong = cord.split(' ').filter(this.RemoveEmptyStrings);
                cordArray.push(new L.LatLng(parseFloat(latLong[1]), parseFloat(latLong[0])));
            }

            //Slice to remove the last cord which in WKT is the same as the first one
            return cordArray.slice(0, cordArray.length-1);
        }

        private RemoveEmptyStrings(value: string): boolean
        {
            return value !== '';
        }

        public FromPolygon(polygon: L.Polygon): string
        {
            //The array that comes from getLatLngs is multidimensional to support multipolygons
            //The UI does not allow multipolygons to be drawn so we access the first array within it with [0]
            var latLongs = polygon.getLatLngs()[0];

            var latLongsArray: string[] = [];
            for (var latLong of latLongs)
            {
                latLongsArray.push(latLong.lng + ' ' + latLong.lat);
            }

            //Adds first line to close polygon
            latLongsArray.push(latLongs[0].lng + ' ' + latLongs[0].lat);

            return 'POLYGON((' + latLongsArray.join(',') + '))';
        }
    }
jblamber commented 7 years ago

I believe this is the same issue as #103

nickescallon commented 6 years ago

Looks like the original fix was accidentally removed when module loader support was added here: https://github.com/arthur-e/Wicket/pull/121.

I've reintroduced it, as well as additional leaflet 1.x support here: https://github.com/arthur-e/Wicket/pull/126