ValidPanel.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.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTWriter;
import org.locationtech.jts.operation.valid.IsSimpleOp;
import org.locationtech.jts.operation.valid.IsValidOp;
import org.locationtech.jts.operation.valid.TopologyValidationError;
import org.locationtech.jtstest.testbuilder.event.ValidPanelEvent;
import org.locationtech.jtstest.testbuilder.event.ValidPanelListener;
import org.locationtech.jtstest.testbuilder.model.TestCaseEdit;
/**
* @version 1.7
*/
public class ValidPanel extends JPanel {
private static final int TEXT_BOX_WIDTH = 240;
TestCaseEdit testCase;
private Coordinate markPoint = null;
//===========================================
JTextField txtIsValid = new JTextField();
JTextField txtIsSimple = new JTextField();
JTextArea taInvalidMsg = new JTextArea();
JLabel lblValidSimple = new JLabel();
JPanel panelValidSimple = new JPanel();
private transient Vector validPanelListeners;
GridLayout gridLayout1 = new GridLayout();
JPanel markPanel = new JPanel();
JPanel markBtnPanel = new JPanel();
JTextField txtMarkLocation = new JTextField();
JTextField txtMarkLabel = new JTextField();
GridBagLayout gridBagLayout1 = new GridBagLayout();
JLabel lblMark = new JLabel();
JButton btnClearMark = new JButton();
JButton btnSetMark = new JButton();
private JCheckBox cbInvertedRingAllowed;
JRadioButton rbA = new JRadioButton();
JRadioButton rbB = new JRadioButton();
JRadioButton rbResult = new JRadioButton();
public ValidPanel() {
try {
jbInit();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
void jbInit() throws Exception {
JButton btnValidate = new JButton();
btnValidate.setText("Valid?");
btnValidate.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
btnValidate_actionPerformed(e);
}
});
JButton btnSimple = new JButton();
btnSimple.setText("Simple?");
btnSimple.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
btnSimple_actionPerformed(e);
}
});
JButton btnClear = new JButton();
btnClear.setText("Clear");
btnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
clearAll();
}
});
rbA.setSelected(true);
rbA.setText(AppStrings.GEOM_LABEL_A);
rbA.setForeground(AppColors.GEOM_A);
rbB.setText(AppStrings.GEOM_LABEL_B);
rbB.setForeground(AppColors.GEOM_B);
rbResult.setText(AppStrings.GEOM_LABEL_RESULT);
rbResult.setForeground(AppColors.GEOM_RESULT);
rbA.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
clearAll();
}
}});
rbB.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
clearAll();
}
}});
rbResult.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
clearAll();
}
}});
ButtonGroup btnGrpStdInFormat = new ButtonGroup();
btnGrpStdInFormat.add(rbA);
btnGrpStdInFormat.add(rbB);
btnGrpStdInFormat.add(rbResult);
JPanel panelABR = new JPanel();
panelABR.setLayout(new BoxLayout(panelABR, BoxLayout.X_AXIS));
panelABR.add(rbA);
panelABR.add(rbB);
panelABR.add(rbResult);
cbInvertedRingAllowed = new JCheckBox();
cbInvertedRingAllowed.setToolTipText(AppStrings.TIP_ALLOW_INVERTED_RINGS);
cbInvertedRingAllowed.setAlignmentX(Component.LEFT_ALIGNMENT);
cbInvertedRingAllowed.setText("Allow Inverted Rings");
txtIsValid.setBackground(AppColors.BACKGROUND);
txtIsValid.setEditable(false);
//txtIsValid.setText("Y");
txtIsValid.setHorizontalAlignment(SwingConstants.CENTER);
Dimension flagSize = new Dimension(40, 24);
txtIsValid.setMinimumSize(flagSize);
txtIsValid.setPreferredSize(flagSize);
txtIsSimple.setBackground(AppColors.BACKGROUND);
txtIsSimple.setEditable(false);
txtIsSimple.setHorizontalAlignment(SwingConstants.CENTER);
txtIsSimple.setMinimumSize(flagSize);
txtIsSimple.setPreferredSize(flagSize);
taInvalidMsg.setPreferredSize(new Dimension(TEXT_BOX_WIDTH, 80));
taInvalidMsg.setMaximumSize(new Dimension(TEXT_BOX_WIDTH, 80));
taInvalidMsg.setMinimumSize(new Dimension(TEXT_BOX_WIDTH, 80));
taInvalidMsg.setLineWrap(true);
taInvalidMsg.setBorder(BorderFactory.createLoweredBevelBorder());
taInvalidMsg.setToolTipText("");
taInvalidMsg.setBackground(AppColors.BACKGROUND);
taInvalidMsg.setEditable(true);
taInvalidMsg.setFont(new java.awt.Font("SansSerif", 0, 12));
lblValidSimple.setToolTipText("");
lblValidSimple.setText("Valid / Simple ");
lblMark.setToolTipText("");
lblMark.setText("Mark Point ( X Y ) ");
btnClearMark.setToolTipText("");
btnClearMark.setText("Clear Mark");
btnClearMark.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
clearMark();
}
});
btnSetMark.setToolTipText("");
btnSetMark.setText("Set Mark");
btnSetMark.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
btnSetMark_actionPerformed(e);
}
});
JPanel panelValid = new JPanel();
panelValid.add(btnValidate);
panelValid.add(txtIsValid);
JPanel panelSimple = new JPanel();
panelSimple.add(btnSimple);
panelSimple.add(txtIsSimple);
JPanel panelMsg = new JPanel();
panelMsg.add(taInvalidMsg);
JPanel panelClear = new JPanel();
panelClear.setLayout(new BorderLayout());
panelClear.add(cbInvertedRingAllowed, BorderLayout.WEST);
panelClear.add(btnClear, BorderLayout.EAST);
panelValidSimple.setLayout(new BoxLayout(panelValidSimple, BoxLayout.Y_AXIS));
panelValidSimple.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panelValidSimple.add(panelABR);
panelValidSimple.add(panelSimple);
panelValidSimple.add(panelValid);
panelValidSimple.add(panelClear);
panelValidSimple.add(panelMsg);
//----------------------------------------------
txtMarkLocation.setBorder(BorderFactory.createLoweredBevelBorder());
txtMarkLocation.setToolTipText("");
txtMarkLocation.setEditable(true);
txtMarkLocation.setFont(new java.awt.Font("SansSerif", 0, 12));
txtMarkLocation.setHorizontalAlignment(SwingConstants.LEFT);
Dimension markDim = new Dimension(TEXT_BOX_WIDTH, 20);
txtMarkLocation.setPreferredSize(markDim);
txtMarkLocation.setMaximumSize(markDim);
txtMarkLocation.setMinimumSize(markDim);
markPanel.setLayout(new BorderLayout());
markBtnPanel.add(btnSetMark);
markBtnPanel.add(btnClearMark);
markPanel.add(lblMark, BorderLayout.NORTH);
markPanel.add(txtMarkLocation, BorderLayout.CENTER);
//markPanel.add(txtMarkLabel, BorderLayout.CENTER);
markPanel.add(markBtnPanel, BorderLayout.SOUTH);
//----------------------------------------------
this.setLayout(new BorderLayout());
this.add(panelValidSimple, BorderLayout.NORTH);
this.add(markPanel, BorderLayout.SOUTH);
}
public void setTestCase(TestCaseEdit testCase) {
this.testCase = testCase;
}
public Coordinate getMarkPoint() { return markPoint; }
void clearAll() {
clearFlag(txtIsValid);
clearFlag(txtIsSimple);
taInvalidMsg.setText("");
clearMark();
}
void btnValidate_actionPerformed(ActionEvent e)
{
clearFlag(txtIsValid);
Geometry geom = getGeometry();
if (geom == null)
return;
TopologyValidationError err = checkValid(geom, cbInvertedRingAllowed.isSelected());
String msg = "";
boolean isValid = true;
Coordinate invalidPoint = null;
if (err != null) {
isValid = false;
msg = err.toString();
invalidPoint = err.getCoordinate();
}
taInvalidMsg.setText(msg);
setFlagText(txtIsValid, isValid);
setMarkPoint(invalidPoint);
}
private TopologyValidationError checkValid(Geometry geom, boolean isAllowInverted) {
TopologyValidationError err = null;
if (geom != null) {
IsValidOp validOp = new IsValidOp(geom);
if (isAllowInverted) {
validOp.setSelfTouchingRingFormingHoleValid(true);
}
err = validOp.getValidationError();
}
return err;
}
private Geometry getGeometry() {
if (rbA.isSelected())
return testCase.getGeometry(0);
if (rbB.isSelected())
return testCase.getGeometry(1);
return testCase.getResult();
}
void btnSimple_actionPerformed(ActionEvent e)
{
boolean isSimple = true;
Coordinate nonSimpleLoc = null;
Geometry geom = getGeometry();
if (geom != null) {
IsSimpleOp simpleOp = new IsSimpleOp(geom);
isSimple = simpleOp.isSimple();
nonSimpleLoc = simpleOp.getNonSimpleLocation();
}
String msg = isSimple ?
""
: "Non-simple intersection at " + WKTWriter.toPoint(nonSimpleLoc);
taInvalidMsg.setText(msg);
setFlagText(txtIsSimple, isSimple);
setMarkPoint(nonSimpleLoc);
}
private void setFlagText(JTextField txt, boolean val) {
txt.setText(val ? "Y" : "N");
txt.setBackground(val ? AppColors.BACKGROUND : AppColors.BACKGROUND_ERROR);
}
private void clearFlag(JTextField txt) {
txt.setText("");
txt.setBackground(AppColors.BACKGROUND);
}
private void setMarkPoint(Coordinate coord)
{
markPoint = coord;
String markText = "";
if (markPoint != null) {
markText = " " + coord.x + " " + coord.y + " ";
}
txtMarkLocation.setText(markText);
fireSetHighlightPerformed(new ValidPanelEvent(this));
}
private void clearMark() {
setMarkPoint(null);
}
public synchronized void removeValidPanelListener(ValidPanelListener l) {
if (validPanelListeners != null && validPanelListeners.contains(l)) {
Vector v = (Vector) validPanelListeners.clone();
v.removeElement(l);
validPanelListeners = v;
}
}
public synchronized void addValidPanelListener(ValidPanelListener l) {
Vector v = validPanelListeners == null ? new Vector(2) : (Vector) validPanelListeners.clone();
if (!v.contains(l)) {
v.addElement(l);
validPanelListeners = v;
}
}
protected void fireSetHighlightPerformed(ValidPanelEvent e) {
if (validPanelListeners != null) {
Vector listeners = validPanelListeners;
int count = listeners.size();
for (int i = 0; i < count; i++) {
((ValidPanelListener) listeners.elementAt(i)).setHighlightPerformed(e);
}
}
}
void btnSetMark_actionPerformed(ActionEvent e) {
String xyStr = txtMarkLocation.getText();
setMarkPoint(parseXY(xyStr));
}
Coordinate parseXY(String xyStr)
{
// remove commas and underscores in case they are present
String cleanStr = xyStr.replace("_", "");
cleanStr = cleanStr.replace(",", " ");
String[] xy = cleanStr.trim().split("\\s+");
double x = parseNumber(xy, 0);
double y = parseNumber(xy, 1);
return new Coordinate(x, y);
}
double parseNumber(String[] xy, int index)
{
if (xy.length <= index) return 0.0;
String s = xy[index];
try {
return Double.parseDouble(s);
}
catch (NumberFormatException ex)
{
// just eat it - not much we can do
}
return 0.0;
}
}