Hi Larry, hi Michaël,
I had a look at the decimation code in Java2DConverter.
This is awesome! Congratulations! :-)
But way not go step further and streamline the model to view
coordination transform. Why to create all this temporary
Coordinate[] stuff? In the end all what matters is a PathIterator
that can handle an AffineTransform coming from Java2D.
Instead of transform the data to a temporary Coordinate array
and used this to construct GeneralPaths we can write a PathIterator
that transforms and decimates the data on-the-fly.
All we have to do is to concatenate the model to view transform to the
incoming matrix.
To archive this we must add a
AffineTransform getModelToViewTransform();
method to the Java2DConverter.PointConverter interface. This
does not hurt because Viewport already implements it.
To see what I mean, look at the DirectPolygonShape that I've
attached. It handles the Polygon case of Java2DConverter.
Add this class to the sources and change the toShape(Polygon)
method to look as follow:
private Shape toShape(Polygon polygon) throws
NoninvertibleTransformException
{
return new DirectPolygonShape(
polygon,
pointConverter.getModelToViewTransform(),
1d / (2d*pointConverter.getScale()));
}
Speaking of performance. On my computer
(very old 1.2 GHz AMD/Athlon-T-Bird running GNU/Linux, Java 6)
the burluc layer is rendered in full extend without the streamling
in about 9.x seconds, with the streamling in about 8.x secs, with
x varying a bit. It's just a second, but it's a second! ;-)
What do you think?
Regards, Sascha
/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui.renderer.java2D;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.NoSuchElementException;
// for more accurate (float instead of int) rendering.
// From larry becker's SkyJUMP code to OpenJUMP [mmichaud]
// Streamlined [s-l-teichmann]
public class DirectPolygonShape
implements Shape
{
private Polygon polygon;
private AffineTransform model2view;
private double halfPixel;
protected DirectPolygonShape(){
}
/**
* @param polygon the JTS polygon
* @param model2view the affine transform from model to view
* @param halfPixel line segments shorter than halfPixel are ignored.
*/
public DirectPolygonShape(
Polygon polygon,
AffineTransform model2view,
double halfPixel
) {
this.polygon = polygon;
this.model2view = model2view;
this.halfPixel = halfPixel;
}
/**
* helper PathIterator that iterates over PathIterators
*/
public final class PathIteratorsIterator
implements PathIterator
{
private Iterator iterators;
private boolean done;
private PathIterator current;
public PathIteratorsIterator(Iterator iterators) {
this.iterators = iterators;
if (!iterators.hasNext())
done = true;
else
current = (PathIterator)iterators.next();
}
public int getWindingRule() {
return WIND_EVEN_ODD;
}
public boolean isDone() {
return done;
}
public void next() {
if (done)
return;
if (current.isDone()) {
if (iterators.hasNext())
current = (PathIterator)iterators.next();
else
done = true;
}
else
current.next();
}
public int currentSegment(float [] coords) {
return current.currentSegment(coords);
}
public int currentSegment(double [] coords) {
return current.currentSegment(coords);
}
} // class PathIteratorsIterator
/**
* Implements a PathIterator and Larry's decimator on-the-fly
*/
public static final class AffinePolygonPath
implements PathIterator
{
private int iterate;
private Coordinate [] points;
private Point2D.Double tmp;
private AffineTransform xform;
private double halfPixel;
private Coordinate p0;
private int segmentType;
public AffinePolygonPath(
Coordinate [] points,
AffineTransform xform,
double halfPixel
){
this.xform = xform;
this.points = points;
this.halfPixel = halfPixel;
tmp = new Point2D.Double();
internalNext();
}
/** Math.abs() is a known for being slow ... */
private static final double abs(double x) {
return x < 0d ? -x : x;
}
private final void internalNext() {
for (;;) {
// issue SEG_CLOSE at end
if (iterate >= points.length) {
segmentType = SEG_CLOSE;
break;
}
// issue first two and last
if (iterate < 2 || iterate == points.length-1) {
Coordinate pi = points[iterate];
tmp.x = pi.x;
tmp.y = pi.y;
xform.transform(tmp, tmp);
p0 = pi;
}
else { // distance lesser than halfPixel?
Coordinate pi = points[iterate];
if (abs(p0.x-pi.x) > halfPixel || abs(p0.y-pi.y) > halfPixel) {
tmp.x = pi.x;
tmp.y = pi.y;
xform.transform(tmp, tmp);
p0 = pi;
}
else { // yes: try next
++iterate;
continue;
}
}
segmentType = iterate == 0
? SEG_MOVETO
: SEG_LINETO;
break;
} // for (;;)
}
public int currentSegment(double[] coords) {
coords[0] = tmp.x;
coords[1] = tmp.y;
return segmentType;
}
public int currentSegment(float[] coords) {
coords[0] = (float)tmp.x;
coords[1] = (float)tmp.y;
return segmentType;
}
public int getWindingRule() {
return GeneralPath.WIND_EVEN_ODD;
}
public boolean isDone() {
return segmentType == SEG_CLOSE;
}
public void next() {
++iterate;
internalNext();
}
} // class AffinePolygonPath
public Rectangle getBounds() {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method getBounds() not yet implemented.");
}
public Rectangle2D getBounds2D() {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method getBounds() not yet implemented.");
}
public boolean contains(double x, double y) {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method contains() not yet implemented.");
}
public boolean contains(Point2D p) {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method contains() not yet implemented.");
}
public boolean intersects(double x, double y, double w, double h) {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method intersects() not yet implemented.");
}
public boolean intersects(Rectangle2D r) {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method intersects() not yet implemented.");
}
public boolean contains(double x, double y, double w, double h) {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method contains() not yet implemented.");
}
public boolean contains(Rectangle2D r) {
/[EMAIL PROTECTED] Implement this java.awt.Shape method*/
throw new java.lang.UnsupportedOperationException(
"Method contains() not yet implemented.");
}
public PathIterator getPathIterator(AffineTransform xform) {
if (xform == null)
xform = model2view;
else {
xform = new AffineTransform(xform);
xform.concatenate(model2view);
}
final AffineTransform at = xform;
return new PathIteratorsIterator(new Iterator() {
int ring;
public boolean hasNext() {
return ring < polygon.getNumInteriorRing() + 1;
}
public Object next() {
if (!hasNext())
throw new NoSuchElementException();
Object x = ring == 0
? new AffinePolygonPath(polygon.getExteriorRing().getCoordinates(), at, halfPixel)
: new AffinePolygonPath(polygon.getInteriorRingN(ring-1).getCoordinates(), at, halfPixel);
++ring;
return x;
}
public void remove() {
throw new UnsupportedOperationException();
}
});
}
public PathIterator getPathIterator(AffineTransform at, double flatness) {
// since we don't support curved geometries, can simply delegate to the simple method
return getPathIterator(at);
}
}
// end of file
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel