Hi Sascha, I've done experiments with doing inline transformations (no AffineTransform), and found that it was no faster either. One theory to explain this is that the bottleneck is in the graphics system itself. However, that is contradicted by other experiments that I have done which show that if you have all of the shape objects already, the time to plot them is not significant on modern accelerated graphics cards (less than a second). It might be different on X11 under Linux though.
What we need is a better understanding of where the time is being spent, but this is difficult to achieve. So far I have not been successful at getting the profile information needed. I do know that the redraw process is responsible for most of the cyclic (new generation) memory consumption in JUMP. This doesn't seem to slow down the program much until the percent of free memory drops to below 5 %. regards, Larry On 6/5/07, Sascha L. Teichmann <[EMAIL PROTECTED]> wrote: > 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 > -- http://amusingprogrammer.blogspot.com/ ------------------------------------------------------------------------- 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