Revision: 6596 http://sourceforge.net/p/jump-pilot/code/6596 Author: michaudm Date: 2020-10-12 19:19:38 +0000 (Mon, 12 Oct 2020) Log Message: ----------- Keep double parameters as long as possible (does not solve the pb described in #507)
Modified Paths: -------------- core/trunk/src/com/vividsolutions/jump/workbench/imagery/geoimg/GeoImage.java Modified: core/trunk/src/com/vividsolutions/jump/workbench/imagery/geoimg/GeoImage.java =================================================================== --- core/trunk/src/com/vividsolutions/jump/workbench/imagery/geoimg/GeoImage.java 2020-10-12 15:05:32 UTC (rev 6595) +++ core/trunk/src/com/vividsolutions/jump/workbench/imagery/geoimg/GeoImage.java 2020-10-12 19:19:38 UTC (rev 6596) @@ -37,6 +37,7 @@ import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.awt.image.renderable.ParameterBlock; @@ -44,10 +45,15 @@ import javax.media.jai.JAI; import javax.media.jai.RenderedOp; +import javax.media.jai.operator.AffineDescriptor; +import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.util.AffineTransformation; +import com.vividsolutions.jts.geom.util.AffineTransformationBuilder; import com.vividsolutions.jump.JUMPException; import com.vividsolutions.jump.feature.Feature; +import com.vividsolutions.jump.util.Timer; import com.vividsolutions.jump.workbench.imagery.ReferencedImage; import com.vividsolutions.jump.workbench.imagery.ReferencedImageException; import com.vividsolutions.jump.workbench.model.Disposable; @@ -57,7 +63,7 @@ public class GeoImage implements ReferencedImage, Disposable, AlphaSetting { private GeoReferencedRaster gtr; private int alpha = 255; - private float last_scale; + private double last_scale; private RenderedOp last_scale_img; private Envelope last_img_env; private RenderedImage last_rendering; @@ -92,6 +98,7 @@ public synchronized void paint(Feature f, java.awt.Graphics2D g, Viewport viewport) throws ReferencedImageException { + //long t0 = Timer.now(); try { // update image envelope, either use geometry's or image's // this allows moving the image via geometry movement @@ -109,17 +116,17 @@ // + Integer.toHexString(img.hashCode())); // get current scale - final float scale = (float) viewport.getScale(); + final double scale = viewport.getScale(); // get current viewport area Envelope envModel_viewport = viewport.getEnvelopeInModelCoordinates(); // if nothing changed, no reason to rerender the whole shebang // this is mainly the case when OJ last and regained focus - if (last_scale == scale && last_img_env instanceof Envelope - && last_img_env.equals(envImage) && last_vwp_env instanceof Envelope + if (last_scale == scale && last_img_env != null + && last_img_env.equals(envImage) && last_vwp_env != null && last_vwp_env.equals(envModel_viewport) - && last_rendering instanceof RenderedImage - && last_transform instanceof AffineTransform) { + && last_rendering != null + && last_transform != null) { draw(g, null); return; } @@ -132,7 +139,7 @@ // reuse a cached version if scale and img_envelope didn't changed // speeds up panning, window resizing if (last_scale == scale && last_scale_img != null - && last_img_env instanceof Envelope + && last_img_env != null && last_img_env.equals(envImage)) { img = last_scale_img; // System.out.println("GI: USE SCALE CACHE"); @@ -140,8 +147,8 @@ // System.out.println("GI: NO SCALE CACHE"); // First, scale the original image - float scaleX = scale * (float) gtr.getDblModelUnitsPerRasterUnit_X(); - float scaleY = scale * (float) gtr.getDblModelUnitsPerRasterUnit_Y(); + double scaleX = scale * gtr.getDblModelUnitsPerRasterUnit_X(); + double scaleY = scale * gtr.getDblModelUnitsPerRasterUnit_Y(); // calculate predicted dimensions double scaledW = scaleX * src_img.getWidth(); @@ -157,7 +164,7 @@ // we cache an overview here for big pictures // speeds up situations when the whole picture is shown - float scaleX_toUse, scaleY_toUse; + double scaleX_toUse, scaleY_toUse; RenderedImage scale_src_img; if ((imgW > 2000 || imgH > 2000) && scaledW < 2000 && scaledH < 2000 ) { // System.out.println("GI: USE FULL SCALE CACHE"); @@ -165,9 +172,9 @@ // this is faster than having JAI create it from scratch from big datasets if (full_scale_img == null) { if (imgW > imgH) { - full_scale = 1 / (imgW / 2000d); + full_scale = 2000d / imgW; } else { - full_scale = 1 / (imgH / 2000d); + full_scale = 2000d / imgH; } // subsample average gives a smoothly resized image pb = new ParameterBlock(); @@ -178,14 +185,14 @@ // System.out.println("GI full scale img: " // + full_scale_img.getWidth()); } - scaleX_toUse = (float) scaleX / (float) full_scale; - scaleY_toUse = (float) scaleY / (float) full_scale; + scaleX_toUse = scaleX / full_scale; + scaleY_toUse = scaleY / full_scale; scale_src_img = full_scale_img; } // scale the original else{ - scaleX_toUse = (float) scaleX; - scaleY_toUse = (float) scaleY; + scaleX_toUse = scaleX; + scaleY_toUse = scaleY; scale_src_img = src_img; } @@ -195,8 +202,8 @@ // so use slow and qualitative inferior bicubic instead // or NOT, to f**g slow, use default interpolation if (scaleX > 0.1 || scaleY > 0.1) { - pb.add(scaleX_toUse); - pb.add(scaleY_toUse); + pb.add((float)scaleX_toUse); + pb.add((float)scaleY_toUse); pb.add(0f); pb.add(0f); // Interpolation interp = Interpolation @@ -204,8 +211,8 @@ // pb.add(interp); // add interpolation method img = JAI.create("scale", pb, hints); } else { - pb.add((double) (scaleX_toUse)); - pb.add((double) (scaleY_toUse)); + pb.add(scaleX_toUse); + pb.add(scaleY_toUse); img = JAI.create("subsampleaverage", pb, hints); } @@ -244,13 +251,13 @@ double ratio_cropW = envModel_viewport.getWidth() / envImage.getWidth(); double ratio_cropH = envModel_viewport.getHeight() / envImage.getHeight(); - float raster_cropX = (int) (ratio_cropX * img.getWidth()); - float raster_cropY = (int) (ratio_cropY * img.getHeight()); - float raster_cropW = (int) (ratio_cropW * img.getWidth()); - float raster_cropH = (int) (ratio_cropH * img.getHeight()); + double raster_cropX = ratio_cropX * img.getWidth(); + double raster_cropY = ratio_cropY * img.getHeight(); + double raster_cropW = ratio_cropW * img.getWidth(); + double raster_cropH = ratio_cropH * img.getHeight(); - float raster_offsetX = 0; - float raster_offsetY = 0; + double raster_offsetX = 0; + double raster_offsetY = 0; if (raster_cropX < 0) { raster_offsetX = -raster_cropX; @@ -260,24 +267,30 @@ raster_offsetY = -raster_cropY; raster_cropY = 0; } + raster_cropX = Math.min((float)raster_cropX, (float)img.getWidth()); + raster_cropY = Math.min((float)raster_cropY, (float)img.getHeight()); raster_cropW = Math - .min(raster_cropW, img.getWidth() - (int) raster_cropX); - raster_cropH = Math.min(raster_cropH, img.getHeight() - - (int) raster_cropY); + .min((float)raster_cropW, (float)img.getWidth() - /*(int)*/ raster_cropX); + raster_cropH = Math.min((float)raster_cropH, (float)img.getHeight() + - /*(int)*/ raster_cropY); pb = new ParameterBlock(); pb.addSource(img); - pb.add(raster_cropX); - pb.add(raster_cropY); - pb.add(raster_cropW); - pb.add(raster_cropH); + //System.out.println("cropx " + (float)raster_cropX); + //System.out.println("cropy " + (float)raster_cropY); + //System.out.println("cropw " + (float)raster_cropW + " " + (img.getWidth() - /*(int)*/ raster_cropX)); + //System.out.println("croph " + (float)raster_cropH + " " + (img.getHeight() - /*(int)*/ raster_cropY)); + pb.add((float)raster_cropX); + pb.add((float)raster_cropY); + pb.add((float)raster_cropW); + pb.add((float)raster_cropH); img = JAI.create("crop", pb, null); // move the image to the model coordinates pb = new ParameterBlock(); pb.addSource(img); - pb.add(raster_offsetX - img.getMinX()); - pb.add(raster_offsetY - img.getMinY()); + pb.add((float)(raster_offsetX - img.getMinX())); + pb.add((float)(raster_offsetY - img.getMinY())); img = JAI.create("translate", pb, null); // cache the current rendering here as used in the @@ -288,6 +301,7 @@ // eventually draw the image, let g render the chain draw(g, img); + //System.out.printf("Display at %f in %d ms%n", scale, Timer.milliSecondsSince(t0)); } catch (Exception ex) { throw new ReferencedImageException(ex); @@ -294,6 +308,77 @@ } } + // [mmichaud 2020-10-12] try to make image display more precise using double-based + // affine transform, but the code does not take advanatage of jai subsample used in + // the previous code and is much slower + //RenderedImage cached2000px = null; + //public synchronized void paint(Feature f, java.awt.Graphics2D g, Viewport viewport) + // throws ReferencedImageException { + // long t0 = Timer.now(); + // long t1 = 0L; + // // Image enveloppe in model coordinates + // Envelope imageEnv = gtr.getEnvelope(f); + // RenderedOp op = gtr.getRenderedOp(); + // RenderedImage im = op; + // RenderingHints hints = gtr.createCacheRenderingHints(); + // + // // Size of an image pixel in the Model (ground coordinates) + // double pixelSizeInModelX = imageEnv.getWidth()/op.getWidth(); + // double pixelSizeInModelY = imageEnv.getHeight()/op.getHeight(); + // double scale = viewport.getScale(); + // // Size of an image pixel in the screen model (number of screen pixel for one image pixel) + // double pixelSizeInViewX = pixelSizeInModelX * scale; + // double pixelSizeInViewY = pixelSizeInModelY * scale; + // // Short circuit : if the full image is < 1 screen pixel, return + // if (pixelSizeInViewX*im.getWidth() < 0.5 && pixelSizeInViewY*im.getHeight() < 0.5) { + // System.out.println("Full image < 1 px"); + // return; + // } + // + // if ((im.getWidth() > 2000 || im.getHeight() > 2000) && pixelSizeInViewX < 1 && pixelSizeInViewY < 1) { + // if (cached2000px == null) { + // full_scale = 2000d / Math.max(im.getWidth(), im.getHeight()); + // ParameterBlock pb = new ParameterBlock(); + // pb.addSource(im); + // pb.add(full_scale); // x scale factor + // pb.add(full_scale); // y scale factor + // cached2000px = JAI.create("subsampleaverage", pb, null); + // } + // im = cached2000px; + // } + // + // System.out.println("Image " + im.getWidth() + " x " + im.getHeight()); + // + // try { + // AffineTransform model2view = viewport.getModelToViewTransform(); + // AffineTransformation imageToModel = new AffineTransformationBuilder( + // new Coordinate(0.0, 0.0), + // new Coordinate(im.getWidth(), 0.0), + // new Coordinate(0.0, im.getHeight()), + // new Coordinate(imageEnv.getMinX(), imageEnv.getMaxY()), + // new Coordinate(imageEnv.getMaxX(), imageEnv.getMaxY()), + // new Coordinate(imageEnv.getMinX(), imageEnv.getMinY()) + // ).getTransformation(); + // + // AffineTransform image2view = new AffineTransform( + // imageToModel.getMatrixEntries()[0], + // imageToModel.getMatrixEntries()[3], + // imageToModel.getMatrixEntries()[1], + // imageToModel.getMatrixEntries()[4], + // imageToModel.getMatrixEntries()[2], + // imageToModel.getMatrixEntries()[5] + // ); + // + // image2view.preConcatenate(model2view); + // im = AffineDescriptor.create(im,image2view, null,null, hints); + // g.drawRenderedImage(im, new AffineTransform()); + // + // System.out.printf("Display at %f (jai %d) (%dx%d) in %d ms%n", scale, t1, im.getWidth(), im.getHeight(), Timer.milliSecondsSince(t0)); + // } catch (NoninvertibleTransformException ex) { + // throw new ReferencedImageException(ex); + // } + //} + private void draw(Graphics2D g, RenderedImage img) { Composite composite = g.getComposite(); // setup transparency @@ -302,7 +387,7 @@ // The image has been translated and scaled by JAI // already. Just draw it with an identity transformation. AffineTransform aft; - if (img instanceof RenderedImage){ + if (img != null) { aft = new AffineTransform(); } // no img given? paint cached last rendering again _______________________________________________ Jump-pilot-devel mailing list Jump-pilot-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel