/*
* File : PolygonDrawPanel.java
* Created : 17-may-2002 10:20
* By : allastar
*
* JClic - Authoring and playing system for educational activities
*
* Copyright (C) 2000 - 2005 Francesc Busquets & Departament
* d'Educacio de la Generalitat de Catalunya
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details (see the LICENSE file).
*/
package edu.xtec.jclic.shapers;
import edu.xtec.util.StrUtils;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
/**
*
* @author allastar
* @author Francesc Busquets (fbusquets@xtec.cat)
* @version 13.09.17
*/
public class PolygonDrawPanel implements java.awt.event.MouseMotionListener, java.awt.event.MouseListener{
private List<EditableShape> vShapes; //List that contains the polygon currently being modified
private static List<EditableShape> vCopied;
private List<EditableShape> vRedrawingLines,vRedrawingLinesBeforeModify,vShapeBeforeModify;
private List<PointListener> vPointListeners;
private double iniX,iniY,finX,finY,lastFinX,lastFinY;
private Point2D iniPoint=null,lastPoint=null;
private boolean bSelectedPoint=false;
private double zoomX=0,zoomY=0,zoomH=-1,zoomW=-1;
private boolean creatingRect=false,creatingEllipse=false, creatingPolygon=false, bRedrawingLines=false, bSelectingArea=false;
private boolean bResizing=false;
private int resizingDirection=NO_RESIZING;
private boolean bSpecialLine=false;
private boolean bMoving=false;
private EditableShape specialLine=null;
private int drawingMode=SELECTING;
static double defaultSensibility=1.5;
private AffineTransform at;
private List<Rectangle> vDrawnBorders=null;
private Shape current=null;
private JComponent container;
private short INITIAL=0;
private short END=1;
public static final int SELECTING=1;
public static final int MOVING=2;
public static final int NEW_POINT=4;
public static final int DRAWING_RECT=5;
public static final int DRAWING_ELLIPSE=6;
public static final int DRAWING_POLYGON=7;
public static final int ZOOM=12;
public static final int NO_RESIZING=-1;
public static final int EAST=0;
public static final int SOUTH=1;
public static final int SOUTH_EAST=2;
private int backgroundComposite=0;
protected HolesEditorPanel hep;
protected boolean canResize;
protected Rectangle lastPreviewArea;
static Cursor[] cursors=null;
public static final int PEN_CURSOR=0;
public static final int CIRCLE_CURSOR=1;
protected Shape esborram=null;
/** Creates new PolygonDrawPanel */
public PolygonDrawPanel(int width, int height, HolesEditorPanel hep, boolean canResize) {
this.hep=hep;
this.canResize=canResize;
vShapes=new ArrayList<EditableShape>();
if(vCopied==null)
vCopied=new ArrayList<EditableShape>();
vRedrawingLines=new ArrayList<EditableShape>();
vRedrawingLinesBeforeModify=new ArrayList<EditableShape>();
vPointListeners=new ArrayList<PointListener>();
at=new AffineTransform();
initDrawnBorders();
if(cursors==null){
cursors=new Cursor[2];
Toolkit tk=Toolkit.getDefaultToolkit();
cursors[PEN_CURSOR]=tk.createCustomCursor(edu.xtec.util.ResourceManager.getImageIcon("cursors/llapis.gif").getImage(), new Point(12,24), "pen");
cursors[CIRCLE_CURSOR]=tk.createCustomCursor(edu.xtec.util.ResourceManager.getImageIcon("cursors/cercle.gif").getImage(), new Point(16,16), "circle");
}
hep.addKeyListener(new PolygonDrawPanel.KeyHandler());
}
public void setDrawingMode(int drawingMode){
if(this.drawingMode!=drawingMode){
this.drawingMode=drawingMode;
if(creatingPolygon)
joinPolygon();
if(drawingMode!=NEW_POINT && drawingMode!=SELECTING) {
endPolygon();
}
hep.repaint(0);
}
}
public int getVisibleWidth(){
return hep.getPreviewPanel().getWidth();
}
public int getVisibleHeight(){
return hep.getPreviewPanel().getHeight();
}
public void initDrawnBorders(){
if(vDrawnBorders!=null)
vDrawnBorders.clear();
else
vDrawnBorders=new ArrayList<Rectangle>();
for(int i=0;i<hep.getNumShapes();i++){
if(i!=hep.currentShape){
Shape s=hep.getHoles().getShape(i,hep.previewArea);
if(s!=null)
vDrawnBorders.addAll(getBorders(s));
}
}
}
private List<Rectangle> getBorders(Shape s){
// Utility function that returns the points that define the "segments" of the polygon 's'.
int xIni=0; int yIni=0;
if(s==null)
return null;
List<Rectangle> vPoints=new ArrayList<Rectangle>();
double x,y;
if(s instanceof GeneralPath){
GeneralPath gp=(GeneralPath)s;
PathIterator it=gp.getPathIterator(new AffineTransform());
double[] coords=new double[6];
while (!it.isDone()){
int type=it.currentSegment(coords);
switch (type){
case PathIterator.SEG_MOVETO:
x=coords[0]; y=coords[1];
vPoints.add(new Rectangle((int)(x+xIni)-(EditableShapeConstants.selectLength/2),(int)(y+yIni)-(EditableShapeConstants.selectLength/2),EditableShapeConstants.selectLength,EditableShapeConstants.selectLength));
break;
case PathIterator.SEG_LINETO:
x=coords[0]; y=coords[1];
vPoints.add(new Rectangle((int)(x+xIni)-(EditableShapeConstants.selectLength/2),(int)(y+yIni)-(EditableShapeConstants.selectLength/2),EditableShapeConstants.selectLength,EditableShapeConstants.selectLength));
break;
case PathIterator.SEG_CUBICTO:
x=coords[4]; y=coords[5];
vPoints.add(new Rectangle((int)(x+xIni)-(EditableShapeConstants.selectLength/2),(int)(y+yIni)-(EditableShapeConstants.selectLength/2),EditableShapeConstants.selectLength,EditableShapeConstants.selectLength));
break;
case PathIterator.SEG_QUADTO:
x=coords[2]; y=coords[3];
vPoints.add(new Rectangle((int)(x+xIni)-(EditableShapeConstants.selectLength/2),(int)(y+yIni)-(EditableShapeConstants.selectLength/2),EditableShapeConstants.selectLength,EditableShapeConstants.selectLength));
break;
case PathIterator.SEG_CLOSE:
break;
default:
}
it.next();
}
}
return vPoints;
}
public void paint(java.awt.Graphics2D g){
Graphics2D g2d=(Graphics2D)g;
if(EditableShapeConstants.showDrawnPoints)
paintDrawnBorders(g);
for(EditableShape esh : vShapes){
if(bSpecialLine && esh==specialLine)
esh.paintWithColor(g,drawingMode,EditableShapeConstants.CUT_COLOR);
else
esh.paintWithColor(g,drawingMode,EditableShapeConstants.ACTIVE_COLOR);
}
if(bMoving)
paintMoved(g);
if(creatingRect){
g.setColor(EditableShapeConstants.selectedColor);
EditableRectangle rect=new EditableRectangle((int)iniX,(int)iniY,(int)(finX-iniX),(int)(finY-iniY));
rect.paintWithColor(g,drawingMode,EditableShapeConstants.selectedColor);
}
if(creatingEllipse){
g.setColor(EditableShapeConstants.selectedColor);
EditableEllipse2D ellipse=new EditableEllipse2D((int)iniX,(int)iniY,(int)(finX-iniX),(int)(finY-iniY));
ellipse.paintWithColor(g,drawingMode,EditableShapeConstants.selectedColor);
}
if(creatingPolygon){
if(lastPoint!=null){
EditableLine2D el=new EditableLine2D(lastPoint.getX(),lastPoint.getY(),finX,finY);
el.paintWithColor(g,drawingMode,EditableShapeConstants.selectedColor);
}
}
}
public void drawGrid(java.awt.Graphics g, int gridWidth){
if(gridWidth<=1)
return;
int width=(int)(hep.previewArea.getWidth());
int height=(int)(hep.previewArea.getHeight());
g.setColor(EditableShapeConstants.gridColor);
for (double i=hep.previewArea.x;i<=hep.previewArea.x+width;i+=(gridWidth*hep.xFactor)){
//from 0 in order to avoid changes in the location of the grid when zoomed
//vertical
g.drawLine((int)i,hep.previewArea.y,(int)i,(int)(hep.previewArea.y+height));
}
for (double i=hep.previewArea.y;i<=hep.previewArea.y+height;i+=(gridWidth*hep.yFactor)){
//horitzontal
g.drawLine(hep.previewArea.x,(int)i,(int)(hep.previewArea.x+width),(int)i);
}
}
protected void paintDrawnBorders(java.awt.Graphics2D g){
for(Rectangle r : vDrawnBorders){
double x=r.getX();
double y=r.getY();
double w=r.getWidth();
double h=r.getHeight();
x=x+(w/4);
y=y+(h/4);
w=w/2;
h=h/2;
g.setColor(EditableShapeConstants.DRAWN_BORDER_COLOR);
g.fillRect((int)x,(int)y,(int)w,(int)h);
}
}
private void paintMoved(java.awt.Graphics2D g){
for(EditableShape esh : vCopied){
EditableShape copied=(EditableShape)esh.clone();
copied.transform(AffineTransform.getTranslateInstance(finX-iniX,finY-iniY));
copied.paintWithColor(g,drawingMode,EditableShapeConstants.movingColor);
}
}
public void updateView(){
List v=getGeneralPath();
if(lastPreviewArea==null)
lastPreviewArea=hep.previewArea;
if(v.size()>0){
move(hep.previewArea.x-lastPreviewArea.x,hep.previewArea.y-lastPreviewArea.y,false,false);
}
try{
lastPreviewArea=(Rectangle)(hep.previewArea.clone());
}
catch(Exception e){
System.err.println("Error updating view:\n"+e);
}
}
public void setShapeData(ShapeData sd, double x, double y, double scaleX, double scaleY){
//x,y indicate the current position
clean();
current=(sd!=null)?sd.getShape(hep.previewArea):null;
double firstX=-1,firstY=-1;
if(sd!=null && sd.primitiveType>=0 && sd.primitivePoints!=null && sd.primitivePoints.length>3){
EditableShape es;
double xTr=(sd.primitivePoints[0]*hep.previewArea.getWidth())+hep.previewArea.getX();
double yTr=(sd.primitivePoints[1]*hep.previewArea.getHeight())+hep.previewArea.getY();
double wSc=sd.primitivePoints[2]*hep.previewArea.getWidth();
double hSc=sd.primitivePoints[3]*hep.previewArea.getHeight();
switch (sd.primitiveType){
case ShapeData.RECTANGLE:
es=new EditableRectangle((int)xTr,(int)yTr,(int)wSc,(int)hSc);
vShapes.add(es);
break;
case ShapeData.ELLIPSE:
es=new EditableEllipse2D((int)xTr,(int)yTr,(int)wSc,(int)hSc);
vShapes.add(es);
break;
}
}
else if(sd!=null){
Shape s=sd.getShape(hep.previewArea);
if(s instanceof GeneralPath){
GeneralPath gp=(GeneralPath)s;
PathIterator it=gp.getPathIterator(new AffineTransform());
double[] coords=new double[6];
while (!it.isDone()){
int type=it.currentSegment(coords);
switch (type){
case PathIterator.SEG_MOVETO:
x=coords[0]; y=coords[1];
if(firstX==-1){ //To close
firstX=x;
firstY=y;
}
break;
case PathIterator.SEG_LINETO:
vShapes.add(new EditableLine2D(x,y,coords[0],coords[1]));
x=coords[0]; y=coords[1];
break;
case PathIterator.SEG_CUBICTO:
vShapes.add(new EditableCubicCurve2D(x,y,coords[0],coords[1],coords[2],coords[3],coords[4],coords[5]));
x=coords[4]; y=coords[5];
break;
case PathIterator.SEG_QUADTO:
vShapes.add(new EditableQuadCurve2D(x,y,coords[0],coords[1],coords[2],coords[3]));
x=coords[2]; y=coords[3];
break;
case PathIterator.SEG_CLOSE:
if(firstX!=-1 && (x!=firstX || y!=firstY)){
vShapes.add(new EditableLine2D(x,y,firstX,firstY));
x=firstX;y=firstY;
}
break;
default:
break;
}
it.next();
}
if(firstX!=-1 && (x!=firstX || y!=firstY)){
// That's to be sure that the shape is always closed
vShapes.add(new EditableLine2D(x,y,firstX,firstY));
}
}
}
removeDrawnBorders(sd);
}
public void clean(){
vShapes=new ArrayList<EditableShape>();
vRedrawingLines=new ArrayList<EditableShape>();
vRedrawingLinesBeforeModify=new ArrayList<EditableShape>();
}
public boolean selectDrawnShape(Point2D p) {
endPolygon();
for (int i=0;i<hep.getNumShapes();i++){
Shape s=hep.getHoles().getShape(i,hep.previewArea);
if(s.contains(p) && hep.currentShape!=i){
hep.setCurrentShape(i);
setShapeData(hep.getHoles().getShapeData(i),0,0,1,1);
return true;
}
}
hep.setCurrentShape(hep.getHoles().getNumCells()+1);
clean();
return false;
}
public void selectShape(int iIndex){
if(iIndex<0)
return;
ShapeData sd=hep.getHoles().getShapeData(iIndex);
if(sd!=null){
setShapeData(sd,0,0,1,1);
}
}
private EditableShape aproximationToLine(double x, double y){
return aproximationToLine(x,y,null);
}
private EditableShape aproximationToLine(double x, double y, List<EditableShape> vRedrawingLines){
//returns an EditableShape when there is a corner at (x,y) that not belongs to the lines in
//the Rectangle List vRedrawingLines. Otherwise returns null
if (vRedrawingLines != null) {
for (EditableShape esh : vRedrawingLines) {
if (!vRedrawingLines.contains(esh)) {
if (esh.hasClickedBorder((int) x, (int) y, false)) {
return esh;
}
}
}
}
return null;
}
private Point2D getTransformedPoint(Point2D p, boolean mustBeOnGrid){
//mustBeOnGrid is used to discard the approach
Point2D mousePoint=new Point2D.Double(p.getX(),p.getY());
if(EditableShapeConstants.gridWidth!=-1 && EditableShapeConstants.pointsOnGrid && mustBeOnGrid)
moveToGrid(mousePoint);
return mousePoint;
}
private void moveToGrid(Point2D p){
//Moves the supplied point to the closest grid point
int x=(int)p.getX();
int y=(int)p.getY();
x-=hep.previewArea.getX();
y-=hep.previewArea.getY();
double wd=EditableShapeConstants.gridWidth*hep.xFactor;
int w=(int)wd;
if(w==-1)
return;
int xLeft=(int)(((int)(x/wd))*wd);
if((x-xLeft)<(w/2))
x=xLeft;
else
x=(int)(((int)((x+w-1)/wd))*wd);
int yUp=(int)(((int)(y/wd))*wd);
if((y-yUp)<(w/2))
y=yUp;
else
y=(int)(((int)((y+w-1)/wd))*wd);
x+=hep.previewArea.getX();
y+=hep.previewArea.getY();
p.setLocation(x,y);
}
public Point2D aproximationToDrawnBorder(double x, double y){
// Returns true if a rectangle in vDrawnBorders contains the point (x,y)
for(Rectangle2D r : vDrawnBorders){
if(r.contains(x,y))
return new Point2D.Double(r.getX()+(r.getWidth()/2),r.getY()+(r.getHeight()/2));
}
return null;
}
protected void redrawingLines(double x, double y){ //moves all the selected shapes containing (x,y) in one of its corners
for(EditableShape esh : vRedrawingLines)
esh.changeBorder(x,y);
}
private void cleanZoom(){
zoomX=0;
zoomY=0;
zoomW=-1;
zoomH=-1;
at=new AffineTransform();
cancelCurrentOperations();
bSelectingArea=false;
hep.repaint(0);
}
public void cancelCurrentOperations(){
creatingRect=false;
creatingEllipse=false;
}
public void cut(double x, double y){
copy(false);
clean();
bMoving=true;
iniX=x;
iniY=y;
finX=iniX;
finY=iniY;
}
public void cut(){
cut(-1,-1);
}
public void copy(boolean needSelected){
vCopied.clear();
for(EditableShape esh : vShapes){
esh=(EditableShape)esh.clone();
if(!needSelected || esh.isSelected()){
vCopied.add(esh);
}
}
}
public void paste(){
bMoving=true;
iniX=-1; iniY=-1; finX=-1; finY=-1;
paste(5,5);
}
public void paste(double x, double y){
List<EditableShape> newCopied=new ArrayList<EditableShape>();
deSelectAll();
for(EditableShape esh : vCopied){
EditableShape copied=(EditableShape)esh.clone();
copied.transform(AffineTransform.getTranslateInstance(x,y));
copied.setSelected(true);
vShapes.add(copied);
newCopied.add(copied); //to avoid overlap of shapes when the user makes "paste" two times
}
vCopied=newCopied;
}
public void deSelectAll(){
for(EditableShape esh : vShapes){
esh.setSelected(false);
}
bSelectedPoint=false;
hep.repaint(0);
}
private EditableShape nearestLine(double x, double y){
EditableShape nearest=null;
double distance=0;
double currentDistance;
for(EditableShape esh : vShapes){
currentDistance=esh.distanceTo(x,y);
if(nearest==null || (currentDistance<distance)){
distance=currentDistance;
nearest=esh;
}
}
return nearest;
}
private void clicatISeleccionada(int x, int y, boolean needSelected){
//With needSelected=false it's not necessary to have selected a shape in order to drag it
// leaves in vRedrawingLines the selected lines with one point near the supplied co-ordinates (x,y)
Point2D redrawingPoint=null;
vRedrawingLines.clear();
for(EditableShape esh : vShapes){
if((!needSelected || esh.isSelected()) && esh.hasClickedBorder(x,y,needSelected)){
Point2D p=esh.getNearestBorder(x,y);
if(redrawingPoint==null || redrawingPoint.equals(p)){
redrawingPoint=p;
vRedrawingLines.add(esh);
}
}
}
vRedrawingLinesBeforeModify=cloneVector(vRedrawingLines);
}
private List<EditableShape> cloneVector(List<EditableShape> v){
List<EditableShape> vClone=new ArrayList<EditableShape>();
if(v!=null){
for(EditableShape es : v){
vClone.add((EditableShape)es.clone());
}
}
return vClone;
}
private void divideShape(EditableShape specialLine,double x, double y){
if(specialLine!=null){
EditableShape[] shapes=specialLine.divide(x,y);
if(shapes!=null){
// -> The two following lines are necessary in order to grant the connection of the resulting shape
// Dividing two times in the same point can create an independent line out of the shape
List<EditableShape> vCheckPoint=new ArrayList<EditableShape>();
vCheckPoint.addAll(vShapes);
vShapes.remove(specialLine);
for (int i=0;i<shapes.length;i++){
if(shapes[i]!=null)
vShapes.add(shapes[i]);
}
boolean bValidate=validateShape();
if(!bValidate)
vShapes=vCheckPoint;
}
hep.updateView();
}
hep.repaint(0);
}
private boolean validateShape(){
return (getGeneralPath().size()==1);
}
public List<GeneralPath> getGeneralPath(){
List<GeneralPath> vGpaths=new ArrayList<GeneralPath>();
GeneralPath currentPolygon=new GeneralPath();
List<EditableShape> shapes=new ArrayList<EditableShape>();
shapes.addAll(vShapes);
if(!(shapes.size()>0))
return vGpaths;
EditableShape esh=shapes.get(0);
shapes.remove(esh);
currentPolygon.append(esh,true);
short notUsedPoint=END; //indicates the side of the last shape non-adjacent to anyone
while (shapes.size()>0){
EditableShape shape=getAdjacent(shapes,esh,notUsedPoint);
if(shape!=null){
currentPolygon.append(shape,true);
notUsedPoint=getNotUsed(esh,shape); //returns the point of the shape non-adjacent to "current"
shapes.remove(shape);
esh=shape;
}
else{
vGpaths.add(currentPolygon);
currentPolygon=new GeneralPath();
notUsedPoint=END;
esh=(EditableShape)shapes.get(0);
shapes.remove(esh);
currentPolygon.append(esh,true);
}
}
vGpaths.add(currentPolygon);
return vGpaths;
}
private short getNotUsed(EditableShape current, EditableShape shape){ //returns the point of the shape non-adjacent to "current"
if(shape.getInitialPoint().equals(current.getInitialPoint())||shape.getInitialPoint().equals(current.getEndPoint()))
return END;
else
return INITIAL;
}
private EditableShape getAdjacent(List<EditableShape> shapes, EditableShape sh, short notUsedPoint){
Point2D p;
if(notUsedPoint==INITIAL)
p=sh.getInitialPoint();
else
p=sh.getEndPoint();
for(EditableShape shape : shapes){
if(shape.isAdjacentTo(p))
return shape;
}
return null;
}
public boolean hasSelectedDrawnShape(Point2D p) {
for (int i=0;i<hep.getNumShapes();i++){
Shape s=hep.getHoles().getShape(i,hep.previewArea);
if(s.contains(p)) {
return true;
}
}
return false;
}
private double distanceToNearest(double x, double y){
EditableShape nearest=nearestLine(x,y);
if(nearest!=null)
return nearest.distanceTo(x,y);
else
return -1;
}
public void deleteSelected(boolean isCut){
if(hasSelectedPoint()){
joinAdjacentsToSelectedPoint();
bSelectedPoint=false;
}
else{
List<EditableShape> vShapesCopy=new ArrayList<EditableShape>();
boolean allSelected=true, noneSelected=true;
vShapesCopy.addAll(vShapes);
for(EditableShape esh : vShapesCopy){
if(!esh.isSelected())
allSelected=false;
else{
noneSelected=false;
if(isCut || vShapes.size()>=4){ //Avoid to delete objects when there are only 3 or less elements, unless is a "cut"
vShapes.remove(esh);
if(!isCut)
joinAdjacentsTo(esh,vShapes);
}
}
}
//allSelected indicates if all the object was selected
if(allSelected || noneSelected){
vShapes.clear();
this.current=null;
hep.getHoles().removeShape(hep.currentShape);
hep.setCurrentShape(hep.getHoles().getNumCells());
}
}
}
private void joinAdjacentsTo(EditableShape current, List<EditableShape> vShapes){
//All the shapes in vShapes will converge in one of the "current" points.
EditableShape s1=getAdjacent(vShapes,current,INITIAL);
if(s1!=null){ //Always
s1.hasClickedBorder(current.getInitialPoint().getX(),current.getInitialPoint().getY(),false);
//hasClickedBorder marks the shape corner nearest to the supplied point. Calling
//changeBorder this corner will be modified to the new point.
s1.changeBorder(current.getEndPoint().getX(),current.getEndPoint().getY());
}
}
private void joinAdjacentsToSelectedPoint(){
if(vShapes.size()!=1 && vShapes.size()<=3)
return;
EditableShape other=null;
int count=0;
for(EditableShape esh : vShapes){
if(esh.hasSelectedBorder()){
if(esh instanceof EditableRectangle){
Point2D p=esh.getNotSelectedBorder();
convertToSimpleShapes();
selectBorder(p.getX(),p.getY());
joinAdjacentsToSelectedPoint();
break;
}
else{
count++;
if(count==1)
other=esh;
else if(other!=null){
Point2D p1=esh.getNotSelectedBorder();
Point2D p2=other.getNotSelectedBorder();
vShapes.add(new EditableLine2D(p1,p2));
vShapes.remove(esh);
vShapes.remove(other);
}
}
}
}
hep.repaint(0);
}
private void setEndToVector(double finX, double finY, List<EditableShape> vRedrawingLines){
//approach of all the lines of vRedrawingLines to the point finX, finY
for(EditableShape esh : vRedrawingLines)
esh.aproximateNearestBorder(finX,finY);
}
public boolean hasSelectedPoint(){
return bSelectedPoint;
}
public List<EditableShape> getSelectedShapes(){
List<EditableShape> v=new ArrayList<EditableShape>();
for(EditableShape esh : vShapes){
if(esh.isSelected())
v.add(esh);
}
return v;
}
public int getNumShapes(){
return vShapes.size();
}
public void deleteCurrent(){
clean();
current=null;
}
public ShapeData getShapeData(){
ShapeData sd=null;
AffineTransform aft=AffineTransform.getScaleInstance((1/hep.previewArea.getWidth()),(1/hep.previewArea.getHeight()));
aft.concatenate(AffineTransform.getTranslateInstance(-hep.previewArea.x,-hep.previewArea.y));
if(getNumShapes()==1){ //Is a rectangle or a ellipse
EditableShape es = (EditableShape)vShapes.get(0).clone();
es.transform(aft);
Shape s;
if(es instanceof EditableEllipse2D)
s=((EditableEllipse2D)es).getEllipse();
else
s=es;
sd=ShapeData.getShapeData(s, null, false);
}
else{
List<GeneralPath> v=getGeneralPath(); //Get only the first polygon found (should be unique)
if(v.size()>0){
GeneralPath gp=(v.get(0));
Shape s=gp.createTransformedShape(aft);
sd=ShapeData.getShapeData(s, null);
}
}
return sd;
}
public void endPolygon(){
endPolygon(false,true);
}
public void endPolygon(boolean changeShape, boolean updateList){
endPolygon(changeShape,updateList,-1);
}
public void endPolygon(boolean changeShape, boolean updateList, int iNextShape){
ShapeData sd=getShapeData();
addCurrentDrawnBorders(sd);
endPolygon(sd,changeShape,updateList,iNextShape);
if(sd!=null)
clean();
bSelectedPoint=false;
}
private void addCurrentDrawnBorders(ShapeData sd){
if(sd!=null && hep!=null){
Shape s=sd.getShape(hep.previewArea);
vDrawnBorders.addAll(getBorders(s));
}
}
private void removeDrawnBorders(ShapeData sd){
Shape s=sd.getShape(hep.previewArea);
vDrawnBorders.removeAll(getBorders(s)); //removeAll removes all the instances of the elements passed over the shapedata (only one instance is needed)
}
public void endPolygon(ShapeData sd, boolean changeShape, boolean updateList,int iNextShape){
//Save the created/modified polygon. changeShape indicates if we "come" from a tab key.
if(sd!=null){
addCurrentDrawnBorders(sd);
if(hep.currentShape<hep.getHoles().getNumCells()){ //hep.currentShape has been modified
hep.getHoles().modifyShape(hep.currentShape,sd);
hep.updateView();
}
else{ //A comment ahs been created
sd.comment=StrUtils.secureString(sd.comment, ""+hep.currentShape);
hep.getHoles().addShape(sd);
hep.updateList();
hep.updateView();
}
}
int iCurrentShape=hep.currentShape+1;
if(changeShape){
if(iNextShape>=0)
iCurrentShape=iNextShape;
else
iCurrentShape=iCurrentShape%hep.getHoles().getNumCells();
}
else iCurrentShape=hep.getHoles().getNumCells(); //Next one will be new
if(hep.currentShape!=iCurrentShape)
hep.setCurrentShape(iCurrentShape);
}
private void aplicateTransformation(AffineTransform aTransf, boolean needSelected){
for(EditableShape esh : vShapes){
if(!needSelected || esh.isSelected()){
esh.transform(aTransf);
}
}
}
public void move(int xInc, int yInc, boolean needSelected, boolean moveAll){ //moveAll indicates if we want to move also the inactive objects
AffineTransform aTransf=AffineTransform.getTranslateInstance(xInc,yInc);
aplicateTransformation(aTransf, needSelected);
hep.repaint(0);
}
public void scale(double xInc, double yInc, boolean needSelected, boolean scaleAll){
Point2D center=getCenter(scaleAll);
AffineTransform aTransf=AffineTransform.getTranslateInstance(center.getX(),center.getY());
aTransf.concatenate(AffineTransform.getScaleInstance(xInc,yInc));
aTransf.concatenate(AffineTransform.getTranslateInstance(-center.getX(),-center.getY()));
aplicateTransformation(aTransf, needSelected);
hep.repaint(0);
}
public void rotate(double theta, boolean needSelected, boolean rotateAll){
convertToSimpleShapes(); //If it is a triangle, it will be necessary to convert it to lines in order to rotate the shape
Point2D center=getCenter(rotateAll);
AffineTransform aTransf=AffineTransform.getRotateInstance(theta,center.getX(),center.getY());
aplicateTransformation(aTransf,needSelected);
hep.repaint(0);
}
private Point2D getCenter(boolean cellCenter){
//Returns the central point of the edited shape when cellCenter==false, otherwise, returns the center of the cell
if(!cellCenter){
GeneralPath gp=new GeneralPath();
for(EditableShape esh: vShapes)
gp.append(esh,false);
Rectangle2D r=gp.getBounds(); //to calculate the central point
return new Point2D.Double(r.getCenterX(),r.getCenterY());
}
else return new Point2D.Double(hep.getPreviewPanel().getX(),hep.getPreviewPanel().getY());
}
private void convertToSimpleShapes(){
//If the edited shape is a rectangle or a ellipse, transform it to a set of segments or cubic lines
for(EditableShape esh: vShapes){
if(esh instanceof EditableRectangle){ //Rectangular shapes must be converted to simple shapes in order to rotate it
vShapes.remove(esh);
EditableShape[] lines=((EditableRectangle)esh).divide(-1,-1,false); //Do no add any point
for (int i=0;i<lines.length;i++)
if(lines[i]!=null)
vShapes.add(lines[i]);
}
}
}
private EditableShape getSelectedShape(boolean hasToBeALine){ //Returns the selected line when there is only one
EditableShape selected=null;
int i=0;
for(EditableShape esh : vShapes){
if(esh.isSelected()){
if(!hasToBeALine || esh instanceof EditableLine2D){
selected=esh;
i++;
}
else{
i=2; //Do nothing
}
}
if(i>=2)
break;
}
if(i==1)
return selected;
else
return null;
}
public void convertToBezier(){
EditableShape selected=getSelectedShape(false);
if(selected!=null){
double x1=selected.getInitialPoint().getX();
double y1=selected.getInitialPoint().getY();
double x2=selected.getEndPoint().getX();
double y2=selected.getEndPoint().getY();
double ctrl1x=x1+((x2-x1)/3);
double ctrl2x=x1+(2*((x2-x1)/3));
double ctrl1y=y1+((y2-y1)/3);
double ctrl2y=y1+(2*((y2-y1)/3));
EditableCubicCurve2D bez=new EditableCubicCurve2D(x1,y1,ctrl1x,ctrl1y,ctrl2x,ctrl2y,x2,y2);
bez.setSelected(true);
vShapes.remove(selected);
vShapes.add(bez);
}
}
public void convertToQuad(){
EditableShape selected=getSelectedShape(false);
if(selected!=null){
double x1=selected.getInitialPoint().getX();
double y1=selected.getInitialPoint().getY();
double x2=selected.getEndPoint().getX();
double y2=selected.getEndPoint().getY();
double ctrlx=x1+((x2-x1)/2);
double ctrly=y1+((y2-y1)/2);
EditableQuadCurve2D quad=new EditableQuadCurve2D(x1,y1,ctrlx,ctrly,x2,y2);
quad.setSelected(true);
vShapes.remove(selected);
vShapes.add(quad);
}
}
public void convertToLine(){
EditableShape selected=getSelectedShape(false);
if(selected!=null && !(selected instanceof EditableRectangle)){
EditableLine2D line=new EditableLine2D(selected.getInitialPoint(),selected.getEndPoint());
line.setSelected(true);
vShapes.remove(selected);
vShapes.add(line);
}
else if(selected!=null && selected instanceof EditableRectangle){ //Convert a rectangle into four lines
vShapes.remove(selected);
EditableShape[] lines=((EditableRectangle)selected).divide(-1,-1,false); //Do not add any point
for (int i=0;i<lines.length;i++)
if (lines[i]!=null)
vShapes.add(lines[i]);
}
}
public void notifyShapeChanged(){
for(PointListener pl : vPointListeners){
pl.shapeChanged();
}
}
public void addPointListener(PointListener listener){
vPointListeners.add(listener);
}
public void undoLastMove(List<EditableShape> vRedrawingLines, List<EditableShape> vRedrawingLinesBeforeModify){
vShapes.removeAll(vRedrawingLines);
vShapes.addAll(vRedrawingLinesBeforeModify);
vRedrawingLines.clear();
}
private boolean isIntoArea(List<EditableShape> vShapes, boolean move){
boolean isInto=true;
Rectangle2D r=new Rectangle2D.Double(hep.previewArea.getX()-1,hep.previewArea.getY()-1,hep.previewArea.getWidth()+2,hep.previewArea.getHeight()+2);
Point2D[] borders;
for(EditableShape esh : vShapes){
if(!isInto)
break;
EditableShape es;
if(!move)
es=esh;
else{
es=(EditableShape)esh.clone();
es.transform(AffineTransform.getTranslateInstance(finX-iniX,finY-iniY));
}
borders=es.getBorders();
if(borders==null)
continue;
for(int j=0;j<borders.length && isInto ;j++)
isInto=r.contains(borders[j]);
}
return isInto;
}
private void joinPolygon(){
if(vShapes.size()>=2){
vShapes.add(new EditableLine2D(lastPoint.getX(),lastPoint.getY(),iniPoint.getX(),iniPoint.getY()));
}
else vShapes.clear();
creatingPolygon=false;
lastPoint=null;
iniPoint=null;
if(bSelectedPoint)
deselectBorder();
bSelectedPoint=false;
hep.setDrawingMode(SELECTING);
}
public void mouseDragged(java.awt.event.MouseEvent mouseEvent) {
if((mouseEvent.getModifiers()&java.awt.event.MouseEvent.BUTTON1_MASK)==0)
return; //Button 1 was not pressed
Point2D mousePoint=getTransformedPoint(mouseEvent.getPoint(),true);
if(bMoving)
hep.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
if(mousePoint.getX()<hep.previewArea.x
|| mousePoint.getY()<hep.previewArea.y
|| mousePoint.getX()>hep.previewArea.x+hep.previewArea.getWidth()
|| mousePoint.getY()>hep.previewArea.y+hep.previewArea.getHeight()){
return;
}
vShapeBeforeModify=(drawingMode==SELECTING && !bMoving)?cloneVector(vRedrawingLines):cloneVector(vCopied);
EditableShape near=null;
Point2D nearDrawn=aproximationToDrawnBorder(mouseEvent.getX(),mouseEvent.getY());
if(nearDrawn!=null && EditableShapeConstants.pointsOnGrid){
finX=nearDrawn.getX();
finY=nearDrawn.getY();
}
else{
finX=mousePoint.getX();
finY=mousePoint.getY();
}
if(creatingRect||creatingEllipse){
near=aproximationToLine(finX,finY);
hep.getPreviewPanel().repaint(0);
}
else if(bRedrawingLines){
redrawingLines(finX,finY);
near=aproximationToLine(finX,finY,vRedrawingLines); //we are over a shape corner not selected near (at less)...
hep.repaint(0);
}
else if(bMoving || esInterior(finX,finY)){
near=nearestLine(finX,finY);
if(near!=null){
double d=near.distanceTo(finX,finY);
if(!bMoving && d>(EditableShapeConstants.selectLength/2))
cut(finX,finY);
}
hep.repaint(0);
}
if(creatingRect||creatingEllipse||bRedrawingLines){
if((near!=null || nearDrawn!=null) && EditableShapeConstants.pointsOnGrid)
hep.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
else
hep.setCursor(cursors[PEN_CURSOR]);
}
boolean b=isIntoArea((drawingMode==SELECTING && !bMoving)?vRedrawingLines:vCopied,(bMoving));
if(!b){
if(drawingMode==SELECTING && !bMoving){
undoLastMove(vRedrawingLines,vShapeBeforeModify);
finX=lastFinX;
finY=lastFinY;
}
if(bMoving){
finX=lastFinX;
finY=lastFinY;
}
}
else {
lastFinX=finX;
lastFinY=finY;
}
if(bResizing)
setResizingCursor(resizingDirection);
}
protected boolean esCantonada(double x, double y){
EditableShape near=aproximationToLine(x,y);
return (near!=null || aproximationToDrawnBorder(x,y)!=null);
}
protected boolean esSobreFigura(double x, double y){
int minimumDistance=Math.max(Math.max(2,EditableShapeConstants.selectLength/2),EditableShapeConstants.gridWidth);
double dist=distanceToNearest(x,y);
return (dist>=0 && dist<minimumDistance);
}
protected boolean esInterior(double x, double y){
return (current!=null && current.contains(x,y));
}
public void mouseMoved(java.awt.event.MouseEvent mouseEvent) {
double x,y;
Point2D mousePoint=mouseEvent.getPoint();
boolean esCantonada=esCantonada(mouseEvent.getPoint().getX(),mouseEvent.getPoint().getY());
if(drawingMode==NEW_POINT || (esCantonada && EditableShapeConstants.pointsOnGrid)){
x=mousePoint.getX();
y=mousePoint.getY();
}
else{
x=mousePoint.getX();
y=mousePoint.getY();
}
if(x<hep.previewArea.x || y<hep.previewArea.y || x>hep.previewArea.x+hep.previewArea.getWidth() || y>hep.previewArea.y+hep.previewArea.getHeight())
return;
if(drawingMode!=NEW_POINT){
if(esCantonada && (!creatingPolygon || EditableShapeConstants.pointsOnGrid))
hep.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
else if(creatingPolygon)
hep.setCursor(cursors[PEN_CURSOR]);
else if(!bMoving && esSobreFigura(x,y))
hep.setCursor(cursors[CIRCLE_CURSOR]);
else if(esInterior(x,y))
hep.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
else
hep.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
if(drawingMode==NEW_POINT){
if(esSobreFigura(x,y)){
bSpecialLine=true; //temporally paint it in another color
specialLine=nearestLine(x,y);
hep.setCursor(cursors[PEN_CURSOR]);
hep.repaint(0);
}
else{
boolean willRepaint=bSpecialLine;
bSpecialLine=false;
hep.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if(willRepaint)
hep.repaint(0);
}
}
if(bMoving){
if(iniX==-1){
deleteSelected(true);
iniX=x;
iniY=y;
}
finX=x;
finY=y;
hep.repaint(0);
}
if(creatingPolygon) {
finX=x;
finY=y;
hep.repaint(0);
}
if(canResize){
if(!bResizing){
int resizing=getResizing(mousePoint);
if(resizing!=NO_RESIZING)
setResizingCursor(resizing);
}
else
setResizingCursor(resizingDirection);
}
}
protected int getResizing(Point2D mousePoint){
if(!canResize)
return NO_RESIZING;
ShapeData sd=hep.getHoles().getEnclosingShapeData();
Rectangle r=hep.getPreviewArea();
double width=r.getWidth();
double height=r.getHeight();
AffineTransform aft=AffineTransform.getTranslateInstance(-hep.previewArea.x,-hep.previewArea.y);
aft.transform(mousePoint,mousePoint);
if(mousePoint.getX()==(width-1) && mousePoint.getY()==(height-1))
return SOUTH_EAST;
else if(mousePoint.getX()==(width-1))
return EAST;
else if (mousePoint.getY()==(height-1))
return SOUTH;
else
return NO_RESIZING;
}
protected void setResizingCursor(int resizing){
if(resizing==EAST)
hep.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR),false);
else if(resizing==SOUTH)
hep.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR),false);
else if(resizing==SOUTH_EAST)
hep.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR),false);
}
protected void selectBorder(double x, double y){
for(EditableShape s : vShapes)
s.selectBorder(x,y);
}
protected void deselectBorder(){
for(EditableShape s : vShapes)
s.deselectBorder();
}
protected boolean removeNullLines(List<EditableShape> vRedrawingLines){
//Removes from vRedrawingLines all the lines having the two points in (approximately) the same co-ordinates
boolean canRemove=false;
for(EditableShape s : vRedrawingLines){
if(canRemove)
break;
if(s instanceof EditableLine2D){
Point2D [] p=s.getBorders();
if(p.length>1){
Rectangle r=new Rectangle((int)(p[0].getX())-(EditableShapeConstants.selectLength/2),(int)(p[0].getY())-(EditableShapeConstants.selectLength/2),EditableShapeConstants.selectLength,EditableShapeConstants.selectLength);
if(r.contains(p[1].getX(),p[1].getY())){
//This line is prescindible
if(vShapes.size()>=4){ //Do not delete any element when there are only 3 or les (except if it's a cut)
canRemove=true;
vShapes.remove(s);
joinAdjacentsTo(s,vShapes);
}
}
}
}
}
return canRemove;
}
public void mouseClicked(java.awt.event.MouseEvent mouseEvent) {
Point2D mousePoint=mouseEvent.getPoint();
boolean bSobreFigura=esSobreFigura(mousePoint.getX(),mousePoint.getY());
if(drawingMode!=NEW_POINT && drawingMode!=DRAWING_POLYGON && !bSobreFigura && selectDrawnShape(mousePoint) && !creatingPolygon){
notifyShapeChanged();
hep.repaint(0);
}
else if(drawingMode!=NEW_POINT && bSobreFigura && !creatingPolygon){
EditableShape line=nearestLine(mousePoint.getX(),mousePoint.getY());
if(line!=null){ //The caller wants to select a fragment of the polygon
if(esCantonada(mousePoint.getX(),mousePoint.getY())) {
Point2D p=line.getNearestBorder(mousePoint.getX(),mousePoint.getY());
deSelectAll();
bSelectedPoint=true;
selectBorder(p.getX(),p.getY());
hep.repaint(0);
}
else{
if(bSelectedPoint)
deselectBorder();
bSelectedPoint=false;
if(line.isSelected())
line.setSelected(false);
else{
if((mouseEvent.getModifiers()&java.awt.event.MouseEvent.SHIFT_MASK)==0)
deSelectAll();
line.setSelected(true);
}
notifyShapeChanged();
hep.repaint(0);
}
}
}
if(creatingPolygon){
if(mouseEvent.getClickCount()==2)
joinPolygon();
else{
mousePoint=mouseEvent.getPoint();
EditableShape near=aproximationToLine(mousePoint.getX(),mousePoint.getY(),vRedrawingLines);
Point2D nearDrawn=null;
Point2D nearDrawnOther=aproximationToDrawnBorder(mousePoint.getX(),mousePoint.getY());
if(near!=null){ // if the ending point is near the mouse, approximate to it
nearDrawn=near.getNearestBorder(mousePoint.getX(),mousePoint.getY());
}
if(nearDrawnOther!=null && EditableShapeConstants.pointsOnGrid){
finX=nearDrawnOther.getX();
finY=nearDrawnOther.getY();
}
else{
mousePoint=getTransformedPoint(mouseEvent.getPoint(),true);
finX=mousePoint.getX();
finY=mousePoint.getY();
}
if(lastPoint!=null){ // isn't the first point
if(nearDrawn!=null && iniPoint.getX()==nearDrawn.getX() && iniPoint.getY()==nearDrawn.getY()){//Has clicked over the starting point of the polygon
if(vShapes.size()>=2)
joinPolygon();
}
else{
if(nearDrawn==null){ //Points cannot be repeated
vShapes.add(new EditableLine2D(lastPoint.getX(),lastPoint.getY(),finX,finY));
lastPoint=new Point2D.Double(finX,finY);
}
}
}
else { //it's the first point
iniPoint=new Point2D.Double(finX,finY);
lastPoint=iniPoint;
}
}
}
}
public void mouseEntered(java.awt.event.MouseEvent mouseEvent) {
}
public void mouseExited(java.awt.event.MouseEvent mouseEvent) {
}
public void mousePressed(java.awt.event.MouseEvent mouseEvent) {
Point2D mousePoint=getTransformedPoint(mouseEvent.getPoint(),drawingMode!=SELECTING); //when selecting, the point doesn't must be in the grid
int x=(int)mousePoint.getX();
int y=(int)mousePoint.getY();
if(canResize){
int resizing=getResizing(mousePoint);
if(resizing!=NO_RESIZING){
if(drawingMode!=SELECTING)
hep.setDrawingMode(SELECTING);
bResizing=true;
resizingDirection=resizing;
}
}
if(x<hep.previewArea.x || y<hep.previewArea.y
|| x>hep.previewArea.x+hep.previewArea.getWidth() || y>hep.previewArea.y+hep.previewArea.getHeight())
return;
if(bMoving){ //CTRL+X has been pressed while moving a shape
paste(finX-iniX,finY-iniY);
bMoving=false;
}
iniX=x;
iniY=y;
if(drawingMode==SELECTING && !bMoving){
clicatISeleccionada(x,y,false); //false: drag is possible despite of having the shape selected or unselected
if(vRedrawingLines.size()>0)
bRedrawingLines=true; //Redraw lines when clicking on a corner
}
else if((drawingMode==DRAWING_RECT || drawingMode==DRAWING_ELLIPSE || drawingMode==DRAWING_POLYGON)&&!hasSelectedDrawnShape(mouseEvent.getPoint())){
if(drawingMode==DRAWING_RECT)
creatingRect=true;
else if(drawingMode==DRAWING_ELLIPSE)
creatingEllipse=true;
else
creatingPolygon=true;
EditableShape near=aproximationToLine(x,y);
Point2D pNear=aproximationToDrawnBorder(x,y);
if (near!=null){
pNear=near.getNearestBorder(x,y);
}
if (pNear!=null){
iniX=pNear.getX();
iniY=pNear.getY();
}
else{
iniX=x;
iniY=y;
}
finX=iniX;
finY=iniY;
hep.repaint(0);
}
else if(drawingMode==NEW_POINT){
EditableShape lineToDivide=specialLine;
EditableShape near=aproximationToLine(x,y,null);
Point2D nearDrawn=null;
boolean isSelect=false;
if(near!=null)
nearDrawn=near.getNearestBorder(x,y);
if(drawingMode==NEW_POINT && (lineToDivide!=null && bSpecialLine
&& (nearDrawn==null || lineToDivide instanceof EditableEllipse2D
|| lineToDivide instanceof EditableCubicCurve2D
|| lineToDivide instanceof EditableQuadCurve2D))){ //A point is added only when the current point is not over another one
divideShape(lineToDivide,x,y);
}
else{
isSelect=selectDrawnShape(mouseEvent.getPoint());
}
if(!isSelect){ //A point has been added, or a click has been done out of any shape
hep.setDrawingMode(SELECTING);
}
}
}
public void mouseReleased(java.awt.event.MouseEvent mouseEvent) {
if((mouseEvent.getModifiers()&java.awt.event.MouseEvent.BUTTON1_MASK)==0){//The button 1 was not pressed
return;
}
if(bMoving){
paste(finX-iniX,finY-iniY);
bMoving=false;
deSelectAll();
}
Point2D mousePoint=mouseEvent.getPoint();
EditableShape near=aproximationToLine(mousePoint.getX(),mousePoint.getY(),vRedrawingLines);
Point2D nearDrawnPropi=null;
Point2D nearDrawn=aproximationToDrawnBorder(mousePoint.getX(),mousePoint.getY()); //Corner of a non-active polygon
if(near!=null || nearDrawn!=null)
hep.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
else
hep.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if(near!=null){ // if there is any nearest point, approximate the ending point to it
nearDrawnPropi=near.getNearestBorder(mousePoint.getX(),mousePoint.getY()); //Corner of the active polygon
}
mousePoint=getTransformedPoint(mouseEvent.getPoint(),true);
if(!(mousePoint.getX()<hep.previewArea.x || mousePoint.getY()<hep.previewArea.y
|| mousePoint.getX()>hep.previewArea.x+hep.previewArea.getWidth()
|| mousePoint.getY()>hep.previewArea.y+hep.previewArea.getHeight())){
if(nearDrawn!=null && EditableShapeConstants.pointsOnGrid){ //Only when approaching
finX=nearDrawn.getX();
finY=nearDrawn.getY();
}
else{
finX=mousePoint.getX(); //This point is maintained as long as the pointer remains into the drawing area
finY=mousePoint.getY();
}
}
if((drawingMode==SELECTING && !bMoving && nearDrawnPropi!=null)|| (!creatingPolygon && vShapes.size()>1 && !validateShape())){
boolean canRemove=removeNullLines(vRedrawingLines);
if(!canRemove){
undoLastMove(vRedrawingLines,vRedrawingLinesBeforeModify);
finX=iniX;
finY=iniY;
}
}
else if(bRedrawingLines){
setEndToVector(finX,finY,vRedrawingLines);
bRedrawingLines=false;
vRedrawingLines.clear();
vRedrawingLinesBeforeModify.clear();
}
if(creatingRect){
creatingRect=false;
vShapes.add(new EditableRectangle((int)iniX,(int)iniY,(int)(finX-iniX),(int)(finY-iniY)));
if(hep.currentShape>=hep.getHoles().getNumCells()){ //Reserve space for the new rectangle when confirmed(in order to give it a name)
ShapeData sd=new ShapeData();
sd.comment = ""+hep.currentShape;
hep.getHoles().addShape(sd);
hep.updateList();
}
}
if(creatingEllipse){
creatingEllipse=false;
vShapes.add(new EditableEllipse2D((int)iniX,(int)iniY,(int)(finX-iniX),(int)(finY-iniY)));
if(hep.currentShape>=hep.getHoles().getNumCells()){ //Reserve space for the new rectangle when confirmed(in order to give it a name)
ShapeData sd=new ShapeData();
sd.comment = ""+hep.currentShape;
hep.getHoles().addShape(sd);
hep.updateList();
}
}
if(bResizing){
if(resizingDirection!=NO_RESIZING){
double x=mousePoint.getX();
double y=mousePoint.getY();
double xInc=x-iniX;
double yInc=y-iniY;
if(resizingDirection==EAST)
yInc=0;
else if(resizingDirection==SOUTH)
xInc=0;
hep.incDrawingArea(xInc,yInc);
}
bResizing=false;
}
ShapeData sd=getShapeData();
current=(sd!=null)?sd.getShape(hep.previewArea):null; //Update the modifications to the shape
bSelectingArea=false;
hep.repaint(0);
if(!creatingPolygon)
notifyShapeChanged();
}
public class KeyHandler extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode()==KeyEvent.VK_DELETE){
deleteSelected(false);
hep.shapeChanged();
}
}
}
private double viewIniX=-1;
private double viewIniY=-1;
}