private bool isNodeEnabled(PlanarGraphNode node, OverlayType operation, Polyline polyline, Polygon polygon, bool inverseArgs) { switch (operation) { case OverlayType.Intersection: if (!node.Label.UsedByObject1 || !node.Label.UsedByObject2) return false; break; case OverlayType.Union: return false; case OverlayType.Difference: case OverlayType.SymmetricDifference: return false; } bool hasEnabledEdges = false; foreach (PlanarGraphEdge edge in node.IncidentEdges) if (isAreaEdgeEnabled(edge, operation, polygon, inverseArgs) || isLinearEdgeEnabled(edge, operation, polygon, inverseArgs)) { hasEnabledEdges = true; break; } return !hasEnabledEdges; }
private void addOrMergeNode(ICoordinate coordinate, IGeometry obj) { double tolerance = PlanimetryAlgorithms.Tolerance; double x = coordinate.X; PlanarGraphNode node; int startIndex = 0, endIndex = _nodes.Count - 1; while (endIndex - startIndex > 1) { int index = startIndex + (endIndex - startIndex) / 2; if (_nodes[index].Point.X < x) startIndex = index; else endIndex = index; } while (startIndex > 0 && _nodes[startIndex].Point.X + tolerance > x) startIndex--; while (endIndex < _nodes.Count - 1 && _nodes[endIndex].Point.X - tolerance < x) endIndex++; for (int i = startIndex; i <= endIndex; i++) { ICoordinate p = _nodes[i].Point; if (Math.Abs(p.X - x) < tolerance && Math.Abs(p.Y - coordinate.Y) < tolerance) if ((_performSnapping && p.ExactEquals(coordinate)) || (!_performSnapping && p.Equals(coordinate))) { _nodes[i].Label.UsedByObject1 = obj == _sourceGeometry1 || _nodes[i].Label.UsedByObject1; _nodes[i].Label.UsedByObject2 = obj == _sourceGeometry2 || _nodes[i].Label.UsedByObject2; return; } if (p.X > x) { node = new PlanarGraphNode(coordinate); node.Label.UsedByObject1 = obj == _sourceGeometry1; node.Label.UsedByObject2 = obj == _sourceGeometry2; if(obj == _sourceGeometry1) node.Label.Object1OccurrencesCount++; if(obj == _sourceGeometry2) node.Label.Object2OccurrencesCount++; _nodes.Insert(i, node); return; } } node = new PlanarGraphNode(coordinate); node.Label.UsedByObject1 = obj == _sourceGeometry1; node.Label.UsedByObject2 = obj == _sourceGeometry2; if (obj == _sourceGeometry1) node.Label.Object1OccurrencesCount++; if (obj == _sourceGeometry2) node.Label.Object2OccurrencesCount++; _nodes.Add(node); }
/// <summary> /// Swap nodes of edges. /// </summary> internal void SwapNodes() { PlanarGraphNode node = _node1; _node1 = _node2; _node2 = node; }
/// <summary> /// Initializes a new instance of MapAround.Geometry.PlanarGraphEdge /// </summary> /// <param name="node1">First node</param> /// <param name="node2">Second node</param> public PlanarGraphEdge(PlanarGraphNode node1, PlanarGraphNode node2) { _node1 = node1; _node2 = node2; }
/// <summary> /// Constructs a contour. /// </summary> private Contour processContour(int startNodeIndex, PlanarGraphNode.NodeLayout layout, bool markObject1EdgesOrientation, bool markObject2EdgesOrientation) { Contour result = null; PlanarGraphNode startNode = _nodes[startNodeIndex]; for (int j = 0; j < startNode.IncidentEdges.Count; j++) { if (!startNode.IncidentEdges[j].IsVisited && startNode.IncidentEdges[j].Enabled) // инцидентное ребро не пройдено { if (result == null) result = new Contour(); result.Vertices.Add((ICoordinate)startNode.Point.Clone()); // первая вершина нового контура PlanarGraphNode currentNode = startNode; Segment previousEdge = new Segment(); bool edgeDetected = false; List<PlanarGraphEdge> possibleEdges = new List<PlanarGraphEdge>(); while (true) { // определение ребра для поворота направо (налево для дырки) possibleEdges.Clear(); foreach (PlanarGraphEdge edge in currentNode.IncidentEdges) if (!edge.IsVisited && edge.Enabled) possibleEdges.Add(edge); if (possibleEdges.Count > 0) { if (!edgeDetected) { previousEdge.V1 = (ICoordinate)currentNode.Point.Clone(); previousEdge.V2 = (ICoordinate)currentNode.Point.Clone(); double l = PlanimetryAlgorithms.Tolerance * 1e10; if (layout == PlanarGraphNode.NodeLayout.Internal) // для 1-го ребра должен определяться угол с вертикалью previousEdge.V2.Y -= l; else previousEdge.V2.Y += l; edgeDetected = true; } double maxAngle = 0; // максимальный найденный угол поворота double minAngle = _twoPi; // минимальный найденный угол поворота PlanarGraphEdge targetEdge = null; // целевое ребро if (possibleEdges.Count == 1) targetEdge = possibleEdges[0]; else { for (int k = 0; k < possibleEdges.Count; k++) // находим ребро с минимальным углом { PlanarGraphEdge edge = possibleEdges[k]; Segment kEdge = new Segment(edge.Node1.Point, edge.Node2.Point); double angle; try { if (result.Vertices.Count < 2) angle = Math.Min(getAngleBetweenEdges(ref previousEdge, ref kEdge, true), getAngleBetweenEdges(ref previousEdge, ref kEdge, false)); else angle = getAngleBetweenEdges(ref previousEdge, ref kEdge, layout == PlanarGraphNode.NodeLayout.Internal); } catch (ArgumentException) { throw new TopologyException(); } if (angle >= _twoPi) angle -= _twoPi; if (result.Vertices.Count > 1) { if (angle > maxAngle) { maxAngle = angle; targetEdge = edge; } } else // первое ребро - особый случай, ищем минимальный угол { if (angle < minAngle) { minAngle = angle; targetEdge = edge; } } } } if (targetEdge != null) { if (targetEdge.Node1.Point.ExactEquals(currentNode.Point)) { if (markObject1EdgesOrientation) targetEdge.OrientationInObject1 = PlanarGraphEdge.EdgeOrientation.Forward; if (markObject2EdgesOrientation) targetEdge.OrientationInObject2 = PlanarGraphEdge.EdgeOrientation.Forward; result.Vertices.Add((ICoordinate)targetEdge.Node2.Point.Clone()); targetEdge.Node2.Layout = layout; currentNode = targetEdge.Node2; } else { if (markObject1EdgesOrientation) targetEdge.OrientationInObject1 = PlanarGraphEdge.EdgeOrientation.Backward; if (markObject2EdgesOrientation) targetEdge.OrientationInObject2 = PlanarGraphEdge.EdgeOrientation.Backward; result.Vertices.Add((ICoordinate)targetEdge.Node1.Point.Clone()); targetEdge.Node1.Layout = layout; currentNode = targetEdge.Node1; } previousEdge = new Segment(targetEdge.Node1.Point, targetEdge.Node2.Point); targetEdge.IsVisited = true; if (currentNode == startNode) // пришли, контур сформирован { result.Vertices.RemoveAt(result.Vertices.Count - 1); break; } } else break; } else { // по какой-то причине контур не может быть завершен throw new TopologyException(); } } break; } } return result; }