docs: void interpolateAttributesForClosedPath(int path, int from_vertex,
  			int to_vertex) {
  		assert (isClosedPath(path));
  
  		if (!m_b_has_attributes)
  			return;
  
  		double sub_length = calculateSubLength2D(path, from_vertex, to_vertex);
  
  		if (sub_length == 0.0)
  			return;
  
  		int nattr = m_vertex_description.getAttributeCount();
  
  		for (int iattr = 1; iattr < nattr; iattr++) {
  			int semantics = m_vertex_description.getSemantics(iattr);
  
  			int interpolation = VertexDescription.getInterpolation(semantics);
  			if (interpolation == VertexDescription.Interpolation.ANGULAR)
  				continue;
  
  			int components = VertexDescription.getComponentCount(semantics);
  
  			for (int ordinate = 0; ordinate < components; ordinate++)
  				interpolateAttributesForClosedPath_(semantics, path,
  						from_vertex, to_vertex, sub_length, ordinate);
  		}
  
  		return;
  	}
  
  	// calculates the length for the specified path between from_vertex and
  	// to_vertex
  	double calculateSubLength2D(int path, int from_vertex, int to_vertex) {
  		int shape_from_index = getVertexIndex(from_vertex);
  		int shape_to_index = getVertexIndex(to_vertex);
  
  		if (shape_from_index < 0 || shape_to_index > getTotalPointCount() - 1)
  			throw new IllegalArgumentException("invalid call");
  
  		if (shape_from_index > shape_to_index) {
  			if (!isClosedPath(path))
  				throw new IllegalArgumentException(
  						"cannot iterate across an open path");
  		}
  
  		double sub_length = 0.0;
  
  		for (int vertex = from_vertex; vertex != to_vertex; vertex = getNextVertex(vertex)) {
  			int vertex_index = getVertexIndex(vertex);
  			Segment segment = getSegmentFromIndex_(vertex_index);
  			if (segment != null) {
  				sub_length += segment.calculateLength2D();
  			} else {
  				int next_vertex_index = getVertexIndex(getNextVertex(vertex));
  				sub_length += m_vertices._getShortestDistance(vertex_index,
  						next_vertex_index);
  			}
  		}
  
  		return sub_length;
  	}
  
  	// set_point modifies the vertex and associated segments.
  	void setPoint(int vertex, Point new_coord) {
  		int vindex = getVertexIndex(vertex);
  		m_vertices.setPointByVal(vindex, new_coord);
  		Segment seg = getSegmentFromIndex_(vindex);
  		if (seg != null) {
  			seg.setStart(new_coord);
  		}
  		int prev = getPrevVertex(vertex);
  		if (prev != -1) {
  			int vindex_p = getVertexIndex(prev);
  			Segment seg_p = getSegmentFromIndex_(vindex_p);
  			if (seg_p != null) {
  				seg.setEnd(new_coord);
  			}
  		}
  	}
  
  	// Queries point for a given vertex.
  	void queryPoint(int vertex, Point point) {
  		int vindex = getVertexIndex(vertex);
  		m_vertices.getPointByVal(vindex, point);
  		// assert(getXY(vertex) == point.getXY());
  	}
  
  	// set_xy modifies the vertex and associated segments.
  	void setXY(int vertex, Point2D new_coord) {
  		setXY(vertex, new_coord.x, new_coord.y);
  	}
  
  	// set_xy modifies the vertex and associated segments.
  	void setXY(int vertex, double new_x, double new_y) {
  		int vindex = getVertexIndex(vertex);
  		m_vertices.setXY(vindex, new_x, new_y);
  		Segment seg = getSegmentFromIndex_(vindex);
  		if (seg != null) {
  			seg.setStartXY(new_x, new_y);
  		}
  		int prev = getPrevVertex(vertex);
  		if (prev != -1) {
  			int vindex_p = getVertexIndex(prev);
  			Segment seg_p = getSegmentFromIndex_(vindex_p);
  			if (seg_p != null) {
  				seg.setEndXY(new_x, new_y);
  			}
  		}
  	}
  
  	Point2D getXY(int vertex) {
  		Point2D pt = new Point2D();
  		int vindex = getVertexIndex(vertex);
  		pt.setCoords(m_vertices.getXY(vindex));
  		return pt;
  	}
  
  	// Returns the coordinates of the vertex.
  	void getXY(int vertex, Point2D ptOut) {
  		int vindex = getVertexIndex(vertex);
  		ptOut.setCoords(m_vertices.getXY(vindex));
  	}
  
  	void getXYWithIndex(int index, Point2D ptOut) {
  		m_xy_stream.read(2 * index, ptOut);
  	}
  
  	// Gets the attribute for the given semantics and ordinate.
  	double getAttributeAsDbl(int semantics, int vertex, int ordinate) {
  		return m_vertices.getAttributeAsDbl(semantics, getVertexIndex(vertex),
  				ordinate);
  	}
  
  	// Sets the attribute for the given semantics and ordinate.
  	void setAttribute(int semantics, int vertex, int ordinate, double value) {
  		m_vertices.setAttribute(semantics, getVertexIndex(vertex), ordinate,
  				value);
  	}
  
  	// Sets the attribute for the given semantics and ordinate.
  	void setAttribute(int semantics, int vertex, int ordinate, int value) {
  		m_vertices.setAttribute(semantics, getVertexIndex(vertex), ordinate,
  				value);
  	}
  
  	// Returns a reference to the vertex description
  	VertexDescription getVertexDescription() {
  		return m_vertex_description;
  	}
  
  	int getMinPathVertexY(int path) {
  		int first_vert = getFirstVertex(path);
  		int minv = first_vert;
  		int vert = getNextVertex(first_vert);
  		while (vert != -1 && vert != first_vert) {
  			if (compareVerticesSimpleY_(vert, minv) < 0)
  				minv = vert;
  			vert = getNextVertex(vert);
  		}
  		return minv;
  	}
  
  	// Returns an index value for the vertex inside of the underlying array of
  	// vertices.
  	// This index is for the use with the get_xy_with_index. get_xy is
  	// equivalent to calling get_vertex_index and get_xy_with_index.
  	int getVertexIndex(int vertex) {
  		return m_vertex_index_list.getField(vertex, 0);
  	}
  
  	// Returns the y coordinate of the vertex.
  	double getY(int vertex) {
  		Point2D pt = new Point2D();
  		getXY(vertex, pt);
  		return pt.y;
  	}
  
  	// returns True if xy coordinates at vertices are equal.
  	boolean isEqualXY(int vertex_1, int vertex_2) {
  		int vindex1 = getVertexIndex(vertex_1);
  		int vindex2 = getVertexIndex(vertex_2);
  		return m_vertices.getXY(vindex1).isEqual(m_vertices.getXY(vindex2));
  	}
  
  	// returns True if xy coordinates at vertices are equal.
  	boolean isEqualXY(int vertex, Point2D pt) {
  		int vindex = getVertexIndex(vertex);
  		return m_vertices.getXY(vindex).isEqual(pt);
  	}
  
  	// Sets weight to the vertex. Weight is used by clustering and cracking.
  	void setWeight(int vertex, double weight) {
  		if (weight < 1.0)
  			weight = 1.0;
  
  		if (m_weights == null) {
  			if (weight == 1.0)
  				return;
  
  			m_weights = (AttributeStreamOfDbl) (AttributeStreamBase
  					.createDoubleStream(m_vertices.getPointCount(), 1.0));
  		}
  
  		int vindex = getVertexIndex(vertex);
  		if (vindex >= m_weights.size()) {
  			m_weights.resize(vindex + 1, 1.0);
  		}
  		
  		m_weights.write(vindex, weight);
  	}
  
  	double getWeight(int vertex) {
  		int vindex = getVertexIndex(vertex);
  		if (m_weights == null || vindex >= m_weights.size())
  			return 1.0;
  		
  		return m_weights.read(vindex);
  	}
  
  	// Removes associated weights
  	void removeWeights() {
  		m_weights = null;
  	}
  
  	// Sets value to the given user index.
  	void setUserIndex(int vertex, int index, int value) {
  		// CHECKVERTEXHANDLE(vertex);
  		AttributeStreamOfInt32 stream = m_indices.get(index);
  		// assert(get_prev_vertex(vertex) != -0x7eadbeaf);//using deleted vertex
  		int vindex = getVertexIndex(vertex);
  		if (stream.size() < m_vertices.getPointCount())
  			stream.resize(m_vertices.getPointCount(), -1);
  		stream.write(vindex, value);
  	}
  
  	int getUserIndex(int vertex, int index) {
  		// CHECKVERTEXHANDLE(vertex);
  		int vindex = getVertexIndex(vertex);
  		AttributeStreamOfInt32 stream = m_indices.get(index);
  		if (vindex < stream.size()) {
  			int val = stream.read(vindex);
  			return val;
  		} else
  			return -1;
  	}