Example #1
0
        isInside(MkGeoMultiMap country, Vertex point, double borderMargin)
        {
            HashSet <string> borders = new HashSet <string>();
            HashSet <string> ins     = new HashSet <string>();
            HashSet <string> outs    = new HashSet <string>();
            List <(string name, double buffer)> buffers = new List <(string name, double buffer)>();
            Dictionary <string, List <(string name, double buffer)> > ret = new Dictionary <string, List <(string name, double buffer)> >();

            foreach (KeyValuePair <string, MultiPolygon> kv in country)
            {
                string       province  = kv.Key;
                MultiPolygon multiPoly = kv.Value;
                double       minBuffer = Double.PositiveInfinity;
                foreach (Polygon poly in multiPoly)
                {
                    LinearRing ring = poly.outerRing;
                    var        res  = isInside(point, ring, borderMargin);
                    if (res.inout == 0)
                    {
                        borders.Add(province);
                    }
                    else if (res.inout == -1)
                    {
                        ins.Add(province);
                    }
                    else if (res.inout == 1)
                    {
                        outs.Add(province);
                    }
                    if (Math.Abs(res.radius) < Math.Abs(minBuffer))
                    {
                        minBuffer = res.radius;
                    }
                }
                if (Math.Abs(minBuffer) < Double.PositiveInfinity)
                {
                    buffers.Add((name: province, buffer: minBuffer));
                }
            }
            HashSet <string> prov = new HashSet <string>(ins);

            prov.UnionWith(borders);
            foreach (string p in prov)
            {
                if (ins.Contains(p))
                {
                    ret["in"] = new List <(string name, double buffer)>();
                    ret["in"].Add((name: p, buffer: 0.0));
                }
                else if (borders.Contains(p))
                {
                    if (ret.ContainsKey("border"))
                    {
                        ret["border"].Add((name: p, buffer: 0.0));
                    }
                    else
                    {
                        ret["border"] = new List <(string name, double buffer)>();
                        ret["border"].Add((name: p, buffer: 0.0));
                    }
                }
            }
            if (buffers.Count > 0)
            {
                ret["buffer"] = buffers;
            }
            Dictionary <string, (string name, double buffer)[]> retn = new Dictionary <string, (string name, double buffer)[]>();
Example #2
0
        void parseGeoJson(JObject jobj)
        {
            string jtype = "";
            JArray features;

            try {
                jtype = jobj["type"].Value <string>();
                if (!jtype.Equals("FeatureCollection"))
                {
                    new Exception("Invalid geo type: " + jtype);
                }
                features = (JArray)jobj["features"];
                foreach (JObject feature in features)
                {
                    string ftype = feature["type"].Value <string>();
                    if (!ftype.Equals("Feature"))
                    {
                        new Exception("Invalid feature type: " + ftype);
                    }
                    // feature["properties"] = {
                    //   "name": "Quebec",
                    //   "cartodb_id": 1,
                    //   "created_at": "2014-10-16T13:22:00Z",
                    //   "updated_at": "2014-10-16T13:22:00Z"
                    // }
                    string name = ((JObject)feature["properties"])["name"].Value <string>();

                    JObject geometry   = (JObject)feature["geometry"];
                    string  gtype      = geometry["type"].Value <string>();
                    JArray  coords     = (JArray)geometry["coordinates"];
                    JArray  polyCoords = null;
                    if (gtype.Equals("MultiPolygon"))
                    {
                        polyCoords = coords;
                    }
                    else if (gtype.Equals("Polygon"))
                    {
                        polyCoords = new JArray();
                        polyCoords.Add(coords);
                    }
                    else
                    {
                        throw new Exception("Unsurported geometry type");
                    }

                    Polygon[] polys = new Polygon[polyCoords.Count];
                    for (int p = 0; p < polyCoords.Count; ++p)
                    {
                        JArray       coords1 = (JArray)polyCoords[p];
                        LinearRing[] rings   = new LinearRing[coords1.Count];
                        for (int r = 0; r < coords1.Count; ++r)
                        {
                            JArray   coords2 = (JArray)coords1[r];
                            Vertex[] verts   = new Vertex[coords2.Count];
                            for (int v = 0; v < coords2.Count; ++v)
                            {
                                JArray vertex = (JArray)coords2[v];
                                verts[v] = new Vertex(vertex[0].Value <double>(), vertex[1].Value <double>());
                            }
                            rings[r] = new LinearRing(verts);
                        }
                        polys[p] = new Polygon(rings);
                    }

                    this[name] = new MultiPolygon(polys);
                }
            } catch (Exception exc) {
                Console.WriteLine("Exception: " + exc.Message);
                throw exc;
            }
        }
Example #3
0
        isInside(Vertex point, LinearRing outerRing, double radiusOfInterest)
        {
            if (DEBUG)
            {
                if (radiusOfInterest < 0.0)
                {
                    throw new Exception("MkGeoAlgo.isInside: radiusOfInterest must be greater than 0");
                }
            }
            // test the bounding box of the ring with radiusOfInterest

            var bb = outerRing.boundingBox();

            if (!isInsideBoundingBox(bb.bottomLeft, bb.topRight, point, radiusOfInterest))
            {
                return(1, nextFloat(radiusOfInterest));
            }

            double bbScale = maxAbs(bb.bottomLeft, bb.topRight);

            if (bbScale < 1.0)
            {
                bbScale = 1.0;
            }
            double epsilon = nextFloat(bbScale) - bbScale;

            int             effectiveLength = outerRing.length - 1;
            Func <int, int> roundIndex      = n => (n + effectiveLength) % effectiveLength;

            EdgeBBTester edgeBBTester = new EdgeBBTester(point, radiusOfInterest);

            int    numIntersection = 0;
            int    inout           = Int32.MaxValue; // should be -1 (inside), 0 (boundary), 1 (outside)
            double buffer          = radiusOfInterest;

            // Determine the initial state. We wlll loop through the verts from "bottom"

            // We will start the loop from bottom

            // bottom is the index of the lowest vert
            int bottom = outerRing.bottomVert;

            Vertex   v1    = outerRing[bottom];
            RayState state = RayState.Below;

            if (v1.y < point.y)
            {
                state = RayState.Below;
            }
            else if (v1.y > point.y)
            {
                state = RayState.RayDone;
                inout = 1;

                // in the following v1.y === point.y
            }
            else if (bb.bottomLeft.y == bb.topRight.y)
            {
                // bounding box degenerates to horizontal line segment
                inout = 0;
                state = RayState.RayDone;
            }
            else
            {
                // Find the left-most bottom
                int j = bottom;
                for (int i = 1; i < outerRing.length; ++i)
                {
                    int    k   = roundIndex(bottom - i);
                    Vertex v_k = outerRing[k];
                    // notice that v1.y is least among all verts
                    // we are sure to find v0
                    if (v_k.y > v1.y)
                    {
                        break;
                    }
                    else
                    {
                        j = k;
                    }
                }
                bottom = j;
                state  = RayState.AboveToMiddle;
            }

            // Assertion: state === RayDone || inout == Int32.MaxValue
            //            state !== RayDone || inout != Int32.MaxValue

            Vertex v2 = outerRing[bottom];
            Vertex v0;
            Vertex xmin, xmax, ymin, ymax;

            v1 = outerRing[roundIndex(bottom - 1)];
            for (int i = 1; i < outerRing.length; ++i)
            {
                v0 = v1;
                v1 = v2;
                v2 = outerRing[roundIndex(bottom + i)];

                if (v1.x < v2.x)
                {
                    xmin = v1;
                    xmax = v2;
                }
                else
                {
                    xmin = v2;
                    xmax = v1;
                }
                if (v1.y < v2.y)
                {
                    ymin = v1;
                    ymax = v2;
                }
                else
                {
                    ymin = v2;
                    ymax = v1;
                }

                if (state == RayState.RayDone)
                {
                    if (buffer == 0.0)
                    {
                        break;
                    }
                    else
                    {
                        // We have to test edges for the distance
                        if (edgeBBTester.isInBoundingBox(xmin, xmax, ymin, ymax))
                        {
                            double updated = updateBorderBuffer(buffer, v0, v1, v2, point, epsilon);

                            // Assertion: updated == buffer || |updated| < |buffer| && |updated| < radiusOfInterest

                            if (Math.Abs(updated) < Math.Abs(buffer))
                            {
                                edgeBBTester.tightenOffset(Math.Abs(updated));
                                buffer = updated;
                            }
                        }
                        continue;
                    }
                }
                else if (state == RayState.Below || state == RayState.Above)
                {
                    if (point.y == v2.y)
                    {
                        // entering Middle
                        if (point.x == v2.x)
                        {
                            inout = 0;
                            state = RayState.RayDone;
                        }
                        else
                        {
                            state = (state == RayState.Below) ? RayState.BelowToMiddle : RayState.AboveToMiddle;
                        }
                    }
                    else if (state == RayState.Below ? v2.y > point.y : v2.y < point.y)
                    {
                        // Below -> Above || Above -> Below
                        state = state == RayState.Below ? RayState.Above : RayState.Below;
                        if (point.x <= xmax.x)
                        {
                            if (point.x <= xmin.x)
                            {
                                // there must be hit
                                numIntersection += 1;
                            }
                            else
                            {
                                // xmin.x < point.x <= xmax.x
                                double d = signedDist(ymin, ymax, point);
                                if (d == 0.0)
                                {
                                    // hit the boundary
                                    inout = 0;
                                    state = RayState.RayDone;
                                }
                                else if (d > 0.0)
                                {
                                    // one hit
                                    numIntersection += 1;
                                }
                                // otherwise, Δ < 0: there is no hit
                            }
                        }
                        else
                        {
                            // point.x > xmax.x: there is no hit
                            // if debug
                            //     println("Test 8.5")
                            // end
                        }
                    }
                    // otherwise, state === Below ? v2.y < point.y : v2.y > point.y, and we remain in Below/Above
                }
                else if (state == RayState.BelowToMiddle || state == RayState.AboveToMiddle)
                {
                    // We are on the Middle line
                    if (point.y == v2.y)
                    {
                        // Stay on the Middle
                        if (xmin.x <= point.x && point.x <= xmax.x)
                        {
                            // we are on the horizontal edge
                            inout = 0;
                            state = RayState.RayDone;
                        }
                    }
                    else if (state == RayState.BelowToMiddle ? v2.y <point.y : v2.y> point.y)
                    {
                        // Below -> BelowToMiddle -> Below
                        // or, Above -> AboveToMiddle -> Above
                        state = state == RayState.BelowToMiddle ? RayState.Below : RayState.Above;
                    }
                    else
                    {
                        // state === BelowToMiddle ? v2.y > point.y : v2.y < point.y
                        // Below -> BelowToMiddle -> Above
                        // or, Above -> AboveToMiddle -> Below
                        state = state == RayState.BelowToMiddle ? RayState.Above : RayState.Below;
                        if (point.x <= v1.x)
                        {
                            numIntersection += 1;
                        }
                    }
                } // end of state transition
            }     // end of the loop through all the verts

            // println("number of intersection = " * string(numIntersection))
            if (inout == Int32.MaxValue)
            {
                if (numIntersection % 2 == 0)
                {
                    inout = 1;
                }
                else
                {
                    inout = -1;
                }
            }
            if (buffer == radiusOfInterest)
            {
                if (radiusOfInterest >= Double.MaxValue)
                {
                    string err = "logical error: the distance to the border cannot be infinity";
                    if (DEBUG)
                    {
                        throw new Exception(err);
                    }
                    else if (geoFenceLogger != null)
                    {
                        geoFenceLogger(err);
                    }
                }
                buffer = inout < 0 ? -nextFloat(radiusOfInterest) : nextFloat(radiusOfInterest);
            }
            return(inout, buffer);
        } // isInside(LinearRing )