001package jmri.jmrit.display.controlPanelEditor.shape; 002 003import java.awt.Graphics; 004import java.awt.Graphics2D; 005import java.awt.Point; 006import java.awt.Rectangle; 007import java.awt.event.ActionEvent; 008import java.awt.geom.GeneralPath; 009import java.awt.geom.PathIterator; 010import java.util.ArrayList; 011 012import javax.swing.Box; 013import javax.swing.BoxLayout; 014import javax.swing.JButton; 015import javax.swing.JLabel; 016import javax.swing.JPanel; 017 018import jmri.jmrit.display.Editor; 019import jmri.util.swing.JmriMouseEvent; 020 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023 024/** 025 * @author Pete Cressman Copyright (c) 2013 026 */ 027public class DrawPolygon extends DrawFrame { 028 029 ArrayList<Point> _vertices; 030 int _curX; 031 int _curY; 032 private static final int NEAR = PositionableShape.SIZE; 033 private final boolean _editing; 034 035 public DrawPolygon(String which, String title, PositionableShape ps, Editor ed, boolean create) { 036 super(which, title, ps, ed, create); 037 _vertices = new ArrayList<>(); 038 _editing = (ps != null); 039 } 040 041 @Override 042 protected JPanel makeParamsPanel() { 043 JPanel panel = super.makeParamsPanel(); 044 int x = getX(); 045 int y = getY(); 046 PathIterator iter = _shape.getPathIterator(null); 047 float[] coord = new float[6]; 048 if (_editing) { 049 while (!iter.isDone()) { 050 iter.currentSegment(coord); 051 _vertices.add(new Point(x + Math.round(coord[0]), y + Math.round(coord[1]))); 052 iter.next(); 053 } 054 } 055 ((PositionablePolygon)_shape).editing(_editing); 056 _shape.drawHandles(); 057 058 panel.add(Box.createVerticalGlue()); 059 panel.add(new JLabel(Bundle.getMessage("drawInstructions2c"))); 060 JPanel p = new JPanel(); 061 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 062 p.add(Box.createHorizontalGlue()); 063 JButton addButton = new JButton(Bundle.getMessage("ButtonAddVertex")); 064 addButton.addActionListener((ActionEvent a) -> addVertex(false)); 065 p.add(addButton); 066 p.add(Box.createHorizontalGlue()); 067 068 JButton deleteButton = new JButton(Bundle.getMessage("ButtonDeleteVertex")); 069 deleteButton.addActionListener((ActionEvent a) -> deleteVertex()); 070 p.add(deleteButton); 071 p.add(Box.createHorizontalGlue()); 072 panel.add(p); 073 panel.add(Box.createVerticalGlue()); 074 return panel; 075 } 076 077 // double click was made - 078 @Override 079 protected PositionableShape makeFigure(Rectangle r, Editor ed) { 080/* Point pt = new Point(event.getX(), event.getY()); 081 boolean closed; Do this later 082 if (near(_vertices.get(0), pt)) { 083 closed = true; // close polygon 084 } else { 085 closed = false; 086 }*/ 087 Point spt = getStartPoint(); 088 _shape = new PositionablePolygon(ed, makePath(spt)); 089 log.debug("makeFigure {} vertices", _vertices.size()); 090 if (_vertices.size() < 2) { 091 return null; 092 } 093 return _shape; 094 } 095 096 /* 097 * Rubber Band line 098 * @see jmri.jmrit.display.controlPanelEditor.shape.DrawFrame#drawLine(int, int) 099 */ 100 protected void moveTo(int x, int y) { 101// log.debug("moveTo ({}, {})", x, y); 102 if (!_editing) { 103 _curX = x; 104 _curY = y; 105 } 106 } 107 108 protected void anchorPoint(int x, int y) { 109 log.debug("anchorPoint ({}, {})", x, y); 110 _curX = x; 111 _curY = y; 112 Point anchorPt = new Point(x, y); 113 for (Point vertex : _vertices) { 114 if (near(vertex, anchorPt)) { 115 _curX = x; 116 _curY = y; 117 return; 118 } 119 } 120 } 121 122 protected void drawShape(Graphics g) { 123 if (!_editing) { 124 if (_vertices.size() < 1 || !(g instanceof Graphics2D)) { 125 return; 126 } 127 Graphics2D g2d = (Graphics2D)g; 128 // disabled to satisfy P Bender 129 //_lineWidth = _lineSlider.getValue(); 130 //BasicStroke stroke = new BasicStroke(_lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f); 131 //g2d.setColor(_lineColor); 132 //g2d.setStroke(stroke); 133 GeneralPath path = makePath(new Point(0, 0)); 134 path.lineTo(_curX, _curY); 135 g2d.draw(path); 136 } 137 } 138 139 protected void makeVertex(JmriMouseEvent event, Editor ed) { 140 log.debug("makeVertex point= ({}, {}), _editing= {}", event.getX(), event.getY(), _editing); 141 if (!_editing) { // creating new polygon 142 Point pt = new Point(event.getX(), event.getY()); 143 int size = _vertices.size(); 144 if ( size == 0 || !near(_vertices.get(size-1), pt)) { 145 _vertices.add(pt); 146 } 147 } 148 } 149 150 protected boolean doHandleMove(int hitIndex, Point pt) { 151 Point p = _vertices.get(hitIndex); 152 p.x += pt.x; 153 p.y += pt.y; 154 if (_editing) { 155 _shape.setShape(makePath(getStartPoint())); 156 } 157 return false; 158 } 159 160 /** 161 * @param pt is "startPoint" the upper left corner of the figure 162 */ 163 private GeneralPath makePath(Point pt) { 164 GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, _vertices.size() + 1); 165 path.moveTo(_vertices.get(0).x - pt.x, _vertices.get(0).y - pt.y); 166 for (int i = 1; i < _vertices.size(); i++) { 167 path.lineTo(_vertices.get(i).x - pt.x, _vertices.get(i).y - pt.y); 168 } 169// if (closed) { 170// path.lineTo(_vertices.get(0).x - pt.x, _vertices.get(0).y - pt.y); 171// } 172 return path; 173 } 174 175 /* 176 * "startPoint" will be the upper left corner of the figure 177 * <p> 178 */ 179 protected Point getStartPoint() { 180 if (_vertices.size() > 0) { 181 int x = _vertices.get(0).x; 182 int y = _vertices.get(0).y; 183 for (int i = 1; i < _vertices.size(); i++) { 184 x = Math.min(x, _vertices.get(i).x); 185 y = Math.min(y, _vertices.get(i).y); 186 } 187 return new Point(x, y); 188 } else { 189 _vertices.add( new Point(_curX, _curY)); 190 return new Point(_curX, _curY); 191 } 192 } 193 194 static private boolean near(Point p1, Point p2) { 195 return Math.abs(p1.x - p2.x) < NEAR && Math.abs(p1.y - p2.y) < NEAR; 196 } 197 198 @Override 199 void setDisplayWidth(int w) { 200 } 201 202 @Override 203 void setDisplayHeight(int h) { 204 } 205 206 /** 207 * Add a vertex to polygon relative to selected vertex 208 * @param up if true, add after selected vertex. otherwise before selected vertex 209 */ 210 protected void addVertex(boolean up) { 211 if (_editing) { 212 int hitIndex = _shape._hitIndex; 213 if (hitIndex < 0) { 214 if (_vertices.size() > 1) { 215 hitIndex = _vertices.size() - 1; 216 } else { 217 hitIndex = 0; 218 if (_vertices.size() == 0) { 219 _vertices.add(new Point(_curX, _curY)); 220 } 221 } 222 _shape._hitIndex = hitIndex; 223 up = true; 224 } 225 Point r1 = _vertices.get(hitIndex); 226 Point newVertex; 227 if (up) { 228 if (hitIndex == _vertices.size() - 1) { 229 newVertex = new Point(r1.x + 20, r1.y + 20); 230 } else { 231 Point r2 = _vertices.get(hitIndex + 1); 232 newVertex = new Point((r1.x + r2.x) / 2, (r1.y + r2.y) / 2); 233 } 234 _shape._hitIndex++; 235 hitIndex++; 236 } else { 237 if (hitIndex > 0) { 238 Point r2 = _vertices.get(hitIndex - 1); 239 newVertex = new Point((r1.x + r2.x) / 2, (r1.y + r2.y) / 2); 240 } else { 241 newVertex = new Point(r1.x + 20, r1.y + 20); 242 } 243 } 244 _vertices.add(hitIndex, newVertex); 245 _shape.setShape(makePath(getStartPoint())); 246 _shape.drawHandles(); 247 _shape.updateSize(); 248 } 249 } 250 251 protected void deleteVertex() { 252 if (_editing) { 253 if (_vertices.size() <= 2) { 254 return; 255 } 256 int hitIndex = _shape._hitIndex; 257 if (hitIndex < 0) { 258 hitIndex = _vertices.size() - 1; 259 } 260 _vertices.remove(hitIndex); 261 if (hitIndex > 0) { 262 _shape._hitIndex--; 263 } 264 _shape.setShape(makePath(getStartPoint())); 265 _shape.drawHandles(); 266 _shape.updateSize(); 267 } 268 } 269 270 private final static Logger log = LoggerFactory.getLogger(DrawPolygon.class); 271}