package org.geogebra.common.euclidian.modes; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.geogebra.common.awt.GPoint2D; import org.geogebra.common.awt.GRectangle; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.euclidian.EuclidianController; import org.geogebra.common.euclidian.EuclidianCursor; import org.geogebra.common.euclidian.EuclidianView; import org.geogebra.common.euclidian.Hits; import org.geogebra.common.euclidian.event.AbstractEvent; import org.geogebra.common.euclidian.event.PointerEventType; import org.geogebra.common.factories.AwtFactory; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.kernel.SegmentType; import org.geogebra.common.kernel.algos.AlgoAttachCopyToView; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.AlgoLocusStroke; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoLocusStroke; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.main.Feature; import org.geogebra.common.util.debug.Log; public class ModeDeleteLocus extends ModeDelete { private EuclidianView view; private EuclidianController ec; private boolean objDeleteMode = false, penDeleteMode = false; private ArrayList<GPoint2D> interPoints; private ArrayList<List<MyPoint>> newDataAndRealPoint = new ArrayList<List<MyPoint>>(); public ModeDeleteLocus(EuclidianView view) { super(view); this.ec = view.getEuclidianController(); this.view = view; this.interPoints = new ArrayList<GPoint2D>(); } private GRectangle rect = AwtFactory.getPrototype().newRectangle(0, 0, 100, 100); @Override public void handleMouseDraggedForDelete(AbstractEvent e, int deleteSize, boolean forceOnlyStrokes) { if (e == null) { return; } int eventX = e.getX(); int eventY = e.getY(); rect.setBounds(eventX - deleteSize / 2, eventY - deleteSize / 2, deleteSize, deleteSize); view.setDeletionRectangle(rect); view.setIntersectionHits(rect); Hits h = view.getHits(); if (!this.objDeleteMode && !this.penDeleteMode) { updatePenDeleteMode(h); } boolean onlyStrokes = forceOnlyStrokes || this.penDeleteMode; // hide cursor, the new "cursor" is the deletion rectangle view.setCursor(EuclidianCursor.TRANSPARENT); Iterator<GeoElement> it = h.iterator(); resetAlgoSet(); while (it.hasNext()) { GeoElement geo = it.next(); // delete tool should delete the object for dragging // at whiteboard // see MOW-97 if (view.getApplication().has(Feature.ERASER) && ec.getMode() == EuclidianConstants.MODE_DELETE) { geo.removeOrSetUndefinedIfHasFixedDescendent(); } else if (geo instanceof GeoLocusStroke) { GeoLocusStroke gps = (GeoLocusStroke) geo; // we need two arrays for the case that AlgoAttachCopyToView is // involved // the original points (dataPoints) are saved, but will be // translated // and everything by the algorithm so that the // GeoLocusStroke-output // holds the points which are really drawn (and should be used // for // hit detection). List<MyPoint> realPoints; if (view.getApplication().has(Feature.PEN_SMOOTHING)) { realPoints = gps.getPointsWithoutControl(); } else { realPoints = gps.getPoints(); } List<MyPoint> dataPoints; if (geo.getParentAlgorithm() != null && (geo .getParentAlgorithm() instanceof AlgoAttachCopyToView)) { AlgoElement ae = geo.getParentAlgorithm(); for (int i = 0; i < ae.getInput().length; i++) { if (ae.getInput()[i] instanceof GeoLocusStroke) { gps = (GeoLocusStroke) ae.getInput()[i]; } } } if (gps.getParentAlgorithm() != null && gps.getParentAlgorithm() instanceof AlgoLocusStroke) { if (view.getApplication().has(Feature.PEN_SMOOTHING)) { dataPoints = ((AlgoLocusStroke) gps .getParentAlgorithm()) .getPointsWithoutControl(); } else { dataPoints = ((AlgoLocusStroke) gps .getParentAlgorithm()).getPoints(); } } else { dataPoints = gps.getPoints(); } boolean hasVisiblePart = false; if (realPoints.size() == dataPoints.size()) { for (int i = 0; i < dataPoints.size(); i++) { MyPoint p = realPoints.get(i); if (p.isDefined() && Math.max( Math.abs(eventX - view.toScreenCoordXd(p.getX())), Math.abs(eventY - view.toScreenCoordYd( p.getY()))) <= deleteSize / 2.0) { // end point of segment is in rectangle if ((i - 1 >= 0 && dataPoints.get(i - 1).isDefined())) { // get intersection point interPoints.clear(); interPoints = getAllIntersectionPoint( dataPoints.get(i - 1), dataPoints.get(i), rect); if (!interPoints.isEmpty() && interPoints.size() == 1) { i = handleEraserAtJoinPointOrEndOfSegments( dataPoints, realPoints, i); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); } } // no intersection point else { i = handleEraserAtPoint(dataPoints, realPoints, i); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); } } } // start point of segment is in rectangle else if (i - 1 >= 0 && !dataPoints.get(i - 1).isDefined() && i + 1 < dataPoints.size() && dataPoints.get(i + 1).isDefined()) { handleEraserAtStartPointOfSegment( dataPoints, realPoints, i); dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); } // handle first/last/single remained point else { handleLastFirstOrSinglePoints(dataPoints, i); dataPoints = newDataAndRealPoint.get(0); } } // eraser is between the endpoints of segment else { if (i < dataPoints.size() - 1 && dataPoints.get(i).isDefined() && dataPoints.get(i + 1).isDefined()) { i = handleEraserBetweenPointsOfSegment( dataPoints, realPoints, i); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); i = i + 2; } } } if (!hasVisiblePart && dataPoints.get(i).isDefined()) { hasVisiblePart = true; } } deleteUnnecessaryUndefPoints(dataPoints, realPoints); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); } updatePolyLineDataPoints(dataPoints, gps); if (view.getApplication().has(Feature.PEN_SMOOTHING) && gps.getParentAlgorithm() != null && gps.getParentAlgorithm() instanceof AlgoLocusStroke) { ((AlgoLocusStroke) gps.getParentAlgorithm()) .updatePointArray( getPointArray(dataPoints)); } } else { Log.debug( "Can't delete points on stroke. Different number of in and output points."); } if (hasVisiblePart) { // still something visible, don't delete it.remove(); // remove this Stroke from hits } } else { if (!this.penDeleteMode) { this.objDeleteMode = true; } if (onlyStrokes) { it.remove(); } } } ec.deleteAll(h); updateAlgoSet(); } private GeoPointND[] getPointArray(List<MyPoint> dataPoints) { GeoPointND[] pointArray = new GeoPointND[dataPoints.size()]; for (int i = 0; i < dataPoints.size(); i++) { pointArray[i] = new GeoPoint(ec.getKernel().getConstruction(), dataPoints.get(i).getInhomX(), dataPoints.get(i).getInhomY(), 1); } return pointArray; } private void updateAlgoSet() { // TODO Auto-generated method stub } private void resetAlgoSet() { // TODO Auto-generated method stub } private void deleteUnnecessaryUndefPoints(List<MyPoint> dataPoints, List<MyPoint> realPoints) { newDataAndRealPoint.clear(); ArrayList<MyPoint> dataPointList = new ArrayList<MyPoint>( dataPoints.size()); ArrayList<MyPoint> realPointList = new ArrayList<MyPoint>( realPoints.size()); int i = 1; while (i < dataPoints.size()) { if ((!dataPoints.get(i).isDefined() && !dataPoints.get(i - 1).isDefined())) { i++; } else { dataPointList.add(dataPoints.get(i - 1)); realPointList.add(realPoints.get(i - 1)); i++; } } if (dataPoints.get(i - 1).isDefined()) { dataPointList.add(dataPoints.get(i - 1)); realPointList.add(realPoints.get(i - 1)); } if (dataPointList.size() != dataPoints.size()) { newDataAndRealPoint.add(dataPointList); newDataAndRealPoint.add(realPointList); } } // add new undefined points and update old points coordinates private static ArrayList<List<MyPoint>> getNewPolyLinePoints( List<MyPoint> dataPoints, List<MyPoint> realPoints, int newSize, int i, int indexInter1, int indexUndef, int indexInter2, double[] realCoords) { ArrayList<List<MyPoint>> dataAndRealPoint = new ArrayList<List<MyPoint>>(); MyPoint[] newDataPoints = Arrays.copyOf( dataPoints.toArray(new MyPoint[0]), dataPoints.size() + newSize); MyPoint[] newRealPoints = Arrays.copyOf( realPoints.toArray(new MyPoint[0]), realPoints.size() + newSize); if (newSize == 1) { for (int j = dataPoints.size(); j > i + 1; j--) { newDataPoints[j + newSize - 1] = dataPoints.get(j - 1); newRealPoints[j + newSize - 1] = realPoints.get(j - 1); } } else if (newSize == -1) { for (int j = dataPoints.size(); j > i; j--) { newDataPoints[j] = dataPoints.get(j - 1); newRealPoints[j] = realPoints.get(j - 1); } } else { for (int j = dataPoints.size(); j > i - newSize + 3; j--) { newDataPoints[j + newSize - 1] = dataPoints.get(j - 1); newRealPoints[j + newSize - 1] = realPoints.get(j - 1); } } newDataPoints[indexInter1] = ngp(realCoords[0], realCoords[1]); newDataPoints[indexUndef] = ngp(); newRealPoints[indexUndef] = ngp(); newDataPoints[indexInter2] = ngp(realCoords[2], realCoords[3]); dataAndRealPoint.add(Arrays.asList(newDataPoints)); dataAndRealPoint.add(Arrays.asList(newRealPoints)); return dataAndRealPoint; } private static MyPoint ngp() { return new MyPoint(Double.NaN, Double.NaN, SegmentType.LINE_TO); } private static MyPoint ngp(double d, double e) { return new MyPoint(d, e, SegmentType.LINE_TO); } private void updatePenDeleteMode(Hits h) { // if we switched to pen deletion just now, some geos may still need // removing Iterator<GeoElement> it2 = h.iterator(); while (it2.hasNext()) { GeoElement geo2 = it2.next(); if (geo2 instanceof GeoLocusStroke) { this.penDeleteMode = true; } } } /** * @param point1 * start point of segment * @param point2 * end point of segment * @param rectangle * eraser * @return intersection point with top of rectangle (if there is any) */ public GPoint2D getTopIntersectionPoint(MyPoint point1, MyPoint point2, GRectangle rectangle) { // Top line return getIntersectionPoint(point1, point2, rectangle.getX(), rectangle.getY(), rectangle.getX() + rectangle.getWidth(), rectangle.getY()); } /** * @param point1 * start point of segment * @param point2 * end point of segment * @param rectangle * eraser * @return intersection point with bottom of rectangle (if there is any) */ public GPoint2D getBottomIntersectionPoint(MyPoint point1, MyPoint point2, GRectangle rectangle) { // Bottom line return getIntersectionPoint(point1, point2, rectangle.getX(), rectangle.getY() + rectangle.getHeight(), rectangle.getX() + rectangle.getWidth(), rectangle.getY() + rectangle.getHeight()); } /** * @param point1 * start point of segment * @param point2 * end point of segment * @param rectangle * eraser * @return intersection point with left side of rectangle (if there is any) */ public GPoint2D getLeftIntersectionPoint(MyPoint point1, MyPoint point2, GRectangle rectangle) { // Left side return getIntersectionPoint(point1, point2, rectangle.getX(), rectangle.getY(), rectangle.getX(), rectangle.getY() + rectangle.getHeight()); } /** * @param point1 * start point of segment * @param point2 * end point of segment * @param rectangle * eraser * @return intersection point with right side of rectangle (if there is any) */ public GPoint2D getRightIntersectionPoint(MyPoint point1, MyPoint point2, GRectangle rectangle) { // Right side return getIntersectionPoint(point1, point2, rectangle.getX() + rectangle.getWidth(), rectangle.getY(), rectangle.getX() + rectangle.getWidth(), rectangle.getY() + rectangle.getHeight()); } /** * method to get all intersection points of a segment with the eraser (with * each side of rectangle) * * @param point1 * start point of segment * @param point2 * end point of segment * @param rectangle * eraser * @return list of intersection points */ public ArrayList<GPoint2D> getAllIntersectionPoint(MyPoint point1, MyPoint point2, GRectangle rectangle) { ArrayList<GPoint2D> interPointList = new ArrayList<GPoint2D>(); // intersection points GPoint2D topInter = getTopIntersectionPoint(point1, point2, rectangle); if (topInter != null) { interPointList.add(topInter); } GPoint2D bottomInter = getBottomIntersectionPoint(point1, point2, rectangle); if (bottomInter != null) { interPointList.add(bottomInter); } GPoint2D leftInter = getLeftIntersectionPoint(point1, point2, rectangle); if (leftInter != null) { interPointList.add(leftInter); } GPoint2D rightInter = getRightIntersectionPoint(point1, point2, rectangle); if (rightInter != null) { interPointList.add(rightInter); } return interPointList; } /** * method to get the intersection point of two segment (not line) * * @param point1 * start point of first segment * @param point2 * end point of first segment * @param startPointX * start coord of start point of second segment * @param startPointY * end coord of start point of second segment * @param endPointX * start coord of end point of second segment * @param endPointY * end coord of end point of second segment * @return intersection point */ public GPoint2D getIntersectionPoint(MyPoint point1, MyPoint point2, double startPointX, double startPointY, double endPointX, double endPointY) { double x1 = view.toScreenCoordXd(point1.getX()); double y1 = view.toScreenCoordYd(point1.getY()); double x2 = view.toScreenCoordXd(point2.getX()); double y2 = view.toScreenCoordYd(point2.getY()); double x3 = startPointX; double y3 = startPointY; double x4 = endPointX; double y4 = endPointY; GPoint2D p = null; double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); // are not parallel if (d != 0.0) { // coords of intersection point with line double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d; double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d; // needed to get only the intersection points with segment // and not with line if (onSegment(Math.round(x1), Math.round(y1), xi, yi, Math.round(x2), Math.round(y2)) && onSegment(Math.round(x3), Math.round(y3), xi, yi, Math.round(x4), Math.round(y4))) { p = new GPoint2D.Double(xi, yi); } } return p; } // check if intersection point is on segment private static boolean onSegment(double segStartX, double segStartY, double interPointX, double interPointY, double segEndX, double segEndY) { if (interPointX <= Math.max(segStartX, segEndX) && interPointX >= Math.min(segStartX, segEndX) && interPointY <= Math.max(segStartY, segEndY) && interPointY >= Math.min(segStartY, segEndY)) { return true; } return false; } // check if the two intersection point is close enough private static boolean areClose(GPoint2D point1, GPoint2D point2) { double distance = Math.hypot(point1.getX() - point2.getX(), point1.getY() - point2.getY()); return distance < 20; } private double[] getInterRealCoords(MyPoint point) { double[] coords = new double[4]; double realX1 = view.toRealWorldCoordX(interPoints.get(0).getX()); double realY1 = view.toRealWorldCoordY(interPoints.get(0).getY()); double realX2 = view.toRealWorldCoordX(interPoints.get(1).getX()); double realY2 = view.toRealWorldCoordY(interPoints.get(1).getY()); double distance1 = Math.hypot(point.getX() - realX1, point.getY() - realY1); double distance2 = Math.hypot(point.getX() - realX2, point.getY() - realY2); // we need to decide the order of intersection points // in order to set correct the intersection points if (distance1 < distance2) { coords[0] = realX1; coords[1] = realY1; coords[2] = realX2; coords[3] = realY2; } else { coords[0] = realX2; coords[1] = realY2; coords[2] = realX1; coords[3] = realY1; } return coords; } @Override public void mousePressed(PointerEventType type) { this.objDeleteMode = false; this.penDeleteMode = false; } private static void updatePolyLineDataPoints(List<MyPoint> dataPoints, GeoLocusStroke gps) { if (gps.getParentAlgorithm() != null && gps.getParentAlgorithm() instanceof AlgoLocusStroke) { ((AlgoLocusStroke) gps.getParentAlgorithm()) .updateFrom(dataPoints); gps.notifyUpdate(); } } @Override public boolean process(Hits hits, boolean control, boolean selPreview) { if (hits.isEmpty() || this.penDeleteMode) { return false; } ec.addSelectedGeo(hits, 1, false, selPreview); if (ec.selGeos() == 1) { GeoElement[] geos = ec.getSelectedGeos(); resetAlgoSet(); // delete only parts of GeoLocusStroke, not the whole object // when eraser tool is used if (geos[0] instanceof GeoLocusStroke && ec.getMode() == EuclidianConstants.MODE_ERASER) { updatePenDeleteMode(hits); int eventX = 0; int eventY = 0; if (ec.getMouseLoc() != null) { eventX = ec.getMouseLoc().getX(); eventY = ec.getMouseLoc().getY(); rect.setBounds(eventX - ec.getDeleteToolSize() / 2, eventY - ec.getDeleteToolSize() / 2, ec.getDeleteToolSize(), ec.getDeleteToolSize()); } else { return false; } GeoLocusStroke gps = (GeoLocusStroke) geos[0]; List<MyPoint> realPoints; if (view.getApplication().has(Feature.PEN_SMOOTHING)) { realPoints = gps.getPointsWithoutControl(); } else { realPoints = gps.getPoints(); } List<MyPoint> dataPoints; if (geos[0].getParentAlgorithm() != null && (geos[0] .getParentAlgorithm() instanceof AlgoAttachCopyToView)) { AlgoElement ae = geos[0].getParentAlgorithm(); for (int i = 0; i < ae.getInput().length; i++) { if (ae.getInput()[i] instanceof GeoLocusStroke) { gps = (GeoLocusStroke) ae.getInput()[i]; } } } if (gps.getParentAlgorithm() != null && gps.getParentAlgorithm() instanceof AlgoLocusStroke) { if (view.getApplication().has(Feature.PEN_SMOOTHING)) { dataPoints = ((AlgoLocusStroke) gps .getParentAlgorithm()) .getPointsWithoutControl(); } else { dataPoints = ((AlgoLocusStroke) gps .getParentAlgorithm()) .getPoints(); } } else { dataPoints = gps.getPoints(); } boolean hasVisiblePart = false; if (realPoints.size() == dataPoints.size()) { for (int i = 0; i < dataPoints.size(); i++) { MyPoint p = realPoints.get(i); if (p.isDefined() && Math.max( Math.abs(eventX - view.toScreenCoordXd(p.getX())), Math.abs(eventY - view.toScreenCoordYd(p.getX()))) <= ec .getDeleteToolSize() / 2.0) { // end point of segment is in rectangle if ((i - 1 >= 0 && dataPoints.get(i - 1).isDefined())) { // get intersection point interPoints.clear(); interPoints = getAllIntersectionPoint( dataPoints.get(i - 1), dataPoints.get(i), rect); // one intersection point if (!interPoints.isEmpty() && interPoints.size() == 1) { i = handleEraserAtJoinPointOrEndOfSegments( dataPoints, realPoints, i); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1) ; } } // no intersection point else { i = handleEraserAtPoint(dataPoints, realPoints, i); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1) ; } } } // start point of segment is in rectangle else if (i - 1 >= 0 && !dataPoints.get(i - 1).isDefined() && i + 1 < dataPoints.size() && dataPoints.get(i + 1).isDefined()) { handleEraserAtStartPointOfSegment( dataPoints, realPoints, i); dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); } // handle first/last/single remained point else { handleLastFirstOrSinglePoints( dataPoints, i); dataPoints = newDataAndRealPoint.get(0); } } // eraser is between the points of segment else { if (i < dataPoints.size() - 1 && dataPoints.get(i).isDefined() && dataPoints.get(i + 1).isDefined()) { i = handleEraserBetweenPointsOfSegment( dataPoints, realPoints, i); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); i = i + 2; } } } if (!hasVisiblePart && dataPoints.get(i).isDefined()) { hasVisiblePart = true; } } deleteUnnecessaryUndefPoints(dataPoints, realPoints); if (newDataAndRealPoint != null && !newDataAndRealPoint.isEmpty()) { dataPoints = newDataAndRealPoint.get(0); realPoints = newDataAndRealPoint.get(1); } updatePolyLineDataPoints(dataPoints, gps); if (view.getApplication().has(Feature.PEN_SMOOTHING) && gps.getParentAlgorithm() != null && gps.getParentAlgorithm() instanceof AlgoLocusStroke) { ((AlgoLocusStroke) gps.getParentAlgorithm()) .updatePointArray(getPointArray(dataPoints)); } } else { Log.debug( "Can't delete points on stroke. Different number of in and output points."); } if (!hasVisiblePart) { // still something visible, don't delete // remove this Stroke geos[0].removeOrSetUndefinedIfHasFixedDescendent(); } updateAlgoSet(); } // delete this object else { geos[0].removeOrSetUndefinedIfHasFixedDescendent(); } return true; } return false; } private void handleLastFirstOrSinglePoints(List<MyPoint> dataPoints, int i) { newDataAndRealPoint.clear(); if ((i == 0 && ((i + 1 < dataPoints.size() && !dataPoints.get(i + 1).isDefined()) || (i + 1 == dataPoints.size()))) || (i - 1 >= 0 && !dataPoints.get(i - 1).isDefined() && i + 1 == dataPoints.size())) { dataPoints.get(i).setUndefined(); } // handle single remained point else if (i - 1 >= 0 && !dataPoints.get(i - 1).isDefined() && i + 1 < dataPoints.size() && !dataPoints.get(i + 1).isDefined()) { dataPoints.get(i).setUndefined(); } newDataAndRealPoint.add(dataPoints); } private void handleEraserAtStartPointOfSegment(List<MyPoint> dataPoints, List<MyPoint> realPoints, int i) { newDataAndRealPoint.clear(); // get intersection points interPoints.clear(); interPoints = getAllIntersectionPoint(dataPoints.get(i), dataPoints.get(i + 1), rect); if (!interPoints.isEmpty() && interPoints.size() == 1) { double realX = view.toRealWorldCoordX(interPoints.get(0).getX()); double realY = view.toRealWorldCoordY(interPoints.get(0).getY()); // switch old point with intersection point dataPoints.get(i).setCoords(realX, realY, 1); } // no intersection else if (interPoints.isEmpty()) { double pointX = view.toScreenCoordXd(dataPoints.get(i + 1).getX()); double pointY = view.toScreenCoordYd(dataPoints.get(i + 1).getY()); GPoint2D point = AwtFactory.getPrototype().newPoint2D(pointX, pointY); // if end point is also inside of the // rectangle if (rect.contains(point)) { // we can set point the start point at // undefined dataPoints.get(i).setUndefined(); } } // 2 intersection points else { if (areClose(interPoints.get(0), interPoints.get(1))) { double realX = view .toRealWorldCoordX(interPoints.get(0).getX()); double realY = view .toRealWorldCoordY(interPoints.get(0).getY()); // switch old point with intersection // point dataPoints.get(i).setCoords(realX, realY, 1); } else { dataPoints.get(i).setUndefined(); } } newDataAndRealPoint.add(dataPoints); newDataAndRealPoint.add(realPoints); } private int handleEraserAtPoint(List<MyPoint> dataPoints, List<MyPoint> realPoints, int i) { int index = i; newDataAndRealPoint.clear(); // no intersection points if (interPoints.isEmpty()) { double pointX = view.toScreenCoordXd(dataPoints.get(i - 1).getX()); double pointY = view.toScreenCoordYd(dataPoints.get(i - 1).getY()); GPoint2D point = AwtFactory.getPrototype().newPoint2D(pointX, pointY); // if the first point is also inside of // rectangle if (rect.contains(point)) { // we can set the end point to undefined dataPoints.get(i).setUndefined(); } } // two intersection points else { if (areClose(interPoints.get(0), interPoints.get(1))) { double realX = view .toRealWorldCoordX(interPoints.get(0).getX()); double realY = view .toRealWorldCoordY(interPoints.get(0).getY()); // switch old point with intersection // point dataPoints.get(i).setCoords(realX, realY, 1); } else { double[] realCoords = getInterRealCoords( dataPoints.get(i - 1)); newDataAndRealPoint = getNewPolyLinePoints( dataPoints, realPoints, 1, i, i - 1, i, i + 1, realCoords); index = i + 2; } } if (newDataAndRealPoint != null && newDataAndRealPoint.isEmpty()) { newDataAndRealPoint.add(dataPoints); newDataAndRealPoint.add(realPoints); } return index; } private int handleEraserAtJoinPointOrEndOfSegments(List<MyPoint> dataPoints, List<MyPoint> realPoints, int i) { int index = i; newDataAndRealPoint.clear(); ArrayList<GPoint2D> secondInterPoints; if (i + 1 < dataPoints.size() && dataPoints.get(i + 1).isDefined()) { // see if there is intersection point with next segment secondInterPoints = getAllIntersectionPoint(dataPoints.get(i), dataPoints.get(i + 1), rect); // case point is the join point of 2 segments if (!secondInterPoints.isEmpty() && secondInterPoints.size() == 1) { interPoints.add(secondInterPoints.get(0)); double[] realCoords = getInterRealCoords( dataPoints.get(i - 1)); if (i + 2 < dataPoints.size() && dataPoints.get(i + 2).isDefined() && i - 2 > 0 && dataPoints.get(i - 2).isDefined()) { // switch old point with // intersection point dataPoints.get(i - 1).setCoords(realCoords[0], realCoords[1], 1); dataPoints.get(i).setUndefined(); // switch old point with // intersection point dataPoints.get(i + 1).setCoords(realCoords[2], realCoords[3], 1); newDataAndRealPoint.add(dataPoints); newDataAndRealPoint.add(realPoints); index = i + 2; } else if (i + 2 < dataPoints.size() && !dataPoints.get(i + 2).isDefined() && i - 2 > 0 && dataPoints.get(i - 2).isDefined()) { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 1, i, i - 1, i, i + 1, realCoords); index = i + 2; } else if (i - 2 > 0 && !dataPoints.get(i - 2).isDefined() && i + 2 < dataPoints.size() && dataPoints.get(i + 2).isDefined()) { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 1, i, i, i + 1, i + 2, realCoords); index = i + 2; } else if (i - 2 > 0 && !dataPoints.get(i - 2).isDefined() && i + 2 < dataPoints.size() && !dataPoints.get(i + 2).isDefined()) { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 2, i, i, i + 1, i + 2, realCoords); index = i + 3; } else { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 1, i, i, i + 1, i + 2, realCoords); index = i + 2; } } } // point is endpoint of segment else { double realX = view.toRealWorldCoordX(interPoints.get(0).getX()); double realY = view.toRealWorldCoordY(interPoints.get(0).getY()); // switch old point with // intersection point dataPoints.get(i).setCoords(realX, realY, 1); newDataAndRealPoint.add(dataPoints); newDataAndRealPoint.add(realPoints); } return index; } private int handleEraserBetweenPointsOfSegment( List<MyPoint> dataPoints, List<MyPoint> realPoints, int i) { int index = i; interPoints.clear(); interPoints = getAllIntersectionPoint(dataPoints.get(i), dataPoints.get(i + 1), rect); newDataAndRealPoint.clear(); if (!interPoints.isEmpty() && interPoints.size() >= 2) { double[] realCoords = getInterRealCoords(dataPoints.get(i)); // case ?,(A),(B),? or ?,(A),(B) if (i - 1 > 0 && !dataPoints.get(i - 1).isDefined() && ((i + 2 < dataPoints.size() && !dataPoints.get(i + 2).isDefined()) || i + 1 == dataPoints.size() - 1)) { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 3, i, i + 1, i + 2, i + 3, realCoords); index = i + 2; } // case ?,(A),(B),... else if (i - 1 > 0 && !dataPoints.get(i - 1).isDefined() && i + 1 != dataPoints.size() - 1) { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 2, i, i + 1, i + 2, i + 3, realCoords); index++; } // case ...,(A),(B),?,... or ...,(A),(B) else if (i + 1 == dataPoints.size() - 1 || (i + 2 < dataPoints.size() && !dataPoints.get(i + 2).isDefined())) { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 2, i, i, i + 1, i + 2, realCoords); index++; } // otherwise else { newDataAndRealPoint = getNewPolyLinePoints(dataPoints, realPoints, 1, i, i, i + 1, i + 2, realCoords); } } return index; } }