/// <summary> /// Update incomplete dirEdge labels from the labelling for the node. /// </summary> /// <param name="nodeLabel"></param> public virtual void UpdateLabelling(Label nodeLabel) { for (IEnumerator it = GetEnumerator(); it.MoveNext();) { DirectedEdge de = (DirectedEdge)it.Current; Label label = de.Label; label.SetAllLocationsIfNull(0, nodeLabel.GetLocation(0)); label.SetAllLocationsIfNull(1, nodeLabel.GetLocation(1)); } }
/// <summary> /// Updates the label of a node to BOUNDARY, /// obeying the mod-2 boundaryDetermination rule. /// </summary> /// <param name="argIndex"></param> public virtual void SetLabelBoundary(int argIndex) { // determine the current location for the point (if any) LocationType loc = LocationType.Null; if (Label != null) { loc = Label.GetLocation(argIndex); } // flip the loc LocationType newLoc; switch (loc) { case LocationType.Boundary: newLoc = LocationType.Interior; break; case LocationType.Interior: newLoc = LocationType.Boundary; break; default: newLoc = LocationType.Boundary; break; } base.Label.SetLocation(argIndex, newLoc); }
/// <summary> /// Adds points using the mod-2 rule of SFS. This is used to add the boundary /// points of dim-1 geometries (Curves/MultiCurves). According to the SFS, /// an endpoint of a Curve is on the boundary /// if it is in the boundaries of an odd number of Geometries. /// </summary> /// <param name="argIndex"></param> /// <param name="coord"></param> private void InsertBoundaryPoint(int argIndex, Coordinate coord) { Node n = Nodes.AddNode(coord); Label lbl = n.Label; // the new point to insert is on a boundary int boundaryCount = 1; // determine the current location for the point (if any) LocationType loc = LocationType.Null; if (lbl != null) { loc = lbl.GetLocation(argIndex, PositionType.On); } if (loc == LocationType.Boundary) { boundaryCount++; } // determine the boundary status of the point according to the Boundary Determination Rule LocationType newLoc = DetermineBoundary(boundaryCount); if (lbl != null) { lbl.SetLocation(argIndex, newLoc); } }
/// <summary> /// Converts a Label to a Line label (that is, one with no side Locations). /// </summary> /// <param name="label">Label to convert.</param> /// <returns>Label as Line label.</returns> public static Label ToLineLabel(Label label) { Label lineLabel = new Label(LocationType.Null); for (int i = 0; i < 2; i++) { lineLabel.SetLocation(i, label.GetLocation(i)); } return(lineLabel); }
/// <summary> /// /// </summary> /// <param name="geomIndex"></param> /// <returns></returns> private bool CheckAreaLabelsConsistent(int geomIndex) { // Since edges are stored in CCW order around the node, // As we move around the ring we move from the right to the left side of the edge IList edges = Edges; // if no edges, trivially consistent if (edges.Count <= 0) { return(true); } // initialize startLoc to location of last Curve side (if any) int lastEdgeIndex = edges.Count - 1; Label startLabel = ((EdgeEnd)edges[lastEdgeIndex]).Label; LocationType startLoc = startLabel.GetLocation(geomIndex, PositionType.Left); Assert.IsTrue(startLoc != LocationType.Null, "Found unlabelled area edge"); LocationType currLoc = startLoc; for (IEnumerator it = GetEnumerator(); it.MoveNext();) { EdgeEnd e = (EdgeEnd)it.Current; Label label = e.Label; // we assume that we are only checking a area Assert.IsTrue(label.IsArea(geomIndex), "Found non-area edge"); LocationType leftLoc = label.GetLocation(geomIndex, PositionType.Left); LocationType rightLoc = label.GetLocation(geomIndex, PositionType.Right); // check that edge is really a boundary between inside and outside! if (leftLoc == rightLoc) { return(false); } // check side location conflict if (rightLoc != currLoc) { return(false); } currLoc = leftLoc; } return(true); }
/// <summary> /// To merge labels for two nodes, /// the merged location for each LabelElement is computed. /// The location for the corresponding node LabelElement is set to the result, /// as long as the location is non-null. /// </summary> /// <param name="label2"></param> public virtual void MergeLabel(Label label2) { for (int i = 0; i < 2; i++) { LocationType loc = ComputeMergedLocation(label2, i); LocationType thisLoc = Label.GetLocation(i); if (thisLoc == LocationType.Null) { Label.SetLocation(i, loc); } } }
/// <summary> /// The location for a given eltIndex for a node will be one /// of { Null, Interior, Boundary }. /// A node may be on both the boundary and the interior of a point; /// in this case, the rule is that the node is considered to be in the boundary. /// The merged location is the maximum of the two input values. /// </summary> /// <param name="label2"></param> /// <param name="eltIndex"></param> public virtual LocationType ComputeMergedLocation(Label label2, int eltIndex) { LocationType loc = Label.GetLocation(eltIndex); if (!label2.IsNull(eltIndex)) { LocationType nLoc = label2.GetLocation(eltIndex); if (loc != LocationType.Boundary) { loc = nLoc; } } return(loc); }
/// <summary> /// Updates an IM from the label for an edge. /// Handles edges from both L and A geometries. /// </summary> /// <param name="label"></param> /// <param name="im"></param> public static void UpdateIm(Label label, IntersectionMatrix im) { im.SetAtLeastIfValid(label.GetLocation(0, PositionType.On), label.GetLocation(1, PositionType.On), DimensionType.Curve); if (!label.IsArea()) { return; } im.SetAtLeastIfValid(label.GetLocation(0, PositionType.Left), label.GetLocation(1, PositionType.Left), DimensionType.Surface); im.SetAtLeastIfValid(label.GetLocation(0, PositionType.Right), label.GetLocation(1, PositionType.Right), DimensionType.Surface); }
/// <summary> /// Merge the RHS label from a DirectedEdge into the label for this EdgeRing. /// The DirectedEdge label may be null. This is acceptable - it results /// from a node which is NOT an intersection node between the Geometries /// (e.g. the end node of a LinearRing). In this case the DirectedEdge label /// does not contribute any information to the overall labelling, and is simply skipped. /// </summary> /// <param name="deLabel"></param> /// <param name="geomIndex"></param> protected virtual void MergeLabel(Label deLabel, int geomIndex) { LocationType loc = deLabel.GetLocation(geomIndex, PositionType.Right); // no information to be had from this label if (loc == LocationType.Null) { return; } // if there is no current RHS value, set it if (_label.GetLocation(geomIndex) == LocationType.Null) { _label.SetLocation(geomIndex, loc); return; } }
/// <summary> /// /// </summary> /// <param name="geomIndex"></param> /// <param name="coord"></param> /// <returns></returns> public virtual bool IsBoundaryNode(int geomIndex, Coordinate coord) { Node node = _nodes.Find(coord); if (node == null) { return(false); } Label label = node.Label; if (label != null && label.GetLocation(geomIndex) == LocationType.Boundary) { return(true); } return(false); }
/// <summary> /// Compute the labelling for all dirEdges in this star, as well /// as the overall labelling. /// </summary> /// <param name="geom"></param> public override void ComputeLabelling(GeometryGraph[] geom) { base.ComputeLabelling(geom); // determine the overall labelling for this DirectedEdgeStar // (i.e. for the node it is based at) _label = new Label(LocationType.Null); IEnumerator it = GetEnumerator(); while (it.MoveNext()) { EdgeEnd ee = (EdgeEnd)it.Current; Edge e = ee.Edge; Label eLabel = e.Label; for (int i = 0; i < 2; i++) { LocationType eLoc = eLabel.GetLocation(i); if (eLoc == LocationType.Interior || eLoc == LocationType.Boundary) { _label.SetLocation(i, LocationType.Interior); } } } }
/// <summary> /// Update incomplete dirEdge labels from the labelling for the node. /// </summary> /// <param name="nodeLabel"></param> public virtual void UpdateLabelling(Label nodeLabel) { for (IEnumerator it = GetEnumerator(); it.MoveNext(); ) { DirectedEdge de = (DirectedEdge)it.Current; Label label = de.Label; label.SetAllLocationsIfNull(0, nodeLabel.GetLocation(0)); label.SetAllLocationsIfNull(1, nodeLabel.GetLocation(1)); } }
/// <summary> /// Converts a Label to a Line label (that is, one with no side Locations). /// </summary> /// <param name="label">Label to convert.</param> /// <returns>Label as Line label.</returns> public static Label ToLineLabel(Label label) { Label lineLabel = new Label(LocationType.Null); for (int i = 0; i < 2; i++) lineLabel.SetLocation(i, label.GetLocation(i)); return lineLabel; }
/// <summary> /// Updates an IM from the label for an edge. /// Handles edges from both L and A geometries. /// </summary> /// <param name="label"></param> /// <param name="im"></param> public static void UpdateIm(Label label, IntersectionMatrix im) { im.SetAtLeastIfValid(label.GetLocation(0, PositionType.On), label.GetLocation(1, PositionType.On), DimensionType.Curve); if (!label.IsArea()) return; im.SetAtLeastIfValid(label.GetLocation(0, PositionType.Left), label.GetLocation(1, PositionType.Left), DimensionType.Surface); im.SetAtLeastIfValid(label.GetLocation(0, PositionType.Right), label.GetLocation(1, PositionType.Right), DimensionType.Surface); }
/// <summary> /// The location for a given eltIndex for a node will be one /// of { Null, Interior, Boundary }. /// A node may be on both the boundary and the interior of a point; /// in this case, the rule is that the node is considered to be in the boundary. /// The merged location is the maximum of the two input values. /// </summary> /// <param name="label2"></param> /// <param name="eltIndex"></param> public virtual LocationType ComputeMergedLocation(Label label2, int eltIndex) { LocationType loc = Label.GetLocation(eltIndex); if (!label2.IsNull(eltIndex)) { LocationType nLoc = label2.GetLocation(eltIndex); if (loc != LocationType.Boundary) loc = nLoc; } return loc; }
/// <summary> /// /// </summary> /// <param name="label"></param> /// <param name="opCode"></param> /// <returns></returns> public static bool IsResultOfOp(Label label, SpatialFunction opCode) { LocationType loc0 = label.GetLocation(0); LocationType loc1 = label.GetLocation(1); return IsResultOfOp(loc0, loc1, opCode); }
/// <summary> /// Merge the RHS label from a DirectedEdge into the label for this EdgeRing. /// The DirectedEdge label may be null. This is acceptable - it results /// from a node which is NOT an intersection node between the Geometries /// (e.g. the end node of a LinearRing). In this case the DirectedEdge label /// does not contribute any information to the overall labelling, and is simply skipped. /// </summary> /// <param name="deLabel"></param> /// <param name="geomIndex"></param> protected virtual void MergeLabel(Label deLabel, int geomIndex) { LocationType loc = deLabel.GetLocation(geomIndex, PositionType.Right); // no information to be had from this label if (loc == LocationType.Null) return; // if there is no current RHS value, set it if (_label.GetLocation(geomIndex) == LocationType.Null) { _label.SetLocation(geomIndex, loc); return; } }
/// <summary> /// /// </summary> /// <param name="geom"></param> public virtual void ComputeLabelling(GeometryGraph[] geom) { ComputeEdgeEndLabels(); // Propagate side labels around the edges in the star // for each parent Geometry PropagateSideLabels(0); PropagateSideLabels(1); /* * If there are edges that still have null labels for a point * this must be because there are no area edges for that point incident on this node. * In this case, to label the edge for that point we must test whether the * edge is in the interior of the point. * To do this it suffices to determine whether the node for the edge is in the interior of an area. * If so, the edge has location Interior for the point. * In all other cases (e.g. the node is on a line, on a point, or not on the point at all) the edge * has the location Exterior for the point. * * Notice that the edge cannot be on the Boundary of the point, since then * there would have been a parallel edge from the Geometry at this node also labelled Boundary * and this edge would have been labelled in the previous step. * * This code causes a problem when dimensional collapses are present, since it may try and * determine the location of a node where a dimensional collapse has occurred. * The point should be considered to be on the Exterior * of the polygon, but locate() will return Interior, since it is passed * the original Geometry, not the collapsed version. * * If there are incident edges which are Line edges labelled Boundary, * then they must be edges resulting from dimensional collapses. * In this case the other edges can be labelled Exterior for this Geometry. * * MD 8/11/01 - NOT True! The collapsed edges may in fact be in the interior of the Geometry, * which means the other edges should be labelled Interior for this Geometry. * Not sure how solve this... Possibly labelling needs to be split into several phases: * area label propagation, symLabel merging, then finally null label resolution. */ bool[] hasDimensionalCollapseEdge = { false, false }; for (IEnumerator it = GetEnumerator(); it.MoveNext();) { EdgeEnd e = (EdgeEnd)it.Current; Label label = e.Label; for (int geomi = 0; geomi < 2; geomi++) { if (label.IsLine(geomi) && label.GetLocation(geomi) == LocationType.Boundary) { hasDimensionalCollapseEdge[geomi] = true; } } } for (IEnumerator it = GetEnumerator(); it.MoveNext();) { EdgeEnd e = (EdgeEnd)it.Current; Label label = e.Label; for (int geomi = 0; geomi < 2; geomi++) { if (label.IsAnyNull(geomi)) { LocationType loc; if (hasDimensionalCollapseEdge[geomi]) { loc = LocationType.Exterior; } else { Coordinate p = e.Coordinate; loc = GetLocation(geomi, p, geom); } label.SetAllLocationsIfNull(geomi, loc); } } } }
/// <summary> /// /// </summary> /// <param name="geomIndex"></param> public virtual void PropagateSideLabels(int geomIndex) { // Since edges are stored in CCW order around the node, // As we move around the ring we move from the right to the left side of the edge LocationType startLoc = LocationType.Null; // initialize loc to location of last Curve side (if any) for (IEnumerator it = GetEnumerator(); it.MoveNext();) { EdgeEnd e = (EdgeEnd)it.Current; Label label = e.Label; if (label.IsArea(geomIndex) && label.GetLocation(geomIndex, PositionType.Left) != LocationType.Null) { startLoc = label.GetLocation(geomIndex, PositionType.Left); } } // no labelled sides found, so no labels to propagate if (startLoc == LocationType.Null) { return; } LocationType currLoc = startLoc; for (IEnumerator it = GetEnumerator(); it.MoveNext();) { EdgeEnd e = (EdgeEnd)it.Current; Label label = e.Label; // set null On values to be in current location if (label.GetLocation(geomIndex, PositionType.On) == LocationType.Null) { label.SetLocation(geomIndex, PositionType.On, currLoc); } // set side labels (if any) // if (label.IsArea()) //ORIGINAL if (label.IsArea(geomIndex)) { LocationType leftLoc = label.GetLocation(geomIndex, PositionType.Left); LocationType rightLoc = label.GetLocation(geomIndex, PositionType.Right); // if there is a right location, that is the next location to propagate if (rightLoc != LocationType.Null) { if (rightLoc != currLoc) { throw new TopologyException(TopologyText.SideLocationConflict, e.Coordinate); } if (leftLoc == LocationType.Null) { throw new TopologyException(TopologyText.SingleNullSide, e.Coordinate); } currLoc = leftLoc; } else { /* RHS is null - LHS must be null too. * This must be an edge from the other point, which has no location * labelling for this point. This edge must lie wholly inside or outside * the other point (which is determined by the current location). * Assign both sides to be the current location. */ Assert.IsTrue(label.GetLocation(geomIndex, PositionType.Left) == LocationType.Null, "found single null side"); label.SetLocation(geomIndex, PositionType.Right, currLoc); label.SetLocation(geomIndex, PositionType.Left, currLoc); } } } }
/// <summary> /// Compute the change in depth as an edge is crossed from R to L. /// </summary> /// <param name="label"></param> private static int DepthDelta(Label label) { LocationType lLoc = label.GetLocation(0, PositionType.Left); LocationType rLoc = label.GetLocation(0, PositionType.Right); if (lLoc == LocationType.Interior && rLoc == LocationType.Exterior) return 1; if (lLoc == LocationType.Exterior && rLoc == LocationType.Interior) return -1; return 0; }