internal bool ClusterNonReciprocal_() { int point_count = m_shape.GetTotalPointCount(); com.epl.geometry.Envelope2D env = m_shape.GetEnvelope2D(); m_origin = env.GetLowerLeft(); double dim = System.Math.Max(env.GetHeight(), env.GetWidth()); double mincell = dim / (com.epl.geometry.NumberUtils.IntMax() - 1); if (m_cell_size < mincell) { m_cell_size = mincell; m_inv_cell_size = 1.0 / m_cell_size; } // This holds clusters. m_clusters = new com.epl.geometry.IndexMultiList(); m_clusters.ReserveLists(m_shape.GetTotalPointCount() / 3 + 1); m_clusters.ReserveNodes(m_shape.GetTotalPointCount() / 3 + 1); m_hash_values = m_shape.CreateUserIndex(); m_new_clusters = m_shape.CreateUserIndex(); // Make the hash table. It serves a purpose of fine grain grid. // Make it 25% larger than the 4 times point count to reduce the chance // of collision. // The 4 times comes from the fact that we check four neighbouring cells // in the grid for each point. m_hash_function = new com.epl.geometry.Clusterer.ClusterHashFunction(this, m_shape, m_origin, m_sqr_tolerance, m_inv_cell_size, m_hash_values); m_hash_table = new com.epl.geometry.IndexHashTable(4 * point_count / 3, m_hash_function); m_hash_table.ReserveElements(m_shape.GetTotalPointCount()); bool b_clustered = false; // Go through all vertices stored in the m_shape and put the handles of // the vertices into the clusters and the hash table. for (int geometry = m_shape.GetFirstGeometry(); geometry != -1; geometry = m_shape.GetNextGeometry(geometry)) { for (int path = m_shape.GetFirstPath(geometry); path != -1; path = m_shape.GetNextPath(path)) { int vertex = m_shape.GetFirstVertex(path); for (int index = 0, nindex = m_shape.GetPathSize(path); index < nindex; index++) { System.Diagnostics.Debug.Assert((vertex != -1)); int hash = m_hash_function.Calculate_hash_from_vertex(vertex); m_shape.SetUserIndex(vertex, m_hash_values, hash); m_hash_table.AddElement(vertex, hash); // add cluster to the // hash table System.Diagnostics.Debug.Assert((m_shape.GetUserIndex(vertex, m_new_clusters) == -1)); vertex = m_shape.GetNextVertex(vertex); } } } { // m_hash_table->dbg_print_bucket_histogram_(); // scope for candidates array com.epl.geometry.AttributeStreamOfInt32 candidates = new com.epl.geometry.AttributeStreamOfInt32(0); candidates.Reserve(10); for (int geometry_1 = m_shape.GetFirstGeometry(); geometry_1 != -1; geometry_1 = m_shape.GetNextGeometry(geometry_1)) { for (int path = m_shape.GetFirstPath(geometry_1); path != -1; path = m_shape.GetNextPath(path)) { int vertex = m_shape.GetFirstVertex(path); for (int index = 0, nindex = m_shape.GetPathSize(path); index < nindex; index++) { if (m_shape.GetUserIndex(vertex, m_new_clusters) == com.epl.geometry.StridedIndexTypeCollection.ImpossibleIndex2()) { vertex = m_shape.GetNextVertex(vertex); continue; } // this vertex was merged with another // cluster. It also was removed from the // hash table. int hash = m_shape.GetUserIndex(vertex, m_hash_values); m_hash_table.DeleteElement(vertex, hash); while (true) { CollectClusterCandidates_(vertex, candidates); if (candidates.Size() == 0) { // no candidate for // clustering has // been found for // the cluster_1. break; } bool clustered = false; for (int candidate_index = 0, ncandidates = candidates.Size(); candidate_index < ncandidates; candidate_index++) { int cluster_node = candidates.Get(candidate_index); int other_vertex = m_hash_table.GetElement(cluster_node); m_hash_table.DeleteNode(cluster_node); clustered |= MergeClusters_(vertex, other_vertex, candidate_index + 1 == ncandidates); } b_clustered |= clustered; candidates.Clear(false); // repeat search for the cluster candidates for // cluster_1 if (!clustered) { break; } } // positions did not change // m_shape->set_user_index(vertex, m_new_clusters, // Strided_index_type_collection::impossible_index_2()); vertex = m_shape.GetNextVertex(vertex); } } } } if (b_clustered) { ApplyClusterPositions_(); } m_hash_table = null; m_hash_function = null; m_shape.RemoveUserIndex(m_hash_values); m_shape.RemoveUserIndex(m_new_clusters); // output_debug_printf("total: %d\n",m_shape->get_total_point_count()); // output_debug_printf("clustered: %d\n",m_dbg_candidate_check_count); return(b_clustered); }
internal bool NeedsCrackingImpl_() { bool b_needs_cracking = false; if (m_sweep_structure == null) { m_sweep_structure = new com.epl.geometry.Treap(); } com.epl.geometry.AttributeStreamOfInt32 event_q = new com.epl.geometry.AttributeStreamOfInt32(0); event_q.Reserve(m_shape.GetTotalPointCount() + 1); com.epl.geometry.EditShape.VertexIterator iter = m_shape.QueryVertexIterator(); for (int vert = iter.Next(); vert != -1; vert = iter.Next()) { event_q.Add(vert); } System.Diagnostics.Debug.Assert((m_shape.GetTotalPointCount() == event_q.Size())); m_shape.SortVerticesSimpleByY_(event_q, 0, event_q.Size()); event_q.Add(-1); // for termination; // create user indices to store edges that end at vertices. int edge_index_1 = m_shape.CreateUserIndex(); int edge_index_2 = m_shape.CreateUserIndex(); m_sweep_comparator = new com.epl.geometry.SweepComparator(m_shape, m_tolerance, !m_bAllowCoincident); m_sweep_structure.SetComparator(m_sweep_comparator); com.epl.geometry.AttributeStreamOfInt32 swept_edges_to_delete = new com.epl.geometry.AttributeStreamOfInt32(0); com.epl.geometry.AttributeStreamOfInt32 edges_to_insert = new com.epl.geometry.AttributeStreamOfInt32(0); // Go throught the sorted vertices int event_q_index = 0; com.epl.geometry.Point2D cluster_pt = new com.epl.geometry.Point2D(); // sweep-line algorithm: for (int vertex = event_q.Get(event_q_index++); vertex != -1;) { m_shape.GetXY(vertex, cluster_pt); do { int next_vertex = m_shape.GetNextVertex(vertex); int prev_vertex = m_shape.GetPrevVertex(vertex); if (next_vertex != -1 && m_shape.CompareVerticesSimpleY_(vertex, next_vertex) < 0) { edges_to_insert.Add(vertex); edges_to_insert.Add(next_vertex); } if (prev_vertex != -1 && m_shape.CompareVerticesSimpleY_(vertex, prev_vertex) < 0) { edges_to_insert.Add(prev_vertex); edges_to_insert.Add(prev_vertex); } // Continue accumulating current cluster int attached_edge_1 = m_shape.GetUserIndex(vertex, edge_index_1); if (attached_edge_1 != -1) { swept_edges_to_delete.Add(attached_edge_1); m_shape.SetUserIndex(vertex, edge_index_1, -1); } int attached_edge_2 = m_shape.GetUserIndex(vertex, edge_index_2); if (attached_edge_2 != -1) { swept_edges_to_delete.Add(attached_edge_2); m_shape.SetUserIndex(vertex, edge_index_2, -1); } vertex = event_q.Get(event_q_index++); }while (vertex != -1 && m_shape.IsEqualXY(vertex, cluster_pt)); bool b_continuing_segment_chain_optimization = swept_edges_to_delete.Size() == 1 && edges_to_insert.Size() == 2; int new_left = -1; int new_right = -1; // Process the cluster for (int i = 0, n = swept_edges_to_delete.Size(); i < n; i++) { // Find left and right neighbour of the edges that terminate at // the cluster (there will be atmost only one left and one // right). int edge = swept_edges_to_delete.Get(i); int left = m_sweep_structure.GetPrev(edge); if (left != -1 && !swept_edges_to_delete.HasElement(left)) { // Note: // for // some // heavy // cases, // it // could // be // better // to // use // binary // search. System.Diagnostics.Debug.Assert((new_left == -1)); new_left = left; } int right = m_sweep_structure.GetNext(edge); if (right != -1 && !swept_edges_to_delete.HasElement(right)) { System.Diagnostics.Debug.Assert((new_right == -1)); new_right = right; } //#ifdef NDEBUG if (new_left != -1 && new_right != -1) { break; } } //#endif System.Diagnostics.Debug.Assert((new_left == -1 || new_left != new_right)); m_sweep_comparator.SetSweepY(cluster_pt.y, cluster_pt.x); // Delete the edges that terminate at the cluster. for (int i_1 = 0, n = swept_edges_to_delete.Size(); i_1 < n; i_1++) { int edge = swept_edges_to_delete.Get(i_1); m_sweep_structure.DeleteNode(edge, -1); } swept_edges_to_delete.Clear(false); if (!b_continuing_segment_chain_optimization && new_left != -1 && new_right != -1) { if (CheckForIntersections_(new_left, new_right)) { b_needs_cracking = true; m_non_simple_result = m_sweep_comparator.GetResult(); break; } } for (int i_2 = 0, n = edges_to_insert.Size(); i_2 < n; i_2 += 2) { int v = edges_to_insert.Get(i_2); int otherv = edges_to_insert.Get(i_2 + 1); int new_edge_1 = -1; if (b_continuing_segment_chain_optimization) { new_edge_1 = m_sweep_structure.AddElementAtPosition(new_left, new_right, v, true, true, -1); b_continuing_segment_chain_optimization = false; } else { new_edge_1 = m_sweep_structure.AddElement(v, -1); } // the // sweep // structure // consist // of // the // origin // vertices // for // edges. // One // can // always // get // the // other // endpoint // as // the // next // vertex. if (m_sweep_comparator.IntersectionDetected()) { m_non_simple_result = m_sweep_comparator.GetResult(); b_needs_cracking = true; break; } int e_1 = m_shape.GetUserIndex(otherv, edge_index_1); if (e_1 == -1) { m_shape.SetUserIndex(otherv, edge_index_1, new_edge_1); } else { System.Diagnostics.Debug.Assert((m_shape.GetUserIndex(otherv, edge_index_2) == -1)); m_shape.SetUserIndex(otherv, edge_index_2, new_edge_1); } } if (b_needs_cracking) { break; } // Start accumulating new cluster edges_to_insert.ResizePreserveCapacity(0); } m_shape.RemoveUserIndex(edge_index_1); m_shape.RemoveUserIndex(edge_index_2); return(b_needs_cracking); }
private bool _simplify() { if (m_shape.GetGeometryType(m_geometry) == com.epl.geometry.Geometry.Type.Polygon.Value() && m_shape.GetFillRule(m_geometry) == com.epl.geometry.Polygon.FillRule.enumFillRuleWinding) { com.epl.geometry.TopologicalOperations ops = new com.epl.geometry.TopologicalOperations(); ops.PlanarSimplifyNoCrackingAndCluster(m_fixSelfTangency, m_shape, m_geometry, m_progressTracker); System.Diagnostics.Debug.Assert((m_shape.GetFillRule(m_geometry) == com.epl.geometry.Polygon.FillRule.enumFillRuleOddEven)); } bool bChanged = false; bool bNeedWindingRepeat = true; bool bWinding = false; m_userIndexSortedIndexToVertex = -1; m_userIndexSortedAngleIndexToVertex = -1; int pointCount = m_shape.GetPointCount(m_geometry); // Sort vertices lexicographically // Firstly copy allvertices to an array. com.epl.geometry.AttributeStreamOfInt32 verticesSorter = new com.epl.geometry.AttributeStreamOfInt32(0); verticesSorter.Reserve(pointCount); for (int path = m_shape.GetFirstPath(m_geometry); path != -1; path = m_shape.GetNextPath(path)) { int vertex = m_shape.GetFirstVertex(path); for (int index = 0, n = m_shape.GetPathSize(path); index < n; index++) { verticesSorter.Add(vertex); vertex = m_shape.GetNextVertex(vertex); } } // Sort verticesSorter.Sort(0, pointCount, new com.epl.geometry.Simplificator.SimplificatorVertexComparer(this)); // SORTDYNAMICARRAYEX(verticesSorter, int, 0, pointCount, // SimplificatorVertexComparer, this); // Copy sorted vertices to the m_sortedVertices list. Make a mapping // from the edit shape vertices to the sorted vertices. m_userIndexSortedIndexToVertex = m_shape.CreateUserIndex(); // this index // is used // to map // from edit // shape // vertex to // the // m_sortedVertices // list m_sortedVertices = new com.epl.geometry.IndexMultiDCList(); m_sortedVerticesListIndex = m_sortedVertices.CreateList(0); for (int i = 0; i < pointCount; i++) { int vertex = verticesSorter.Get(i); { // debug com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); m_shape.GetXY(vertex, pt); // for debugging double y = pt.x; } int vertexlistIndex = m_sortedVertices.AddElement(m_sortedVerticesListIndex, vertex); m_shape.SetUserIndex(vertex, m_userIndexSortedIndexToVertex, vertexlistIndex); } // remember the sorted list element on the // vertex. // When we remove a vertex, we also remove associated sorted list // element. m_userIndexSortedAngleIndexToVertex = m_shape.CreateUserIndex(); // create // additional // list // to // store // angular // sort // mapping. m_nextVertexToProcess = -1; if (_cleanupSpikes()) { // cleanup any spikes on the polygon. bChanged = true; } // External iteration loop for the simplificator. // ST. I am not sure if it actually needs this loop. TODO: figure this // out. while (bNeedWindingRepeat) { bNeedWindingRepeat = false; int max_iter = m_shape.GetPointCount(m_geometry) + 10 > 30 ? 1000 : (m_shape.GetPointCount(m_geometry) + 10) * (m_shape.GetPointCount(m_geometry) + 10); // Simplify polygon int iRepeatNum = 0; bool bNeedRepeat = false; do { // Internal iteration loop for the simplificator. // ST. I am not sure if it actually needs this loop. TODO: figure // this out. // while (bNeedRepeat); bNeedRepeat = false; bool bVertexRecheck = false; m_firstCoincidentVertex = -1; int coincidentCount = 0; com.epl.geometry.Point2D ptFirst = new com.epl.geometry.Point2D(); com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); // Main loop of the simplificator. Go through the vertices and // for those that have same coordinates, for (int vlistindex = m_sortedVertices.GetFirst(m_sortedVerticesListIndex); vlistindex != com.epl.geometry.IndexMultiDCList.NullNode();) { int vertex = m_sortedVertices.GetData(vlistindex); { // debug // Point2D pt = new Point2D(); m_shape.GetXY(vertex, pt); double d = pt.x; } if (m_firstCoincidentVertex != -1) { // Point2D pt = new Point2D(); m_shape.GetXY(vertex, pt); if (ptFirst.IsEqual(pt)) { coincidentCount++; } else { ptFirst.SetCoords(pt); m_nextVertexToProcess = vlistindex; // we remeber the // next index in // the member // variable to // allow it to // be updated if // a vertex is // removed // inside of the // _ProcessBunch. if (coincidentCount > 0) { bool result = _processBunch(); // process a // bunch of // coinciding // vertices if (result) { // something has changed. // Note that ProcessBunch may // change m_nextVertexToProcess // and m_firstCoincidentVertex. bNeedRepeat = true; if (m_nextVertexToProcess != com.epl.geometry.IndexMultiDCList.NullNode()) { int v = m_sortedVertices.GetData(m_nextVertexToProcess); m_shape.GetXY(v, ptFirst); } } } vlistindex = m_nextVertexToProcess; m_firstCoincidentVertex = vlistindex; coincidentCount = 0; } } else { m_firstCoincidentVertex = vlistindex; m_shape.GetXY(m_sortedVertices.GetData(vlistindex), ptFirst); coincidentCount = 0; } if (vlistindex != -1) { //vlistindex can be set to -1 after ProcessBunch call above vlistindex = m_sortedVertices.GetNext(vlistindex); } } m_nextVertexToProcess = -1; if (coincidentCount > 0) { bool result = _processBunch(); if (result) { bNeedRepeat = true; } } if (iRepeatNum++ > 10) { throw com.epl.geometry.GeometryException.GeometryInternalError(); } if (bNeedRepeat) { _fixOrphanVertices(); } // fix broken structure of the shape if (_cleanupSpikes()) { bNeedRepeat = true; } bNeedWindingRepeat |= bNeedRepeat && bWinding; bChanged |= bNeedRepeat; }while (bNeedRepeat); } // while (bNeedWindingRepeat) // Now process rings. Fix ring orientation and determine rings that need // to be deleted. m_shape.RemoveUserIndex(m_userIndexSortedIndexToVertex); m_shape.RemoveUserIndex(m_userIndexSortedAngleIndexToVertex); bChanged |= com.epl.geometry.RingOrientationFixer.Execute(m_shape, m_geometry, m_sortedVertices, m_fixSelfTangency); return(bChanged); }
internal virtual bool FixRingOrientation_() { bool bFound = false; if (m_fixSelfTangency) { bFound = FixRingSelfTangency_(); } if (m_shape.GetPathCount(m_geometry) == 1) { int path = m_shape.GetFirstPath(m_geometry); double area = m_shape.GetRingArea(path); m_shape.SetExterior(path, true); if (area < 0) { int first = m_shape.GetFirstVertex(path); m_shape.ReverseRingInternal_(first); m_shape.SetLastVertex_(path, m_shape.GetPrevVertex(first)); // fix // last // after // the // reverse return(true); } return(false); } m_path_orientation_index = m_shape.CreatePathUserIndex(); // used to // store // discovered // orientation // (3 - // extrior, // 2 - // interior) m_path_parentage_index = m_shape.CreatePathUserIndex(); // used to // resolve OGC // order for (int path_1 = m_shape.GetFirstPath(m_geometry); path_1 != -1; path_1 = m_shape.GetNextPath(path_1)) { m_shape.SetPathUserIndex(path_1, m_path_orientation_index, 0); m_shape.SetPathUserIndex(path_1, m_path_parentage_index, -1); } com.epl.geometry.AttributeStreamOfInt32 bunch = new com.epl.geometry.AttributeStreamOfInt32(0); m_y_scanline = com.epl.geometry.NumberUtils.TheNaN; com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); m_unknown_ring_orientation_count = m_shape.GetPathCount(m_geometry); m_node_1_user_index = m_shape.CreateUserIndex(); m_node_2_user_index = m_shape.CreateUserIndex(); for (int ivertex = m_sorted_vertices.GetFirst(m_sorted_vertices.GetFirstList()); ivertex != -1; ivertex = m_sorted_vertices.GetNext(ivertex)) { int vertex = m_sorted_vertices.GetData(ivertex); m_shape.GetXY(vertex, pt); if (pt.y != m_y_scanline && bunch.Size() != 0) { bFound |= ProcessBunchForRingOrientationTest_(bunch); m_sweep_comparator.Reset(); bunch.Clear(false); } bunch.Add(vertex); // all vertices that have same y are added to the // bunch m_y_scanline = pt.y; if (m_unknown_ring_orientation_count == 0) { break; } } if (m_unknown_ring_orientation_count > 0) { bFound |= ProcessBunchForRingOrientationTest_(bunch); bunch.Clear(false); } m_shape.RemoveUserIndex(m_node_1_user_index); m_shape.RemoveUserIndex(m_node_2_user_index); // dbg_verify_ring_orientation_();//debug for (int path_2 = m_shape.GetFirstPath(m_geometry); path_2 != -1;) { if (m_shape.GetPathUserIndex(path_2, m_path_orientation_index) == 3) { // exterior m_shape.SetExterior(path_2, true); int afterPath = path_2; for (int nextHole = m_shape.GetPathUserIndex(path_2, m_path_parentage_index); nextHole != -1;) { int p = m_shape.GetPathUserIndex(nextHole, m_path_parentage_index); m_shape.MovePath(m_geometry, m_shape.GetNextPath(afterPath), nextHole); afterPath = nextHole; nextHole = p; } path_2 = m_shape.GetNextPath(afterPath); } else { m_shape.SetExterior(path_2, false); path_2 = m_shape.GetNextPath(path_2); } } m_shape.RemovePathUserIndex(m_path_orientation_index); m_shape.RemovePathUserIndex(m_path_parentage_index); return(bFound); }