Hi!

It's only that temp array, there are actually two. In case
of decimation the first allocated is copied over to a second
to archive tight fitting.
Not to forget the Coordinate->Point2D->Coordinate
transformations with the PointConverter, which also
introduces a lot of temporal object allocation. The
new created GeneralPaths stores another internal copy
of the data too if the moveTo()/lineTo() calls are done
to fill it.

I experimented with caching the result of the
on-the-fly DirectPolygon in case of filled polygons
where the geometry is rendered twice (border + fill).
In this case the inline decimation is run twice per
polygon. You can log the transformation result from
the first rendering and associate it with last transform.
If the second path iterator call is coming you can
compare the last transform and new one and in case
of equality you can run a simple and fast replay PathIterator
for the last result. But this does _not_ lead to
speed improvements. The extra book keeping seems to be more
expensive than the simply run the decimation twice.
I've code for this, but I think we do better without this.

The streamlining is a good idea! I will do the same
optimization to LineStrings too, if you approve.

BTW: If I turn on the OpenGL backend (-Dsun.java2d.opengl=true)
the burlulc layer renders a second faster when compared to
the plain X11 backend. As soon as I've access to a 3D accelerated
MS Windows I will have a look if this holds for Direct3D too.

regards, Sascha



Larry Becker schrieb:
> I don't have time to look at it closely right now, but it sounds like
> a logical simplification.  I hate that temp array too.
> 
> regards,
> Larry
> 
> On 6/4/07, Michaël Michaud <[EMAIL PROTECTED]> wrote:
>> Hi Sascha;
>>
>> Sounds interesting.
>> Please, let me some more time to have a closer look and see how your
>> code compare to the one in CVS.
>> Note : I made a recent change in CVS to have the resolution as a
>> property and modify it as needed (default=1/2 pixel) for special renderers.
>>
>> Michael
>>
>> Sascha L. Teichmann a écrit :
>>
>>> 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
>>>
>>>
>>
>> -------------------------------------------------------------------------
>> 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
>>
> 
> 

-------------------------------------------------------------------------
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

Reply via email to