com.vividsolutions.jtstest.testbuilder.GeometryEditPanel Maven / Gradle / Ivy
The newest version!
/*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; 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.jtstest.testbuilder;
import java.text.NumberFormat;
import java.util.List;
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jtstest.testbuilder.model.*;
import com.vividsolutions.jtstest.testbuilder.ui.*;
import com.vividsolutions.jtstest.testbuilder.ui.style.AWTUtil;
import com.vividsolutions.jtstest.testbuilder.ui.tools.*;
import com.vividsolutions.jtstest.testbuilder.ui.render.*;
import com.vividsolutions.jtstest.testbuilder.ui.render.GeometryPainter;
/**
* Panel which displays rendered geometries.
*
* Zoom methods take arguments in model space.
*
* @version 1.7
*/
public class GeometryEditPanel extends JPanel
{
/*
private static Color[] selectedPointColor = { new Color(0, 64, 128, 255),
new Color(170, 64, 0, 255) };
*/
private TestBuilderModel tbModel;
private DrawingGrid grid = new DrawingGrid();
private GridRenderer gridRenderer;
boolean stateAddingPoints = false;
Coordinate markPoint;
Point2D lastPt = new Point2D.Double();
private Tool currentTool = null; //PolygonTool.getInstance();
private Viewport viewport = new Viewport(this);
private RenderManager renderMgr;
//private OperationMonitorManager opMonitor;
//----------------------------------------
BorderLayout borderLayout1 = new BorderLayout();
GeometryPopupMenu menu = new GeometryPopupMenu();
public GeometryEditPanel() {
gridRenderer = new GridRenderer(viewport, grid);
try {
initUI();
} catch (Exception ex) {
ex.printStackTrace();
}
renderMgr = new RenderManager(this);
//opMonitor = new OperationMonitorManager(this, viewport);
}
void initUI() throws Exception {
this.addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentResized(ComponentEvent e) {
this_componentResized(e);
}
});
this.setBackground(Color.white);
this.setBorder(BorderFactory.createLoweredBevelBorder());
this.setLayout(borderLayout1);
setToolTipText("");
setBorder(BorderFactory.createEmptyBorder());
// deactivate for now, since it interferes with right-click zoom-out
//addMouseListener(new PopupClickListener());
}
class PopupClickListener extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
if (e.isPopupTrigger())
doPopUp(e);
}
public void mouseReleased(MouseEvent e)
{
if (e.isPopupTrigger())
doPopUp(e);
}
private void doPopUp(MouseEvent e)
{
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
public void setModel(TestBuilderModel model) {
this.tbModel = model;
}
public TestBuilderModel getModel() {
return tbModel;
}
public GeometryEditModel getGeomModel()
{
return tbModel.getGeometryEditModel();
}
public void setGridEnabled(boolean isEnabled) {
gridRenderer.setEnabled(isEnabled);
}
public Viewport getViewport() { return viewport; }
public void updateView()
{
// fireGeometryChanged(new GeometryEvent(this));
forceRepaint();
}
public void forceRepaint() {
renderMgr.setDirty(true);
Component source = SwingUtilities.windowForComponent(this);
if (source == null)
source = this;
source.repaint();
}
private LayerList getLayerList()
{
return tbModel.getLayers();
}
public void setShowingInput(boolean isEnabled)
{
if (tbModel == null) return;
getLayerList().getLayer(LayerList.LYR_A).setEnabled(isEnabled);
getLayerList().getLayer(LayerList.LYR_B).setEnabled(isEnabled);
forceRepaint();
}
public void setShowingGeometryA(boolean isEnabled) {
if (tbModel == null) return;
getLayerList().getLayer(LayerList.LYR_A).setEnabled(isEnabled);
forceRepaint();
}
public void setShowingGeometryB(boolean isEnabled) {
if (tbModel == null) return;
getLayerList().getLayer(LayerList.LYR_B).setEnabled(isEnabled);
forceRepaint();
}
public void setShowingResult(boolean isEnabled)
{
if (tbModel == null) return;
getLayerList().getLayer(LayerList.LYR_RESULT).setEnabled(isEnabled);
forceRepaint();
}
public void setGridSize(double gridSize) {
grid.setGridSize(gridSize);
forceRepaint();
}
public void setHighlightPoint(Coordinate pt) {
markPoint = pt;
}
public boolean isAddingPoints() {
return stateAddingPoints;
}
public void updateGeom()
{
renderMgr.setDirty(true);
getGeomModel().geomChanged();
}
public String getToolTipText(MouseEvent event) {
// if (event.getPoint().x < 100) return null;
Coordinate pt = viewport.toModelCoordinate(event.getPoint());
double toleranceInModel = AppConstants.TOLERANCE_PIXELS / getViewport().getScale();
// avoid wierd scale issues
if (toleranceInModel <= 0.0) return null;
return GeometryLocationsWriter.writeLocation(getLayerList(), pt, toleranceInModel);
// return viewport.toModel(event.getPoint()).toString();
// return null;
}
public double getToleranceInModel()
{
return AppConstants.TOLERANCE_PIXELS / getViewport().getScale();
}
public String getInfo(Coordinate pt)
{
double toleranceInModel = AppConstants.TOLERANCE_PIXELS / getViewport().getScale();
GeometryLocationsWriter writer = new GeometryLocationsWriter();
writer.setHtml(false);
return writer.writeLocationString(getLayerList(), pt, toleranceInModel);
}
public double getGridSize() {
return grid.getGridSize();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
renderMgr.render();
renderMgr.copyImage(g);
}
/*
// MD - obsolete
public void render(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gridRenderer.paint(g2);
getLayerList().paint((Graphics2D) g2, viewport);
}
*/
private static int VERTEX_SIZE = AppConstants.VERTEX_SIZE + 1;
private static double VERTEX_SIZE_OVER_2 = VERTEX_SIZE / 2;
private static int INNER_SIZE = VERTEX_SIZE - 2;
private static double INNER_SIZE_OVER_2 = INNER_SIZE / 2;
private void drawHighlightedVertices(Graphics2D g, List coords, Color clr) {
Rectangle2D rect = new Rectangle2D.Double();
for (int i = 0; i < coords.size(); i++) {
Coordinate pt = (Coordinate) coords.get(i);
Point2D p = viewport.toView(pt);
rect.setFrame(
p.getX() - VERTEX_SIZE_OVER_2,
p.getY() - VERTEX_SIZE_OVER_2,
VERTEX_SIZE,
VERTEX_SIZE);
g.setColor(clr);
g.fill(rect);
Rectangle2D rectInner = new Rectangle2D.Double(
p.getX() - INNER_SIZE_OVER_2,
p.getY() - INNER_SIZE_OVER_2,
INNER_SIZE,
INNER_SIZE);
g.setColor(AppConstants.VERTEX_HIGHLIGHT_CLR);
g.fill(rectInner);
}
}
private void drawHighlightedVertex(Graphics2D g, Coordinate pt, Color clr) {
Rectangle2D rect = new Rectangle2D.Double();
Point2D p = viewport.toView(pt);
rect.setFrame(
p.getX() - VERTEX_SIZE_OVER_2,
p.getY() - VERTEX_SIZE_OVER_2,
VERTEX_SIZE,
VERTEX_SIZE);
g.setColor(clr);
g.fill(rect);
Rectangle2D rectInner = new Rectangle2D.Double(
p.getX() - INNER_SIZE_OVER_2,
p.getY() - INNER_SIZE_OVER_2,
INNER_SIZE,
INNER_SIZE);
g.setColor(AppConstants.VERTEX_HIGHLIGHT_CLR);
g.fill(rectInner);
}
private static double VERTEX_SHADOW_SIZE_OVER_2 = AppConstants.VERTEX_SHADOW_SIZE / 2;
private void drawVertexShadow(Graphics2D g, Coordinate pt, Color clr) {
Ellipse2D rect = new Ellipse2D.Double();
Point2D p = viewport.toView(pt);
rect.setFrame(
p.getX() - VERTEX_SHADOW_SIZE_OVER_2,
p.getY() - VERTEX_SHADOW_SIZE_OVER_2,
AppConstants.VERTEX_SHADOW_SIZE,
AppConstants.VERTEX_SHADOW_SIZE);
g.setColor(clr);
g.fill(rect);
}
private void drawMark(Graphics2D g) {
if (markPoint == null)
return;
String markLabel = markPoint.x + ", " + markPoint.y;
int strWidth = g.getFontMetrics().stringWidth(markLabel);
double markSize = AppConstants.HIGHLIGHT_SIZE;
Point2D highlightPointView = viewport.toView(markPoint);
double markX = highlightPointView.getX();
double markY = highlightPointView.getY();
Ellipse2D.Double shape = new Ellipse2D.Double(
markX - markSize / 2,
markY - markSize / 2,
markSize, markSize);
AWTUtil.setStroke(g, 4);
g.setColor(AppConstants.HIGHLIGHT_CLR);
g.draw(shape);
// draw label box
Envelope viewEnv = viewport.getViewEnv();
int bottomOffset = 10;
int boxHgt = 20;
int boxPadX = 20;
int boxWidth = strWidth + 2 * boxPadX;
int arrowWidth = 10;
int arrowOffset = 2;
int labelOffsetY = 5;
int bottom = (int) viewEnv.getMaxY() - bottomOffset;
int centreX = (int) (viewEnv.getMinX() + viewEnv.getMaxX()) / 2;
int boxMinX = centreX - boxWidth/2;
int boxMaxX = centreX + boxWidth/2;
int boxMinY = bottom - boxHgt;
int boxMaxY = bottom;
int[] xpts = new int[] {
boxMinX, centreX - arrowWidth/2, (int) markX, centreX + arrowWidth/2,
boxMaxX, boxMaxX, boxMinX };
int[] ypts = new int[] {
boxMinY, boxMinY, (int) (markY + arrowOffset), boxMinY,
boxMinY, boxMaxY, boxMaxY };
Polygon poly = new Polygon(xpts, ypts, xpts.length);
g.setColor(AppConstants.HIGHLIGHT_FILL_CLR);
g.fill(poly);
AWTUtil.setStroke(g, 1);
g.setColor(ColorUtil.opaque(AppConstants.HIGHLIGHT_CLR));
g.draw(poly);
// draw mark point label
g.setColor(Color.BLACK);
g.drawString(markLabel, centreX - strWidth/2, boxMaxY - labelOffsetY);
}
/**
* Draws a mask surround to indicate that geometry is being visually altered
* @param g
*/
private void drawMagnifyMask(Graphics2D g) {
double viewWidth = viewport.getWidthInView();
double viewHeight = viewport.getHeightInView();
float minExtent = (float) Math.min(viewWidth, viewHeight);
float maskWidth = (float) (minExtent * AppConstants.MASK_WIDTH_FRAC / 2);
Area mask = new Area(new Rectangle2D.Float(
(float) 0, (float) 0,
(float) viewWidth, (float) viewHeight));
Area maskHole = new Area(new Rectangle2D.Float(
(float) maskWidth,
(float) maskWidth,
((float) viewWidth) - 2 * maskWidth,
((float) viewHeight) - 2 * maskWidth));
mask.subtract(maskHole);
g.setColor(AppConstants.MASK_CLR);
g.fill(mask);
}
public void flash(Geometry g)
{
Graphics2D gr = (Graphics2D) getGraphics();
gr.setXORMode(Color.white);
Stroke stroke = new BasicStroke(5);
Geometry flashGeom = g;
if (g instanceof com.vividsolutions.jts.geom.Point)
flashGeom = flashPointGeom(g);
try {
GeometryPainter.paint(flashGeom, viewport, gr, Color.RED, null, stroke);
Thread.sleep(200);
GeometryPainter.paint(flashGeom, viewport, gr, Color.RED, null, stroke);
}
catch (Exception ex) {
// nothing we can do
}
gr.setPaintMode();
}
private Geometry flashPointGeom(Geometry g)
{
double ptRadius = viewport.toModel(4);
return g.buffer(ptRadius);
}
public Point2D snapToGrid(Point2D modelPoint) {
return grid.snapToGrid(modelPoint);
}
void this_componentResized(ComponentEvent e) {
renderMgr.componentResized();
viewport.update(this.getSize());
}
/**
*
* @param newTool tool to set, or null to clear tool
*/
public void setCurrentTool(Tool newTool) {
if (currentTool != null) currentTool.deactivate();
currentTool = newTool;
if (currentTool != null) currentTool.activate(this);
}
public void zoomToGeometry(int i) {
Geometry g = getGeomModel().getGeometry(i);
if (g == null) return;
zoom(g.getEnvelopeInternal());
}
public void zoomToInput() {
zoom(getGeomModel().getEnvelope());
}
public void zoomToResult() {
zoom(getGeomModel().getEnvelopeResult());
}
public void zoomToFullExtent() {
zoom(getGeomModel().getEnvelopeAll());
}
public void zoom(Geometry geom)
{
if (geom == null) return;
zoom(geom.getEnvelopeInternal());
}
public void zoom(Point2D zoomBox1, Point2D zoomBox2)
{
Envelope zoomEnv = new Envelope();
zoomEnv.expandToInclude(zoomBox1.getX(), zoomBox1.getY());
zoomEnv.expandToInclude(zoomBox2.getX(), zoomBox2.getY());
zoom(zoomEnv);
}
public void zoom(Envelope zoomEnv) {
if (zoomEnv == null)
return;
if (zoomEnv.isNull()) {
viewport.zoomToInitialExtent();
return;
}
double averageExtent = (zoomEnv.getWidth() + zoomEnv.getHeight()) / 2d;
// fix to allow zooming to points
if (averageExtent == 0.0)
averageExtent = 1.0;
double buffer = averageExtent * 0.1;
zoomEnv.expandBy(buffer);
viewport.zoom(zoomEnv);
}
/**
* Zoom to a point, ensuring that the zoom point remains in the same screen location.
*
* @param zoomPt
* @param zoomFactor
*/
public void zoom(Point2D zoomPt, double zoomFactor) {
double zoomScale = getViewport().getScale() * zoomFactor;
viewport.zoom(zoomPt, zoomScale);
}
public void zoomPan(double dx, double dy) {
getViewport().zoomPan(dx, dy);
}
public String cursorLocationString(Point2D pView)
{
Point2D p = getViewport().toModel(pView);
NumberFormat format = getViewport().getScaleFormat();
return format.format(p.getX())
+ ", "
+ format.format(p.getY());
}
public Renderer getRenderer()
{
return new GeometryEditPanelRenderer();
}
class GeometryEditPanelRenderer implements Renderer
{
private GeometryStretcherView stretchView = null;
private Renderer currentRenderer = null;
private boolean isMagnifyingTopology = false;
private boolean isRenderingStretchVertices = false;
public GeometryEditPanelRenderer()
{
if (tbModel.isMagnifyingTopology()) {
stretchView = new GeometryStretcherView(getGeomModel());
stretchView.setStretchSize(viewport.toModel(tbModel.getTopologyStretchSize()));
stretchView.setNearnessTolerance(viewport.toModel(GeometryStretcherView.NEARNESS_TOL_IN_VIEW));
stretchView.setEnvelope(viewport.getModelEnv());
isMagnifyingTopology = tbModel.isMagnifyingTopology();
isRenderingStretchVertices = stretchView.isViewPerformant();
}
}
public void render(Graphics2D g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (isMagnifyingTopology) {
if (isRenderingStretchVertices) {
//renderMagnifiedVertexShadows(g2);
renderMagnifiedVertexMask(g2);
}
else {
// render indicator that shows stretched view is non-performant
renderMagnifyWarning(g2);
}
}
gridRenderer.paint(g2);
renderLayers(g2);
if (isMagnifyingTopology && isRenderingStretchVertices) {
renderMagnifiedVertices(g2);
}
drawMark(g2);
}
public void renderLayers(Graphics2D g)
{
LayerList layerList = getLayerList();
int n = layerList.size();
for (int i = 0; i < n; i++) {
if (isMagnifyingTopology && isRenderingStretchVertices
&& stretchView != null && i < 2) {
//System.out.println("rendering stretch verts");
currentRenderer = new LayerRenderer(layerList.getLayer(i),
new StaticGeometryContainer(stretchView.getStretchedGeometry(i)),
viewport);
}
else {
currentRenderer = new LayerRenderer(layerList.getLayer(i), viewport);
}
currentRenderer.render(g);
}
currentRenderer = null;
}
public void renderMagnifiedVertices(Graphics2D g)
{
LayerList layerList = getLayerList();
for (int i = 0; i < 2; i++) {
// respect layer visibility
if (! layerList.getLayer(i).isEnabled()) continue;
List stretchedVerts = stretchView.getStretchedVertices(i);
if (stretchedVerts == null) continue;
for (int j = 0; j < stretchedVerts.size(); j++) {
Coordinate p = (Coordinate) stretchedVerts.get(j);
drawHighlightedVertex(g, p,
i == 0 ? GeometryDepiction.GEOM_A_HIGHLIGHT_CLR :
GeometryDepiction.GEOM_B_HIGHLIGHT_CLR);
}
}
}
public void renderMagnifiedVertexShadows(Graphics2D g)
{
if (stretchView == null) return;
for (int i = 0; i < 2; i++) {
List stretchedVerts = stretchView.getStretchedVertices(i);
if (stretchedVerts == null) continue;
for (int j = 0; j < stretchedVerts.size(); j++) {
Coordinate p = (Coordinate) stretchedVerts.get(j);
drawVertexShadow(g, p, AppConstants.VERTEX_SHADOW_CLR);
}
}
}
public void renderMagnifiedVertexMask(Graphics2D g)
{
if (stretchView == null) return;
// render lowlight background
Rectangle2D rect = new Rectangle2D.Float();
rect.setFrame(
0,
0,
viewport.getWidthInView(),
viewport.getHeightInView());
g.setColor(AppConstants.MASK_CLR);
g.fill(rect);
// highlight mag vertices
for (int i = 0; i < 2; i++) {
List stretchedVerts = stretchView.getStretchedVertices(i);
if (stretchedVerts == null) continue;
for (int j = 0; j < stretchedVerts.size(); j++) {
Coordinate p = (Coordinate) stretchedVerts.get(j);
drawVertexShadow(g, p, Color.WHITE);
}
}
}
public void renderMagnifyWarning(Graphics2D g)
{
if (stretchView == null) return;
float maxx = (float) viewport.getWidthInView();
float maxy = (float) viewport.getHeightInView();
GeneralPath path = new GeneralPath();
path.moveTo(0, 0);
path.lineTo(maxx, maxy);
path.moveTo(0, maxy);
path.lineTo(maxx, 0);
// render lowlight background
g.setColor(AppConstants.MASK_CLR);
g.setStroke(new BasicStroke(30));
g.draw(path);
}
public synchronized void cancel()
{
if (currentRenderer != null)
currentRenderer.cancel();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy