Revision: 5809 http://sourceforge.net/p/jump-pilot/code/5809 Author: michaudm Date: 2018-05-27 21:13:28 +0000 (Sun, 27 May 2018) Log Message: ----------- improvement of SkeletonPlugIn -> 0.5.8
Modified Paths: -------------- plug-ins/GraphToolboxPlugin/trunk/build.xml plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/SkeletonPlugIn.java plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph.properties plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_cz.properties plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fi.properties plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fr.properties plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_it.properties Modified: plug-ins/GraphToolboxPlugin/trunk/build.xml =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/build.xml 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/build.xml 2018-05-27 21:13:28 UTC (rev 5809) @@ -17,7 +17,7 @@ <property name="dist" value="dist" /> <property name="javadoc" value="javadoc" /> - <property name="version" value="0.5.6" /> + <property name="version" value="0.5.8" /> <!-- =================================================================== --> <!-- Defines the classpath used for compilation and test. --> Modified: plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/SkeletonPlugIn.java =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/SkeletonPlugIn.java 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/SkeletonPlugIn.java 2018-05-27 21:13:28 UTC (rev 5809) @@ -9,6 +9,7 @@ import com.vividsolutions.jts.operation.linemerge.LineMerger; import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier; import com.vividsolutions.jts.triangulate.VoronoiDiagramBuilder; +import com.vividsolutions.jump.I18N; import com.vividsolutions.jump.feature.*; import com.vividsolutions.jump.geom.Angle; import com.vividsolutions.jump.task.TaskMonitor; @@ -49,6 +50,8 @@ private static String AUTO_WIDTH_PARAMETER_TT = I18NPlug.getI18N("SkeletonPlugIn.auto-width-parameter-tooltip"); private static String MIN_WIDTH = I18NPlug.getI18N("SkeletonPlugIn.min-width"); private static String MIN_WIDTH_TT = I18NPlug.getI18N("SkeletonPlugIn.min-width-tooltip"); + private static String BUFFER_THINER_THAN = I18NPlug.getI18N("SkeletonPlugIn.buffer-thiner-than"); + private static String BUFFER_THINER_THAN_TT = I18NPlug.getI18N("SkeletonPlugIn.buffer-thiner-than-tooltip"); private static String MIN_FORK_LENGTH_FROM_MEAN_WIDTH = I18NPlug.getI18N("SkeletonPlugIn.min-fork-length-from-mean-width"); private static String MIN_FORK_LENGTH_FROM_MEAN_WIDTH_TT = I18NPlug.getI18N("SkeletonPlugIn.min-fork-length-from-mean-width-tooltip"); private static String MIN_FORK_LENGTH_IN_MAP_UNITS = I18NPlug.getI18N("SkeletonPlugIn.min-fork-length-in-map-units"); @@ -61,20 +64,24 @@ private static String DESCRIPTION = I18NPlug.getI18N("SkeletonPlugIn.description"); private String layerName; - private boolean autoWidth = true; - private double minWidth = 1.0; // minimum width of the polygon - private double meanWidth = 2.0; // mean width of the polygon - private int maxIterations = 8192; // maximum iteration to eliminate forks - private double forkLengthMul = 2.5; // minimum length of a fork - private double minForkLength = 10.0; // minimum length of a fork - private boolean fromMeanWidth = true; // minimum fork length from mean width - private boolean fromMapUnits = false; // minimum fork length in map units - private boolean snapEnds = false; // wheter the skeletton must snap the polygon boundary + private boolean autoWidth = true; + private double minWidth = 1.0; // minimum width of the polygon + private double bufferThinerThan = 0.1; // buffer polygon thiner than a value + private double simplification = 0.2; // by default, simplification factor is minWidth/5 + private double densification = 0.5; // by default, densification factor is minWidth/2 + private double meanWidth = 2.0; // mean width of the polygon + private int maxIterations = 8192; // maximum iteration to eliminate forks + private double forkLengthMul = 2.5; // minimum length of a fork + private double minForkLength = 10.0; // minimum length of a fork + private boolean fromMeanWidth = true; // minimum fork length from mean width + private boolean fromMapUnits = false; // minimum fork length in map units + private boolean snapEnds = false; // wheter the skeletton must snap the polygon boundary + private boolean displayVoronoiEdges = false; - private static Collection debugGeometries = new ArrayList<Geometry>(); + //private static Collection debugGeometries = new ArrayList<Geometry>(); - public void initialize(PlugInContext context) throws Exception { + public void initialize(PlugInContext context) { workbenchContext = context.getWorkbenchContext(); FeatureInstaller featureInstaller = new FeatureInstaller(workbenchContext); @@ -87,6 +94,12 @@ createEnableCheck(context.getWorkbenchContext())); } + @Override + public String getName() { + // Otherwise, I18N class looks for SkeletonPlugIn key in the main OpenJUMP resource file + return I18NPlug.getI18N("SkeletonPlugIn"); + } + private static MultiEnableCheck createEnableCheck(WorkbenchContext workbenchContext) { EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext); return new MultiEnableCheck().add(checkFactory.createAtLeastNLayersMustExistCheck(1)); @@ -93,7 +106,7 @@ } - public boolean execute(PlugInContext context) throws Exception{ + public boolean execute(PlugInContext context) { this.reportNothingToUndoYet(context); MultiInputDialog dialog = new MultiInputDialog( @@ -114,11 +127,13 @@ final JCheckBox autoWidthJcb = dialog.addCheckBox(AUTO_WIDTH_PARAMETER, autoWidth,AUTO_WIDTH_PARAMETER_TT); final JTextField minWidthTF = dialog.addDoubleField(MIN_WIDTH, minWidth, 12, MIN_WIDTH_TT); + minWidthTF.setEnabled(!autoWidth); + final JTextField bufferThinerThanTF = dialog.addDoubleField(BUFFER_THINER_THAN, bufferThinerThan, 12, BUFFER_THINER_THAN_TT); final JTextField minForkLengthTF = dialog.addDoubleField(MIN_FORK_LENGTH, forkLengthMul, 12, MIN_FORK_LENGTH_TT); final JRadioButton mflFromMinWidthJRB = dialog.addRadioButton(MIN_FORK_LENGTH_FROM_MEAN_WIDTH, "fork-length-units", fromMeanWidth, MIN_FORK_LENGTH_FROM_MEAN_WIDTH_TT); - final JRadioButton mflFromMapUnitsJRB = dialog.addRadioButton(MIN_FORK_LENGTH_IN_MAP_UNITS, + final JRadioButton mflInMapUnitsJRB = dialog.addRadioButton(MIN_FORK_LENGTH_IN_MAP_UNITS, "fork-length-units", fromMapUnits, MIN_FORK_LENGTH_IN_MAP_UNITS_TT); dialog.addCheckBox(SNAP_TO_BOUNDARY, snapEnds, SNAP_TO_BOUNDARY_TT); @@ -129,6 +144,7 @@ @Override public void actionPerformed(ActionEvent e) { minWidthTF.setEnabled(!autoWidthJcb.isSelected()); + bufferThinerThanTF.setEnabled(autoWidthJcb.isSelected()); } }); } @@ -137,6 +153,7 @@ layerName = dialog.getLayer(SOURCE_LAYER).getName(); autoWidth = dialog.getBoolean(AUTO_WIDTH_PARAMETER); minWidth = dialog.getDouble(MIN_WIDTH); + bufferThinerThan = dialog.getDouble(BUFFER_THINER_THAN); forkLengthMul = dialog.getDouble(MIN_FORK_LENGTH); fromMeanWidth = dialog.getBoolean(MIN_FORK_LENGTH_FROM_MEAN_WIDTH); fromMapUnits = dialog.getBoolean(MIN_FORK_LENGTH_IN_MAP_UNITS); @@ -153,6 +170,8 @@ schema.addAttribute("min_width", AttributeType.DOUBLE); schema.addAttribute("min_fork_length", AttributeType.DOUBLE); schema.addAttribute("iteration_number", AttributeType.INTEGER); + schema.addAttribute("duration_ms", AttributeType.INTEGER); + schema.addAttribute("comment", AttributeType.STRING); //schema.addAttribute("snap_ends", AttributeType.BOOLEAN); FeatureCollection outputFC = new FeatureDataset(schema); int count = 0; @@ -165,6 +184,7 @@ if (!geom.isValid()) geom = geom.buffer(0); for (int i = 0 ; i < geom.getNumGeometries() ; i++) { //Feature newFeature = feature.clone(false, false); + long t0 = System.currentTimeMillis(); Feature newFeature = new BasicFeature(schema); Object[] objects = new Object[schema.getAttributeCount()]; System.arraycopy(feature.getAttributes(), 0, objects, 0, feature.getSchema().getAttributeCount()); @@ -180,7 +200,9 @@ newFeature.setAttribute("min_fork_length", minForkLength); g = skeletonize(g, edges); newFeature.setGeometry(g); - newFeature.setAttribute("iteration_number", g.getUserData()); + newFeature.setAttribute("iteration_number", ((Object[])g.getUserData())[0]); + newFeature.setAttribute("duration_ms", (int)(System.currentTimeMillis()-t0)); + newFeature.setAttribute("comment", ((Object[])g.getUserData())[1]); g.setUserData(null); outputFC.add(newFeature); } @@ -202,7 +224,7 @@ } // Get minWidth and meanWidth from the geometry - private void computeParams(Geometry geometry) throws Exception { + private void computeParams(Geometry geometry) { meanWidth = getMeanWidth(geometry); double SQRT2 = Math.sqrt(2.0); if (meanWidth==0) meanWidth = geometry.getLength()/geometry.getNumPoints()/5; @@ -229,6 +251,8 @@ } else if (fromMapUnits) { minForkLength = forkLengthMul; } + simplification = minWidth/5.0; + densification = minWidth/2.0; } // Computes the mean width of a polygon @@ -248,12 +272,20 @@ } // Simplification/densification of input geometry - private Geometry preprocess(Geometry geometry) throws Exception { - geometry = TopologyPreservingSimplifier.simplify(geometry, minWidth/5); + private Geometry preprocess(Geometry geometry) { + // 0.5.8 : create a buffer if the min width is very small compared to mean width + // to avoid very heavy calculation du to high densification of the outline + if (minWidth < bufferThinerThan) { + minWidth = bufferThinerThan; + geometry = geometry.buffer(minWidth); + simplification = minWidth/5.0; + densification = minWidth/2.0; + } + geometry = TopologyPreservingSimplifier.simplify(geometry, simplification); if (geometry.isEmpty() || Double.isNaN(minWidth)) { return geometry; } else { - geometry = Densifier.densify(geometry, minWidth/2); + geometry = Densifier.densify(geometry, densification); return geometry; } } @@ -267,13 +299,17 @@ voronoiBuilder.setSites(geometry.getFactory().createMultiPoint(geometry.getCoordinates())); Envelope env = geometry.getEnvelopeInternal(); env.expandBy(env.getWidth()/3, env.getHeight()/3); - voronoiBuilder.setClipEnvelope(env); try { + voronoiBuilder.setClipEnvelope(env); return voronoiBuilder.getDiagram(geometry.getFactory()); } catch(Exception e) { e.printStackTrace(); - Geometry newGeometry = preprocess(geometry.buffer(minWidth/10)); - if (newGeometry.equals(geometry)) throw new Exception("Cannot process " + geometry); + simplification = simplification * Math.sqrt(2.0); + densification = densification * Math.sqrt(2.0); + Geometry newGeometry = preprocess(geometry); + //if (newGeometry.equals(geometry)) throw new Exception("Cannot process " + geometry); + if (minWidth > Math.sqrt(geometry.getArea())) throw new Exception("Cannot process " + geometry); + newGeometry.setUserData("Voronoi calculation problem"); return getVoronoiDiagram(newGeometry); } } @@ -345,10 +381,14 @@ private Geometry skeletonize(Geometry geometry, List<Geometry> list) throws Exception { + Object userData[] = new Object[2]; + // 1 - Build voronoi diagram and extract the edges long t0 = System.currentTimeMillis(); Set<LineString> edges = new HashSet<LineString>(); - getEdges(getVoronoiDiagram(preprocess(geometry)), edges); + Geometry voronoi = getVoronoiDiagram(preprocess(geometry)); + userData[1] = voronoi.getUserData(); + getEdges(voronoi, edges); //System.out.println("voronoi : " + (System.currentTimeMillis()-t0)/1000); // 2 - Filter voronoi edges strictly included in the geometry @@ -358,7 +398,7 @@ // 3 - Merge filtered edges LineMerger merger = new LineMerger(); merger.add(edges); - edges = new HashSet(merger.getMergedLineStrings()); + edges = new HashSet<LineString>(merger.getMergedLineStrings()); //System.out.println("merge : " + (System.currentTimeMillis()-t0)/1000); if (displayVoronoiEdges) list.addAll(edges); @@ -386,11 +426,20 @@ for (FeatureAsEdge f : finalEdges) { f.setGeometry(TopologyPreservingSimplifier.simplify(f.getGeometry(), minWidth/5)); EdgeNodes nodes = new EdgeNodes(graph, f); + String snapError; if (nodes.srcDegree == 1) { - f.setGeometry(snapStart(f.getGeometry(), geometry.getBoundary(), snapEnds)); + try { + f.setGeometry(snapStart(f.getGeometry(), geometry.getBoundary(), snapEnds)); + } catch(Exception e) { + userData[1] = "Snapping error"; + } } if (nodes.tgtDegree == 1) { - f.setGeometry(snapEnd(f.getGeometry(), geometry.getBoundary(), snapEnds)); + try { + f.setGeometry(snapEnd(f.getGeometry(), geometry.getBoundary(), snapEnds)); + } catch(Exception e) { + userData[1] = "Snapping error"; + } } } @@ -399,7 +448,9 @@ // 7 - Retourner une geometrie Geometry geom = graph2geometry(graph); geom = TopologyPreservingSimplifier.simplify(geom, minWidth/5); - geom.setUserData(i); // set the number of iteration used + userData[0] = i; + if (geom.isEmpty()) userData[1] = "Empty"; + geom.setUserData(userData); // set the number of iteration used return geom; } Modified: plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph.properties =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph.properties 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph.properties 2018-05-27 21:13:28 UTC (rev 5809) @@ -130,6 +130,8 @@ SkeletonPlugIn.auto-width-parameter-tooltip = Computes automatically a minimum width for each feature SkeletonPlugIn.min-width = Minimum width SkeletonPlugIn.min-width-tooltip = Boundary is densified according to this parameter +SkeletonPlugIn.buffer-thiner-than = Buffer polygons thiner than +SkeletonPlugIn.buffer-thiner-than-tooltip = Buffer the polygon to avoid over-densification SkeletonPlugIn.min-fork-length = Minimum length of forks SkeletonPlugIn.min-fork-length-tooltip = Minimum length of forks Modified: plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_cz.properties =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_cz.properties 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_cz.properties 2018-05-27 21:13:28 UTC (rev 5809) @@ -124,6 +124,8 @@ SkeletonPlugIn.auto-width-parameter-tooltip = #T: Computes automatically a minimum width for each feature SkeletonPlugIn.min-width = #T: Minimum width SkeletonPlugIn.min-width-tooltip = #T: Boundary is densified according to this parameter +SkeletonPlugIn.buffer-thiner-than = Buffer polygons thiner than +SkeletonPlugIn.buffer-thiner-than-tooltip = Buffer the polygon to avoid over-densification SkeletonPlugIn.min-fork-length = #T: Minimum length of forks SkeletonPlugIn.min-fork-length-tooltip = #T: Minimum length of forks Modified: plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fi.properties =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fi.properties 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fi.properties 2018-05-27 21:13:28 UTC (rev 5809) @@ -118,6 +118,8 @@ SkeletonPlugIn.auto-width-parameter-tooltip = Laskee automaattisesti minimileveyden jokaiselle kohteelle SkeletonPlugIn.min-width = Minimileveys SkeletonPlugIn.min-width-tooltip = Reunaviiva tihennet\u00E4\u00E4n t\u00E4m\u00E4n parametrin perusteella +SkeletonPlugIn.buffer-thiner-than = Buffer polygons thiner than +SkeletonPlugIn.buffer-thiner-than-tooltip = Buffer the polygon to avoid over-densification SkeletonPlugIn.min-fork-length = Haarojen minimipituus SkeletonPlugIn.min-fork-length-tooltip = Haarojen minimipituus Modified: plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fr.properties =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fr.properties 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_fr.properties 2018-05-27 21:13:28 UTC (rev 5809) @@ -131,6 +131,8 @@ SkeletonPlugIn.auto-width-parameter-tooltip = Calcul automatiquement une largeur minimale adapt\xE9e \xE0 chaque objet SkeletonPlugIn.min-width = Largeur minimale SkeletonPlugIn.min-width-tooltip = La fronti\xE8re est densifi\xE9e en fonction de se param\xE8tre +SkeletonPlugIn.buffer-thiner-than = Elargir les polygones trop fins +SkeletonPlugIn.buffer-thiner-than-tooltip = Elargir le polygone pour \xE9viter une densification trop importante SkeletonPlugIn.min-fork-length = Longueur minimale des embranchements SkeletonPlugIn.min-fork-length-tooltip = Longueur minimale des embranchements Modified: plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_it.properties =================================================================== --- plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_it.properties 2018-05-27 07:37:30 UTC (rev 5808) +++ plug-ins/GraphToolboxPlugin/trunk/src/fr/michaelm/jump/plugin/graph/graph_it.properties 2018-05-27 21:13:28 UTC (rev 5809) @@ -116,6 +116,8 @@ SkeletonPlugIn.auto-width-parameter-tooltip = #T: Computes automatically a minimum width for each feature SkeletonPlugIn.min-width = #T: Minimum width SkeletonPlugIn.min-width-tooltip = #T: Boundary is densified according to this parameter +SkeletonPlugIn.buffer-thiner-than = Buffer polygons thiner than +SkeletonPlugIn.buffer-thiner-than-tooltip = Buffer the polygon to avoid over-densification SkeletonPlugIn.min-fork-length = #T: Minimum length of forks SkeletonPlugIn.min-fork-length-tooltip = #T: Minimum length of forks ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Jump-pilot-devel mailing list Jump-pilot-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel