Beispiel #1
0
        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);
        }
Beispiel #3
0
        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);
        }