converts the string from a polyline points-attribute to a string for a
    Path object d-attribute
344482
def polyline2pathd(polyline_d, is_polygon=False):
    """"""
    points = COORD_PAIR_TMPLT.findall(polyline_d)
    closed = (float(points[0][0]) == float(points[-1][0]) and
              float(points[0][1]) == float(points[-1][1]))

    # The `parse_path` call ignores redundant 'z' (closure) commands
    # e.g. `parse_path('M0 0L100 100Z') == parse_path('M0 0L100 100L0 0Z')`
    # This check ensures that an n-point polygon is converted to an n-Line path.
    if is_polygon and closed:
        points.append(points[0])

    d = 'M' + 'L'.join('{0} {1}'.format(x,y) for x,y in points)
    if is_polygon or closed:
        d += 'z'
    return d
1253634
def path_to_str(path):
    
    try:
        from pathlib import Path as _Path
    except ImportError:  # Python < 3.4
        class _Path:
            pass
    if isinstance(path, _Path):
        return str(path)
    return path
625217
void interpolateAttributes(int from_path_index, int from_point_index,
			int to_path_index, int to_point_index) {
		for (int ipath = from_path_index; ipath < to_path_index - 1; ipath++) {
			if (isClosedPath(ipath))
				throw new IllegalArgumentException(
						"cannot interpolate across closed paths");
		}

		int nattr = m_description.getAttributeCount();

		if (nattr == 1)
			return; // only has position

		double sub_length = calculateSubLength2D(from_path_index,
				from_point_index, to_path_index, to_point_index);

		if (sub_length == 0.0)
			return;

		for (int iattr = 1; iattr < nattr; iattr++) {
			int semantics = m_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++)
				interpolateAttributes_(semantics, from_path_index,
						from_point_index, to_path_index, to_point_index,
						sub_length, ordinate);
		}
	}

	// TODO: Add code for interpolation type (none and angular)
	void interpolateAttributesForSemantics(int semantics, int from_path_index,
			int from_point_index, int to_path_index, int to_point_index) {
		if (semantics == VertexDescription.Semantics.POSITION)
			return;

		if (!hasAttribute(semantics))
			throw new IllegalArgumentException(
					"does not have the given attribute");

		int interpolation = VertexDescription.getInterpolation(semantics);
		if (interpolation == VertexDescription.Interpolation.ANGULAR)
			throw new IllegalArgumentException(
					"not implemented for the given semantics");

		for (int ipath = from_path_index; ipath < to_path_index - 1; ipath++) {
			if (isClosedPath(ipath))
				throw new IllegalArgumentException(
						"cannot interpolate across closed paths");
		}

		double sub_length = calculateSubLength2D(from_path_index,
				from_point_index, to_path_index, to_point_index);

		if (sub_length == 0.0)
			return;

		int components = VertexDescription.getComponentCount(semantics);

		for (int ordinate = 0; ordinate < components; ordinate++)
			interpolateAttributes_(semantics, from_path_index,
					from_point_index, to_path_index, to_point_index,
					sub_length, ordinate);
	}

	void interpolateAttributes(int path_index, int from_point_index,
			int to_point_index) {
		int nattr = m_description.getAttributeCount();

		if (nattr == 1)
			return; // only has position

		double sub_length = calculateSubLength2D(path_index, from_point_index,
				to_point_index);

		if (sub_length == 0.0)
			return;

		for (int iattr = 1; iattr < nattr; iattr++) {
			int semantics = m_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++)
				interpolateAttributes_(semantics, path_index, from_point_index,
						to_point_index, sub_length, ordinate);
		}
	}

	void interpolateAttributesForSemantics(int semantics, int path_index,
			int from_point_index, int to_point_index) {
		if (semantics == VertexDescription.Semantics.POSITION)
			return;

		if (!hasAttribute(semantics))
			throw new IllegalArgumentException(
					"does not have the given attribute");

		int interpolation = VertexDescription.getInterpolation(semantics);
		if (interpolation == VertexDescription.Interpolation.ANGULAR)
			throw new IllegalArgumentException(
					"not implemented for the given semantics");

		double sub_length = calculateSubLength2D(path_index, from_point_index,
				to_point_index);

		if (sub_length == 0.0)
			return;

		int components = VertexDescription.getComponentCount(semantics);

		for (int ordinate = 0; ordinate < components; ordinate++)
			interpolateAttributes_(semantics, path_index, from_point_index,
					to_point_index, sub_length, ordinate);
	}

	// 
	void interpolateAttributes_(int semantics, int from_path_index,
			int from_point_index, int to_path_index, int to_point_index,
			double sub_length, int ordinate) {
		SegmentIteratorImpl seg_iter = querySegmentIterator();

		int absolute_from_index = getPathStart(from_path_index)
				+ from_point_index;
		int absolute_to_index = getPathStart(to_path_index) + to_point_index;

		double from_attribute = getAttributeAsDbl(semantics,
				absolute_from_index, ordinate);
		double to_attribute = getAttributeAsDbl(semantics, absolute_to_index,
				ordinate);
		double interpolated_attribute = from_attribute;
		double cumulative_length = 0.0;

		seg_iter.resetToVertex(absolute_from_index);

		do {
			if (seg_iter.hasNextSegment()) {
				seg_iter.nextSegment();

				if (seg_iter.getStartPointIndex() == absolute_to_index)
					return;

				setAttribute(semantics, seg_iter.getStartPointIndex(),
						ordinate, interpolated_attribute);

				seg_iter.previousSegment();

				do {
					Segment segment = seg_iter.nextSegment();

					if (seg_iter.getEndPointIndex() == absolute_to_index)
						return;

					double segment_length = segment.calculateLength2D();
					cumulative_length += segment_length;
					double t = cumulative_length / sub_length;
					interpolated_attribute = MathUtils.lerp(from_attribute,  to_attribute, t);

					if (!seg_iter.isClosingSegment())
						setAttribute(semantics, seg_iter.getEndPointIndex(),
								ordinate, interpolated_attribute);

				} while (seg_iter.hasNextSegment());
			}

		} while (seg_iter.nextPath());
	}

	void interpolateAttributes_(int semantics, int path_index,
			int from_point_index, int to_point_index, double sub_length,
			int ordinate) {
		assert (m_bPolygon);
		SegmentIteratorImpl seg_iter = querySegmentIterator();

		int absolute_from_index = getPathStart(path_index) + from_point_index;
		int absolute_to_index = getPathStart(path_index) + to_point_index;

		if (absolute_to_index == absolute_from_index)
			return;

		double from_attribute = getAttributeAsDbl(semantics,
				absolute_from_index, ordinate);
		double to_attribute = getAttributeAsDbl(semantics, absolute_to_index,
				ordinate);
		double cumulative_length = 0.0;

		seg_iter.resetToVertex(absolute_from_index);
		seg_iter.setCirculator(true);

		double prev_interpolated_attribute = from_attribute;

		do {
			Segment segment = seg_iter.nextSegment();
			setAttribute(semantics, seg_iter.getStartPointIndex(), ordinate,
					prev_interpolated_attribute);

			double segment_length = segment.calculateLength2D();
			cumulative_length += segment_length;
			double t = cumulative_length / sub_length;
			prev_interpolated_attribute = MathUtils.lerp(from_attribute, to_attribute, t);

		} while (seg_iter.getEndPointIndex() != absolute_to_index);
	}

	@Override
	public void setEmpty() {
		m_curveParamwritePoint = 0;
		m_bPathStarted = false;
		m_paths = null;
		m_pathFlags = null;
		m_segmentParamIndex = null;
		m_segmentFlags = null;
		m_segmentParams = null;
		_setEmptyImpl();
	}

	@Override
	public void applyTransformation(Transformation2D transform) {
		applyTransformation(transform, -1);
	}

	public void applyTransformation(Transformation2D transform, int pathIndex) {
		if (isEmpty())
			return;

		if (transform.isIdentity())
			return;

		_verifyAllStreams();
		AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0];
		Point2D ptStart = new Point2D();
		Point2D ptControl = new Point2D();

		boolean bHasNonLinear;
		int fistIdx;
		int lastIdx;
		if (pathIndex < 0) {
			bHasNonLinear = hasNonLinearSegments();
			fistIdx = 0;
			lastIdx = m_pointCount;
		} else {
			bHasNonLinear = hasNonLinearSegments(pathIndex);
			fistIdx = getPathStart(pathIndex);
			lastIdx = getPathEnd(pathIndex);
		}

		for (int ipoint = fistIdx; ipoint < lastIdx; ipoint++) {
			ptStart.x = points.read(ipoint * 2);
			ptStart.y = points.read(ipoint * 2 + 1);

			if (bHasNonLinear) {
				int segIndex = m_segmentParamIndex.read(ipoint);
				if (segIndex >= 0) {
					int segmentType = (int) m_segmentFlags.read(ipoint);
					int type = segmentType & SegmentFlags.enumSegmentMask;
					switch (type) {
					case SegmentFlags.enumBezierSeg: {
						ptControl.x = m_segmentParams.read(segIndex);
						ptControl.y = m_segmentParams.read(segIndex + 1);
						transform.transform(ptControl, ptControl);
						m_segmentParams.write(segIndex, ptControl.x);
						m_segmentParams.write(segIndex + 1, ptControl.y);

						ptControl.x = m_segmentParams.read(segIndex + 3);
						ptControl.y = m_segmentParams.read(segIndex + 4);
						transform.transform(ptControl, ptControl);
						m_segmentParams.write(segIndex + 3, ptControl.x);
						m_segmentParams.write(segIndex + 4, ptControl.y);
					}
						break;
					case SegmentFlags.enumArcSeg:
						throw GeometryException.GeometryInternalError();

					}
				}
			}

			transform.transform(ptStart, ptStart);
			points.write(ipoint * 2, ptStart.x);
			points.write(ipoint * 2 + 1, ptStart.y);
		}

		notifyModified(DirtyFlags.DirtyCoordinates);
		// REFACTOR: reset the exact envelope only and transform the loose
		// envelope
	}

	@Override
	public void applyTransformation(Transformation3D transform) {
		if (isEmpty())
			return;

		addAttribute(VertexDescription.Semantics.Z);
		_verifyAllStreams();
		AttributeStreamOfDbl points = (AttributeStreamOfDbl) m_vertexAttributes[0];
		AttributeStreamOfDbl zs = (AttributeStreamOfDbl) m_vertexAttributes[1];
		Point3D ptStart = new Point3D();
		Point3D ptControl = new Point3D();
		boolean bHasNonLinear = hasNonLinearSegments();
		for (int ipoint = 0; ipoint < m_pointCount; ipoint++) {
			ptStart.x = points.read(ipoint * 2);
			ptStart.y = points.read(ipoint * 2 + 1);
			ptStart.z = zs.read(ipoint);

			if (bHasNonLinear) {
				int segIndex = m_segmentParamIndex.read(ipoint);
				if (segIndex >= 0) {
					int segmentType = (int) m_segmentFlags.read(ipoint);
					int type = segmentType & (int) SegmentFlags.enumSegmentMask;
					switch (type) {
					case SegmentFlags.enumBezierSeg: {
						ptControl.x = m_segmentParams.read(segIndex);
						ptControl.y = m_segmentParams.read(segIndex + 1);
						ptControl.z = m_segmentParams.read(segIndex + 2);
						ptControl = transform.transform(ptControl);
						m_segmentParams.write(segIndex, ptControl.x);
						m_segmentParams.write(segIndex + 1, ptControl.y);
						m_segmentParams.write(segIndex + 1, ptControl.z);

						ptControl.x = m_segmentParams.read(segIndex + 3);
						ptControl.y = m_segmentParams.read(segIndex + 4);
						ptControl.z = m_segmentParams.read(segIndex + 5);
						ptControl = transform.transform(ptControl);
						m_segmentParams.write(segIndex + 3, ptControl.x);
						m_segmentParams.write(segIndex + 4, ptControl.y);
						m_segmentParams.write(segIndex + 5, ptControl.z);
					}
						break;
					case SegmentFlags.enumArcSeg:
						throw GeometryException.GeometryInternalError();

					}
				}
			}

			ptStart = transform.transform(ptStart);
			points.write(ipoint * 2, ptStart.x);
			points.write(ipoint * 2 + 1, ptStart.y);
			zs.write(ipoint, ptStart.z);
		}

		// REFACTOR: reset the exact envelope only and transform the loose
		// envelope

		notifyModified(DirtyFlags.DirtyCoordinates);
	}

	@Override
	protected void _verifyStreamsImpl() {
		if (m_paths == null) {
			m_paths = (AttributeStreamOfInt32) AttributeStreamBase
					.createIndexStream(1, 0);
			m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase
					.createByteStream(1, (byte) 0);
		}

		if (m_segmentFlags != null) {
			m_segmentFlags.resize(m_reservedPointCount,
					(byte) SegmentFlags.enumLineSeg);
			m_segmentParamIndex.resize(m_reservedPointCount, -1);
		}
	}

	@Override
	void _copyToImpl(MultiVertexGeometryImpl dst) {
		MultiPathImpl dstPoly = (MultiPathImpl) dst;
		dstPoly.m_bPathStarted = false;
		dstPoly.m_curveParamwritePoint = m_curveParamwritePoint;
		dstPoly.m_fill_rule = m_fill_rule;
		
		if (m_paths != null)
			dstPoly.m_paths = new AttributeStreamOfInt32(m_paths);
		else
			dstPoly.m_paths = null;

		if (m_pathFlags != null)
			dstPoly.m_pathFlags = new AttributeStreamOfInt8(m_pathFlags);
		else
			dstPoly.m_pathFlags = null;

		if (m_segmentParamIndex != null)
			dstPoly.m_segmentParamIndex = new AttributeStreamOfInt32(
					m_segmentParamIndex);
		else
			dstPoly.m_segmentParamIndex = null;

		if (m_segmentFlags != null)
			dstPoly.m_segmentFlags = new AttributeStreamOfInt8(m_segmentFlags);
		else
			dstPoly.m_segmentFlags = null;

		if (m_segmentParams != null)
			dstPoly.m_segmentParams = new AttributeStreamOfDbl(m_segmentParams);
		else
			dstPoly.m_segmentParams = null;

		dstPoly.m_cachedLength2D = m_cachedLength2D;
		dstPoly.m_cachedArea2D = m_cachedArea2D;

		if (!_hasDirtyFlag(DirtyFlags.DirtyRingAreas2D)) {
			dstPoly.m_cachedRingAreas2D = (AttributeStreamOfDbl) m_cachedRingAreas2D;
		} else
			dstPoly.m_cachedRingAreas2D = null;

	}

	@Override
	public double calculateLength2D() {
		if (!_hasDirtyFlag(DirtyFlags.DirtyLength2D)) {
			return m_cachedLength2D;
		}

		SegmentIteratorImpl segIter = querySegmentIterator();
		MathUtils.KahanSummator len = new MathUtils.KahanSummator(0);
		while (segIter.nextPath()) {
			while (segIter.hasNextSegment()) {
				len.add(segIter.nextSegment().calculateLength2D());
			}
		}

		m_cachedLength2D = len.getResult();
		_setDirtyFlag(DirtyFlags.DirtyLength2D, false);

		return len.getResult();
	}

	@Override
	public boolean equals(Object other) {
		if (other == this)
			return true;

		if (!(other instanceof MultiPathImpl))
			return false;

		if (!super.equals(other))
			return false;

		MultiPathImpl otherMultiPath = (MultiPathImpl) other;

		int pathCount = getPathCount();
		int pathCountOther = otherMultiPath.getPathCount();

		if (pathCount != pathCountOther)
			return false;

		if (pathCount > 0 && m_paths != null
				&& !m_paths.equals(otherMultiPath.m_paths, 0, pathCount + 1))
			return false;

		if (m_fill_rule != otherMultiPath.m_fill_rule)
			return false;

		{
			// Note: OGC flags do not participate in the equals operation by
			// design.
			// Because for the polygon pathFlags will have all enum_closed set,
			// we do not need to compare this stream. Only for polyline.
			// Polyline does not have OGC flags set.
			if (!m_bPolygon) {
				if (m_pathFlags != null
						&& !m_pathFlags.equals(otherMultiPath.m_pathFlags, 0,
								pathCount))
					return false;
			}
		}
	      
		return super.equals(other);
	}

	/**
	 * Returns a SegmentIterator that set to a specific vertex of the
	 * MultiPathImpl. The call to NextSegment will return the segment that
	 * starts at the vertex. Call to PreviousSegment will return the segment
	 * that starts at the previous vertex.
	 */
	public SegmentIteratorImpl querySegmentIteratorAtVertex(int startVertexIndex) {
		if (startVertexIndex < 0 || startVertexIndex >= getPointCount())
			throw new IndexOutOfBoundsException();

		SegmentIteratorImpl iter = new SegmentIteratorImpl(this,
				startVertexIndex);
		return iter;
	}

	// void QuerySegmentIterator(int fromVertex, SegmentIterator iterator);
	public SegmentIteratorImpl querySegmentIterator() {
		return new SegmentIteratorImpl(this);
	}

	@Override
	public void _updateXYImpl(boolean bExact) {
		super._updateXYImpl(bExact);
		boolean bHasCurves = hasNonLinearSegments();
		if (bHasCurves) {
			SegmentIteratorImpl segIter = querySegmentIterator();
			while (segIter.nextPath()) {
				while (segIter.hasNextSegment()) {
					Segment curve = segIter.nextCurve();
					if (curve != null) {
						Envelope2D env2D = new Envelope2D();
						curve.queryEnvelope2D(env2D);
						m_envelope.merge(env2D);
					} else
						break;
				}
			}
		}
	}

	@Override
	void calculateEnvelope2D(Envelope2D env, boolean bExact) {
		super.calculateEnvelope2D(env, bExact);
		boolean bHasCurves = hasNonLinearSegments();
		if (bHasCurves) {
			SegmentIteratorImpl segIter = querySegmentIterator();
			while (segIter.nextPath()) {
				while (segIter.hasNextSegment()) {
					Segment curve = segIter.nextCurve();
					if (curve != null) {
						Envelope2D env2D = new Envelope2D();
						curve.queryEnvelope2D(env2D);
						env.merge(env2D);
					} else
						break;
				}
			}
		}
	}

	@Override
	public void _notifyModifiedAllImpl() {
		if (m_paths == null || m_paths.size() == 0)// if (m_paths == null ||
													// !m_paths.size())
			m_pointCount = 0;
		else
			m_pointCount = m_paths.read(m_paths.size() - 1);
	}

	@Override
	public double calculateArea2D() {
		if (!m_bPolygon)
			return 0.0;

		_updateRingAreas2D();

		return m_cachedArea2D;
	}

	/**
	 * Returns True if the ring is an exterior ring. Valid only for simple
	 * polygons.
	 */
	public boolean isExteriorRing(int ringIndex) {
		if (!m_bPolygon)
			return false;

		if (!_hasDirtyFlag(DirtyFlags.DirtyOGCFlags))
			return (m_pathFlags.read(ringIndex) & (byte) PathFlags.enumOGCStartPolygon) != 0;

		_updateRingAreas2D();
		return m_cachedRingAreas2D.read(ringIndex) > 0;
		// Should we make a function called _UpdateHasNonLinearSegmentsFlags and
		// call it here?
	}

	public double calculateRingArea2D(int pathIndex) {
		if (!m_bPolygon)
			return 0.0;

		_updateRingAreas2D();

		return m_cachedRingAreas2D.read(pathIndex);
	}

	public void _updateRingAreas2D() {
		if (_hasDirtyFlag(DirtyFlags.DirtyRingAreas2D)) {
			int pathCount = getPathCount();

			if (m_cachedRingAreas2D == null)
				m_cachedRingAreas2D = new AttributeStreamOfDbl(pathCount);
			else if (m_cachedRingAreas2D.size() != pathCount)
				m_cachedRingAreas2D.resize(pathCount);

			MathUtils.KahanSummator totalArea = new MathUtils.KahanSummator(0);
			MathUtils.KahanSummator pathArea = new MathUtils.KahanSummator(0);
			Point2D pt = new Point2D();
			int ipath = 0;
			SegmentIteratorImpl segIter = querySegmentIterator();
			while (segIter.nextPath()) {
				pathArea.reset();
				getXY(getPathStart(segIter.getPathIndex()), pt);// get the area
																// calculation
																// origin to be
																// the origin of
																// the ring.
				while (segIter.hasNextSegment()) {
					pathArea.add(segIter.nextSegment()._calculateArea2DHelper(
							pt.x, pt.y));
				}

				totalArea.add(pathArea.getResult());

				int i = ipath++;
				m_cachedRingAreas2D.write(i, pathArea.getResult());
			}

			m_cachedArea2D = totalArea.getResult();
			_setDirtyFlag(DirtyFlags.DirtyRingAreas2D, false);
		}
	}

	int getOGCPolygonCount() {
		if (!m_bPolygon)
			return 0;

		_updateOGCFlags();

		int polygonCount = 0;
		int partCount = getPathCount();
		for (int ipart = 0; ipart < partCount; ipart++) {
			if (((int) m_pathFlags.read(ipart) & (int) PathFlags.enumOGCStartPolygon) != 0)
				polygonCount++;
		}

		return polygonCount;
	}

	protected void _updateOGCFlags() {
		if (_hasDirtyFlag(DirtyFlags.DirtyOGCFlags)) {
			_updateRingAreas2D();

			int pathCount = getPathCount();
			if (pathCount > 0 && (m_pathFlags == null || m_pathFlags.size() < pathCount))
				m_pathFlags = (AttributeStreamOfInt8) AttributeStreamBase
						.createByteStream(pathCount + 1);

			int firstSign = 1;
			for (int ipath = 0; ipath < pathCount; ipath++) {
				double area = m_cachedRingAreas2D.read(ipath);
				if (ipath == 0)
					firstSign = area > 0 ? 1 : -1;
				if (area * firstSign > 0.0)
					m_pathFlags.setBits(ipath,
							(byte) PathFlags.enumOGCStartPolygon);
				else
					m_pathFlags.clearBits(ipath,
							(byte) PathFlags.enumOGCStartPolygon);
			}
			_setDirtyFlag(DirtyFlags.DirtyOGCFlags, false);
		}
	}

	public int getPathIndexFromPointIndex(int pointIndex) {
		int positionHint = m_currentPathIndex;// in case of multithreading
												// thiswould simply produce an
												// invalid value
		int pathCount = getPathCount();

		// Try using the hint position first to get the path index.
		if (positionHint >= 0 && positionHint < pathCount) {
			if (pointIndex < getPathEnd(positionHint)) {
				if (pointIndex >= getPathStart(positionHint))
					return positionHint;
				positionHint--;
			} else {
				positionHint++;
			}

			if (positionHint >= 0 && positionHint < pathCount) {
				if (pointIndex >= getPathStart(positionHint)
						&& pointIndex < getPathEnd(positionHint)) {
					m_currentPathIndex = positionHint;
					return positionHint;
				}
			}
		}

		if (pathCount < 5) {// TODO: time the performance to choose when to use
							// linear search.
			for (int i = 0; i < pathCount; i++) {
				if (pointIndex < getPathEnd(i)) {
					m_currentPathIndex = i;
					return i;
				}
			}
			throw new GeometryException("corrupted geometry");
		}

		// Do binary search:
		int minPathIndex = 0;
		int maxPathIndex = pathCount - 1;
		while (maxPathIndex > minPathIndex) {
			int mid = minPathIndex + ((maxPathIndex - minPathIndex) >> 1);
			int pathStart = getPathStart(mid);
			if (pointIndex < pathStart)
				maxPathIndex = mid - 1;
			else {
				int pathEnd = getPathEnd(mid);
				if (pointIndex >= pathEnd)
					minPathIndex = mid + 1;
				else {
					m_currentPathIndex = mid;
					return mid;
				}
			}
		}

		m_currentPathIndex = minPathIndex;
		return minPathIndex;
	}

	int getHighestPointIndex(int path_index) {
		assert (path_index >= 0 && path_index < getPathCount());

		AttributeStreamOfDbl position = (AttributeStreamOfDbl) (getAttributeStreamRef(VertexDescription.Semantics.POSITION));
		AttributeStreamOfInt32 paths = (AttributeStreamOfInt32) (getPathStreamRef());

		int path_end = getPathEnd(path_index);
		int path_start = getPathStart(path_index);
		int max_index = -1;
		Point2D max_point = new Point2D(), pt = new Point2D();
		max_point.y = NumberUtils.negativeInf();
		max_point.x = NumberUtils.negativeInf();

		for (int i = path_start + 0; i < path_end; i++) {
			position.read(2 * i, pt);
			if (max_point.compare(pt) == -1) {
				max_index = i;
				max_point.setCoords(pt);
			}
		}

		return max_index;
	}

	/**
	 * Returns total segment count in the MultiPathImpl.
	 */
	public int getSegmentCount() {
		int segCount = getPointCount();
		if (!m_bPolygon) {
			segCount -= getPathCount();
			for (int i = 0, n = getPathCount(); i < n; i++)
				if (isClosedPath(i))
					segCount++;
		}

		return segCount;
	}

	public int getSegmentCount(int path_index) {
		int segCount = getPathSize(path_index);
		if (!isClosedPath(path_index))
			segCount--;
		return segCount;
	}

	// HEADER defintions
	@Override
	public Geometry createInstance() {
		return new MultiPathImpl(m_bPolygon, getDescription());
	}

	@Override
	public int getDimension() {
		return m_bPolygon ? 2 : 1;
	}

	@Override
	public Geometry.Type getType() {
		return m_bPolygon ? Type.Polygon : Type.Polyline;
	}

	/**
	 * Returns True if the class is envelope. THis is not an exact method. Only
	 * addEnvelope makes this true.
	 */
	public boolean isEnvelope() {
		return !_hasDirtyFlag(DirtyFlags.DirtyIsEnvelope);
	}

	/**
	 * Returns a reference to the AttributeStream of MultiPathImpl parts
	 * (Paths).
	 * 
	 * For the non empty MultiPathImpl, that stream contains start points of the
	 * MultiPathImpl curves. In addition, the last element is the total point
	 * count. The number of vertices in a given part is parts[i + 1] - parts[i].
	 */
	public AttributeStreamOfInt32 getPathStreamRef() {
		throwIfEmpty();
		return m_paths;
	}

	/**
	 * sets a reference to an AttributeStream of MultiPathImpl paths (Paths).
	 */
	public void setPathStreamRef(AttributeStreamOfInt32 paths) {
		m_paths = paths;
		notifyModified(DirtyFlags.DirtyAll);
	}

	/**
	 * Returns a reference to the AttributeStream of Segment flags (SegmentFlags
	 * flags). Can be NULL when no non-linear segments are present.
	 * 
	 * Segment flags indicate what kind of segment originates (starts) on the
	 * given point. The last vertices of open Path parts has enumNone flag.
	 */
	public AttributeStreamOfInt8 getSegmentFlagsStreamRef() {
		throwIfEmpty();
		return m_segmentFlags;
	}

	/**
	 * Returns a reference to the AttributeStream of Path flags (PathFlags
	 * flags).
	 * 
	 * Each start point of a path has a flag set to indicate if the Path is open
	 * or closed.
	 */
	public AttributeStreamOfInt8 getPathFlagsStreamRef() {
		throwIfEmpty();
		return m_pathFlags;
	}

	/**
	 * sets a reference to an AttributeStream of Path flags (PathFlags flags).
	 */
	public void setPathFlagsStreamRef(AttributeStreamOfInt8 pathFlags) {
		m_pathFlags = pathFlags;
		notifyModified(DirtyFlags.DirtyAll);
	}

	public AttributeStreamOfInt32 getSegmentIndexStreamRef() {
		throwIfEmpty();
		return m_segmentParamIndex;
	}

	public AttributeStreamOfDbl getSegmentDataStreamRef() {
		throwIfEmpty();
		return m_segmentParams;
	}

	public int getPathCount() {
		return (m_paths != null) ? m_paths.size() - 1 : 0;
	}

	public int getPathEnd(int partIndex) {
		return m_paths.read(partIndex + 1);
	}

	public int getPathSize(int partIndex) {
		return m_paths.read(partIndex + 1) - m_paths.read(partIndex);
	}

	public int getPathStart(int partIndex) {
		return m_paths.read(partIndex);
	}

	@Override
	public Object _getImpl() {
		return this;
	}

	public void setDirtyOGCFlags(boolean bYesNo) {
		_setDirtyFlag(DirtyFlags.DirtyOGCFlags, bYesNo);
	}

	public boolean hasDirtyOGCStartFlags() {
		return _hasDirtyFlag(DirtyFlags.DirtyOGCFlags);
	}

	public void setDirtyRingAreas2D(boolean bYesNo) {
		_setDirtyFlag(DirtyFlags.DirtyRingAreas2D, bYesNo);
	}

	public boolean hasDirtyRingAreas2D() {
		return _hasDirtyFlag(DirtyFlags.DirtyRingAreas2D);
	}

	public void setRingAreasStreamRef(AttributeStreamOfDbl ringAreas) {
		m_cachedRingAreas2D = ringAreas;
		_setDirtyFlag(DirtyFlags.DirtyRingAreas2D, false);
	}

	// HEADER defintions

	// // TODO check this against current implementation in native
	// public void notifyModified(int flags)
	// {
	// if(flags == DirtyFlags.DirtyAll)
	// {
	// m_reservedPointCount = -1;
	// _notifyModifiedAllImpl();
	// }
	// m_flagsMask |= flags;
	// _clearAccelerators();
	//
	//
	// // ROHIT's implementation
	// // if (m_paths == null || 0 == m_paths.size())
	// // m_pointCount = 0;
	// // else
	// // m_pointCount = m_paths.read(m_paths.size() - 1);
	// //
	// // super.notifyModified(flags);
	// }

	@Override
	public boolean _buildRasterizedGeometryAccelerator(double toleranceXY,
			GeometryAccelerationDegree accelDegree) {
		if (m_accelerators == null)// (!m_accelerators)
		{
			m_accelerators = new GeometryAccelerators();
		}

		int rasterSize = RasterizedGeometry2D
				.rasterSizeFromAccelerationDegree(accelDegree);
		RasterizedGeometry2D rgeom = m_accelerators.getRasterizedGeometry();
		if (rgeom != null) {
			if (rgeom.getToleranceXY() < toleranceXY
					|| rasterSize > rgeom.getRasterSize()) {
				m_accelerators._setRasterizedGeometry(null);
			} else
				return true;
		}

		rgeom = RasterizedGeometry2D.create(this, toleranceXY, rasterSize);
		m_accelerators._setRasterizedGeometry(rgeom);
		//rgeom.dbgSaveToBitmap("c:/temp/ddd.bmp");
		return true;
	}

	@Override
	public int hashCode() {
		int hashCode = super.hashCode();

		if (!isEmptyImpl()) {
			int pathCount = getPathCount();

			if (m_paths != null)
				m_paths.calculateHashImpl(hashCode, 0, pathCount + 1);

			if (m_pathFlags != null)
				m_pathFlags.calculateHashImpl(hashCode, 0, pathCount);
		}

		return hashCode;
	}

	public byte getSegmentFlags(int ivertex) {
		if (m_segmentFlags != null)
			return m_segmentFlags.read(ivertex);
		else
			return (byte) SegmentFlags.enumLineSeg;
	}

	public void getSegment(int startVertexIndex, SegmentBuffer segBuffer,
			boolean bStripAttributes) {
		int ipath = getPathIndexFromPointIndex(startVertexIndex);
		if (startVertexIndex == getPathEnd(ipath) - 1 && !isClosedPath(ipath))
			throw new GeometryException("index out of bounds");

		_verifyAllStreams();
		AttributeStreamOfInt8 segFlagStream = getSegmentFlagsStreamRef();
		int segFlag = SegmentFlags.enumLineSeg;
		if (segFlagStream != null)
			segFlag = segFlagStream.read(startVertexIndex)
					& SegmentFlags.enumSegmentMask;

		switch (segFlag) {
		case SegmentFlags.enumLineSeg:
			segBuffer.createLine();
			break;
		case SegmentFlags.enumBezierSeg:
			throw GeometryException.GeometryInternalError();
		case SegmentFlags.enumArcSeg:
			throw GeometryException.GeometryInternalError();
		default:
			throw GeometryException.GeometryInternalError();
		}

		Segment currentSegment = segBuffer.get();
		if (!bStripAttributes)
			currentSegment.assignVertexDescription(m_description);
		else
			currentSegment
					.assignVertexDescription(VertexDescriptionDesignerImpl
							.getDefaultDescriptor2D());

		int endVertexIndex;
		if (startVertexIndex == getPathEnd(ipath) - 1 && isClosedPath(ipath)) {
			endVertexIndex = getPathStart(ipath);
		} else
			endVertexIndex = startVertexIndex + 1;

		Point2D pt = new Point2D();
		getXY(startVertexIndex, pt);
		currentSegment.setStartXY(pt);
		getXY(endVertexIndex, pt);
		currentSegment.setEndXY(pt);

		if (!bStripAttributes) {
			for (int i = 1, nattr = m_description.getAttributeCount(); i < nattr; i++) {
				int semantics = m_description._getSemanticsImpl(i);
				int ncomp = VertexDescription.getComponentCount(semantics);
				for (int ord = 0; ord < ncomp; ord++) {
					double vs = getAttributeAsDbl(semantics, startVertexIndex,
							ord);
					currentSegment.setStartAttribute(semantics, ord, vs);
					double ve = getAttributeAsDbl(semantics, endVertexIndex,
							ord);
					currentSegment.setEndAttribute(semantics, ord, ve);
				}
			}
		}
	}

	void queryPathEnvelope2D(int path_index, Envelope2D envelope) {
		if (path_index >= getPathCount())
			throw new IllegalArgumentException();

		if (isEmpty()) {
			envelope.setEmpty();
			return;
		}

		if (hasNonLinearSegments(path_index)) {
			throw new GeometryException("not implemented");
		} else {
			AttributeStreamOfDbl stream = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION);
			Point2D pt = new Point2D();
			Envelope2D env = new Envelope2D();
			env.setEmpty();
			for (int i = getPathStart(path_index), iend = getPathEnd(path_index); i < iend; i++) {
				stream.read(2 * i, pt);
				env.merge(pt);
			}
			envelope.setCoords(env);
		}
	}

	public void queryLoosePathEnvelope2D(int path_index, Envelope2D envelope) {
		if (path_index >= getPathCount())
			throw new IllegalArgumentException();

		if (isEmpty()) {
			envelope.setEmpty();
			return;
		}

		if (hasNonLinearSegments(path_index)) {
			throw new GeometryException("not implemented");
		} else {
			AttributeStreamOfDbl stream = (AttributeStreamOfDbl) getAttributeStreamRef(VertexDescription.Semantics.POSITION);
			Point2D pt = new Point2D();
			Envelope2D env = new Envelope2D();
			env.setEmpty();
			for (int i = getPathStart(path_index), iend = getPathEnd(path_index); i < iend; i++) {
				stream.read(2 * i, pt);
				env.merge(pt);
			}
			envelope.setCoords(env);
		}
	}
	
	@Override
	public boolean _buildQuadTreeAccelerator(GeometryAccelerationDegree d) {
		if (m_accelerators == null)// (!m_accelerators)
		{
			m_accelerators = new GeometryAccelerators();
		}

		if (d == GeometryAccelerationDegree.enumMild || getPointCount() < 16)
			return false;

		QuadTreeImpl quad_tree_impl = InternalUtils.buildQuadTree(this);
		m_accelerators._setQuadTree(quad_tree_impl);

		return true;
	}

	boolean _buildQuadTreeForPathsAccelerator(GeometryAccelerationDegree degree) {
		if (m_accelerators == null) {
			m_accelerators = new GeometryAccelerators();
		}

		// TODO: when less than two envelopes - no need to this.

		if (m_accelerators.getQuadTreeForPaths() != null)
			return true;

		m_accelerators._setQuadTreeForPaths(null);
		QuadTreeImpl quad_tree_impl = InternalUtils.buildQuadTreeForPaths(this);
		m_accelerators._setQuadTreeForPaths(quad_tree_impl);

		return true;
	}

	void setFillRule(int rule) {
		assert (m_bPolygon);
		m_fill_rule = rule;
	}

	int getFillRule() {
		return m_fill_rule;
	}

	void clearDirtyOGCFlags() { 
		_setDirtyFlag(DirtyFlags.DirtyOGCFlags, false);
	}
}
837169
def get_pltdotstr(self, **kws_usr):
        """"""
        dotstrs = self.get_pltdotstrs(**kws_usr)
        assert len(dotstrs) == 1
        return dotstrs[0]
17226
def import_string(impstr, attr=None):
    
    if "::" in impstr:
        impstr, attr = impstr.split("::")
    imported = wz_import_string(impstr)
    if attr is not None:
        return getobjpath(imported, attr)
    return imported
60745
function convertPaths(path) {
  var pathTemplate = new URITemplate(path).parse(), // must call parse to populate parts
    expressPath = '';

  _.forEach(pathTemplate.parts, function (part) {
    switch (typeof part) {
      case 'string':
        if (part.length > 0) {
          expressPath += part;
        }
        break;
      case 'object':
        if (part.expression.length > 0 && part.expression.match(PATH_REGEX)) {
          expressPath += ':' + _.first(part.variables).name;
        }
        break;
      default:
      // TODO throw error
    }
  });

  return expressPath;
}
1162875
def set_path(self, path, val):
        
        path = tuple(path.split('.')) if isinstance(path , str) else tuple(path)

        disallowed = [p for p in path if not type(self)._sanitizer.allowable(p)]
        if any(disallowed):
            raise Exception("Attribute strings in path elements cannot be "
                            "correctly escaped : %s" % ','.join(repr(el) for el in disallowed))
        if len(path) > 1:
            attrtree = self.__getattr__(path[0])
            attrtree.set_path(path[1:], val)
        else:
            self.__setattr__(path[0], val)
393481
function() {
    // convert to a poly point string
    for (var i = 0, il = this.value.length, array = []; i < il; i++)
      array.push(this.value[i].join(','))

    return array.join(' ')
  }
201346
function parseAttributePath(attrPath, context) {
    const parsed = attrPath.split('.');
    parsed.forEach(item => checkIdentifier(item, context));
    return parsed;
}
545900
function parsePointsAttribute(points) {

    // points attribute is required and must not be empty
    if (!points) return null;

    points = points.trim();
    var asPairs = points.indexOf(',') > -1;

    points = points.split(/\s+/);
    var parsedPoints = [ ];

    // points could look like "10,20 30,40" or "10 20 30 40"
    if (asPairs) {
     for (var i = 0, len = points.length; i < len; i++) {
       var pair = points[i].split(',');
       parsedPoints.push({ x: parseFloat(pair[0]), y: parseFloat(pair[1]) });
     }
    }
    else {
      for (var i = 0, len = points.length; i < len; i+=2) {
        parsedPoints.push({ x: parseFloat(points[i]), y: parseFloat(points[i+1]) });
      }
    }

    // odd number of points is an error
    if (parsedPoints.length % 2 !== 0) {
      // return null;
    }

    return parsedPoints;
  }
1272855
function generatePathString(paths) {
  let pathString = '';

  if (!paths || !paths.length) return pathString;

  if (paths.length > 1) {
    pathString = paths.map(pathItem => filepathName(pathItem));
    // Trim long lists
    if (pathString.length > maxInputStringLength) {
      const remainder = pathString.length - maxInputStringLength;

      pathString = `${pathString
        .slice(0, maxInputStringLength)
        .join(', ')} ...and ${remainder} other${remainder > 1 ? 's' : ''}`;
    } else {
      pathString = pathString.join(', ');
    }
  } else {
    pathString = filepathName(paths[0]);
  }

  return pathString;
}
318259
def to_string(self):
        """"""


        # RMF: special case defaults for node, edge and graph properties.
        #
        node = quote_if_necessary(self.obj_dict['name'])

        node_attr = list()

        for attr in sorted(self.obj_dict['attributes']):
            value = self.obj_dict['attributes'][attr]
            if value == '':
                value = '""'
            if value is not None:
                node_attr.append(
                    '%s=%s' % (attr, quote_if_necessary(value) ) )
            else:
                node_attr.append( attr )


        # No point in having nodes setting any defaults if the don't set
        # any attributes...
        #
        if node in ('graph', 'node', 'edge') and len(node_attr) == 0:
            return ''

        node_attr = ', '.join(node_attr)

        if node_attr:
            node += ' [' + node_attr + ']'

        return node + ';'
18176
def _dump_multilinestring(obj, big_endian, meta):
    
    coords = obj['coordinates']
    vertex = coords[0][0]
    num_dims = len(vertex)

    wkb_string, byte_fmt, byte_order = _header_bytefmt_byteorder(
        'MultiLineString', num_dims, big_endian, meta
    )

    ls_type = _WKB[_INT_TO_DIM_LABEL.get(num_dims)]['LineString']
    if big_endian:
        ls_type = BIG_ENDIAN + ls_type
    else:
        ls_type = LITTLE_ENDIAN + ls_type[::-1]

    # append the number of linestrings
    wkb_string += struct.pack('%sl' % byte_order, len(coords))

    for linestring in coords:
        wkb_string += ls_type
        # append the number of vertices in each linestring
        wkb_string += struct.pack('%sl' % byte_order, len(linestring))
        for vertex in linestring:
            wkb_string += struct.pack(byte_fmt, *vertex)

    return wkb_string
1055011
private void  parseAttributesPolyLine(SVG.PolyLine obj, Attributes attributes, String tag) throws SVGParseException
   {
      for (int i=0; i<attributes.getLength(); i++)
      {
         if (SVGAttr.fromString(attributes.getLocalName(i)) == SVGAttr.points)
         {
            TextScanner scan = new TextScanner(attributes.getValue(i));
            List<Float> points = new ArrayList<>();
            scan.skipWhitespace();

            while (!scan.empty()) {
               float x = scan.nextFloat();
               if (Float.isNaN(x))
                  throw new SVGParseException("Invalid <"+tag+"> points attribute. Non-coordinate content found in list.");
               scan.skipCommaWhitespace();
               float y = scan.nextFloat();
               if (Float.isNaN(y))
                  throw new SVGParseException("Invalid <"+tag+"> points attribute. There should be an even number of coordinates.");
               scan.skipCommaWhitespace();
               points.add(x);
               points.add(y);
            }
            obj.points = new float[points.size()];
            int j = 0;
            for (float f: points) {
               obj.points[j++] = f;
            }
         }
      }
   }
330938
private static SVG.PathDefinition  parsePath(String val)
   {
      TextScanner  scan = new TextScanner(val);

      float   currentX = 0f, currentY = 0f;    // The last point visited in the subpath
      float   lastMoveX = 0f, lastMoveY = 0f;  // The initial point of current subpath
      float   lastControlX = 0f, lastControlY = 0f;  // Last control point of the just completed bezier curve.
      float   x,y, x1,y1, x2,y2;
      float   rx,ry, xAxisRotation;
      Boolean largeArcFlag, sweepFlag;

      SVG.PathDefinition  path = new SVG.PathDefinition();

      if (scan.empty())
         return path;

      int  pathCommand = scan.nextChar();

      if (pathCommand != 'M' && pathCommand != 'm')
         return path;  // Invalid path - doesn't start with a move

      while (true)
      {
         scan.skipWhitespace();

         switch (pathCommand)
         {
            // Move
            case 'M':
            case 'm':
               x = scan.nextFloat();
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               // Relative moveto at the start of a path is treated as an absolute moveto.
               if (pathCommand=='m' && !path.isEmpty()) {
                  x += currentX;
                  y += currentY;
               }
               path.moveTo(x, y);
               currentX = lastMoveX = lastControlX = x;
               currentY = lastMoveY = lastControlY = y;
               // Any subsequent coord pairs should be treated as a lineto.
               pathCommand = (pathCommand=='m') ? 'l' : 'L';
               break;

               // Line
            case 'L':
            case 'l':
               x = scan.nextFloat();
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='l') {
                  x += currentX;
                  y += currentY;
               }
               path.lineTo(x, y);
               currentX = lastControlX = x;
               currentY = lastControlY = y;
               break;

               // Cubic bezier
            case 'C':
            case 'c':
               x1 = scan.nextFloat();
               y1 = scan.checkedNextFloat(x1);
               x2 = scan.checkedNextFloat(y1);
               y2 = scan.checkedNextFloat(x2);
               x = scan.checkedNextFloat(y2);
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='c') {
                  x += currentX;
                  y += currentY;
                  x1 += currentX;
                  y1 += currentY;
                  x2 += currentX;
                  y2 += currentY;
               }
               path.cubicTo(x1, y1, x2, y2, x, y);
               lastControlX = x2;
               lastControlY = y2;
               currentX = x;
               currentY = y;
               break;

               // Smooth curve (first control point calculated)
            case 'S':
            case 's':
               x1 = 2 * currentX - lastControlX;
               y1 = 2 * currentY - lastControlY;
               x2 = scan.nextFloat();
               y2 = scan.checkedNextFloat(x2);
               x = scan.checkedNextFloat(y2);
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='s') {
                  x += currentX;
                  y += currentY;
                  x2 += currentX;
                  y2 += currentY;
               }
               path.cubicTo(x1, y1, x2, y2, x, y);
               lastControlX = x2;
               lastControlY = y2;
               currentX = x;
               currentY = y;
               break;

               // Close path
            case 'Z':
            case 'z':
               path.close();
               currentX = lastControlX = lastMoveX;
               currentY = lastControlY = lastMoveY;
               break;

               // Horizontal line
            case 'H':
            case 'h':
               x = scan.nextFloat();
               if (Float.isNaN(x)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='h') {
                  x += currentX;
               }
               path.lineTo(x, currentY);
               currentX = lastControlX = x;
               break;

               // Vertical line
            case 'V':
            case 'v':
               y = scan.nextFloat();
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='v') {
                  y += currentY;
               }
               path.lineTo(currentX, y);
               currentY = lastControlY = y;
               break;

               // Quadratic bezier
            case 'Q':
            case 'q':
               x1 = scan.nextFloat();
               y1 = scan.checkedNextFloat(x1);
               x = scan.checkedNextFloat(y1);
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='q') {
                  x += currentX;
                  y += currentY;
                  x1 += currentX;
                  y1 += currentY;
               }
               path.quadTo(x1, y1, x, y);
               lastControlX = x1;
               lastControlY = y1;
               currentX = x;
               currentY = y;
               break;

               // Smooth quadratic bezier
            case 'T':
            case 't':
               x1 = 2 * currentX - lastControlX;
               y1 = 2 * currentY - lastControlY;
               x = scan.nextFloat();
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y)) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='t') {
                  x += currentX;
                  y += currentY;
               }
               path.quadTo(x1, y1, x, y);
               lastControlX = x1;
               lastControlY = y1;
               currentX = x;
               currentY = y;
               break;

               // Arc
            case 'A':
            case 'a':
               rx = scan.nextFloat();
               ry = scan.checkedNextFloat(rx);
               xAxisRotation = scan.checkedNextFloat(ry);
               largeArcFlag = scan.checkedNextFlag(xAxisRotation);
               sweepFlag = scan.checkedNextFlag(largeArcFlag);
               x = scan.checkedNextFloat(sweepFlag);
               y = scan.checkedNextFloat(x);
               if (Float.isNaN(y) || rx < 0 || ry < 0) {
                  Log.e(TAG, "Bad path coords for "+((char)pathCommand)+" path segment");
                  return path;
               }
               if (pathCommand=='a') {
                  x += currentX;
                  y += currentY;
               }
               path.arcTo(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y);
               currentX = lastControlX = x;
               currentY = lastControlY = y;
               break;

            default:
               return path;
         }

         scan.skipCommaWhitespace();
         if (scan.empty())
            break;

         // Test to see if there is another set of coords for the current path command
         if (scan.hasLetter()) {
            // Nope, so get the new path command instead
            pathCommand = scan.nextChar();
         }
      }
      return path;
   }
1135809
function getSplinePath(points, isInCircle, constaint) {
    var data = [];
    var first = points[0];
    var prePoint = null;
    if (points.length <= 2) {
      return PathUtil.getLinePath(points, isInCircle);
    }
    Util.each(points, function (point) {
      if (!prePoint || !(prePoint.x === point.x && prePoint.y === point.y)) {
        data.push(point.x);
        data.push(point.y);
        prePoint = point;
      }
    });
    constaint = constaint || [// 范围
    [0, 0], [1, 1]];
    var splinePath = Spline.catmullRom2bezier(data, isInCircle, constaint);
    splinePath.unshift(['M', first.x, first.y]);
    return splinePath;
  }
1087212
def _resolve_path(obj, path=None):
        
        if path:
            for attr_name in path.split('__'):
                obj = getattr(obj, attr_name)
        return obj