GeometryEditPanel.java
/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jtstest.testbuilder;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Stroke;
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 java.text.NumberFormat;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.util.AffineTransformation;
import org.locationtech.jtstest.testbuilder.model.DisplayParameters;
import org.locationtech.jtstest.testbuilder.model.GeometryEditModel;
import org.locationtech.jtstest.testbuilder.model.GeometryStretcherView;
import org.locationtech.jtstest.testbuilder.model.Layer;
import org.locationtech.jtstest.testbuilder.model.LayerList;
import org.locationtech.jtstest.testbuilder.model.StaticGeometryContainer;
import org.locationtech.jtstest.testbuilder.model.TestBuilderModel;
import org.locationtech.jtstest.testbuilder.ui.ColorUtil;
import org.locationtech.jtstest.testbuilder.ui.GeometryLocationsWriter;
import org.locationtech.jtstest.testbuilder.ui.Viewport;
import org.locationtech.jtstest.testbuilder.ui.render.DrawingGrid;
import org.locationtech.jtstest.testbuilder.ui.render.GeometryPainter;
import org.locationtech.jtstest.testbuilder.ui.render.GridElement;
import org.locationtech.jtstest.testbuilder.ui.render.LayerRenderer;
import org.locationtech.jtstest.testbuilder.ui.render.LegendElement;
import org.locationtech.jtstest.testbuilder.ui.render.RenderManager;
import org.locationtech.jtstest.testbuilder.ui.render.Renderer;
import org.locationtech.jtstest.testbuilder.ui.render.TitleElement;
import org.locationtech.jtstest.testbuilder.ui.render.ViewStyle;
import org.locationtech.jtstest.testbuilder.ui.style.AWTUtil;
import org.locationtech.jtstest.testbuilder.ui.tools.Tool;
/**
* Panel which displays rendered geometries.
*
* Zoom methods take arguments in model space.
*
* @version 1.7
*/
public class GeometryEditPanel extends JPanel
{
private TestBuilderModel tbModel;
private DrawingGrid grid = new DrawingGrid();
private GridElement gridElement;
private LegendElement legendElement;
private TitleElement titleElement;
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();
private ViewStyle viewStyle;
public GeometryEditPanel() {
viewStyle = new ViewStyle();
gridElement = new GridElement(viewport, grid);
legendElement = new LegendElement(viewport);
titleElement = new TitleElement(viewport);
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(viewStyle.getBackground());
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 ViewStyle getViewStyle() {
return viewStyle;
}
public void setViewStyle(ViewStyle viewStyle) {
this.viewStyle = viewStyle;
}
public Color getBackgroundColor() {
return viewStyle.getBackground();
}
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 setShowingGrid(boolean isEnabled)
{
viewStyle.setGridEnabled(isEnabled);
forceRepaint();
}
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 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 weird 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 void paintComponent(Graphics g) {
super.paintComponent(g);
renderMgr.render();
renderMgr.copyImage(g);
}
private void drawBorder(Graphics2D g, Color clr) {
Stroke strokeBox = new BasicStroke(1, // Width of stroke
BasicStroke.CAP_BUTT, // End cap style
BasicStroke.JOIN_MITER, // Join style
10, // Miter limit
null, // Dash pattern
0); // Dash phase
g.setStroke(strokeBox);
g.setPaint(clr);
int height = (int) viewport.getHeightInView();
int width = (int) viewport.getWidthInView();
g.drawRect(0,0,width - 1, height - 1);
}
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 drawRevealMask(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 draw(Geometry geom, Color lineClr, Color fillClr) {
Graphics2D gr = (Graphics2D) getGraphics();
GeometryPainter.paint(geom, getViewport(), gr, lineClr, fillClr);
}
public void flash(Geometry g)
{
Graphics2D gr = (Graphics2D) getGraphics();
gr.setXORMode(viewStyle.getBackground());
Stroke stroke = new BasicStroke(5);
Geometry flashGeom = g;
double vSize = viewSize(g);
if (vSize <= 2 || g instanceof org.locationtech.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 double viewSize(Geometry geom) {
Envelope env = geom.getEnvelopeInternal();
return viewport.toView(env.getDiameter());
}
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);
}
else {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
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 static final double LAYER_SHIFT_GUTTER_FACTOR = 0.3;
private GeometryStretcherView stretchView = null;
private Renderer currentRenderer = null;
private boolean isRevealingTopology = false;
private boolean isRenderingStretchVertices = false;
private double layerShiftX;
public GeometryEditPanelRenderer()
{
if (DisplayParameters.isRevealingTopology()) {
stretchView = new GeometryStretcherView(getGeomModel());
stretchView.setStretchSize(viewport.toModel(DisplayParameters.getTopologyStretchSize()));
stretchView.setNearnessTolerance(viewport.toModel(GeometryStretcherView.NEARNESS_TOL_IN_VIEW));
stretchView.setEnvelope(viewport.getModelEnv());
isRevealingTopology = DisplayParameters.isRevealingTopology();
isRenderingStretchVertices = stretchView.isViewPerformant();
}
}
public void render(Graphics2D g2)
{
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (isRevealingTopology) {
if (isRenderingStretchVertices) {
//renderMagnifiedVertexShadows(g2);
renderMagnifiedVertexMask(g2);
}
else {
// render indicator that shows stretched view is non-performant
renderRevealTopoWarning(g2);
}
}
if (viewStyle.isGridEnabled()) {
gridElement.paint(g2);
}
if (viewStyle.isBorderEnabled()) {
drawBorder(g2, viewStyle.getBorderColor());
}
layerShiftX = computeLayerShift(tbModel.getLayersAll());
renderLayersTheme(tbModel.getLayersBase(), g2);
renderLayersCore(getLayerList(), g2);
renderLayersTheme(tbModel.getLayersTop(), g2);
if (isRevealingTopology && isRenderingStretchVertices) {
renderMagnifiedVertices(g2);
}
if (viewStyle.isGridEnabled()) {
gridElement.paintTop(g2);
}
drawMark(g2);
if (viewStyle.isLegendEnabled()) {
legendElement.setBorderEnabled(viewStyle.isLegendBorderEnabled());
legendElement.setStatsEnabled(viewStyle.isLegendStatsEnabled());
legendElement.setMetricsEnabled(viewStyle.isLegendMetricsEnabled());
legendElement.setBorderColor(viewStyle.getBorderColor());
legendElement.setFill(viewStyle.getLegendFill());
legendElement.paint(tbModel.getLayersLegend(), g2);
}
if (viewStyle.isTitleEnabled()) {
titleElement.setBorderColor(viewStyle.getBorderColor());
titleElement.setBorderEnabled(viewStyle.isTitleBorderEnabled());
titleElement.setFill(viewStyle.getTitleFill());
titleElement.setTitle(viewStyle.getTitle());
titleElement.paint(g2);
}
}
private double computeLayerShift(LayerList lyrList) {
Envelope envBase = computeLayersEnv(lyrList, false);
Envelope envShifted = computeLayersEnv(lyrList, true);
if (envShifted.isNull())
return 0;
double offsetX = envBase.getMaxX() - envShifted.getMinX();
return (1 + LAYER_SHIFT_GUTTER_FACTOR) * offsetX;
}
private Envelope computeLayersEnv(LayerList lyrList, boolean isShifted) {
Envelope env = new Envelope();
int n = lyrList.size();
for (int i = 0; i < n; i++) {
Layer layer = lyrList.getLayer(i);
if (isShifted == layer.getLayerStyle().isShifted()) {
env.expandToInclude(layer.getEnvelope());
}
}
return env;
}
private void renderLayersCore(LayerList layerList, Graphics2D g)
{
int n = layerList.size();
for (int i = 0; i < n; i++) {
Layer layer = layerList.getLayer(i);
currentRenderer = createRendererCore(layer, i);
currentRenderer.render(g);
}
currentRenderer = null;
}
private void renderLayersTheme(LayerList layerList, Graphics2D g)
{
int n = layerList.size();
for (int i = n - 1; i >= 0; i--) {
Layer layer = layerList.getLayer(i);
currentRenderer = createRenderer(layer);
currentRenderer.render(g);
}
currentRenderer = null;
}
private Renderer createRendererCore(Layer layer, int i) {
if (isRevealingTopology && isRenderingStretchVertices
&& stretchView != null && i < 2) {
//System.out.println("rendering stretch verts");
return new LayerRenderer(layer,
new StaticGeometryContainer(stretchView.getStretchedGeometry(i)),
viewport);
}
return createRenderer(layer);
}
private Geometry offsetGeometry(Geometry geom, double offsetX) {
if (geom == null) return null;
AffineTransformation trans = AffineTransformation.translationInstance(offsetX, 0);
return trans.transform(geom);
}
private Renderer createRenderer(Layer layer) {
if (layerShiftX > 0
&& layer.getLayerStyle().isShifted()) {
return new LayerRenderer(layer,
new StaticGeometryContainer(offsetGeometry(layer.getGeometry(), layerShiftX)),
viewport);
}
return new LayerRenderer(layer, viewport);
}
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 ? AppColors.GEOM_A_HIGHLIGHT_CLR :
AppColors.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 renderRevealTopoWarning(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();
}
}
}