/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2010-2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.display2d.style.j2d; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; /** * * @author Johann Sorel (Geomatys) * @module */ public class PathWalker { private final PathIterator pathIterator; private final float lastPoint[] = new float[6]; private final float currentPoint[] = new float[6]; private float lastmoveToX = 0f; private float lastmoveToY = 0f; private float segmentStartX = 0f; private float segmentStartY = 0f; private float segmentEndX = 0f; private float segmentEndY = 0f; private float segmentLenght = 0f; private float remaining = 0f; private float angle = Float.NaN; private boolean finished = false; public PathWalker(final PathIterator iterator) { this.pathIterator = iterator; //get the first segment boolean first = true; while (first && !pathIterator.isDone()) { final int type = pathIterator.currentSegment(currentPoint); switch (type) { case PathIterator.SEG_MOVETO: System.arraycopy(currentPoint, 0, lastPoint, 0, 6); segmentStartX = lastPoint[0]; segmentStartY = lastPoint[1]; segmentEndX = currentPoint[0]; segmentEndY = currentPoint[1]; //keep point for close instruction lastmoveToX = currentPoint[0]; lastmoveToY = currentPoint[1]; break; case PathIterator.SEG_CLOSE: currentPoint[0] = lastmoveToX; currentPoint[1] = lastmoveToY; // Fall into.... case PathIterator.SEG_LINETO: segmentStartX = lastPoint[0]; segmentStartY = lastPoint[1]; segmentEndX = currentPoint[0]; segmentEndY = currentPoint[1]; segmentLenght = distance(segmentStartX, segmentStartY, segmentEndX, segmentEndY); angle = Float.NaN; remaining = segmentLenght; first = false; break; } System.arraycopy(currentPoint, 0, lastPoint, 0, 6); pathIterator.next(); } } public boolean isFinished() { return finished; //|| (pathIterator.isDone() && remaining <= 0); } /** * Get the remaining distance until the current line segment end. * @return float */ public float getSegmentLengthRemaining(){ return remaining; } public void walk(float distance) { if (remaining > distance) { remaining -= distance; } else { distance -= remaining; remaining = 0; while (!pathIterator.isDone()) { final int type = pathIterator.currentSegment(currentPoint); switch (type) { case PathIterator.SEG_MOVETO: System.arraycopy(currentPoint, 0, lastPoint, 0, 6); segmentStartX = lastPoint[0]; segmentStartY = lastPoint[1]; segmentEndX = currentPoint[0]; segmentEndY = currentPoint[1]; //keep point for close instruction lastmoveToX = currentPoint[0]; lastmoveToY = currentPoint[1]; break; case PathIterator.SEG_CLOSE: currentPoint[0] = lastmoveToX; currentPoint[1] = lastmoveToY; // Fall into.... case PathIterator.SEG_LINETO: segmentStartX = lastPoint[0]; segmentStartY = lastPoint[1]; segmentEndX = currentPoint[0]; segmentEndY = currentPoint[1]; segmentLenght = distance(segmentStartX, segmentStartY, segmentEndX, segmentEndY); angle = Float.NaN; remaining = segmentLenght; break; } System.arraycopy(currentPoint, 0, lastPoint, 0, 6); pathIterator.next(); if (remaining >= distance) { remaining -= distance; distance = 0; return; } else { distance -= remaining; remaining = 0; } } //if we reach here, it means the iterator is finished and nothing left finished = true; } } public Point2D getPosition(final Point2D pt) { //bad geometries have overlaping points final double perc = (segmentLenght>0.0) ? (1d - remaining / segmentLenght) : 0.0; final double tlX = (segmentEndX - segmentStartX) * perc + segmentStartX; final double tlY = (segmentEndY - segmentStartY) * perc + segmentStartY; if(pt == null){ return new Point2D.Double(tlX, tlY); }else{ pt.setLocation(tlX, tlY); return pt; } } public float getRotation() { if(Float.isNaN(angle)){ angle = angle(segmentStartX, segmentStartY, segmentEndX, segmentEndY); } return angle; } public static float distance(final float x1, final float y1, final float x2, final float y2) { float dx = x1 - x2; float dy = y1 - y2; return (float) Math.sqrt(dx * dx + dy * dy); } public static float angle(final float x1, final float y1, final float x2, final float y2) { float dx = x2 - x1; float dy = y2 - y1; return (float) Math.atan2(dy, dx); } }