Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2008-2013 LimeTri. All rights reserved.
*
* AgroSense 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 3 of the License, or (at your option) any later
* version.
*
* There are special exceptions to the terms and conditions of the GPLv3 as it
* is applied to this software, see the FLOSS License Exception
* .
*
* AgroSense 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
* AgroSense. If not, see .
*/
package eu.limetri.client.mapviewer.swing.jxmap.map;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import org.openide.nodes.Node;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import com.vividsolutions.jts.operation.polygonize.Polygonizer;
import eu.limetri.client.mapviewer.api.SingleObjectLayer;
import eu.limetri.client.mapviewer.api.SplitGeometryHandler;
import eu.limetri.client.mapviewer.swing.JXMapViewer;
import eu.limetri.client.mapviewer.swing.render.DrawingRenderer;
import eu.limetri.client.mapviewer.swing.render.SplitPolygonDrawingRenderer;
/**
* Split a polygon into two parts based on a drawn line.
*
* @author johan
*/
@NbBundle.Messages({
"# {0} - name of object being split",
"SplitPolygonDrawingContext.description=splitting geometry for {0}",
"SplitPolygonDrawingContext.error no geometry=There is no source geometry to split",
"# {0} - number of polygons in a multipolygon",
"SplitPolygonDrawingContext.error more than one polygon=Only single polygons are supported, the source multi-polygon contains {0} polygons",
"SplitPolygonDrawingContext.error not a polygon=The source geometry is not a (multi-)polygon",
"SplitPolygonDrawingContext.error empty polygon=The source polygon contains no points",
"SplitPolygonDrawingContext.warn polygon holes=Polygon holes aren't handled yet and will be lost when splitting",
})
public class SplitPolygonDrawingContext extends AbstractLineDrawingContext {
private static final Logger LOGGER = Logger.getLogger(SplitPolygonDrawingContext.class.getName());
private final Node node;
private final Polygon polygonToSplit;
private final List results = new ArrayList<>();
private final SplitGeometryHandler handler;
public SplitPolygonDrawingContext(Node node, JXMapViewer mapViewer) {
super(node.getLookup().lookup(SingleObjectLayer.class), mapViewer);
this.handler = node.getLookup().lookup(SplitGeometryHandler.class);
this.node = node;
this.polygonToSplit = validateSource(handler.getSource());
}
@Override
public boolean canStart() {
return polygonToSplit != null;
}
/**
* Try to extract a single polygon from the source geometry.
* TODO:
* - support multipolygons and holes.
* - see if this can be combined with the geometry validation from AGROSENSE-824.
* - create a testable validation class
*
* @param source
* @return the extracted polygon if successful, null otherwise
*/
private Polygon validateSource(Geometry source) {
Polygon polygon;
if (source == null) {
// should already have been handled by disabling the split action
LOGGER.severe(Bundle.SplitPolygonDrawingContext_error_no_geometry());
return null;
}
if (source instanceof Polygon) {
polygon = (Polygon) source;
} else if (source instanceof MultiPolygon) {
MultiPolygon multiPolygon = (MultiPolygon) source;
int num = multiPolygon.getNumGeometries();
if (num != 1) {
LOGGER.log(Level.SEVERE, Bundle.SplitPolygonDrawingContext_error_more_than_one_polygon(num));
return null;
}
polygon = (Polygon) multiPolygon.getGeometryN(0);
} else {
LOGGER.severe(Bundle.SplitPolygonDrawingContext_error_not_a_polygon());
return null;
}
if (polygon.isEmpty()) {
LOGGER.severe(Bundle.SplitPolygonDrawingContext_error_empty_polygon());
return null;
}
if (polygon.getNumInteriorRing() > 0) {
LOGGER.warning(Bundle.SplitPolygonDrawingContext_warn_polygon_holes());
}
return polygon;
}
@Override
public boolean canFinish() {
// enough points in splitline?
if (coords.size() < 2) {
return false;
}
// is the source split into two parts?
return results.size() == 2;
}
private void split() {
results.clear();
// enough points in splitline?
int len = coords.size();
if (len < 2) {
return;
}
// create the splitline geometry:
CoordinateSequence coordSequence = new CoordinateArraySequence(coords.toArray(new Coordinate[len]));
LineString splitLine = new LineString(coordSequence, geometryFactory);
// since we're splitting into two parts, the intersection should be a single LineString:
Geometry intersection = splitLine.intersection(polygonToSplit);
if (intersection == null || intersection.isEmpty() || !(intersection instanceof LineString)) {
return;
}
// ensure that the line segments are properly noded and that vertices are created at line intersections:
// using strategy from http://stackoverflow.com/a/6263275
// TODO: handle polygon holes
MultiLineString mls = new MultiLineString(new LineString[] {splitLine, polygonToSplit.getExteriorRing()}, geometryFactory);
Geometry union = mls.union();
Polygonizer polygonizer = new Polygonizer();
polygonizer.add(union);
Collection polygons = polygonizer.getPolygons();
if (polygons.size() == 2) {
results.addAll(polygons);
}
}
@Override
protected void pointAdded() {
split();
}
@Override
protected void pointRemoved() {
split();
}
@Override
public boolean finish() {
if (handler.handle(results.toArray(new Geometry[2]), node)) {
cleanup();
return true;
}
return false;
}
@Override
public DrawingRenderer getRenderer() {
return new SplitPolygonDrawingRenderer(coords, polygonToSplit, results);
}
@Override
public String getDescription() {
return Bundle.SplitPolygonDrawingContext_description(node.getDisplayName());
}
/**
* Placeholder action for selecting helplines.
*
* TODO: toggle between two mutually exclusive modes: either select a line or draw one.
*/
@NbBundle.Messages({
"drawing_select_helpline_action_name=Select helpline",
"drawing_select_helpline_action_tooltip=Select helpline",
"drawing_select_helpline_action_icon=eu/limetri/client/mapviewer/swing/jxmap/icons/map24.png"})
private class SelectHelplineAction extends AbstractAction {
public SelectHelplineAction() {
putValue(SHORT_DESCRIPTION, Bundle.drawing_select_helpline_action_tooltip());
putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(Bundle.drawing_select_helpline_action_icon(), true));
setEnabled(false);
}
@Override
public void actionPerformed(ActionEvent e) {
}
}
}