eu.limetri.client.mapviewer.swing.render.ShapeStroke Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapviewer-swing Show documentation
Show all versions of mapviewer-swing Show documentation
MapViewer Swing implementation
The newest version!
/**
* Copyright (C) 2008-2013 LimeTri. All rights reserved.
*
* AgroSense is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* There are special exceptions to the terms and conditions of the GPLv3 as it
* is applied to this software, see the FLOSS License Exception
* .
*
* AgroSense 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* AgroSense. If not, see .
*/
package eu.limetri.client.mapviewer.swing.render;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
/**
*
* @author Timon Veenstra
*/
public class ShapeStroke implements Stroke {
private Shape shapes[];
private float advance;
private boolean stretchToFit = false;
private boolean repeat = true;
private AffineTransform t = new AffineTransform();
private static final float FLATNESS = 1;
public ShapeStroke( Shape shapes, float advance ) {
this( new Shape[] { shapes }, advance );
}
public ShapeStroke( Shape shapes[], float advance ) {
this.advance = advance;
this.shapes = new Shape[shapes.length];
for ( int i = 0; i < this.shapes.length; i++ ) {
Rectangle2D bounds = shapes[i].getBounds2D();
t.setToTranslation( -bounds.getCenterX(), -bounds.getCenterY() );
this.shapes[i] = t.createTransformedShape( shapes[i] );
}
}
public Shape createStrokedShape( Shape shape ) {
GeneralPath result = new GeneralPath();
PathIterator it = new FlatteningPathIterator( shape.getPathIterator( null ), FLATNESS );
float points[] = new float[6];
float moveX = 0, moveY = 0;
float lastX = 0, lastY = 0;
float thisX = 0, thisY = 0;
int type = 0;
boolean first = false;
float next = 0;
int currentShape = 0;
int length = shapes.length;
float factor = 1;
while ( currentShape < length && !it.isDone() ) {
type = it.currentSegment( points );
switch( type ){
case PathIterator.SEG_MOVETO:
moveX = lastX = points[0];
moveY = lastY = points[1];
result.moveTo( moveX, moveY );
first = true;
next = 0;
break;
case PathIterator.SEG_CLOSE:
points[0] = moveX;
points[1] = moveY;
// Fall into....
case PathIterator.SEG_LINETO:
thisX = points[0];
thisY = points[1];
float dx = thisX-lastX;
float dy = thisY-lastY;
float distance = (float)Math.sqrt( dx*dx + dy*dy );
if ( distance >= next ) {
float r = 1.0f/distance;
float angle = (float)Math.atan2( dy, dx );
while ( currentShape < length && distance >= next ) {
float x = lastX + next*dx*r;
float y = lastY + next*dy*r;
t.setToTranslation( x, y );
t.rotate( angle );
result.append( t.createTransformedShape( shapes[currentShape] ), false );
next += advance;
currentShape++;
if ( repeat )
currentShape %= length;
}
}
next -= distance;
first = false;
lastX = thisX;
lastY = thisY;
break;
}
it.next();
}
return result;
}
}