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); }