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