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 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 virtual bool FixRingSelfTangency_() { com.epl.geometry.AttributeStreamOfInt32 self_tangent_paths = new com.epl.geometry.AttributeStreamOfInt32(0); com.epl.geometry.AttributeStreamOfInt32 self_tangency_clusters = new com.epl.geometry.AttributeStreamOfInt32(0); int tangent_path_first_vertex_index = -1; int tangent_vertex_cluster_index = -1; com.epl.geometry.Point2D pt_prev = new com.epl.geometry.Point2D(); pt_prev.SetNaN(); int prev_vertex = -1; int old_path = -1; int current_cluster = -1; com.epl.geometry.Point2D pt = new com.epl.geometry.Point2D(); 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); int path = m_shape.GetPathFromVertex(vertex); if (pt_prev.IsEqual(pt) && old_path == path) { if (tangent_vertex_cluster_index == -1) { tangent_path_first_vertex_index = m_shape.CreatePathUserIndex(); tangent_vertex_cluster_index = m_shape.CreateUserIndex(); } if (current_cluster == -1) { current_cluster = self_tangency_clusters.Size(); m_shape.SetUserIndex(prev_vertex, tangent_vertex_cluster_index, current_cluster); self_tangency_clusters.Add(1); int p = m_shape.GetPathUserIndex(path, tangent_path_first_vertex_index); if (p == -1) { m_shape.SetPathUserIndex(path, tangent_path_first_vertex_index, prev_vertex); self_tangent_paths.Add(path); } } m_shape.SetUserIndex(vertex, tangent_vertex_cluster_index, current_cluster); self_tangency_clusters.SetLast(self_tangency_clusters.GetLast() + 1); } else { current_cluster = -1; pt_prev.SetCoords(pt); } prev_vertex = vertex; old_path = path; } if (self_tangent_paths.Size() == 0) { return(false); } // Now self_tangent_paths contains list of clusters of tangency for each // path. // The clusters contains list of clusters and for each cluster it // contains a list of vertices. com.epl.geometry.AttributeStreamOfInt32 vertex_stack = new com.epl.geometry.AttributeStreamOfInt32(0); com.epl.geometry.AttributeStreamOfInt32 cluster_stack = new com.epl.geometry.AttributeStreamOfInt32(0); for (int ipath = 0, npath = self_tangent_paths.Size(); ipath < npath; ipath++) { int path = self_tangent_paths.Get(ipath); int first_vertex = m_shape.GetPathUserIndex(path, tangent_path_first_vertex_index); int cluster = m_shape.GetUserIndex(first_vertex, tangent_vertex_cluster_index); vertex_stack.Clear(false); cluster_stack.Clear(false); vertex_stack.Add(first_vertex); cluster_stack.Add(cluster); for (int vertex = m_shape.GetNextVertex(first_vertex); vertex != first_vertex; vertex = m_shape.GetNextVertex(vertex)) { int vertex_to = vertex; int cluster_to = m_shape.GetUserIndex(vertex_to, tangent_vertex_cluster_index); if (cluster_to != -1) { if (cluster_stack.Size() == 0) { cluster_stack.Add(cluster_to); vertex_stack.Add(vertex_to); continue; } if (cluster_stack.GetLast() == cluster_to) { int vertex_from = vertex_stack.GetLast(); // peel the loop from path int from_next = m_shape.GetNextVertex(vertex_from); int from_prev = m_shape.GetPrevVertex(vertex_from); int to_next = m_shape.GetNextVertex(vertex_to); int to_prev = m_shape.GetPrevVertex(vertex_to); m_shape.SetNextVertex_(vertex_from, to_next); m_shape.SetPrevVertex_(to_next, vertex_from); m_shape.SetNextVertex_(vertex_to, from_next); m_shape.SetPrevVertex_(from_next, vertex_to); // vertex_from is left in the path we are processing, // while the vertex_to is in the loop being teared off. bool[] first_vertex_correction_requied = new bool[] { false }; int new_path = m_shape.InsertClosedPath_(m_geometry, -1, from_next, m_shape.GetFirstVertex(path), first_vertex_correction_requied); m_shape.SetUserIndex(vertex, tangent_vertex_cluster_index, -1); // Fix the path after peeling if the peeled loop had the // first path vertex in it if (first_vertex_correction_requied[0]) { m_shape.SetFirstVertex_(path, to_next); } int path_size = m_shape.GetPathSize(path); int new_path_size = m_shape.GetPathSize(new_path); path_size -= new_path_size; System.Diagnostics.Debug.Assert((path_size >= 3)); m_shape.SetPathSize_(path, path_size); self_tangency_clusters.Set(cluster_to, self_tangency_clusters.Get(cluster_to) - 1); if (self_tangency_clusters.Get(cluster_to) == 1) { self_tangency_clusters.Set(cluster_to, 0); cluster_stack.RemoveLast(); vertex_stack.RemoveLast(); } // this cluster has more than two vertices in it. first_vertex = vertex_from; // reset the counter to // ensure we find all loops. vertex = vertex_from; } else { vertex_stack.Add(vertex); cluster_stack.Add(cluster_to); } } } } m_shape.RemovePathUserIndex(tangent_path_first_vertex_index); m_shape.RemoveUserIndex(tangent_vertex_cluster_index); return(true); }