/* * This is part of Geomajas, a GIS framework, http://www.geomajas.org/. * * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium. * * The program is available in open source according to the GNU Affero * General Public License. All contributions in this program are covered * by the Geomajas Contributors License Agreement. For full licensing * details, see LICENSE.txt in the project root. */ package org.geomajas.plugin.editing.gwt.client.gfx; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.geomajas.geometry.Coordinate; import org.geomajas.geometry.Geometry; import org.geomajas.gwt.client.controller.GraphicsController; import org.geomajas.gwt.client.controller.MapEventParser; import org.geomajas.gwt.client.gfx.GraphicsContext; import org.geomajas.gwt.client.gfx.paintable.Composite; import org.geomajas.gwt.client.gfx.style.ShapeStyle; import org.geomajas.gwt.client.map.event.MapViewChangedEvent; import org.geomajas.gwt.client.map.event.MapViewChangedHandler; import org.geomajas.gwt.client.spatial.Bbox; import org.geomajas.gwt.client.spatial.geometry.LineString; import org.geomajas.gwt.client.spatial.geometry.LinearRing; import org.geomajas.gwt.client.spatial.geometry.MultiLineString; import org.geomajas.gwt.client.spatial.geometry.MultiPoint; import org.geomajas.gwt.client.spatial.geometry.MultiPolygon; import org.geomajas.gwt.client.spatial.geometry.Point; import org.geomajas.gwt.client.spatial.geometry.Polygon; import org.geomajas.gwt.client.util.GeometryConverter; import org.geomajas.gwt.client.widget.MapWidget; import org.geomajas.gwt.client.widget.MapWidget.RenderGroup; import org.geomajas.plugin.editing.client.event.GeometryEditChangeStateEvent; import org.geomajas.plugin.editing.client.event.GeometryEditChangeStateHandler; import org.geomajas.plugin.editing.client.event.GeometryEditMoveEvent; import org.geomajas.plugin.editing.client.event.GeometryEditMoveHandler; import org.geomajas.plugin.editing.client.event.GeometryEditResumeEvent; import org.geomajas.plugin.editing.client.event.GeometryEditResumeHandler; import org.geomajas.plugin.editing.client.event.GeometryEditShapeChangedEvent; import org.geomajas.plugin.editing.client.event.GeometryEditShapeChangedHandler; import org.geomajas.plugin.editing.client.event.GeometryEditStartEvent; import org.geomajas.plugin.editing.client.event.GeometryEditStartHandler; import org.geomajas.plugin.editing.client.event.GeometryEditStopEvent; import org.geomajas.plugin.editing.client.event.GeometryEditStopHandler; import org.geomajas.plugin.editing.client.event.GeometryEditSuspendEvent; import org.geomajas.plugin.editing.client.event.GeometryEditSuspendHandler; import org.geomajas.plugin.editing.client.event.GeometryEditTentativeMoveEvent; import org.geomajas.plugin.editing.client.event.GeometryEditTentativeMoveHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexDeselectedEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexDeselectedHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexDisabledEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexDisabledHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexEnabledEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexEnabledHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexHighlightBeginEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexHighlightBeginHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexHighlightEndEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexHighlightEndHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexMarkForDeletionBeginEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexMarkForDeletionBeginHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexMarkForDeletionEndEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexMarkForDeletionEndHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexSelectedEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexSelectedHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexSnappingBeginEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexSnappingBeginHandler; import org.geomajas.plugin.editing.client.event.state.GeometryIndexSnappingEndEvent; import org.geomajas.plugin.editing.client.event.state.GeometryIndexSnappingEndHandler; import org.geomajas.plugin.editing.client.gfx.GeometryRenderer; import org.geomajas.plugin.editing.client.handler.AbstractGeometryIndexMapHandler; import org.geomajas.plugin.editing.client.handler.EdgeMapHandlerFactory; import org.geomajas.plugin.editing.client.handler.GeometryIndexMapHandlerFactory; import org.geomajas.plugin.editing.client.handler.VertexMapHandlerFactory; import org.geomajas.plugin.editing.client.service.GeometryEditService; import org.geomajas.plugin.editing.client.service.GeometryEditState; import org.geomajas.plugin.editing.client.service.GeometryIndex; import org.geomajas.plugin.editing.client.service.GeometryIndexNotFoundException; import org.geomajas.plugin.editing.client.service.GeometryIndexType; import org.geomajas.plugin.editing.client.snap.event.CoordinateSnapEvent; import org.geomajas.plugin.editing.client.snap.event.CoordinateSnapHandler; import org.geomajas.plugin.editing.gwt.client.controller.CompositeGeometryIndexController; import org.geomajas.plugin.editing.gwt.client.handler.EditingHandlerRegistry; import com.google.gwt.event.shared.HandlerRegistration; import com.smartgwt.client.types.Cursor; /** * ... * * @author Pieter De Graef */ public class GeometryRendererImpl implements GeometryRenderer, GeometryEditStartHandler, GeometryEditStopHandler, GeometryEditSuspendHandler, GeometryEditResumeHandler, GeometryIndexHighlightBeginHandler, GeometryIndexHighlightEndHandler, GeometryEditMoveHandler, GeometryEditShapeChangedHandler, GeometryEditChangeStateHandler, GeometryIndexSelectedHandler, GeometryIndexDeselectedHandler, GeometryIndexDisabledHandler, GeometryIndexEnabledHandler, GeometryIndexMarkForDeletionBeginHandler, GeometryIndexMarkForDeletionEndHandler, GeometryIndexSnappingBeginHandler, GeometryIndexSnappingEndHandler, GeometryEditTentativeMoveHandler, MapViewChangedHandler, CoordinateSnapHandler { private final MapWidget mapWidget; private final GeometryEditService editingService; private final Map<String, Composite> groups = new HashMap<String, Composite>(); private final List<VertexMapHandlerFactory> customVertexFactories = new ArrayList<VertexMapHandlerFactory>(); private final List<EdgeMapHandlerFactory> customEdgeFactories = new ArrayList<EdgeMapHandlerFactory>(); private final String insertMoveEdgeId1 = "insert-move-edge1"; private final String insertMoveEdgeId2 = "insert-move-edge2"; private StyleService styleService = new DefaultStyleService(); private String baseName = "editing"; private HandlerRegistration mapViewRegistration; public GeometryRendererImpl(MapWidget mapWidget, GeometryEditService editingService, MapEventParser eventParser) { this.mapWidget = mapWidget; this.editingService = editingService; } // ------------------------------------------------------------------------ // Public methods: // ------------------------------------------------------------------------ public void redraw() { groups.clear(); mapWidget.getVectorContext().deleteGroup(editingService.getGeometry()); draw(editingService.getGeometry()); } // ------------------------------------------------------------------------ // MapViewChangedHandler: // ------------------------------------------------------------------------ public void onMapViewChanged(MapViewChangedEvent event) { // Slow, but it works: redraw(); } // ------------------------------------------------------------------------ // GeometryEditWorkflowHandler: // ------------------------------------------------------------------------ public void onGeometryEditStart(GeometryEditStartEvent event) { // Also look at the map for changes in the MapView: mapViewRegistration = mapWidget.getMapModel().getMapView().addMapViewChangedHandler(this); // Render the geometry on the map: groups.clear(); draw(event.getGeometry()); } public void onGeometryEditStop(GeometryEditStopEvent event) { // Remove the handler that follows changes in the map view: if (mapViewRegistration != null) { mapViewRegistration.removeHandler(); mapViewRegistration = null; } // Cleanup the geometry from the map: groups.clear(); mapWidget.getVectorContext().deleteGroup(event.getGeometry()); } @Override public void onGeometryEditSuspend(GeometryEditSuspendEvent event) { redraw(); } @Override public void onGeometryEditResume(GeometryEditResumeEvent event) { redraw(); } // ------------------------------------------------------------------------ // GeometryEditSelectionHandler: // ------------------------------------------------------------------------ public void onGeometryIndexSelected(GeometryIndexSelectedEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } public void onGeometryIndexDeselected(GeometryIndexDeselectedEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } // ------------------------------------------------------------------------ // GeometryEditDisableHandler: // ------------------------------------------------------------------------ public void onGeometryIndexDisabled(GeometryIndexDisabledEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } public void onGeometryIndexEnabled(GeometryIndexEnabledEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } // ------------------------------------------------------------------------ // GeometryEditHighlightHandler: // ------------------------------------------------------------------------ public void onGeometryIndexHighlightBegin(GeometryIndexHighlightBeginEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } public void onGeometryIndexHighlightEnd(GeometryIndexHighlightEndEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } // ------------------------------------------------------------------------ // GeometryEditMarkForDeletionHandlers: // ------------------------------------------------------------------------ public void onGeometryIndexMarkForDeletionBegin(GeometryIndexMarkForDeletionBeginEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } public void onGeometryIndexMarkForDeletionEnd(GeometryIndexMarkForDeletionEndEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } // ------------------------------------------------------------------------ // GeometryEditSnappingHandlers: // ------------------------------------------------------------------------ public void onGeometryIndexSnappingEnd(GeometryIndexSnappingEndEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } public void onGeometryIndexSnappingBegin(GeometryIndexSnappingBeginEvent event) { for (GeometryIndex index : event.getIndices()) { update(event.getGeometry(), index, false); } } // ------------------------------------------------------------------------ // GeometryEditOperationHandler: // ------------------------------------------------------------------------ public void onGeometryEditMove(GeometryEditMoveEvent event) { // Find the elements that need updating: Map<GeometryIndex, Boolean> indicesToUpdate = new HashMap<GeometryIndex, Boolean>(); for (GeometryIndex index : event.getIndices()) { if (!indicesToUpdate.containsKey(index)) { indicesToUpdate.put(index, false); if (!Geometry.POINT.equals(editingService.getGeometry().getGeometryType()) && !Geometry.MULTI_POINT.equals(editingService.getGeometry().getGeometryType())) { try { List<GeometryIndex> neighbors = null; switch (editingService.getIndexService().getType(index)) { case TYPE_VERTEX: // Move current vertex to the back. This helps the delete operation. indicesToUpdate.put(index, true); neighbors = editingService.getIndexService().getAdjacentEdges(event.getGeometry(), index); if (neighbors != null) { for (GeometryIndex neighborIndex : neighbors) { if (!indicesToUpdate.containsKey(neighborIndex)) { indicesToUpdate.put(neighborIndex, false); } } } neighbors = editingService.getIndexService().getAdjacentVertices(event.getGeometry(), index); if (neighbors != null) { for (GeometryIndex neighborIndex : neighbors) { if (!indicesToUpdate.containsKey(neighborIndex)) { indicesToUpdate.put(neighborIndex, false); } } } break; case TYPE_EDGE: neighbors = editingService.getIndexService().getAdjacentVertices(event.getGeometry(), index); if (neighbors != null) { for (GeometryIndex neighborIndex : neighbors) { if (!indicesToUpdate.containsKey(neighborIndex)) { indicesToUpdate.put(neighborIndex, false); } } } break; default: } } catch (GeometryIndexNotFoundException e) { throw new IllegalStateException(e); } } } } // Check if we need to draw the background (nice, but slows down): if (styleService.getBackgroundStyle() != null && styleService.getBackgroundStyle().getFillOpacity() > 0) { if (event.getGeometry().getGeometryType().equals(Geometry.POLYGON)) { org.geomajas.gwt.client.spatial.geometry.Geometry transformed = mapWidget.getMapModel() .getMapView().getWorldViewTransformer() .worldToPan(GeometryConverter.toGwt(event.getGeometry())); mapWidget.getVectorContext().drawPolygon(groups.get(baseName + ".background"), "background", (Polygon) transformed, styleService.getBackgroundStyle()); } else if (event.getGeometry().getGeometryType().equals(Geometry.MULTI_POLYGON) && event.getGeometry().getGeometries() != null) { for (int i = 0; i < event.getGeometry().getGeometries().length; i++) { Geometry polygon = event.getGeometry().getGeometries()[i]; org.geomajas.gwt.client.spatial.geometry.Geometry transformed = mapWidget.getMapModel() .getMapView().getWorldViewTransformer().worldToPan(GeometryConverter.toGwt(polygon)); mapWidget.getVectorContext().drawPolygon( groups.get(baseName + ".geometry" + i + ".background"), "background", (Polygon) transformed, styleService.getBackgroundStyle()); } } } // Next, redraw the list: for (GeometryIndex index : indicesToUpdate.keySet()) { update(event.getGeometry(), index, indicesToUpdate.get(index)); } } public void onGeometryShapeChanged(GeometryEditShapeChangedEvent event) { redraw(); } // ------------------------------------------------------------------------ // GeometryEditChangeStateHandler: // ------------------------------------------------------------------------ public void onChangeEditingState(GeometryEditChangeStateEvent event) { switch (event.getEditingState()) { case DRAGGING: mapWidget.setCursor(Cursor.MOVE); break; case IDLE: default: mapWidget.setCursorString(mapWidget.getDefaultCursorString()); redraw(); // Remove the temporary insert move line: if (editingService.getInsertIndex() != null) { String id = baseName + "." + editingService.getIndexService().format(editingService.getInsertIndex()); Object parentGroup = groups.get(id.substring(0, id.lastIndexOf('.')) + ".edges"); mapWidget.getVectorContext().deleteElement(parentGroup, insertMoveEdgeId1); mapWidget.getVectorContext().deleteElement(parentGroup, insertMoveEdgeId2); } } } // ------------------------------------------------------------------------ // GeometryEditInsertMoveHandler: // ------------------------------------------------------------------------ public void onTentativeMove(GeometryEditTentativeMoveEvent event) { try { Coordinate[] vertices = editingService.getIndexService().getSiblingVertices(editingService.getGeometry(), editingService.getInsertIndex()); String geometryType = editingService.getIndexService().getGeometryType(editingService.getGeometry(), editingService.getInsertIndex()); if (vertices != null && Geometry.LINE_STRING.equals(geometryType)) { String identifier = baseName + "." + editingService.getIndexService().format(editingService.getInsertIndex()); Object parentGroup = groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".edges"); Coordinate temp1 = event.getOrigin(); Coordinate temp2 = event.getCurrentPosition(); Coordinate c1 = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp1); Coordinate c2 = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp2); LineString edge = mapWidget.getMapModel().getGeometryFactory() .createLineString(new Coordinate[] { c1, c2 }); mapWidget.getVectorContext().drawLine(parentGroup, insertMoveEdgeId1, edge, styleService.getEdgeTentativeMoveStyle()); } else if (vertices != null && Geometry.LINEAR_RING.equals(geometryType)) { String identifier = baseName + "." + editingService.getIndexService().format(editingService.getInsertIndex()); Object parentGroup = groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".edges"); // Line 1 Coordinate temp1 = event.getOrigin(); Coordinate temp2 = event.getCurrentPosition(); Coordinate c1 = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp1); Coordinate c2 = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp2); LineString edge = mapWidget.getMapModel().getGeometryFactory() .createLineString(new Coordinate[] { c1, c2 }); mapWidget.getVectorContext().drawLine(parentGroup, insertMoveEdgeId1, edge, styleService.getEdgeTentativeMoveStyle()); // Line 2 if (styleService.isCloseRingWhileInserting()) { temp1 = vertices[vertices.length - 1]; c1 = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp1); edge = mapWidget.getMapModel().getGeometryFactory().createLineString(new Coordinate[] { c1, c2 }); mapWidget.getVectorContext().drawLine(parentGroup, insertMoveEdgeId2, edge, styleService.getEdgeTentativeMoveStyle()); } } } catch (GeometryIndexNotFoundException e) { throw new IllegalStateException(e); } } // ------------------------------------------------------------------------ // CoordinateSnappedHandler implementation: // ------------------------------------------------------------------------ public void onCoordinateSnapAttempt(CoordinateSnapEvent event) { if (editingService.getEditingState() == GeometryEditState.INSERTING) { String identifier = baseName + "." + editingService.getIndexService().format(editingService.getInsertIndex()); Object parentGroup = groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".vertices"); Coordinate temp = event.getTo(); Coordinate coordinate = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp); addShapeToGraphicsContext(mapWidget.getVectorContext(), parentGroup, identifier, coordinate, event.hasSnapped() ? styleService.getVertexSnappedStyle() : new ShapeStyle()); } } public void setVisible(boolean visible) { if (visible) { mapWidget.getVectorContext().hide(editingService.getGeometry()); } else { mapWidget.getVectorContext().unhide(editingService.getGeometry()); } } public void addVertexHandlerFactory(VertexMapHandlerFactory factory) { customVertexFactories.add(factory); } public void addEdgeHandlerFactory(EdgeMapHandlerFactory factory) { customEdgeFactories.add(factory); } public void addGeometryHandlerFactory(GeometryIndexMapHandlerFactory factory) { EditingHandlerRegistry.addGeometryHandlerFactory(factory); } public void removeGeometryHandlerFactory(GeometryIndexMapHandlerFactory factory) { EditingHandlerRegistry.removeGeometryHandlerFactory(factory); } // ------------------------------------------------------------------------ // Geometry rendering methods: // ------------------------------------------------------------------------ public StyleService getStyleService() { return styleService; } private void update(Geometry geometry, GeometryIndex index, boolean bringToFront) { try { switch (editingService.getIndexService().getType(index)) { case TYPE_VERTEX: updateVertex(geometry, index, bringToFront); break; case TYPE_EDGE: updateEdge(geometry, index, bringToFront); break; case TYPE_GEOMETRY: default: updateGeometry(geometry, index, bringToFront); } } catch (GeometryIndexNotFoundException e) { } } // TODO make use of the findGeometryStyle method. private void updateGeometry(Geometry geometry, GeometryIndex index, boolean bringToFront) throws GeometryIndexNotFoundException { // Some initialization: String identifier = baseName + "." + editingService.getIndexService().format(index); boolean marked = editingService.getIndexStateService().isMarkedForDeletion(index); // Find current and previous parent groups: Composite parentGroup = groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".geometries"); // Find the correct style: ShapeStyle style = new ShapeStyle(); if (marked) { style = styleService.getBackgroundMarkedForDeletionStyle(); } // Draw the inner ring: org.geomajas.gwt.client.spatial.geometry.Geometry transformed = mapWidget.getMapModel().getMapView() .getWorldViewTransformer() .worldToPan(GeometryConverter.toGwt(editingService.getIndexService().getGeometry(geometry, index))); if (transformed instanceof LinearRing) { Polygon polygon = mapWidget.getMapModel().getGeometryFactory() .createPolygon((LinearRing) transformed, null); mapWidget.getVectorContext().drawPolygon(parentGroup, identifier + ".background", polygon, style); } } private void updateVertex(Geometry geometry, GeometryIndex index, boolean moveToBack) throws GeometryIndexNotFoundException { // Some initialization: String identifier = baseName + "." + editingService.getIndexService().format(index); Composite parentGroup = groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".vertices"); Coordinate temp = editingService.getIndexService().getVertex(geometry, index); Coordinate coordinate = mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp); addShapeToGraphicsContext(mapWidget.getVectorContext(), parentGroup, identifier, coordinate, findVertexStyle(index)); if (moveToBack) { mapWidget.getVectorContext().moveToBack(parentGroup, identifier); } } private void updateEdge(Geometry geometry, GeometryIndex index, boolean bringToFront) throws GeometryIndexNotFoundException { // Some initialization: String identifier = baseName + "." + editingService.getIndexService().format(index); Object parentGroup = groups.get(identifier.substring(0, identifier.lastIndexOf('.')) + ".edges"); Coordinate[] c = editingService.getIndexService().getEdge(geometry, index); LineString temp = mapWidget.getMapModel().getGeometryFactory().createLineString(c); LineString edge = (LineString) mapWidget.getMapModel().getMapView().getWorldViewTransformer().worldToPan(temp); mapWidget.getVectorContext().drawLine(parentGroup, identifier, edge, findEdgeStyle(index)); } private void draw(Geometry geometry) { org.geomajas.gwt.client.spatial.geometry.Geometry transformed = mapWidget.getMapModel().getMapView() .getWorldViewTransformer().worldToPan(GeometryConverter.toGwt(geometry)); GraphicsContext graphics = mapWidget.getVectorContext(); graphics.drawGroup(mapWidget.getGroup(RenderGroup.VECTOR), geometry); if (transformed instanceof MultiPolygon) { draw(geometry, null, (MultiPolygon) transformed, graphics); } else if (transformed instanceof MultiPoint) { draw(geometry, null, (MultiPoint) transformed, graphics); } else if (transformed instanceof MultiLineString) { draw(geometry, null, (MultiLineString) transformed, graphics); } else if (transformed instanceof Polygon) { draw(geometry, null, (Polygon) transformed, graphics); } else if (transformed instanceof LineString) { draw(geometry, null, (LineString) transformed, graphics); } else if (transformed instanceof Point) { draw(geometry, null, (Point) transformed, graphics); } } private void draw(Object parentGroup, GeometryIndex parentIndex, MultiPoint mp, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite geometryGroup = getOrCreateGroup(parentGroup, groupName + ".geometries"); // Draw all polygons: for (int i = 0; i < mp.getNumGeometries(); i++) { GeometryIndex pointIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, i); draw(geometryGroup, pointIndex, (Point) mp.getGeometryN(i), graphics); } } private void draw(Object parentGroup, GeometryIndex parentIndex, MultiLineString mls, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite geometryGroup = getOrCreateGroup(parentGroup, groupName + ".geometries"); // Draw all polygons: for (int i = 0; i < mls.getNumGeometries(); i++) { GeometryIndex pointIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, i); draw(geometryGroup, pointIndex, (LineString) mls.getGeometryN(i), graphics); } } private void draw(Object parentGroup, GeometryIndex parentIndex, MultiPolygon mp, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite geometryGroup = getOrCreateGroup(parentGroup, groupName + ".geometries"); // Draw all polygons: for (int i = 0; i < mp.getNumGeometries(); i++) { GeometryIndex polygonIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, i); draw(geometryGroup, polygonIndex, (Polygon) mp.getGeometryN(i), graphics); } } private void draw(Object parentGroup, GeometryIndex parentIndex, Polygon polygon, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite bgGroup = getOrCreateGroup(parentGroup, groupName + ".background"); Composite geometryGroup = getOrCreateGroup(parentGroup, groupName + ".geometries"); // Draw the exterior ring: GeometryIndex shellIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, 0); if (!polygon.isEmpty()) { if (styleService.getBackgroundStyle() != null && styleService.getBackgroundStyle().getFillOpacity() > 0) { graphics.drawPolygon(bgGroup, "background", polygon, findGeometryStyle(shellIndex)); } draw(geometryGroup, shellIndex, polygon.getExteriorRing(), graphics); } // Draw the interior rings: for (int i = 0; i < polygon.getNumInteriorRing(); i++) { GeometryIndex holeIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_GEOMETRY, i + 1); draw(geometryGroup, holeIndex, polygon.getInteriorRingN(i), graphics); } } private void draw(Object parentGroup, GeometryIndex parentIndex, LinearRing linearRing, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite edgeGroup = getOrCreateGroup(parentGroup, groupName + ".edges"); Composite vertexGroup = getOrCreateGroup(parentGroup, groupName + ".vertices"); Coordinate[] coordinates = linearRing.getCoordinates(); if (coordinates != null) { // Check if we have to draw the background as well (if there are controllers defined for it): GraphicsController controller = createGeometryController(parentIndex); if (controller != null) { Polygon polygon = mapWidget.getMapModel().getGeometryFactory().createPolygon(linearRing, null); graphics.drawPolygon(parentGroup, groupName + ".background", polygon, new ShapeStyle()); if (!editingService.isSuspended()) { graphics.setController(parentGroup, groupName + ".background", controller); } } // Draw individual edges: int max = coordinates.length; if (!styleService.isCloseRingWhileInserting() && editingService.getEditingState() == GeometryEditState.INSERTING && editingService.getIndexService().isChildOf(parentIndex, editingService.getInsertIndex())) { max--; } for (int i = 1; i < max; i++) { GeometryIndex edgeIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_EDGE, i - 1); String identifier = baseName + "." + editingService.getIndexService().format(edgeIndex); LineString edge = linearRing.getGeometryFactory().createLineString( new Coordinate[] { coordinates[i - 1], coordinates[i] }); graphics.drawLine(edgeGroup, identifier, edge, findEdgeStyle(edgeIndex)); if (!editingService.isSuspended()) { graphics.setController(edgeGroup, identifier, createEdgeController(edgeIndex)); } } addInivisibleShapeToGraphicsContext(graphics, vertexGroup); for (int i = 0; i < coordinates.length - 1; i++) { GeometryIndex vertexIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_VERTEX, i); String identifier = baseName + "." + editingService.getIndexService().format(vertexIndex); addShapeToGraphicsContext(graphics, vertexGroup, identifier, coordinates[i], findVertexStyle(vertexIndex)); if (!editingService.isSuspended()) { graphics.setController(vertexGroup, identifier, createVertexController(vertexIndex)); } } } } private void draw(Object parentGroup, GeometryIndex parentIndex, LineString lineString, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite edgeGroup = getOrCreateGroup(parentGroup, groupName + ".edges"); Composite vertexGroup = getOrCreateGroup(parentGroup, groupName + ".vertices"); Coordinate[] coordinates = lineString.getCoordinates(); if (coordinates != null) { // Draw individual edges: for (int i = 1; i < coordinates.length; i++) { GeometryIndex edgeIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_EDGE, i - 1); String identifier = baseName + "." + editingService.getIndexService().format(edgeIndex); LineString edge = lineString.getGeometryFactory().createLineString( new Coordinate[] { coordinates[i - 1], coordinates[i] }); graphics.drawLine(edgeGroup, identifier, edge, findEdgeStyle(edgeIndex)); if (!editingService.isSuspended()) { graphics.setController(edgeGroup, identifier, createEdgeController(edgeIndex)); } } addInivisibleShapeToGraphicsContext(graphics, vertexGroup); for (int i = 0; i < coordinates.length; i++) { GeometryIndex vertexIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_VERTEX, i); String identifier = baseName + "." + editingService.getIndexService().format(vertexIndex); addShapeToGraphicsContext(graphics, vertexGroup, identifier, coordinates[i], findVertexStyle(vertexIndex)); if (!editingService.isSuspended()) { graphics.setController(vertexGroup, identifier, createVertexController(vertexIndex)); } } } } private void addInivisibleShapeToGraphicsContext(GraphicsContext graphics, Composite parentGroup) { int halfVertexSize = getStyleService().getPointSymbolizerShapeAndSize().getSize() / 2 ; addShapeToGraphicsContext(graphics, parentGroup, "first", new Coordinate(halfVertexSize, halfVertexSize), new ShapeStyle()); } private void draw(Object parentGroup, GeometryIndex parentIndex, Point point, GraphicsContext graphics) { String groupName = baseName; if (parentIndex != null) { groupName += "." + editingService.getIndexService().format(parentIndex); } Composite vertexGroup = getOrCreateGroup(parentGroup, groupName + ".vertices"); addInivisibleShapeToGraphicsContext(graphics, vertexGroup); if (!point.isEmpty()) { GeometryIndex vertexIndex = editingService.getIndexService().addChildren(parentIndex, GeometryIndexType.TYPE_VERTEX, 0); String identifier = baseName + "." + editingService.getIndexService().format(vertexIndex); addShapeToGraphicsContext(graphics, vertexGroup, identifier, point.getCoordinate(), findVertexStyle(vertexIndex)); if (!editingService.isSuspended()) { graphics.setController(vertexGroup, identifier, createVertexController(vertexIndex)); } } } /** * Used in creating the "edges", "selection" and "vertices" groups for LineStrings and LinearRings. */ private Composite getOrCreateGroup(Object parent, String name) { if (groups.containsKey(name)) { return groups.get(name); } Composite group = new Composite(name); mapWidget.getVectorContext().drawGroup(parent, group); groups.put(name, group); return group; } private ShapeStyle findVertexStyle(GeometryIndex index) { if (editingService.getIndexStateService().isMarkedForDeletion(index)) { return styleService.getVertexMarkForDeletionStyle(); } else if (!editingService.getIndexStateService().isEnabled(index)) { return styleService.getVertexDisabledStyle(); } else if (editingService.getIndexStateService().isSnapped(index)) { return styleService.getVertexSnappedStyle(); } boolean selected = editingService.getIndexStateService().isSelected(index); boolean highlighted = editingService.getIndexStateService().isHightlighted(index); if (selected && highlighted) { return styleService.getVertexSelectHoverStyle(); } else if (selected) { return styleService.getVertexSelectStyle(); } else if (highlighted) { return styleService.getVertexHoverStyle(); } return styleService.getVertexStyle(); } private ShapeStyle findEdgeStyle(GeometryIndex index) { if (editingService.getIndexStateService().isMarkedForDeletion(index)) { return styleService.getEdgeMarkForDeletionStyle(); } else if (!editingService.getIndexStateService().isEnabled(index)) { return styleService.getEdgeDisabledStyle(); } boolean selected = editingService.getIndexStateService().isSelected(index); boolean highlighted = editingService.getIndexStateService().isHightlighted(index); if (selected && highlighted) { return styleService.getEdgeSelectHoverStyle(); } else if (selected) { return styleService.getEdgeSelectStyle(); } else if (highlighted) { return styleService.getEdgeHoverStyle(); } return styleService.getEdgeStyle(); } private ShapeStyle findGeometryStyle(GeometryIndex index) { if (!editingService.getIndexStateService().isEnabled(index)) { return styleService.getBackgroundDisabledStyle(); } else if (editingService.getIndexStateService().isMarkedForDeletion(index)) { return styleService.getBackgroundMarkedForDeletionStyle(); } return styleService.getBackgroundStyle(); } private GraphicsController createVertexController(GeometryIndex index) { CompositeGeometryIndexController controller = new CompositeGeometryIndexController(mapWidget, editingService, index, editingService.getEditingState() == GeometryEditState.DRAGGING); for (AbstractGeometryIndexMapHandler handler : EditingHandlerRegistry.getVertexHandlers()) { controller.addMapHandler(handler); } for (VertexMapHandlerFactory factory : customVertexFactories) { controller.addMapHandler(factory.create()); } return controller; } private GraphicsController createEdgeController(GeometryIndex index) { CompositeGeometryIndexController controller = new CompositeGeometryIndexController(mapWidget, editingService, index, editingService.getEditingState() == GeometryEditState.DRAGGING); for (AbstractGeometryIndexMapHandler handler : EditingHandlerRegistry.getEdgeHandlers()) { controller.addMapHandler(handler); } for (EdgeMapHandlerFactory factory : customEdgeFactories) { controller.addMapHandler(factory.create()); } EdgeMarkerHandler edgeMarkerHandler = new EdgeMarkerHandler(mapWidget, editingService, controller); controller.addMouseOutHandler(edgeMarkerHandler); controller.addMouseMoveHandler(edgeMarkerHandler); controller.addMapDownHandler(edgeMarkerHandler); return controller; } private GraphicsController createGeometryController(GeometryIndex index) { List<AbstractGeometryIndexMapHandler> handlers = EditingHandlerRegistry.getGeometryHandlers(); if (handlers == null || handlers.size() == 0) { return null; } CompositeGeometryIndexController controller = new CompositeGeometryIndexController(mapWidget, editingService, index, editingService.getEditingState() == GeometryEditState.DRAGGING); for (AbstractGeometryIndexMapHandler handler : handlers) { controller.addMapHandler(handler); } return controller; } private void addShapeToGraphicsContext(GraphicsContext graphics, Object parentGroup, String identifier, Coordinate coordinate, ShapeStyle style) { int vertexSize = getStyleService().getPointSymbolizerShapeAndSize().getSize() ; int halfVertexSize = vertexSize / 2 ; switch(styleService.getPointSymbolizerShapeAndSize().getShape()) { case SQUARE: Bbox rectangle = new Bbox(coordinate.getX() - halfVertexSize, coordinate.getY() - halfVertexSize, vertexSize, vertexSize); graphics.drawRectangle(parentGroup, identifier, rectangle, style); break; case CIRCLE: graphics.drawCircle(parentGroup, identifier, coordinate, vertexSize, style); break; } } }