private boolean _cleanupSpikes() { boolean bModified = false; for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { int vertex = m_shape.getFirstVertex(path); for (int vindex = 0, n = m_shape.getPathSize(path); vindex < n && n > 1; ) { int prev = m_shape.getPrevVertex(vertex); int next = m_shape.getNextVertex(vertex); if (m_shape.isEqualXY(prev, next)) { bModified = true; _beforeRemoveVertex(vertex, false); m_shape.removeVertex(vertex, true); // not internal, because // path is valid at this // point _beforeRemoveVertex(next, false); m_shape.removeVertex(next, true); vertex = prev; vindex = 0; n = m_shape.getPathSize(path); } else { vertex = next; vindex++; } } if (m_shape.getPathSize(path) < 2) { int vertexL = m_shape.getFirstVertex(path); for (int vindex = 0, n = m_shape.getPathSize(path); vindex < n; vindex++) { _beforeRemoveVertex(vertexL, false); vertexL = m_shape.getNextVertex(vertexL); } path = m_shape.removePath(path); bModified = true; } else path = m_shape.getNextPath(path); } return bModified; }
private void _fixOrphanVertices() { int pathCount = 0; // clean any path info for (int node = m_sortedVertices.getFirst(m_sortedVertices.getFirstList()); node != -1; node = m_sortedVertices.getNext(node)) { int vertex = m_sortedVertices.getData(node); m_shape.setPathToVertex_(vertex, -1); } int geometrySize = 0; for (int path = m_shape.getFirstPath(m_geometry); path != -1; ) { int first = m_shape.getFirstVertex(path); if (first == -1 || m_shape.getPathFromVertex(first) != -1) { int p = path; path = m_shape.getNextPath(path); m_shape.removePathOnly_(p); continue; } m_shape.setPathToVertex_(first, path); int pathSize = 1; for (int vertex = m_shape.getNextVertex(first); vertex != first; vertex = m_shape.getNextVertex(vertex)) { // _ASSERT(m_shape.getPathFromVertex(vertex) == -1); m_shape.setPathToVertex_(vertex, path); // _ASSERT(m_shape.getNextVertex(m_shape.getPrevVertex(vertex)) // == vertex); pathSize++; } m_shape.setPathSize_(path, pathSize); m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); geometrySize += pathSize; pathCount++; path = m_shape.getNextPath(path); } // produce new paths for the orphan vertices. for (int node = m_sortedVertices.getFirst(m_sortedVertices.getFirstList()); node != -1; node = m_sortedVertices.getNext(node)) { int vertex = m_sortedVertices.getData(node); if (m_shape.getPathFromVertex(vertex) != -1) continue; int path = m_shape.insertPath(m_geometry, -1); int pathSize = 0; int first = vertex; while (true) { m_shape.setPathToVertex_(vertex, path); pathSize++; int next = m_shape.getNextVertex(vertex); // _ASSERT(m_shape.getNextVertex(m_shape.getPrevVertex(vertex)) // == vertex); if (next == first) break; vertex = next; } m_shape.setClosedPath(path, true); m_shape.setPathSize_(path, pathSize); m_shape.setFirstVertex_(path, first); m_shape.setLastVertex_(path, m_shape.getPrevVertex(first)); geometrySize += pathSize; pathCount++; } m_shape.setGeometryPathCount_(m_geometry, pathCount); int totalPointCount = m_shape.getTotalPointCount() - m_shape.getPointCount(m_geometry); m_shape.setGeometryVertexCount_(m_geometry, geometrySize); m_shape.setTotalPointCount_(totalPointCount + geometrySize); }
private boolean _simplify() { boolean bChanged = false; boolean bNeedWindingRepeat = true; boolean bWinding = false; m_userIndexSortedIndexToVertex = -1; m_userIndexSortedAngleIndexToVertex = -1; int pointCount = m_shape.getPointCount(m_geometry); // Sort vertices lexicographically // Firstly copy allvertices to an array. AttributeStreamOfInt32 verticesSorter = new 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 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 IndexMultiDCList(); m_sortedVerticesListIndex = m_sortedVertices.createList(0); for (int i = 0; i < pointCount; i++) { int vertex = verticesSorter.get(i); { // debug Point2D pt = new 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; boolean bNeedRepeat = false; // Internal iteration loop for the simplificator. // ST. I am not sure if it actually needs this loop. TODO: figure // this out. do // while (bNeedRepeat); { bNeedRepeat = false; boolean bVertexRecheck = false; m_firstCoincidentVertex = -1; int coincidentCount = 0; Point2D ptFirst = new Point2D(); Point2D pt = new 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 != 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) { boolean 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 != 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; } vlistindex = m_sortedVertices.getNext(vlistindex); } m_nextVertexToProcess = -1; if (coincidentCount > 0) { boolean result = _processBunch(); if (result) bNeedRepeat = true; } if (iRepeatNum++ > 10) { throw new GeometryException("internal error."); } 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 |= RingOrientationFixer.execute(m_shape, m_geometry, m_sortedVertices); return bChanged; }