package org.geogebra.common.geogebra3D.euclidian3D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import org.geogebra.common.awt.GPoint;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.euclidian.EuclidianController;
import org.geogebra.common.euclidian.EuclidianControllerCompanion;
import org.geogebra.common.euclidian.EuclidianCursor;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.euclidian.EuclidianViewInterfaceSlim;
import org.geogebra.common.euclidian.Hits;
import org.geogebra.common.euclidian.Previewable;
import org.geogebra.common.euclidian.draw.DrawDropDownList;
import org.geogebra.common.euclidian.event.AbstractEvent;
import org.geogebra.common.euclidian.event.PointerEventType;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawConic3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawConicSection3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawExtrusionOrConify3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawIntersectionCurve3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawLine3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawPoint3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawPolyLine3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawPolygon3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawPolyhedron3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.DrawSegment3D;
import org.geogebra.common.geogebra3D.euclidian3D.draw.Drawable3D;
import org.geogebra.common.geogebra3D.euclidianFor3D.EuclidianControllerFor3DCompanion;
import org.geogebra.common.geogebra3D.kernel3D.ConstructionDefaults3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoDependentVector3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoDispatcher3D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoIntersectCS1D2D;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoIntersectCS1D2D.ConfigLinePlane;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoIntersectPlanes;
import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoUnitVector3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoConic3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoConicSection;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoCoordSys1D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPlane3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPolygon3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPolyhedron;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3D;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3DLimited;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3DPart;
import org.geogebra.common.geogebra3D.kernel3D.geos.GeoVector3D;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.ModeSetter;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.Region;
import org.geogebra.common.kernel.Matrix.CoordMatrix4x4;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoDynamicCoordinatesInterface;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.algos.AlgoTranslate;
import org.geogebra.common.kernel.algos.AlgoVectorPoint;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.MyDouble;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.FromMeta;
import org.geogebra.common.kernel.geos.GeoAngle;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoElement.HitType;
import org.geogebra.common.kernel.geos.GeoFunctionNVar;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.geos.Test;
import org.geogebra.common.kernel.geos.Transformable;
import org.geogebra.common.kernel.kernelND.GeoConicND;
import org.geogebra.common.kernel.kernelND.GeoCoordSys;
import org.geogebra.common.kernel.kernelND.GeoCoordSys2D;
import org.geogebra.common.kernel.kernelND.GeoDirectionND;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoImplicitSurfaceND;
import org.geogebra.common.kernel.kernelND.GeoLineND;
import org.geogebra.common.kernel.kernelND.GeoPlaneND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoPolyhedronInterface;
import org.geogebra.common.kernel.kernelND.GeoQuadric3DLimitedInterface;
import org.geogebra.common.kernel.kernelND.GeoQuadricND;
import org.geogebra.common.kernel.kernelND.GeoSegmentND;
import org.geogebra.common.kernel.kernelND.GeoVectorND;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Feature;
import org.geogebra.common.main.error.ErrorHandler;
import org.geogebra.common.plugin.Operation;
import org.geogebra.common.util.AsyncOperation;
import org.geogebra.common.util.debug.Log;
import org.geogebra.common.util.lang.Unicode;
/**
* Controller for the 3D view
*
* @author Mathieu
*
*/
public abstract class EuclidianController3D extends EuclidianController {
/** 3D point that is currently moved */
// protected GeoPoint3D movedGeoPoint3D = null;
/** min/max values for moving a point */
private double[] xMinMax, yMinMax;
/** min/max values for moving a point along z */
protected double[] zMinMax;
/** current plane where the movedGeoPoint3D lies */
protected CoordMatrix4x4 currentPlane = null;
/** 3D view controlled by this */
protected EuclidianView3D view3D; // TODO move to EuclidianViewInterface
private GPoint mouseLocOld = new GPoint();
private Coords positionOld = new Coords(4);
/** says that a free point has just been created (used for 3D cursor) */
private boolean freePointJustCreated = false;
/** says if a rotation of the view occurred (with right-button) */
protected boolean viewRotationOccured = false;
/**
* scale factor for changing angle of view : 2Pi <-> 360 pixels (so 1 pixel
* = 1degrees )
*/
static final public double ANGLE_TO_DEGREES = 2 * Math.PI / 360;
/** maximum vertical angle */
static final public int ANGLE_MAX = 90;
/** for animated rotation */
protected double animatedRotSpeed;
/** used when time is needed */
protected double timeOld;
/** used to record x information */
private int xOld;
private Hits3D goodHits;
/**
* Store infos for intersection curve
*/
public static class IntersectionCurve {
protected GeoElement geo1, geo2;
public Drawable3D drawable;
/**
* constructor
*
* @param geo1
* first geo for the intersection
* @param geo2
* second geo for the intersection
* @param result
* result intersection
*
* @param drawable
* drawable for the intersection
*/
public IntersectionCurve(GeoElement geo1, GeoElement geo2,
Drawable3D drawable) {
this.geo1 = geo1;
this.geo2 = geo2;
this.drawable = drawable;
}
}
/**
* array list for intersection curves
*/
private ArrayList<IntersectionCurve> intersectionCurveList = new ArrayList<IntersectionCurve>();
// private ArrayList<Drawable3D> intersectionCurves = new
// ArrayList<Drawable3D>();
// SELECTED GEOS
/** 2D coord sys (plane, polygon, ...) */
/**
* common constructor
*
* @param app
* application
*/
public EuclidianController3D(App app) {
super(app);
// inits min max
xMinMax = new double[2];
yMinMax = new double[2];
zMinMax = new double[2];
}
private EuclidianController3DCompanion companion3D;
@Override
protected EuclidianControllerCompanion newCompanion() {
companion3D = new EuclidianController3DCompanion(this);
return companion3D;
}
/**
* sets the view controlled by this
*
* @param view
* euclidian view (3D assumed, not checked)
*/
public void setView3D(EuclidianView view) {
this.view3D = (EuclidianView3D) view;
}
// //////////////////////////////////////////
// setters movedGeoElement -> movedGeoPoint, ...
private static double[] getMinMax(double min, double val, double max) {
double min1 = min, max1 = max;
if (val < min) {
min1 = val;
} else if (val > max) {
max1 = val;
}
return new double[] { min1, max1 };
}
@Override
public void setMovedGeoPoint(GeoElementND geo) {
movedGeoPoint = (GeoPointND) geo;
((EuclidianView3D) getView()).setPointDecorations(movedGeoPoint);
AlgoElement algo = movedGeoPoint.getParentAlgorithm();
if (algo instanceof AlgoDynamicCoordinatesInterface) {
movedGeoPoint = ((AlgoDynamicCoordinatesInterface) algo)
.getParentPoint();
}
Coords coords = movedGeoPoint.getInhomCoordsInD3();
// sets the min/max values
double pointSize = movedGeoPoint.getPointSize()
* DrawPoint3D.DRAW_POINT_FACTOR;
double size;
size = pointSize / view3D.getXscale();
xMinMax = getMinMax(view3D.getXmin() + size, coords.getX(),
view3D.getXmax() - size);
size = pointSize / view3D.getYscale();
yMinMax = getMinMax(view3D.getYmin() + size, coords.getY(),
view3D.getYmax() - size);
size = pointSize / view3D.getZscale();
zMinMax = getMinMax(view3D.getZmin() + size, coords.getZ(),
view3D.getZmax() - size);
updateMovedGeoPointStartValues(coords);
view3D.setDragCursor();
}
/**
* update values needed to move a point
*
* @param coords
* start point coords
*/
final public void updateMovedGeoPointStartValues(Coords coords) {
getCompanion().updateMovedGeoPointStartValues(coords, movedGeoPoint,
getCurrentPlane());
}
// //////////////////////////////////////////:
// moving points
/**
* return the current plane for moving
*
* @return the current plane
*/
protected CoordMatrix4x4 getCurrentPlane() {
if (currentPlane == null) {
currentPlane = CoordMatrix4x4.Identity();
}
return currentPlane;
}
/**
* set the current plane for moving
*
* @param plane
* a plane
*/
protected void setCurrentPlane(CoordMatrix4x4 plane) {
currentPlane = plane;
}
/**
* set the current plane to the path's moving plane
*
* @param path
* a path
*/
/*
* private void setCurrentPlane(Path3D path){ Ggb3DMatrix4x4 plane =
* path.getMovingMatrix(view3D.getToScreenMatrix());
* view3D.toSceneCoords3D(plane); setCurrentPlane(plane); }
*/
/**
* moves the point according to the current moving plane and mouse location
*
* @param point
* the point to move
* @param useOldMouse
* if true, shift the point according to old mouse location
*/
protected void movePointOnCurrentPlane(GeoPointND point,
boolean useOldMouse) {
// Michael Borcherds
// move mouse fast, sometimes get mouseLoc = null
if (mouseLoc == null) {
return;
}
// getting current pick point and direction v
Coords o;
if (useOldMouse) {
// if (movePointMode != MOVE_POINT_MODE_XY){
mouseLocOld.setLocation(mouseLoc.x, mouseLoc.y);
positionOld = point.getCoords().copyVector();
// movePointMode = MOVE_POINT_MODE_XY;
// }
o = view3D.getPickFromScenePoint(positionOld,
mouseLoc.x - mouseLocOld.x, mouseLoc.y - mouseLocOld.y);
} else {
o = view3D.getPickPoint(mouseLoc);
}
view3D.toSceneCoords3D(o);
addOffsetForTranslation(o);
// getting new position of the point
if (Kernel.isEqual(
view3D.getHittingDirection()
.dotproduct(getCurrentPlane().getVz()),
0.0, Kernel.STANDARD_PRECISION)) {
// hitting direction is parallel to the plane
// project on (mouse position, hitting direction) line
point.getInhomCoordsInD3().projectLine(o,
view3D.getHittingDirection(), tmpCoords2);
// now project on plane
tmpCoords2.projectPlane(getCurrentPlane(), tmpCoords);
} else {
o.projectPlaneThruV(getCurrentPlane(), view3D.getHittingDirection(),
tmpCoords);
}
// min-max x and y values
checkXYMinMax(tmpCoords);
// capturing points
((EuclidianController3DCompanion) companion)
.checkPointCapturingXY(tmpCoords);
// set point coords
point.setCoords(tmpCoords, true);
}
private Coords tmpCoords = new Coords(4);
private Coords tmpCoords2 = new Coords(4);
protected boolean checkXYMinMax(Coords v) {
if (getMoveMode() != EuclidianController.MOVE_POINT) {
return false;
}
boolean changed = false;
// min-max x value
if (v.getX() > xMinMax[1]) {
v.setX(xMinMax[1]);
changed = true;
} else if (v.getX() < xMinMax[0]) {
v.setX(xMinMax[0]);
changed = true;
}
// min-max y value
if (v.getY() > yMinMax[1]) {
v.setY(yMinMax[1]);
changed = true;
} else if (v.getY() < yMinMax[0]) {
v.setY(yMinMax[0]);
changed = true;
}
return changed;
}
/**
* set the mouse information (location and viewing direction in real world
* coordinates) to the point
*
* @param point
* a point
*/
final protected void setMouseInformation(GeoPoint3D point) {
setMouseOrigin(point);
point.setWillingDirection(view3D.getHittingDirection());
point.setZScale(view3D.getZscale());
}
/**
* set mouse origin information
*
* @param point
* a point
*/
final protected void setMouseOrigin(GeoPoint3D point) {
getCompanion().setMouseOrigin(point, mouseLoc);
}
/**
* add offset when needed
*
* @param o
* coords
*/
public void addOffsetForTranslation(Coords o) {
if (moveMode == MOVE_POINT_WITH_OFFSET) {
o.setAdd(o, translationVec3D);
}
}
@Override
protected void moveTextAbsoluteLocation() {
Coords o = view3D.getPickPoint(mouseLoc);
view3D.toSceneCoords3D(o);
// o =
// (o.sub(startPoint3D)).projectPlaneThruVIfPossible(CoordMatrix4x4.IDENTITY,
// view3D.getViewDirection())[0];
o.projectPlaneThruVIfPossible(CoordMatrix4x4.IDENTITY,
view3D.getHittingDirection(), tmpCoords);
// Application.debug(o);
// ((GeoPoint2)
// movedGeoText.getStartPoint()).setCoords(o.getX(),o.getY(), 1.0);
((GeoPoint) movedGeoText.getStartPoint()).setCoords(
tmpCoords.getX() - startPoint3DxOy.getX(),
tmpCoords.getY() - startPoint3DxOy.getY(), 1.0);
}
// ////////////////////////////////////////////
// creating a new point
@Override
protected Hits getRegionHits(Hits hits) {
return hits.getHits(Test.REGION3D, tempRegionHitsArrayList);
}
/**
*
* @param point
* cursor
* @return free point from cursor coords
*/
private GeoPoint3D getNewPointFree(GeoPointND point) {
GeoPoint3D point3D = (GeoPoint3D) kernel.getManager3D().Point3D(null, 0,
0, 0, false);
point3D.setCoords(point);
point3D.updateCoords();
view3D.setCursor3DType(EuclidianView3D.PREVIEW_POINT_ALREADY);
view3D.updateMatrixForCursor3D();
GeoPoint3D cursor = view3D.getCursor3D();
cursor.setRegion(null);
cursor.setPath(null);
cursor.setMoveMode(point3D.getMoveMode());
if (isModeForCreatingPoint(mode)) {
freePointJustCreated = true;
}
return point3D;
}
private boolean lastGetNewPointWasExistingPoint = false;
/**
* return a copy of the preview point if one
*/
@Override
protected GeoPointND getNewPoint(Hits hits, boolean onPathPossible,
boolean inRegionPossible, boolean intersectPossible,
boolean complex) {
GeoPoint3D point = view3D.getCursor3D();
GeoPoint3D point3D;
GeoPointND ret;
lastGetNewPointWasExistingPoint = false;
// Application.debug("view3D.getCursor3DType()="+view3D.getCursor3DType());
switch (view3D.getCursor3DType()) {
case EuclidianView3D.PREVIEW_POINT_FREE:
point3D = getNewPointFree(point);
ret = point3D;
pointCreated = point3D;
break;
case EuclidianView3D.PREVIEW_POINT_PATH:
if (onPathPossible) {
Path path = point.getPath();
if (path.toGeoElement().isGeoElement3D()
|| (path.toGeoElement().isGeoList()
&& ((GeoList) path.toGeoElement())
.containsGeoElement3D())) {
point3D = (GeoPoint3D) getKernel().getManager3D()
.Point3D(null, path, false);
point3D.setWillingCoords(point.getCoords());
point3D.doPath();
point3D.setWillingCoordsUndefined();
point3D.setWillingDirectionUndefined();
ret = point3D;
pointCreated = point3D;
} else {
Coords coords = point.getCoordsInD2();
pointCreated = createNewPoint2D(null, false, path,
coords.getX(), coords.getY(), false, false);
return pointCreated;
}
} else {
pointCreated = null;
return null;
}
break;
case EuclidianView3D.PREVIEW_POINT_REGION:
case EuclidianView3D.PREVIEW_POINT_REGION_AS_PATH:
if (inRegionPossible) {
Region region = point.getRegion();
if (region == getKernel().getXOYPlane()) {
point3D = getNewPointFree(point);
ret = point3D;
pointCreated = point3D;
} else if (region.isRegion3D()) {
Coords coords = point.getCoords();
point3D = (GeoPoint3D) getKernel().getManager3D()
.Point3DIn(null, region, coords, true, false);
point3D.doRegion();
point3D.setWillingCoordsUndefined();
point3D.setWillingDirectionUndefined();
ret = point3D;
pointCreated = point3D;
} else {
Coords coords = point.getCoordsInD2();
pointCreated = createNewPoint2D(null, false, region,
coords.getX(), coords.getY(), false, false);
return pointCreated;
}
} else {
pointCreated = null;
return null;
}
break;
case EuclidianView3D.PREVIEW_POINT_DEPENDENT:
if (intersectPossible) {
// get last intersection preview point
GeoPointND intersectionPoint = view3D.getIntersectionPoint();
// add it to construction
intersectionPoint.getParentAlgorithm().addToConstructionList();
intersectionPoint.setLabel(null);
pointCreated = intersectionPoint;
// check if it's a 3D point
if (intersectionPoint.isGeoElement3D()) {
point3D = (GeoPoint3D) intersectionPoint;
} else {
return intersectionPoint;
}
} else {
point3D = null;
pointCreated = null;
}
return point3D;
case EuclidianView3D.PREVIEW_POINT_ALREADY:
// current mode is not MOVE
// we return current moved point if first hitted
GeoPointND firstPoint = (GeoPointND) hits
.getFirstHit(Test.GEOPOINTND);
if (firstPoint == getMovedGeoPoint()) {
lastGetNewPointWasExistingPoint = true;
return firstPoint;
}
resetMovedGeoPoint();
return null;
case EuclidianView3D.PREVIEW_POINT_NONE:
default:
pointCreated = super.getNewPoint(hits, onPathPossible,
inRegionPossible, intersectPossible, false);
return pointCreated;
}
ret.update();
setMovedGeoPoint(point3D);
view3D.setCursor3DType(EuclidianView3D.PREVIEW_POINT_ALREADY);
view3D.updateMatrixForCursor3D();
return ret;
}
/** put sourcePoint coordinates in point */
@Override
protected void createNewPoint(GeoPointND sourcePoint) {
GeoPoint3D point3D = view3D.getCursor3D();
// set coords
point3D.setCoords(sourcePoint.getCoordsInD3(), false);
// set/remove path/region
point3D.setPath(sourcePoint.getPath());
point3D.setRegion(sourcePoint.getRegion());
// update cursor 3D infos
if (sourcePoint.isIndependent() || !sourcePoint.isGeoElement3D()) {
point3D.setMoveNormalDirection(Coords.VZ);
} else if (sourcePoint.hasRegion()) {
point3D.setMoveNormalDirection(
sourcePoint.getRegionParameters().getNormal());
}
view3D.setCursor3DType(EuclidianView3D.PREVIEW_POINT_ALREADY);
point3D.setMoveMode(sourcePoint.getMoveMode());
point3D.setPointSize(sourcePoint.getPointSize());
// Application.debug("sourcePoint:\n"+sourcePoint.getCoordsInD3()+"\ncursor:\n"+view3D.getCursor3D().getCoordsInD3());
}
/** put intersectionPoint coordinates in point */
@Override
protected void createNewPointIntersection(GeoPointND intersectionPoint) {
GeoPoint3D point3D = view3D.getCursor3D();
point3D.setCoords(point3D.getCoords()
.setInhomCoords(intersectionPoint.getCoordsInD3()), false);
view3D.setCursor3DType(EuclidianView3D.PREVIEW_POINT_DEPENDENT);
view3D.setIntersectionPoint(intersectionPoint);
// Application.debug("\nintersectionPoint="+intersectionPoint);
}
@Override
protected boolean createNewPointInRegionPossible(GeoConicND conic) {
return conic.getLastHitType() == HitType.ON_FILLING;
}
/*
* protected void updateMovedGeoPoint(GeoPointND point){ //movedGeoPoint3D =
* (GeoPoint3D) point; setMovedGeoPoint((GeoPoint3D) point); }
*/
private GeoPointND singleIntersectionPoint;
// tries to get a single intersection point for the given hits
// i.e. hits has to include two intersectable objects.
@Override
protected GeoPointND getSingleIntersectionPoint(Hits hits) {
// Log.debug(hits);
if (hits.isEmpty() || hits.size() < 2) {
return null;
}
if (mouseLoc == null) {
return null;
}
GeoElement a = hits.get(0);
// remove planes containing a (when a is line, conic, or polygon --
// notice that a plane containing a line is ever after in hits order)
if (a.isGeoLine()) { // remove planes containing line a
while (hits.size() >= 2) {
if (hits.get(1).isGeoPlane() && AlgoIntersectCS1D2D
.getConfigLinePlane((GeoLineND) a, ((GeoCoordSys2D) hits
.get(1))) == ConfigLinePlane.CONTAINED) {
hits.remove(1);
} else {
break;
}
}
} else if (a.isGeoConic()) { // remove planes containing conic a
while (hits.size() >= 2) {
if (hits.get(1).isGeoPlane() && AlgoIntersectPlanes
.getConfigPlanePlane((((GeoConicND) a).getCoordSys()),
(((GeoCoordSys2D) hits.get(1))
.getCoordSys())) == AlgoIntersectPlanes.RESULTCATEGORY_CONTAINED) {
hits.remove(1);
} else {
break;
}
}
} else if (a.isGeoPolygon()) { // remove planes containing polygon a
while (hits.size() >= 2) {
if (hits.get(1) instanceof GeoCoordSys2D && AlgoIntersectPlanes
.getConfigPlanePlane((((GeoPolygon) a).getCoordSys()),
(((GeoCoordSys2D) hits.get(1))
.getCoordSys())) == AlgoIntersectPlanes.RESULTCATEGORY_CONTAINED) {
hits.remove(1);
} else {
break;
}
}
}
if (hits.size() < 2) {
return null;
}
// Application.debug(hits.toString());
GeoElement b = hits.get(1);
singleIntersectionPoint = null;
boolean oldSilentMode = getKernel().isSilentMode();
kernel.setSilentMode(true);
// check if a and b are two 2D geos
if (!a.isGeoElement3D() && !b.isGeoElement3D()) {
// get pick point coords in xOy plane
view3D.getToSceneMatrix().mul(view3D.getPickPoint(mouseLoc))
.projectPlaneThruVIfPossible(CoordMatrix4x4.IDENTITY,
view3D.getViewDirection(), tmpCoords);
xRW = tmpCoords.getX();
yRW = tmpCoords.getY();
// apply 2D method
singleIntersectionPoint = ((EuclidianControllerFor3DCompanion) companion)
.getSingleIntersectionPointFrom2D(a, b, false);
// Log.debug("\npoint="+point+"\nmouse=\n"+project);
}
// line/line, line/plane, line/conic, line/quadric
else if (a.isGeoLine()) {
if (b.isGeoLine()) {
singleIntersectionPoint = (GeoPoint3D) getKernel()
.getManager3D()
.Intersect(null, (GeoLineND) a, (GeoLineND) b);
} else if (b.isGeoConic()) {
Coords picked = view3D.getPickPoint(mouseLoc);
singleIntersectionPoint = getKernel().getManager3D()
.IntersectLineConicSingle(null, (GeoLineND) a,
(GeoConicND) b, picked.getX(), picked.getY(),
view3D.getToScreenMatrix());
} else if (b instanceof GeoCoordSys2D) {
singleIntersectionPoint = (GeoPoint3D) getKernel()
.getManager3D().Intersect(null, (GeoLineND) a,
(GeoCoordSys2D) b, false);
} else if (b instanceof GeoQuadric3D) {
Coords picked = view3D.getPickPoint(mouseLoc);
singleIntersectionPoint = getKernel().getManager3D()
.IntersectLineQuadricSingle(null, (GeoLineND) a,
(GeoQuadric3D) b, picked.getX(), picked.getY(),
view3D.getToScreenMatrix());
}
}
// plane/line, conic/line, quadric/line
else if (b.isGeoLine()) {
if (a.isGeoConic()) {
Coords picked = view3D.getPickPoint(mouseLoc);
singleIntersectionPoint = getKernel().getManager3D()
.IntersectLineConicSingle(null, (GeoLineND) b,
(GeoConicND) a, picked.getX(), picked.getY(),
view3D.getToScreenMatrix());
} else if (a instanceof GeoCoordSys2D) {
singleIntersectionPoint = (GeoPoint3D) getKernel()
.getManager3D().Intersect(null, (GeoLineND) b,
(GeoCoordSys2D) a, true);
} else if (a instanceof GeoQuadric3D) {
Coords picked = view3D.getPickPoint(mouseLoc);
singleIntersectionPoint = getKernel().getManager3D()
.IntersectLineQuadricSingle(null, (GeoLineND) b,
(GeoQuadric3D) a, picked.getX(), picked.getY(),
view3D.getToScreenMatrix());
}
}
// conic/conic
else if (a.isGeoConic() && b.isGeoConic()) {
Coords picked = view3D.getPickPoint(mouseLoc);
singleIntersectionPoint = getKernel().getManager3D()
.IntersectConicsSingle(null, (GeoConicND) a, (GeoConicND) b,
picked.getX(), picked.getY(),
view3D.getToScreenMatrix());
}
// TODO: conic/plane, conic/quadric
kernel.setSilentMode(oldSilentMode);
// Application.debug("point is defined : "+point.isDefined());
if (singleIntersectionPoint == null) {
return null;
}
if (singleIntersectionPoint.isDefined()) {
if (singleIntersectionPoint.isGeoElement3D()) {
// if the resulting point is defined, but is not around the
// mouse, discard it. (2011/8/8 Tam)
Coords picked = view3D.getPickPoint(mouseLoc);
Coords toScreenCoords = view3D
.projectOnScreen(singleIntersectionPoint
.getCoords().getCoordsLast1());
// Log.debug("\nmouse="+mouseLoc.x+","+mouseLoc.y+"\npicked=\n"+picked+"\ncoords\n"+toScreenCoords);
// Log.debug("X: "+Math.abs(picked.getX() -
// toScreenCoords.getX()) + "\n" +
// "Y: "+Math.abs(picked.getY() - toScreenCoords.getY()));
if (Math.abs(picked.getX() - toScreenCoords.getX()) > 15 || Math
.abs(picked.getY() - toScreenCoords.getY()) > 15) {
return null;
}
}
view3D.setIntersectionThickness(a, b);
// Application.printStacktrace("\npoint="+point);
singleIntersectionPoint.setCartesian3D();
singleIntersectionPoint.update();
return singleIntersectionPoint;
}
return null;
}
// /////////////////////////////////////
// creating new objects
/**
* return selected points as 3D points
*
* @return selected points
*/
final protected GeoPoint3D[] getSelectedPoints3D() {
GeoPoint3D[] ret = new GeoPoint3D[getSelectedPointList().size()];
getSelectedPointsND(ret);
// Application.printStacktrace("");
return ret;
}
/**
* @return selected 3D lines
*/
final protected GeoCoordSys1D[] getSelectedLines3D() {
GeoCoordSys1D[] lines = new GeoCoordSys1D[getSelectedLineList().size()];
getSelectedLinesND(lines);
return lines;
}
// build polygon
/*
* protected void polygon(){ //check if there is a 3D point GeoPointND[]
* points = getSelectedPointsND();
*
* boolean point3D = false; for (int i=0; i<points.length && !point3D; i++)
* point3D = point3D || (points[i]).isGeoElement3D(); if (point3D)
* kernel.getManager3D().Polygon3D(null, points); else kernel.Polygon(null,
* getSelectedPointsND()); }
*/
protected void circleOrSphere(GeoNumberValue num) {
GeoPointND[] points = getSelectedPointsND();
getKernel().getManager3D().Sphere(null, points[0], num);
}
/**
* get center point and number
*
* @param hits
* @return true if sphere created
*/
final protected boolean spherePointRadius(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return false;
}
addSelectedPoint(hits, 1, false, selPreview);
// we got the center point
if (selPoints() == 1) {
getDialogManager()
.showNumberInputDialogSpherePointRadius(
app.getLocalization()
.getMenu(EuclidianConstants
.getModeText(mode)),
getSelectedPointsND()[0], this);
return true;
}
return false;
}
/**
* get center point and number
*
* @param hits
* @return true if cone created
*/
final protected boolean coneTwoPointsRadius(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return false;
}
addSelectedPoint(hits, 2, false, selPreview);
// we got the center point
if (selPoints() == 2) {
GeoPointND[] points = getSelectedPointsND();
getDialogManager()
.showNumberInputDialogConeTwoPointsRadius(
app.getLocalization()
.getMenu(EuclidianConstants
.getModeText(mode)),
points[0], points[1], this);
return true;
}
return false;
}
/**
* get center point and number
*
* @param hits
* @return true if cylinder created
*/
final protected boolean cylinderTwoPointsRadius(Hits hits,
boolean selPreview) {
if (hits.isEmpty()) {
return false;
}
addSelectedPoint(hits, 2, false, selPreview);
// we got the center point
if (selPoints() == 2) {
GeoPointND[] points = getSelectedPointsND();
getDialogManager()
.showNumberInputDialogCylinderTwoPointsRadius(
app.getLocalization()
.getMenu(EuclidianConstants
.getModeText(mode)),
points[0], points[1], this);
return true;
}
return false;
}
/**
* get two points and eventually direction
*
* @param hits
* hits
* @param name
* name of the solid
* @return true if solid created
*/
final protected GeoElementND[] archimedeanSolid(Hits hits, Commands name,
boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
if (addSelectedPoint(hits, 2, false, selPreview) == 0
&& selPoints() == 0 && selDirections() == 0) {
// select a plane only if no point is selected
addSelectedCS2D(hits, 1, false, selPreview);
}
// we got the center point
if (selPoints() == 2) {
GeoPointND[] points = getSelectedPointsND();
GeoDirectionND direction;
if (selCS2D() == 1) {
direction = getSelectedCS2D()[0];
Coords v = direction.getDirectionInD3();
if (v.dotproduct(view3D.getViewDirection()) > 0) { // reverse
// direction
MyDouble a = new MyDouble(kernel);
a.set(-1);
GeoVector3D orientation = (GeoVector3D) (new AlgoUnitVector3D(
kernel.getConstruction(), direction, true))
.getVector();
ExpressionNode en = new ExpressionNode(kernel, a,
Operation.MULTIPLY, orientation);
direction = new AlgoDependentVector3D(
kernel.getConstruction(), en).getVector3D();
}
return new GeoElement[] {
kernel.getManager3D().ArchimedeanSolid(null, points[0],
points[1], direction, name)[0] };
}
return new GeoElement[] { kernel.getManager3D()
.ArchimedeanSolid(null, points[0], points[1], name)[0] };
}
return null;
}
/**
*
* @param hits
* geos hitted
* @return net of a polyhedron
*/
final protected GeoElement[] polyhedronNet(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
addSelectedGeo(hits.getPolyhedronsIncludingMetaHits(), 1, false,
selPreview);
if (selGeos() == 1) {
GeoElement polyhedron = getSelectedGeos()[0];
GeoNumeric slider = GeoNumeric.setSliderFromDefault(
new GeoNumeric(kernel.getConstruction()), false);
slider.setIntervalMin(0);
slider.setIntervalMax(1);
slider.setAnimationStep(0.01);
slider.setLabel(null);
slider.setValue(1);
// slider.setSliderLocation(x, y, true);
slider.update();
return new GeoElement[] { kernel.getManager3D().PolyhedronNet(null,
polyhedron, slider, null, null)[0] // no bottom face, no
// pivot segments
};
}
return null;
}
/**
* get point and line or vector; // create plane through point orthogonal to
* line or vector
*
* @param hits
* @return orthogonal plane
*/
final protected GeoElement[] orthogonalPlane(Hits hits,
boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
boolean hitPoint = (addSelectedPoint(hits, 1, false, selPreview) != 0);
if (!hitPoint) {
if (selLines() == 0) {
addSelectedVector(hits, 1, false, selPreview);
}
if (selVectors() == 0) {
addSelectedLine(hits, 1, false, selPreview);
}
}
if (selPoints() == 1) {
if (selVectors() == 1) {
// fetch selected point and vector
GeoPointND[] points = getSelectedPointsND();
GeoVectorND[] vectors = getSelectedVectorsND();
// create new plane
GeoElement[] ret = { null };
ret[0] = (GeoPlane3D) getKernel().getManager3D()
.OrthogonalPlane3D(null, points[0], vectors[0]);
return ret;
} else if (selLines() == 1) {
// fetch selected point and line
GeoPointND[] points = getSelectedPointsND();
GeoLineND[] lines = getSelectedLinesND();
// create new plane
GeoElement[] ret = { null };
ret[0] = (GeoPlane3D) getKernel().getManager3D()
.OrthogonalPlane3D(null, points[0], lines[0]);
return ret;
}
}
return null;
}
/**
* get axis and point create circle with axis and through the point
*
* @param hits
* hits
* @param selPreview
* whether this is just for preview
* @return circle created
*
*/
final protected GeoElement[] circleAxisPoint(Hits hits,
boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
if (addSelectedPoint(hits, 1, false, selPreview) == 0) { // add line
// only if
// no
// point to avoid dummy
// circle
addSelectedLine(hits, 1, false, selPreview);
}
if (selPoints() == 1 && selLines() == 1) {
return new GeoElement[] { getKernel().getManager3D().Circle3D(null,
getSelectedLinesND()[0], getSelectedPointsND()[0]) };
}
return null;
}
/**
* get point, direction, enter radius create circle with center, radius,
* axis parallel to direction
*
* @param hits
* @return true if circle created
*
*/
final protected boolean circlePointRadiusDirection(Hits hits,
boolean selPreview) {
if (hits.isEmpty()) {
return false;
}
if (addSelectedPoint(hits, 1, false, selPreview) == 0) {
addSelectedDirection(hits, 1, false, selPreview);
}
if (selPoints() == 1 && selDirections() == 1) {
app.getDialogManager()
.showNumberInputDialogCirclePointDirectionRadius(
app.getLocalization()
.getMenu(EuclidianConstants
.getModeText(mode)),
getSelectedPointsND()[0],
getSelectedDirections()[0], this);
return true;
}
return false;
}
private TextDispatcher3D textDispatcher;
@Override
protected TextDispatcher3D getTextDispatcher() {
if (textDispatcher == null) {
textDispatcher = new TextDispatcher3D(kernel, view3D);
}
return textDispatcher;
}
/**
*
* @param hits
* geos hitted
* @return volume of a geo (from hits) that has a volume
*/
final protected boolean volume(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return false;
}
addSelectedGeo(hits.getFiniteVolumeIncludingMetaHits(), 1, false,
selPreview);
if (selGeos() == 1) {
GeoElement hasVolume = getSelectedGeos()[0];
getTextDispatcher().createVolumeText(hasVolume, mouseLoc);
return true;
}
return false;
}
/**
* create plane containing polygon / 2 lines / line & point / 3 points
*
* @param hits0
* hits
* @param selPreview
* whether this is just preview
* @return true if a plane has been created
*/
final protected GeoElementND[] planeContaining(Hits hits0,
boolean selPreview) {
// keep only one type between points/lines/2D coord sys
Hits hits = hits0.keepFirsts(Test.GEOPOINTND, Test.GEOLINEND,
Test.GEOCOORDSYS2DNOTPLANE);
// Log.debug("\n=================\n"+hits0+"\n====\n"+hits+"\n=================\n");
if (hits.isEmpty()) {
return null;
}
// first try with polygon, conic, etc.
if (selPoints() == 0 && selLines() == 0) {
addSelectedCS2D(hits, 1, false, selPreview);
}
if (selCS2D() == 1) {
GeoCoordSys[] cs = getSelectedCS2D();
GeoElementND[] ret = new GeoElementND[] { getKernel()
.getManager3D().Plane3D(null, (GeoCoordSys2D) cs[0]) };
return ret;
}
// then try with points
addSelectedPoint(hits, 3, false, selPreview);
if (selPoints() == 3) { // 3 points
GeoPointND[] points = getSelectedPointsND();
GeoElement[] ret = new GeoElement[] { getKernel().getManager3D()
.Plane3D(null, points[0], points[1], points[2]) };
return ret;
} else if (selPoints() == 1) { // try point & line
// only one line allowed
addSelectedLine(hits, 1, false, selPreview);
if (selLines() == 1) {
// fetch selected point and line
GeoPointND[] points = getSelectedPointsND();
GeoLineND[] lines = getSelectedLinesND();
// create new plane
GeoElementND[] ret = new GeoElementND[] { getKernel()
.getManager3D().Plane3D(null, points[0], lines[0]) };
return ret;
}
} else if (selPoints() == 0) { // maybe two lines
addSelectedLine(hits, 2, false, selPreview);
if (selLines() == 2) {
// plane containing two lines
GeoLineND[] lines = getSelectedLinesND();
GeoElement[] ret = new GeoElement[] { getKernel().getManager3D()
.Plane3D(null, lines[0], lines[1]) };
return ret;
}
}
return null;
}
/**
* process view in front of mode
*
* @param hits
* @return false (kernel won't change)
*/
final protected boolean viewInFrontOf(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return false;
}
// Application.debug(hits);
addSelectedGeo(hits.getTopHits(), 1, false, selPreview);// TODO
// hits.getTopHits()
// ?
if (selGeos() == 1) { // clear selection
GeoElement geo = getSelectedGeos()[0];
Coords vn = geo.getMainDirection();
if (vn != null) {
if (view3D.hasMouse()) {
view3D.setRotAnimation(view3D.getCursorNormal());
} else {// doesn't come from 3D view
view3D.setClosestRotAnimation(vn, true);
}
}
}
return false;
}
/**
* get point and plane; create line through point parallel to plane
*
* @param hits
* hits
* @param selPreview
* whether this is for preview
* @return plane created
*/
final protected GeoElementND[] parallelPlane(Hits hits,
boolean selPreview) {
// Application.debug(hits.toString());
if (hits.isEmpty()) {
return null;
}
boolean hitPoint = (addSelectedPoint(hits, 1, false, selPreview) != 0);
if (!hitPoint) {
addSelectedCS2D(hits, 1, false, selPreview);
}
if (selPoints() == 1) {
if (selCS2D() == 1) {
// fetch selected point and vector
GeoPointND[] points = getSelectedPointsND();
GeoCoordSys[] cs = getSelectedCS2D();// TODO
// create new plane
return new GeoElementND[] { getKernel().getManager3D()
.Plane3D(null,
points[0], (GeoCoordSys2D) cs[0]) };
}
}
return null;
}
private boolean dialogOccurred = false;
@Override
public void setDialogOccurred() {
dialogOccurred = true;
}
/**
* get basis and height; create prism/cylinder
*
* @param hits
* @return prism created
*/
final protected GeoElement[] extrusionOrConify(Hits hits,
boolean selPreview) {
if (dialogOccurred) {
dialogOccurred = false;
return null;
}
if (!hits.isEmpty()) { // hits may be empty at the end of using the tool
// we don't need to replace or de-select a polygon, since
// we'll open immediately a dialog
int basisAdded = selPolygons() + selConics();
if (basisAdded == 0) { // if no basis for now, try to add polygon
basisAdded += addSelectedPolygon(hits, 1, false, selPreview);
if (basisAdded == 0) { // try to add conic
basisAdded += addSelectedConic(hits, 1, false, selPreview);
if (basisAdded == 0) { // if polygon/conic has been added,
// the height
// will be entered through dialog manager
addSelectedNumberValue(hits, 1, false, selPreview);
}
}
}
}
if (selNumberValues() == 1) {
if (selPolygons() == 1) {
GeoPolygon[] basis = getSelectedPolygons();
GeoNumberValue[] height = getSelectedNumberValues();
if (mode == EuclidianConstants.MODE_EXTRUSION) {
return new GeoElement[] { // return only the prism
getKernel().getManager3D().Prism(null, basis[0],
height[0])[0] };
}
return new GeoElement[] { // return only the pyramid
getKernel().getManager3D().Pyramid(null, basis[0],
height[0])[0] };
} else if (selConics() == 1) {
GeoConicND[] basis = getSelectedConicsND();
GeoNumberValue[] height = getSelectedNumberValues();
if (mode == EuclidianConstants.MODE_EXTRUSION) {
return new GeoElement[] { // return only the cylinder
getKernel().getManager3D().CylinderLimited(null,
basis[0], height[0])[0] };
}
return new GeoElement[] { // return only the cone
getKernel().getManager3D().ConeLimited(null, basis[0],
height[0])[0] };
}
}
return null;
}
@Override
protected boolean draggingOccurredBeforeRelease(boolean notAlreadyStarted) {
if (notAlreadyStarted && lastGetNewPointWasExistingPoint
&& draggingOccurredBeforeRelease) {
// don't select a first point on dragging
return true;
}
return super.draggingOccurredBeforeRelease(notAlreadyStarted);
}
private GeoPointND[] pyramidBasis = null;
private boolean polygonForPyramidBasis = false;
/**
* get basis and top point; create pyramid
*
* @param hits
* hits
* @return pyramid/prism created
*/
final protected GeoElement[] pyramidOrPrism(Hits hits, boolean selPreview) {
// if (pyramidBasis!=null) Application.debug(pyramidBasis.length);
polygonForPyramidBasis = false;
if (hits.isEmpty()) {
return null;
}
if (draggingOccurredBeforeRelease((pyramidBasis == null)
&& selPoints() == 0 && selPolygons() == 0)) {
// don't select a first point on dragging
return null;
}
if (pyramidBasis == null) { // try to find/create a polygon
if (selPolygons() == 0) { // try to create a polygon
// if the first point is clicked again, we create a polygon
if (selPoints() > 2) {
// check if first point was clicked again
boolean finished = !selPreview
&& hits.contains(getSelectedPointList().get(0));
if (finished) {
// store basis
((DrawPolyhedron3D) view3D.getPreviewDrawable())
.previewBasisIsFinished();
pyramidBasis = getSelectedPointsND();
// cancel last switch of point move mode
cancelSwitchPointMoveModeIfNeeded();
return null;
}
}
if (addSelectedPoint(hits, GeoPolygon.POLYGON_MAX_POINTS, false,
selPreview) != 0
|| (!selPreview && !getSelectedPointList().isEmpty()
&& hits.contains(
getSelectedPointList().get(0)))) {
return null; // add/remove point : don't check polygon
}
}
boolean selectionOccured = false;
if (selPoints() < 2) { // already two points : not a polygon for
// basis
if (addSelectedPolygon(hits, 1, false, selPreview) == 1) {
polygonForPyramidBasis = true;
selectionOccured = true;
}
}
// there is 1 polygon, look for top point
if (!selectionOccured) {
addSelectedPoint(hits, 1, false, selPreview);
}
if (selPoints() == 1 && selPolygons() == 1) {
// fetch selected point and vector
GeoPolygon[] basis = getSelectedPolygons();
GeoPointND[] points = getSelectedPointsND();
// create new pyramid or prism
view3D.disposePreview();
switch (mode) {
case EuclidianConstants.MODE_PYRAMID:
return new GeoElement[] { getKernel().getManager3D()
.Pyramid(null, basis[0], points[0])[0] };
case EuclidianConstants.MODE_PRISM:
return new GeoElement[] { getKernel().getManager3D()
.Prism(null, basis[0], points[0])[0] };
}
}
} else { // there are points for basis
addSelectedPoint(hits, 1, false, selPreview);
if (selPoints() == 1) {
// fetch selected point and vector
GeoPointND[] points = new GeoPointND[pyramidBasis.length + 1];
for (int i = 0; i < pyramidBasis.length; i++) {
points[i] = pyramidBasis[i];
}
points[pyramidBasis.length] = getSelectedPointsND()[0];
// create new pyramid or prism
view3D.disposePreview();
switch (mode) {
case EuclidianConstants.MODE_PYRAMID:
pyramidBasis = null;
return new GeoElement[] { getKernel().getManager3D()
.Pyramid(null, points)[0] };
case EuclidianConstants.MODE_PRISM:
pyramidBasis = null;
return new GeoElement[] {
getKernel().getManager3D().Prism(null, points)[0] };
}
}
return null;
}
return null;
}
// /////////////////////////////////////////
// moved GeoElements
@Override
public GeoElement getMovedGeoPoint() {
return (GeoElement) movedGeoPoint;
}
// /////////////////////////////////////////
// mouse released
@Override
public void wrapMouseReleased(AbstractEvent e) {
if (!draggingOccured && !app.isControlDown(e)) {
view3D.switchMoveCursor();
}
super.wrapMouseReleasedND(e, true);
}
@Override
protected void processReleaseForMovedGeoPoint(boolean rightClick) {
((EuclidianView3D) getView()).setPointDecorations(null);
if (isModeForMovingPoint(mode)) {
if (freePointJustCreated) {
// avoid switch if the point is created by a click
freePointJustCreated = false;
} else {
// switch the direction of move (xy or z) in case of left-click
// if (!movedGeoPointDragged){
if (!draggingOccured && !rightClick
&& movedGeoPoint.isIndependent()) {
if (mode == EuclidianConstants.MODE_MOVE
&& !movedGeoPoint.isGeoElement3D()) {
// 2D point will be replaced by 3D point (only for move
// mode)
GeoPoint replaceable = (GeoPoint) movedGeoPoint;
// create new 3D point
Construction cons = kernel.getConstruction();
GeoPoint3D newGeo = (GeoPoint3D) kernel.getManager3D()
.Point3D(replaceable.getInhomX(),
replaceable.getInhomY(), 0, false);
try {
cons.replace(replaceable, newGeo);
} catch (Exception e) {
e.printStackTrace();
} finally {
// update geo selected
String newLabel = newGeo.isLabelSet()
? newGeo.getLabelSimple()
: replaceable.getLabelSimple();
GeoElement geo = kernel.lookupLabel(newLabel);
setMovedGeoPoint(geo);
// update hits
Hits3D hits = view3D.getHits3D();
hits.init();
hits.add(geo);
// update selection
app.getSelectionManager().clearSelectedGeos(false,
false);
app.getSelectionManager().addSelectedGeo(geo, true,
true);
}
}
if (mode == EuclidianConstants.MODE_MOVE
|| mode == EuclidianConstants.MODE_POINT) {
switchPointMoveMode();
} else {
Hits hits = view3D.getHits();
if (!hits.isEmpty() && hits.get(0) == movedGeoPoint) {
switchPointMoveMode();
}
}
((EuclidianView3D) getView()).getCursor3D()
.setMoveMode(movedGeoPoint.getMoveMode());
((EuclidianView3D) getView())
.setDefaultCursorWillBeHitCursor();
}
}
}
if (movedGeoPoint instanceof GeoPoint3D) {
GeoPoint3D movedGeoPoint3D = (GeoPoint3D) movedGeoPoint;
movedGeoPoint3D.setWillingCoordsUndefined();
movedGeoPoint3D.setWillingDirectionUndefined();
}
super.processReleaseForMovedGeoPoint(rightClick);
}
private int pointMoveMode = GeoPointND.MOVE_MODE_XY;
@Override
protected void switchPointMoveMode() {
if (pointMoveMode == GeoPointND.MOVE_MODE_XY) {
pointMoveMode = GeoPointND.MOVE_MODE_Z;
} else {
pointMoveMode = GeoPointND.MOVE_MODE_XY;
}
}
private void cancelSwitchPointMoveModeIfNeeded() {
if (!draggingOccurredBeforeRelease && movedGeoPoint != null
&& movedGeoPoint.isIndependent()) {
switchPointMoveMode();
}
}
private void initPointMoveMode() {
if (mode == EuclidianConstants.MODE_MOVE) {
pointMoveMode = GeoPointND.MOVE_MODE_XY;
} else {
pointMoveMode = GeoPointND.MOVE_MODE_Z;
}
}
/**
*
* @return current tool point move mode
*/
public int getPointMoveMode() {
return pointMoveMode;
}
/**
* update mouse moved, 3D mouse values, etc.
*/
public void updateInput3D() {
// no input 3D
}
// /////////////////////////////////////////
// mouse moved
protected boolean mouseMoved = false;
protected AbstractEvent mouseEvent = null;
@Override
public void wrapMousePressed(AbstractEvent e) {
mouseMoved = false;
// mousePressed = true;
// maybe called by twoTouchEnd()
// we don't want a "screen translate and scale"
// refresh after that
view3D.stopScreenTranslateAndScale();
super.wrapMousePressed(e);
}
@Override
protected void processMouseMoved(AbstractEvent e) {
// for next mouse move process
setMouseMovedEvent(e);
mouseMoved = true;
// needed for non-animated renderers
view3D.repaintView();
}
/**
* store the mouse move event
*
* @param e
* event
*/
protected void setMouseMovedEvent(AbstractEvent e) {
mouseEvent = e;
}
/**
* update mouse moved after picking
*/
public void update() {
processMouseMoved();
}
/**
* tells to proceed mouseMoved() (for synchronization with 3D renderer)
*/
protected void processMouseMoved() {
if (mouseMoved && view3D.hasMouse()) {
// make sure new GeoPoint3Ds aren't counted as 3D objects for uses3D
// flag in XML
kernel.getConstruction().setIgnoringNewTypes(true);
((EuclidianView3D) getView()).updateCursor3D();
super.processMouseMoved(mouseEvent);
kernel.getConstruction().setIgnoringNewTypes(false);
mouseMoved = false;
}
}
@Override
protected void initNewMode(int newMode) {
super.initNewMode(newMode);
}
@Override
protected Previewable switchPreviewableForInitNewMode(int previewMode) {
Previewable previewDrawable = null;
// Log.debug(mode);
switch (previewMode) {
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
previewDrawable = view3D
.createPreviewSphere(getSelectedPointList());
break;
case EuclidianConstants.MODE_EXTRUSION:
previewDrawable = view3D.createPreviewExtrusion(
getSelectedPolygonList(), getSelectedConicNDList());
break;
case EuclidianConstants.MODE_CONIFY:
previewDrawable = view3D.createPreviewConify(
getSelectedPolygonList(), getSelectedConicNDList());
break;
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
previewDrawable = view3D.createPreviewPyramidOrPrism(
getSelectedPointList(), getSelectedPolygonList(),
previewMode);
break;
case EuclidianConstants.MODE_INTERSECTION_CURVE: // line through two
// points
break;
default:
previewDrawable = super.switchPreviewableForInitNewMode(
previewMode);
break;
}
return previewDrawable;
}
// not only moveable hits are selected in move mode
@Override
protected boolean getSelectables(Hits hits, boolean selPreview) {
Hits top = hits.getTopHits(1);
super.getSelectables(top, selPreview);
// display correctly oriented 3D cursor
GeoPointND point = (GeoPointND) top.getFirstHit(Test.GEOPOINTND);
if (point != null) {
view3D.updateCursor3D(hits);
}
return false;
}
/*
* protected void mouseClickedMode(MouseEvent e, int mode){
*
*
* switch (mode) { case EuclidianView3D.MODE_VIEW_IN_FRONT_OF:
* //Application.debug("ici"); Hits hits = view.getHits().getTopHits();
* if(!hits.isEmpty()){ GeoElementND geo =
* view.getHits().getTopHits().get(0); Coords vn = geo.getMainDirection();
* if (vn!=null){
* view3D.setRotAnimation(view3D.getCursor3D().getDrawingMatrix().getVz());
* } }
*
* break; default: super.mouseClickedMode(e,mode); } }
*/
@Override
public void processModeLock() {
// TODO
}
// /////////////////////////////////////////
// EMPTY METHODS IN EuclidianController USED FOR EuclidianView3D
@Override
protected void processRightPressFor3D(AbstractEvent event) {
if (viewHasHitsForMouseDragged()) {
// maybe needed if geo hitted is not moveable
processPressForRotate3D();
return;
}
temporaryMode = true;
oldMode = mode; // remember current mode
getView().setMode(EuclidianConstants.MODE_ROTATEVIEW);
switchModeForMousePressed(event);
}
private void processPressForRotate3D() {
if (view3D.isRotAnimated()) {
view3D.stopAnimation();
viewRotationOccured = true;
}
// remembers mouse location
startLoc = mouseLoc;
getView().rememberOrigins();
getView().setCursor(EuclidianCursor.DEFAULT);
timeOld = app.getMillisecondTime();
xOld = startLoc.x;
animatedRotSpeed = 0;
}
/**
* right-drag the mouse makes 3D rotation
*
* @return true
*/
@Override
protected boolean processRotate3DView() {
double time = app.getMillisecondTime();
int x = mouseLoc.x;
double dx = x - xOld;
animatedRotSpeed = dx / (time - timeOld);
timeOld = time;
// Log.debug("animatedRotSpeed=" + animatedRotSpeed + "\nxOld = " + xOld
// + "\nx=" + x);
xOld = x;
getView().setCoordSystemFromMouseMove(mouseLoc.x - startLoc.x,
mouseLoc.y - startLoc.y, MOVE_ROTATE_VIEW);
viewRotationOccured = true;
getView().repaintView();
return true;
}
@Override
protected boolean allowSelectionRectangle() {
return false;
}
/**
* right-release the mouse makes stop 3D rotation
*
* @return true if a rotation occured
*/
@Override
protected boolean processReleaseForRotate3D(PointerEventType type) {
if (temporaryMode) {
getView().setMode(oldMode, ModeSetter.EXIT_TEMPORARY_MODE);
temporaryMode = false;
if (!dontClearSelection) {
clearSelections();
}
dontClearSelection = false;
}
if (viewRotationOccured) {
viewRotationOccured = false;
setViewHits(type);
// Application.debug("hits"+getView().getHits().toString());
((EuclidianView3D) getView()).updateCursor3D();
getView().setCursor(EuclidianCursor.HIT);
app.storeUndoInfo();
setRotContinueAnimation();
// Application.debug("animatedRotSpeed="+animatedRotSpeed);
return true;
}
return false;
}
protected void setRotContinueAnimation() {
((EuclidianView3D) getView()).setRotContinueAnimation(
app.getMillisecondTime() - timeOld, animatedRotSpeed);
}
// /////////////////////////////////////////
// PROCESS MODE
@Override
protected boolean switchModeForProcessMode(Hits hits, boolean isControlDown,
AsyncOperation<Boolean> callback, boolean selectionPreview) {
boolean changedKernel = false;
GeoElementND[] ret = null;
switch (mode) {
case EuclidianConstants.MODE_INTERSECTION_CURVE:
ret = intersectionCurve(hits, selectionPreview);
if (ret != null) { // remove current intersection curve
intersectionCurveList.remove(resultedIntersectionCurve);
view3D.setPreview(null);
}
break;
case EuclidianConstants.MODE_PLANE_THREE_POINTS:
ret = threePoints(hits, mode, selectionPreview);
break;
case EuclidianConstants.MODE_PLANE:
ret = planeContaining(hits, selectionPreview);
break;
case EuclidianConstants.MODE_ORTHOGONAL_PLANE:
ret = orthogonalPlane(hits, selectionPreview);
break;
case EuclidianConstants.MODE_PARALLEL_PLANE:
ret = parallelPlane(hits, selectionPreview);
break;
case EuclidianConstants.MODE_EXTRUSION:
case EuclidianConstants.MODE_CONIFY:
ret = extrusionOrConify(hits, selectionPreview);
break;
case EuclidianConstants.MODE_TETRAHEDRON:
ret = archimedeanSolid(hits, Commands.Tetrahedron,
selectionPreview);
break;
case EuclidianConstants.MODE_CUBE:
ret = archimedeanSolid(hits, Commands.Cube, selectionPreview);
break;
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
ret = pyramidOrPrism(hits, selectionPreview);
break;
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
ret = circleOrSphere2(hits, mode, selectionPreview);
break;
case EuclidianConstants.MODE_SPHERE_POINT_RADIUS:
changedKernel = spherePointRadius(hits, selectionPreview);
break;
case EuclidianConstants.MODE_CONE_TWO_POINTS_RADIUS:
changedKernel = coneTwoPointsRadius(hits, selectionPreview);
break;
case EuclidianConstants.MODE_CYLINDER_TWO_POINTS_RADIUS:
changedKernel = cylinderTwoPointsRadius(hits, selectionPreview);
break;
case EuclidianConstants.MODE_NET:
ret = polyhedronNet(hits, selectionPreview);
break;
case EuclidianConstants.MODE_VIEW_IN_FRONT_OF:
changedKernel = viewInFrontOf(hits, selectionPreview);
break;
case EuclidianConstants.MODE_CIRCLE_AXIS_POINT:
ret = circleAxisPoint(hits, selectionPreview);
break;
case EuclidianConstants.MODE_CIRCLE_POINT_RADIUS_DIRECTION:
changedKernel = circlePointRadiusDirection(hits, selectionPreview);
break;
case EuclidianConstants.MODE_MIRROR_AT_PLANE:
ret = mirrorAtPlane(hits.getTopHits(), selectionPreview);
break;
case EuclidianConstants.MODE_ROTATE_AROUND_LINE:
ret = rotateAroundLine(hits.getTopHits(), selectionPreview);
break;
case EuclidianConstants.MODE_VOLUME:
changedKernel = volume(hits, selectionPreview);
break;
default:
return super.switchModeForProcessMode(hits, isControlDown, callback,
selectionPreview);
}
return endOfSwitchModeForProcessMode(ret,
changedKernel || (ret != null), callback, selectionPreview);
}
/**
* for some modes, polygons are not to be removed
*
* @param hits
* hits
*/
@Override
protected void switchModeForRemovePolygons(Hits hits) {
switch (mode) {
case EuclidianConstants.MODE_PARALLEL_PLANE:
hits.removePolygonsIfNotOnlyCS2D();
break;
case EuclidianConstants.MODE_TETRAHEDRON:
case EuclidianConstants.MODE_CUBE:
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
case EuclidianConstants.MODE_AREA:
case EuclidianConstants.MODE_VOLUME:
case EuclidianConstants.MODE_EXTRUSION:
case EuclidianConstants.MODE_NET:
case EuclidianConstants.MODE_CONIFY:
hits.removeAllPolygonsButOne();
break;
case EuclidianConstants.MODE_INTERSECTION_CURVE:
case EuclidianConstants.MODE_INTERSECT:
break;
case EuclidianConstants.MODE_PLANE:
break;
default:
super.switchModeForRemovePolygons(hits);
}
}
@Override
protected GeoElement[] switchModeForThreePoints(int threePointsMode) {
switch (threePointsMode) {
case EuclidianConstants.MODE_PLANE_THREE_POINTS:
GeoPointND[] points = getSelectedPointsND();
GeoPlane3D ret0 = (GeoPlane3D) getKernel().getManager3D()
.Plane3D(null, points[0], points[1], points[2]);
GeoElement[] ret = { ret0 };
return ret;
default:
return super.switchModeForThreePoints(threePointsMode);
}
}
@Override
protected GeoElement[] switchModeForCircleOrSphere2(int sphereNDMode) {
switch (sphereNDMode) {
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
GeoPointND[] points = getSelectedPointsND();
GeoElement[] ret = { null };
ret[0] = getKernel().getManager3D().Sphere(null, points[0],
points[1]);
return ret;
default:
return super.switchModeForCircleOrSphere2(sphereNDMode);
}
}
// /////////////////////////////////////////
// MOUSE PRESSED
@Override
protected void createNewPointForModePoint(Hits hits, boolean complex) {
// super.createNewPointForModePoint(hits, false);
createNewPoint(hits, true, true, true, true, false);
}
@Override
protected void createNewPointForModeOther(Hits hits) {
createNewPoint(hits, true, true, true, true, false);
}
@Override
protected void switchModeForMousePressed(AbstractEvent e) {
// needed to stop animated rotation
processPressForRotate3D();
Hits hits;
PointerEventType type = e.getType();
switch (mode) {
case EuclidianConstants.MODE_PLANE_THREE_POINTS:
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
case EuclidianConstants.MODE_SPHERE_POINT_RADIUS:
case EuclidianConstants.MODE_CONE_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_CYLINDER_TWO_POINTS_RADIUS:
setViewHits(type);
hits = getView().getHits();
hits.removePolygons();
createNewPoint(hits, true, true, true, true, false);
break;
case EuclidianConstants.MODE_ORTHOGONAL_PLANE:
setViewHits(type);
hits = getView().getHits();
hits.removePolygons();
createNewPoint(hits, false, false, true);
break;
case EuclidianConstants.MODE_PLANE:
setViewHits(type);
hits = getView().getHits();
break;
case EuclidianConstants.MODE_PARALLEL_PLANE:
setViewHits(type);
hits = getView().getHits();
hits.removePolygons();
createNewPoint(hits, true, false, false, true, false);
break;
case EuclidianConstants.MODE_EXTRUSION:
case EuclidianConstants.MODE_CONIFY:
setViewHits(type);
hits = getView().getHits();
hits.removeAllPlanes();
switchModeForRemovePolygons(hits);
// Application.debug(hits.toString());
extrusionOrConify(hits, false);
view3D.updatePreviewable();
break;
case EuclidianConstants.MODE_TETRAHEDRON:
case EuclidianConstants.MODE_CUBE:
setViewHits(type);
hits = getView().getHits();
// hits.removePolygons();
boolean createPointAnywhere = false;
if (selCS2D() == 1 || selPoints() != 0) { // create point anywhere
// when direction has
// been selected
createPointAnywhere = true;
} else {
if (view3D
.getCursor3DType() == EuclidianView3D.PREVIEW_POINT_REGION) {
if (view3D.getCursor3D().getRegion() == kernel
.getXOYPlane()) {
createPointAnywhere = true;
}
}
}
if (createPointAnywhere) {
createNewPoint(hits, true, true, true, true, false);
} else {
createNewPoint(hits, true, false, true, true, false);
}
break;
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
setViewHits(type);
hits = getView().getHits();
if (selPolygons() == 1 || hits.getPolyCount() == 0) {
createNewPoint(hits, true, true, true, true, false);
} else {
switchModeForRemovePolygons(hits);
createNewPoint(hits, true, false, false, true, false);
}
break;
case EuclidianConstants.MODE_ROTATEVIEW:
moveMode = MOVE_ROTATE_VIEW;
break;
case EuclidianConstants.MODE_CIRCLE_AXIS_POINT:
case EuclidianConstants.MODE_CIRCLE_POINT_RADIUS_DIRECTION:
setViewHits(type);
hits = getView().getHits();
hits.removePolygons();
if (hits.size() == 0) {
createNewPoint(hits, false, true, true);
}
break;
case EuclidianConstants.MODE_INTERSECTION_CURVE:
// no need to do anything for preview when mouse is pressed
break;
case EuclidianConstants.MODE_VOLUME:
setViewHits(type);
hits = getView().getHits();
break;
case EuclidianConstants.MODE_NET:
setViewHits(type);
hits = getView().getHits();
break;
default:
super.switchModeForMousePressedND(e);
}
}
// /////////////////////////////////////////
// MOUSE RELEASED
@Override
protected boolean switchModeForMouseReleased(int releaseMode, Hits hits,
boolean changedKernel, boolean control, PointerEventType type,
boolean runScripts) {
switch (releaseMode) {
case EuclidianConstants.MODE_PARALLEL_PLANE:
return true;
case EuclidianConstants.MODE_EXTRUSION:
((DrawExtrusionOrConify3D) view3D.getPreviewDrawable())
.createPolyhedron();
return true;
case EuclidianConstants.MODE_CONIFY:
((DrawExtrusionOrConify3D) view3D.getPreviewDrawable())
.createPolyhedron();
return true;
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
return changedKernel;
case EuclidianConstants.MODE_MIRROR_AT_PLANE:
case EuclidianConstants.MODE_ROTATE_AROUND_LINE:
return true;
case EuclidianConstants.MODE_VIEW_IN_FRONT_OF:
// Application.debug("hop");
// TODO implement choose geo
return true;
default:
return super.switchModeForMouseReleased(releaseMode, hits,
changedKernel, control, type, runScripts);
}
}
@Override
protected Hits addPointCreatedForMouseReleased(Hits hits) {
hits.add((GeoElement) pointCreated);
return hits;
}
@Override
public void showDrawingPadPopup(GPoint mouseLoc1) {
app.getGuiManager().showDrawingPadPopup3D(getView(), mouseLoc1);
}
// /////////////////////////////////////////
// INTERSECTIONS
// /////////////////////////////////////////
// INTERSECTIONS
/**
* get two objects (lines or conics) and create intersection point
*/
@Override
protected GeoElementND[] intersect(Hits hits0, boolean selPreview) {
Hits hits = hits0;
// AppD.debug(hits);
if (hits.isEmpty()) {
return null;
}
if (hits.containsGeoPoint()) {
hits.clear();
return null;
}
hits.removePolygonsIfSidePresent();
if (goodHits == null) {
goodHits = new Hits3D();
} else {
goodHits.clear();
}
GeoPointND singlePoint = null;
if (selGeos() == 0) { // either single intersection point or single
// highlighting
// we may have a dependent point found by 3D cursor
if (view3D
.getCursor3DType() == EuclidianView3D.PREVIEW_POINT_DEPENDENT) {
singlePoint = singleIntersectionPoint;
} else {
singlePoint = getSingleIntersectionPoint(hits);
}
// single intersection succeeds, select one geo from hits
if (singlePoint != null) {
hits.clear();
hits.add(singlePoint.getParentAlgorithm()
.getInput()[0]);
hits.add(singlePoint.getParentAlgorithm()
.getInput()[1]);
} else {
hits.getHits(new Test[] { Test.GEOLINEND, Test.GEOCOORDSYS2D,
Test.GEOQUADRICND }, false, goodHits);
hits = hits.getHits(1);
}
} else if (selGeos() == 1) {
// Should have selGeos() == 1. Need to optimize the hits
// see what we had selected
if (selCS2D() == 1 || selQuadric() == 1) {// 2d geo: can only
// intersect with 1d
// ones.
hits.getHits(
new Test[] { Test.GEOCOORDSYS2D, Test.GEOQUADRIC3D },
true, goodHits);
} else { // 1d geo: can intersect with 1d or 2d geo
hits.getHits(
new Test[] { Test.GEOLINEND, Test.GEOCOORDSYS2D,
Test.GEOQUADRICND, Test.GEOIMPLICITSURFACE },
false, goodHits);
// does not have to test this. we will select only the top
// element!
// we can only have at most one polygon
/*
* ((Hits3D)goodHits).removeAllPolygonsButOne(); if
* (!(goodHits.size()>=2) || !(goodHits.get(0)).isGeoConic() ||
* !(goodHits.get(1)).isGeoConic())
* ((Hits3D)goodHits).removeAllPolygonsAndQuadricsButOne();
*/
}
// remove incidence. TODO: test incidence by construction, instead
// of numerically.
GeoElement selected = getSelectedGeoList().get(0);
if (selected.isGeoLine()) {
while (goodHits.size() >= 1) {
if (goodHits.get(0).isGeoPlane() && AlgoIntersectCS1D2D
.getConfigLinePlane((GeoLineND) selected,
((GeoCoordSys2D) goodHits.get(
0))) == ConfigLinePlane.CONTAINED) {
goodHits.remove(0);
} else {
break;
}
}
} else if (selected.isGeoConic()) {
while (goodHits.size() >= 1) {
if (goodHits.get(0).isGeoPlane()
&& AlgoIntersectPlanes.getConfigPlanePlane(
(((GeoConicND) selected).getCoordSys()),
(((GeoCoordSys2D) goodHits.get(0))
.getCoordSys())) == AlgoIntersectPlanes.RESULTCATEGORY_CONTAINED) {
goodHits.remove(0);
} else {
break;
}
}
} else if (selected.isGeoPolygon()) {
while (goodHits.size() >= 1) {
if (goodHits.get(0) instanceof GeoCoordSys2D
&& AlgoIntersectPlanes.getConfigPlanePlane(
(((GeoPolygon) selected).getCoordSys()),
(((GeoCoordSys2D) goodHits.get(0))
.getCoordSys())) == AlgoIntersectPlanes.RESULTCATEGORY_CONTAINED) {
goodHits.remove(0);
} else {
break;
}
}
}
if (goodHits.size() == 0) {
// return immediately, so that the selected geo is not fetched
return null;
}
// we focus on the selected geo and a new one from goodHits
hits.clear();
hits.add(selected);
hits.add(goodHits.get(0));
}
addSelectedLine(hits, 10, true, selPreview);
addSelectedConic(hits, 10, true, selPreview);
addSelectedPlane(hits, 1, true, selPreview);
addSelectedPolygon(hits, 1, true, selPreview);
addSelectedQuadric(hits, 1, true, selPreview);
addSelectedImplicitSurface(hits, 1, true, selPreview);
if (selLines() >= 2) {// two lines
GeoLineND[] lines = getSelectedLinesND();
GeoPointND point = getAlgoDispatcher().IntersectLines(null,
lines[0], lines[1]);
checkCoordCartesian3D(point);
return new GeoElementND[] { point };
} else if (selLines() == 1) {
if (selConics() >= 1) {// line-conic
GeoLineND line = getSelectedLinesND()[0];
GeoConicND conic = getSelectedConicsND()[0];
GeoElementND[] ret = new GeoElementND[2];
GeoPointND[] points = getAlgoDispatcher()
.IntersectLineConic(null, line, conic);
for (int i = 0; i < 2; i++) {
ret[i] = points[i];
}
return ret;
} else if (selQuadric() == 1) { // line-quadric3D
GeoLineND line = getSelectedLinesND()[0];
GeoQuadricND quadric = getSelectedQuadric()[0];
GeoElementND[] ret = new GeoElementND[2];
GeoPointND[] points = getKernel().getManager3D()
.IntersectLineQuadric(null, line, quadric);
for (int i = 0; i < 2; i++) {
ret[i] = points[i];
}
return ret;
} else if (selPolygons() == 1) {// line-polygon
return getKernel().getManager3D().IntersectionPoint(
new String[] { null }, getSelectedLinesND()[0],
getSelectedPolygons()[0]);
} else if (selPlanes() == 1) {// line-plane
GeoElement[] ret = new GeoElement[1];
ret[0] = getKernel().getManager3D().Intersect(null,
getSelectedLinesND()[0], getSelectedPlanes()[0], false);
return ret;
} else if (selImplicitSurfaces() == 1) {// line-plane
return getKernel().getAlgoDispatcher()
.IntersectImplicitSurfaceLine(null,
getSelectedImplicitSurface()[0],
getSelectedLinesND()[0]);
}
} else if (selConics() >= 2) {// conic-conic
GeoConicND[] conics = getSelectedConicsND();
GeoElementND[] ret = new GeoElement[4];
GeoPointND[] points = getKernel().getAlgoDispatcher()
.IntersectConics(null, conics[0], conics[1]);
for (int i = 0; i < points.length; i++) {
checkCoordCartesian3D(points[i]);
ret[i] = points[i];
}
return ret;
} else if (selConics() >= 1 && selPlanes() == 1) {
GeoPlaneND plane = getSelectedPlanes()[0];
GeoConicND conic = getSelectedConicsND()[0];
GeoElementND[] ret = new GeoElementND[2];
GeoPointND[] points = getKernel().getManager3D()
.IntersectPlaneConic(null, plane, conic);
for (int i = 0; i < 2; i++) {
ret[i] = points[i];
}
return ret;
} else if (selConics() >= 1 && selQuadric() == 1) {
GeoQuadricND quadric = getSelectedQuadric()[0];
GeoConicND conic = getSelectedConicsND()[0];
GeoElementND[] ret = new GeoElementND[2];
GeoPointND[] points = getKernel().getManager3D()
.IntersectConics(null, conic, quadric);
for (int i = 0; i < 2; i++) {
ret[i] = points[i];
}
return ret;
} else if (selPolygons() == 1 && selPlanes() == 1) { // plane-polygon
return getKernel().getManager3D().IntersectionPoint(null,
getSelectedPlanes()[0], getSelectedPolygons()[0]);
}
return null;
}
/**
* ensure that the point will show 3D cartesion coords
*
* @param point
* point
*/
private static void checkCoordCartesian3D(GeoPointND point) {
if (point.getMode() != Kernel.COORD_CARTESIAN_3D) {
point.setCartesian3D();
point.updateRepaint();
}
}
public ArrayList<IntersectionCurve> getIntersectionCurves() {
return intersectionCurveList;
}
protected boolean mouseMovedForIntersectionCurve() {
return mouseMoved;
}
/**
*
* @param hits
* @return true if a curve is created
*/
protected GeoElement[] intersectionCurve(Hits hits, boolean selPreview) {
if (hits == null) {
resultedGeo = null;
return null;
}
if (hits.isEmpty()) {
resultedGeo = null;
return null;
}
// add selected geo into consideration
// if (selectedGeos.size()==1 && !hits.contains(selectedGeos.get(0)))
// hits.addAll(0, selectedGeos);
if (mouseMovedForIntersectionCurve() && view3D.hasMouse2D()) { // process
// new
// intersection
// only if mouse has moved
// for (int i = 0; i < intersectionCurveList.size(); ++i) {
// intersectionCurveList.get(i).hitted = false;
// }
// Log.debug(hits);
for (int i = 0; i < hits.size(); ++i) {
for (int j = i + 1; j < hits.size(); ++j) {
this.createIntersectionCurve(hits.get(i), hits.get(j));
}
}
/*
* debug String s = ">>>> BEFORE PICKING"; for (Drawable3D
* d:intersectionCurves){ s+="\n=== geo="
* +d.getGeoElement()+"\nzPickMin="
* +d.zPickMin+"\nzPickMax="+d.zPickMax; } Application.debug(s);
* //end debug
*/
// calls the renderer to pick the curves
view3D.getRenderer().pickIntersectionCurves();
/*
* debug s = "AFTER PICKING <<<<"; for (Drawable3D
* d:intersectionCurves){ s+="\n=== geo="
* +d.getGeoElement()+"\nzPickMin="
* +d.zPickMin+"\nzPickMax="+d.zPickMax; } Application.debug(s);
* //end debug
*/
decideIntersection(hits);
}
if (goodHits != null) {
addSelectedPolygon(goodHits, 1, false, selPreview);
addSelectedPlane(goodHits, 2, true, selPreview);
addSelectedQuadric(goodHits, 2, true, selPreview);
addSelectedPolyhedron(goodHits, 1, false, selPreview);
addSelectedQuadricLimited(goodHits, 1, false, selPreview);
} else {
Hits firstSurface = hits
.getFirstSurfaceBefore(getSelectedGeoList());
addSelectedPolygon(firstSurface, 1, false, selPreview);
addSelectedPlane(firstSurface, 2, false, selPreview);
addSelectedQuadric(firstSurface, 2, false, selPreview);
addSelectedPolyhedron(firstSurface, 1, false, selPreview);
addSelectedQuadricLimited(firstSurface, 1, false, selPreview);
addSelectedFunction2Var(firstSurface, 1, false, selPreview);
addSelectedImplicitSurface(firstSurface, 1, false, selPreview);
}
if (selPlanes() == 1) {
if (selQuadric() >= 1) { // plane-quadric
GeoPlaneND plane = getSelectedPlanes()[0];
GeoQuadricND quad = getSelectedQuadric()[0];
GeoElement[] ret = {
kernel.getManager3D().Intersect(null, plane, quad) };
if (ret[0].isDefined()) {
return ret;
}
return null;
} else if (selPolyhedron() == 1) { // plane-polyhedron
GeoElement[] ret = getKernel().getManager3D().IntersectRegion(
new String[] { null }, getSelectedPlanes()[0],
getSelectedPolyhedron()[0].toGeoElement(), null);
if (ret[0].isDefined()) {
return ret;
}
return null;
} else if (selQuadricLimited() == 1) { // plane-limited quadric
GeoElement[] ret = new GeoElement[1];
ret[0] = kernel.getManager3D().IntersectQuadricLimited(null,
getSelectedPlanes()[0],
(GeoQuadricND) getSelectedQuadricLimited()[0]);
if (!ret[0].isDefined()) {
return null;
}
// also compute corner points
kernel.getManager3D().Corner(null, (GeoConicSection) ret[0]);
return ret;
} else if (selPolygons() == 1) { // plane-polygon
GeoPlaneND plane = getSelectedPlanes()[0];
GeoPolygon poly = getSelectedPolygons()[0];
GeoElement[] ret = getKernel().getManager3D()
.IntersectPath(new String[] { null }, plane, poly);
if (ret[0].isDefined()) {
// create also intersect points
getKernel().getManager3D().IntersectionPoint(
new String[] { null }, plane, poly);
return ret;
}
return null;
} else if (selFunctionsNVar() == 1) { // plane-function NVar
GeoPlaneND plane = getSelectedPlanes()[0];
GeoFunctionNVar funNVar = getSelectedFunctionsNVar()[0];
return getKernel().getManager3D()
.IntersectPlaneFunctionNVar(null, plane, funNVar);
} else if (selImplicitSurfaces() == 1) { // plane-function NVar
Log.debug(selImplicitSurfaces() + "," + selPlanes());
GeoPlaneND plane = getSelectedPlanes()[0];
GeoImplicitSurfaceND surface = getSelectedImplicitSurface()[0];
GeoElement[] ret = getKernel().getManager3D()
.IntersectPlaneImplicitSurface(plane, surface);
ret[0].setLabel(null);
return ret;
}
} else if (selQuadric() >= 2) { // quadric-quadric : intersection
// circles
GeoQuadricND[] quads = getSelectedQuadric();
GeoElement[] ret = kernel.getManager3D().IntersectAsCircle(null,
quads[0], quads[1]);
if (ret[0].isDefined()) {
return ret;
}
return null;
} else if (selPlanes() >= 2) { // plane-plane
GeoPlaneND[] planes = getSelectedPlanes();
return new GeoElement[] { kernel.getManager3D()
.IntersectPlanes(null, planes[0], planes[1]) };
}
// //////////////////////////////////////
return null;
}
public boolean createIntersectionCurve(GeoElement A, GeoElement B) {
boolean intersectable = false;
for (int i = 0; i < intersectionCurveList.size(); ++i) {
IntersectionCurve intersection = intersectionCurveList.get(i);
if (intersection.geo1 == getMetaIfJustOne(A)
&& intersection.geo2 == getMetaIfJustOne(B)
|| intersection.geo1 == getMetaIfJustOne(B)
&& intersection.geo2 == getMetaIfJustOne(A)) {
intersection.drawable.setWaitForUpdate();
return true;
}
}
/*
* TODO line/polygon preview if (A.isGeoLine() && B.isGeoPolygon()) {
* //add intersection to tempArrayList} else
*/
if (A.isGeoPlane() && B.isGeoPlane()) {
// add intersection to tempArrayList
// if intersection of A,B does not exist, create it
GeoElement[] ret = new GeoElement[1];
// tells the kernel not to record the algo
boolean oldSilentMode = getKernel().isSilentMode();
getKernel().setSilentMode(true);
ret[0] = getKernel().getManager3D().IntersectPlanes((GeoPlaneND) A,
(GeoPlaneND) B);
getKernel().setSilentMode(oldSilentMode);
Drawable3D d = new DrawLine3D(view3D, (GeoLineND) ret[0]);
processIntersectionCurve(A, B, ret[0], d);
intersectable = true;
// plane - polyhedron
} else if (A.isGeoPlane() && B.isGeoPolygon()) {
createIntersectionCurvePlanePolygon(A, (GeoPolygon) B);
} else if (B.isGeoPlane() && A.isGeoPolygon()) {
createIntersectionCurvePlanePolygon(B, (GeoPolygon) A);
} else if (A.isGeoPlane() && B.isGeoPolyhedron()) {
createIntersectionCurvePlanePolyhedron(A, (GeoPolyhedron) B);
} else if (B.isGeoPlane() && A.isGeoPolyhedron()) {
createIntersectionCurvePlanePolyhedron(B, (GeoPolyhedron) A);
// plane-quadric
} else if (A.isGeoPlane() && B instanceof GeoQuadric3D) {
intersectable = createIntersectionCurvePlaneQuadric(A, B);
} else if (B.isGeoPlane() && A instanceof GeoQuadric3D) {
intersectable = createIntersectionCurvePlaneQuadric(B, A);
// plane-quadric limited
} else if (A.isGeoPlane() && B instanceof GeoQuadric3DLimited) {
intersectable = createIntersectionCurvePlaneQuadricLimited(A, B);
} else if (B.isGeoPlane() && A instanceof GeoQuadric3DLimited) {
intersectable = createIntersectionCurvePlaneQuadricLimited(B, A);
// quadric-quadric : intersection circles
} else if (A instanceof GeoQuadricND && B instanceof GeoQuadricND) {
// add intersection to tempArrayList
boolean oldSilentMode = getKernel().isSilentMode();
getKernel().setSilentMode(true);// tells the kernel not to record
// the algo
GeoElement ret = kernel.getManager3D()
.IntersectAsCircle((GeoQuadricND) A, (GeoQuadricND) B)[0];
Drawable3D d = new DrawConic3D(view3D, (GeoConic3D) ret);
getKernel().setSilentMode(oldSilentMode);
processIntersectionCurve(A, B, ret, d);
intersectable = true;
// // plane-quadric
// } else if (A.isGeoPlane() && B instanceof GeoFunctionNVar) {
// intersectable = createIntersectionCurvePlaneFunctionNVar(
// (GeoPlane3D) A, (GeoFunctionNVar) B);
// } else if (B.isGeoPlane() && A instanceof GeoFunctionNVar) {
// intersectable = createIntersectionCurvePlaneFunctionNVar(
// (GeoPlane3D) B, (GeoFunctionNVar) A);
}
return intersectable;
}
private boolean createIntersectionCurvePlanePolygon(GeoElement A,
GeoPolygon B) {
// check first if B is linked to polyhedron
if (B.getMetasLength() == 1) {
GeoElement polyhedron = B.getMetas()[0];
if (!polyhedron.isGeoPolyhedron()) { // e.g. for a net
return false;
}
createIntersectionCurvePlanePolyhedron(A,
(GeoPolyhedron) polyhedron);
return true;
}
// if B is linked to no (or more than one) polyhedron, create
// intersection segment(s)
boolean oldSilentMode = getKernel().isSilentMode();
getKernel().setSilentMode(true);// tells the kernel not to record the
// algo
GeoElement[] ret = kernel.getManager3D().IntersectPath((GeoPlaneND) A,
B);
DrawIntersectionCurve3D drawSegments = new DrawIntersectionCurve3D(
view3D, ret[0]);
for (GeoElement geo : ret) {
DrawSegment3D d = new DrawSegment3D(view3D, (GeoSegmentND) geo);
drawSegments.add(d);
processIntersectionCurve(A, B, geo, drawSegments);
}
getKernel().setSilentMode(oldSilentMode);
return true;
}
private void createIntersectionCurvePlanePolyhedron(GeoElement A,
GeoPolyhedron polyhedron) {
boolean oldSilentMode = getKernel().isSilentMode();
getKernel().setSilentMode(true);// tells the kernel not to record
// the algo
GeoElement[] ret = kernel.getManager3D().IntersectRegion((GeoPlaneND) A,
polyhedron);
boolean goAhead = true;
DrawIntersectionCurve3D drawPolygons = new DrawIntersectionCurve3D(
view3D, ret[0]);
for (int i = 0; i < ret.length && goAhead; i++) {
GeoElement geo = ret[i];
if (geo instanceof GeoPolygon3D) {
DrawPolygon3D d = new DrawPolygon3D(view3D, (GeoPolygon3D) geo);
drawPolygons.add(d);
processIntersectionCurve(A, polyhedron, geo, drawPolygons);
} else {
goAhead = false;
}
}
getKernel().setSilentMode(oldSilentMode);
}
private boolean createIntersectionCurvePlaneQuadric(GeoElement A,
GeoElement B) {
// add intersection to tempArrayList
boolean oldSilentMode = getKernel().isSilentMode();
getKernel().setSilentMode(true);// tells the kernel not to record the
// algo
GeoElement ret;
Drawable3D d;
GeoQuadricND quad;
if (B instanceof GeoQuadric3DPart) {
quad = (GeoQuadric3DLimited) ((GeoQuadric3DPart) B).getMetas()[0];
if (quad != null) {
ret = kernel.getManager3D()
.IntersectQuadricLimited((GeoPlaneND) A, quad);
d = new DrawConicSection3D(view3D, (GeoConicSection) ret);
} else {
quad = (GeoQuadricND) B;
ret = kernel.getManager3D().Intersect((GeoPlaneND) A, quad);
d = new DrawConic3D(view3D, (GeoConicND) ret);
}
} else {
quad = (GeoQuadric3D) B;
ret = kernel.getManager3D().Intersect((GeoPlaneND) A, quad);
d = new DrawConic3D(view3D, (GeoConicND) ret);
}
getKernel().setSilentMode(oldSilentMode);
processIntersectionCurve(A, quad, ret, d);
return true;
}
private boolean createIntersectionCurvePlaneQuadricLimited(GeoElement A,
GeoElement B) {
// add intersection to tempArrayList
boolean oldSilentMode = getKernel().isSilentMode();
getKernel().setSilentMode(true);// tells the kernel not to record the
// algo
GeoElement ret = kernel.getManager3D().IntersectQuadricLimited(
(GeoPlaneND) A, (GeoQuadric3DLimited) B);
Drawable3D d = new DrawConicSection3D(view3D, (GeoConicSection) ret);
getKernel().setSilentMode(oldSilentMode);
processIntersectionCurve(A, B, ret, d);
return true;
}
private void processIntersectionCurve(GeoElement A, GeoElement B,
GeoElement intersection, Drawable3D d) {
intersection.setLineThickness(3);
intersection.setIsPickable(false);
intersection.setObjColor(ConstructionDefaults3D.colIntersectionCurve);
intersectionCurveList.add(new IntersectionCurve(A, B, d));
}
private IntersectionCurve resultedIntersectionCurve;
private static GeoElement getMetaIfJustOne(GeoElement geo) {
if (geo instanceof FromMeta) {
if (geo.getMetasLength() == 1) {
return ((FromMeta) geo).getMetas()[0];
}
}
return geo;
}
private void decideIntersection(Hits hits) {
resultedGeo = null;
// find the nearest intersection curve (if exists)
double zNear = Double.NEGATIVE_INFINITY;
// App.error(""+intersectionCurveList.size());
for (IntersectionCurve intersectionCurve : intersectionCurveList) {
Drawable3D d = intersectionCurve.drawable;
// Log.debug("\n"+d+"\ntype:
// "+d.getPickingType()+"\nz="+d.getZPickNear()+"\ngeo1:"+intersectionCurve.geo1+"\ngeo2:"+intersectionCurve.geo2);
if (d.getZPickNear() > zNear) {
resultedGeo = d.getGeoElement();
resultedIntersectionCurve = intersectionCurve;
zNear = d.getZPickNear();
}
}
// Log.debug("\n\n==== INTER: "+resultedGeo+"\nz="+zNear+"\n\n");
/*
* if (resultedIntersectionCurve != null)
* Log.debug("\ngeo1:"+resultedIntersectionCurve
* .geo1+"\ngeo2:"+resultedIntersectionCurve.geo2);
*/
if (resultedGeo == null) {
view3D.setPreview(null);
goodHits = null;
return;
}
// check if the intersection curve is visible
int i = 0;
boolean checking = true;
while (checking && i < hits.size()) {
// while(checking && i<existingDrawables.size()){
/*
* Drawable3D d = existingDrawables.get(i); GeoElement geo =
* d.getGeoElement();
*/
GeoElement geo = hits.get(i);
Drawable3D d = (Drawable3D) view3D.getDrawableND(geo);
// Log.debug("\nhits("+i+"): "+geo+"\nd="+d);
if (d != null) {
// Log.debug("\nd.getZPickNear()="+d.getZPickNear()+"\nzNear="+zNear);
if (d.getZPickNear() < zNear) {
// all next drawables are behind the intersection curve
checking = false;
} else if (d.getZPickNear() > zNear + 1 // check if existing geo
// is really over the
// curve, with 1 pixel
// tolerance
&& (!geo.isRegion() || geo
.getAlphaValue() > MAX_TRANSPARENT_ALPHA_VALUE)) {
// only non-region or non-transparent surfaces can hide the
// curve
checking = false;
resultedGeo = null;
// Application.debug("=== d.zPickMin<z:
// "+geo+"\nz-d.zPickMin="+(z-d.zPickMin));
}
}
i++;
}
if (resultedGeo == null) {
view3D.setPreview(null);
return;
}
// Log.debug("resultedGeo:"+resultedGeo);
// Log.debug(hits+"\nA="+A+"\nB="+B);
// Application.debug(hits);
// for (int j=0; j<hits.size(); ++j) {
// System.out.print((hits.get(j)).isPickable()? "pickable "
// : "non-pickable");
// System.out.println((hits.get(j)).getObjectColor());
// }
if (hits.size() == 0) {
return;
}
if (goodHits == null) {
goodHits = new Hits3D();
} else {
goodHits.clear();
}
// since resultedGeo!=null, hits contains at least two element.
// if one of the two is not one of A or B, we say that
// resultedGeo is blocked by unrelated geo,
// and then we just keep the first hit as goodHit and hide the
// intersection
if (hits.size() < 2 // check first if there are at least 2 geos
|| (!(getMetaIfJustOne(
hits.get(0)) == resultedIntersectionCurve.geo1
&& getMetaIfJustOne(
hits.get(1)) == resultedIntersectionCurve.geo2)
&& !(getMetaIfJustOne(
hits.get(0)) == resultedIntersectionCurve.geo2
&& getMetaIfJustOne(hits.get(
1)) == resultedIntersectionCurve.geo1))) {
addToGoodHits(hits.get(0));
return;
}
// else, we show the intersection, and add A,B to highligtedgeos
addToGoodHits(hits.get(0));
addToGoodHits(hits.get(1));
view3D.setPreview((Previewable) resultedIntersectionCurve.drawable);
// resultedGeo.setIsPickable(false);
}
final private void addToGoodHits(GeoElement geo) {
goodHits.add(getMetaIfJustOne(geo));
}
// /////////////////////////////////////////
// POINT CAPTURING
@Override
public void transformCoords() {
// TODO point capturing
}
// /////////////////////////////////////////
// PASTE PREVIEW
@Override
protected void updatePastePreviewPosition() {
GeoPoint3D p = view3D.getCursor3D();
if (translationVec3D == null) {
translationVec3D = new Coords(3);
}
translationVec3D.setX(p.getInhomX() - getStartPointX());
translationVec3D.setY(p.getInhomY() - getStartPointY());
translationVec3D.setZ(p.getInhomZ() - getStartPointZ());
setStartPointLocation(p.getInhomX(), p.getInhomY(), p.getInhomZ());
if (tmpCoordsL3 == null) {
tmpCoordsL3 = new Coords(3);
}
tmpCoordsL3.setX(p.getInhomX());
tmpCoordsL3.setY(p.getInhomY());
tmpCoordsL3.setZ(p.getInhomZ());
GeoElement.moveObjects(pastePreviewSelected, translationVec3D,
tmpCoordsL3, view3D.getViewDirection(), view3D);
}
protected double startPointZ;
protected double getStartPointZ() {
return startPointZ;
}
protected void setStartPointLocation(double x, double y, double z) {
setStartPointLocation(x, y);
startPointZ = z;
}
// /////////////////////////////////////////
// SELECTIONS
// /////////////////////////////////////////
// selectedCS2D list, similar to selectedCS1D
/** selected 2D coord sys */
/**
* add hits to selectedCS2D
*
* @param hits
* hits
* @param max
* max number of hits to add
* @param addMoreThanOneAllowed
* if adding more than one is allowed
* @return TODO
*/
final protected int addSelectedCS2D(Hits hits, int max,
boolean addMoreThanOneAllowed, boolean selPreview) {
return handleAddSelected(hits, max, addMoreThanOneAllowed,
selection.getSelectedCS2DList(), Test.GEOCOORDSYS2D,
selPreview);
}
/**
* return number of selected 2D coord sys
*
* @return number of selected 2D coord sys
*/
final int selCS2D() {
return selection.getSelectedCS2DList().size();
}
/**
* return selected 2D coord sys also clear all selected 2D coord sys.
*
* @return selected 2D coord sys
*/
final protected GeoCoordSys[] getSelectedCS2D() {
GeoCoordSys[] planes = new GeoCoordSys[selection.getSelectedCS2DList()
.size()];
int i = 0;
Iterator<GeoCoordSys> it = selection.getSelectedCS2DList().iterator();
while (it.hasNext()) {
planes[i] = it.next();
i++;
}
clearSelection(selection.getSelectedCS2DList());
return planes;
}
/**
* add hits to selectedPlane
*
* @param hits
* hits
* @param max
* max number of hits to add
* @param addMoreThanOneAllowed
* if adding more than one is allowed
* @return TODO
*/
final protected int addSelectedPlane(Hits hits, int max,
boolean addMoreThanOneAllowed, boolean selPreview) {
return handleAddSelected(hits, max, addMoreThanOneAllowed,
selection.getSelectedPlaneList(), Test.GEOPLANEND, selPreview);
}
/**
* return number of selected planes
*
* @return number of selected planes
*/
final int selPlanes() {
return selection.getSelectedPlaneList().size();
}
/**
* @return selected implicit surfaces
*/
final int selImplicitSurfaces() {
return getSelectedImplicitSurfaceList().size();
}
/**
* return selected planes also clear all selected planes.
*
* @return selected planes
*/
final protected GeoPlaneND[] getSelectedPlanes() {
GeoPlaneND[] planes = new GeoPlane3D[selection.getSelectedPlaneList()
.size()];
int i = 0;
Iterator<GeoPlaneND> it = selection.getSelectedPlaneList().iterator();
while (it.hasNext()) {
planes[i] = it.next();
i++;
}
clearSelection(selection.getSelectedPlaneList());
return planes;
}
// /for quadric
/**
* @return number of selected quadrics
*/
final int selQuadric() {
return selection.getSelectedQuadricList().size();
}
final protected int addSelectedQuadric(Hits hits, int max,
boolean addMoreThanOneAllowed, boolean selPreview) {
return handleAddSelected(hits, max, addMoreThanOneAllowed,
selection.getSelectedQuadricList(), Test.GEOQUADRIC3D,
selPreview);
}
final protected GeoQuadricND[] getSelectedQuadric() {
GeoQuadricND[] quads = new GeoQuadricND[selection
.getSelectedQuadricList().size()];
int i = 0;
Iterator<GeoQuadricND> it = selection.getSelectedQuadricList()
.iterator();
while (it.hasNext()) {
quads[i] = it.next();
i++;
}
clearSelection(selection.getSelectedQuadricList());
return quads;
}
// /for quadric
final int selQuadricLimited() {
return selection.getSelectedQuadricLimitedList().size();
}
final protected int addSelectedQuadricLimited(Hits hits, int max,
boolean addMoreThanOneAllowed, boolean selPreview) {
return handleAddSelected(hits, max, addMoreThanOneAllowed,
selection.getSelectedQuadricLimitedList(),
Test.GEOQUADRIC3DLIMITED, selPreview);
}
final protected GeoQuadric3DLimitedInterface[] getSelectedQuadricLimited() {
GeoQuadric3DLimitedInterface[] quads = new GeoQuadric3DLimitedInterface[selection
.getSelectedQuadricLimitedList().size()];
int i = 0;
Iterator<GeoQuadric3DLimitedInterface> it = selection
.getSelectedQuadricLimitedList().iterator();
while (it.hasNext()) {
quads[i] = it.next();
i++;
}
clearSelection(selection.getSelectedQuadricLimitedList());
return quads;
}
// /for polyhedrons
final int selPolyhedron() {
return selection.getSelectedPolyhedronList().size();
}
final protected int addSelectedPolyhedron(Hits hits, int max,
boolean addMoreThanOneAllowed, boolean selPreview) {
return handleAddSelected(hits, max, addMoreThanOneAllowed,
selection.getSelectedPolyhedronList(), Test.GEOPOLYHEDRON,
selPreview);
}
final protected GeoPolyhedronInterface[] getSelectedPolyhedron() {
GeoPolyhedronInterface[] polyh = new GeoPolyhedron[selection
.getSelectedPolyhedronList().size()];
int i = 0;
Iterator<GeoPolyhedronInterface> it = selection
.getSelectedPolyhedronList().iterator();
while (it.hasNext()) {
polyh[i] = it.next();
i++;
}
clearSelection(selection.getSelectedPolyhedronList());
return polyh;
}
@Override
protected GeoElement chooseGeo(ArrayList<GeoElement> geos,
boolean includeFixed) {
return chooseGeo(geos, includeFixed, false);
}
@Override
protected GeoElement chooseGeo(ArrayList<GeoElement> geos,
boolean includeFixed, boolean includeConstants) {
// Application.printStacktrace(((Hits) geos).toString());
if (!geos.isEmpty()) {
// if the geo hitted is one of view3D's geos, then chooseGeo return
// null
if (!includeConstants && view3D.owns(geos.get(0))) {
return null;
}
// doesn't use choosing dialog TODO use choosing dialog ?
// return super.chooseGeo(geos, includeFixed);
// return first element : ordering done in hits
GeoElement geo = geos.get(0);
if (!includeFixed && geo.isLocked()) {
return null;
}
return geo;
}
return null;
}
// /////////////////////////////////////////
//
/*
* public void mouseWheelMoved(MouseWheelEvent e) {
*
* double r = e.getWheelRotation();
*
* switch (moveMode) { case MOVE_VIEW: default:
* view3D.setMoveCursor();//setZoomCursor
* view3D.setScale(view3D.getXscale()+r*10); view3D.updateMatrix();
* view.setHits(mouseLoc); ((EuclidianView getView().ew).updateCursor3D();
* view3D.setHitCursor(); //((Kernel3D) getKernel()).notifyRepaint();
*
* break;
*
* case MOVE_POINT: case MOVE_POINT_WHEEL: /* TODO //p = p + r*vn
* Ggb3DVector p1 = (Ggb3DVector)
* movedGeoPoint3D.getCoords().add(EuclidianView3D.vz.mul(-r*0.1));
* movedGeoPoint3D.setCoords(p1);
*
*
*
*
*
* objSelected.updateCascade();
*
*
* movedGeoPoint3D.updateRepaint();//for highlighting in algebraView
* //kernel3D.notifyRepaint();
*
*
* break;
*
*
* }
*
*
*
*
* }
*/
// ////////////////////////////////////
// SELECTED GEOS
// ////////////////////////////////////
// ///////////////////////////////////////////////////
//
// CURSOR
//
// ///////////////////////////////////////////////////
private static boolean isModeForMovingPoint(int mode) {
switch (mode) {
case EuclidianConstants.MODE_MOVE:
case EuclidianConstants.MODE_ATTACH_DETACH:
return true;
default:
return isModeForCreatingPoint(mode);
}
}
private static boolean isModeForCreatingPoint(int mode) {
switch (mode) {
case EuclidianConstants.MODE_POINT:
case EuclidianConstants.MODE_POINT_ON_OBJECT:
case EuclidianConstants.MODE_JOIN:
case EuclidianConstants.MODE_SEGMENT:
case EuclidianConstants.MODE_RAY:
case EuclidianConstants.MODE_VECTOR:
case EuclidianConstants.MODE_POLYGON:
case EuclidianConstants.MODE_POLYLINE:
case EuclidianConstants.MODE_CIRCLE_THREE_POINTS:
case EuclidianConstants.MODE_CIRCLE_ARC_THREE_POINTS:
case EuclidianConstants.MODE_PLANE_THREE_POINTS:
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
case EuclidianConstants.MODE_SPHERE_POINT_RADIUS:
case EuclidianConstants.MODE_CONE_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_CYLINDER_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
return true;
default:
return false;
}
}
/**
* @param cursorType
* type of the cursor
* @return if the 3D cursor is visible for current mode
*/
public boolean cursor3DVisibleForCurrentMode(int cursorType) {
if (cursorType == EuclidianView3D.PREVIEW_POINT_ALREADY) {
// cross arrows for moving point
switch (mode) {
// modes in which the result could be a dependent point
case EuclidianConstants.MODE_MOVE:
case EuclidianConstants.MODE_POINT:
return true;
default:
if (isModeForMovingPoint(mode)) {
// can only move the last created point
GeoElement movedPoint = getMovedGeoPoint();
if (movedPoint == null) {
return false;
}
Hits hits = view3D.getHits();
if (!hits.isEmpty() && hits.get(0) == movedPoint) {
return true;
}
return false;
}
return false;
}
} else if (cursorType == EuclidianView3D.PREVIEW_POINT_DEPENDENT) {
switch (mode) {
// modes in which the result could be a dependent point
case EuclidianConstants.MODE_POINT:
case EuclidianConstants.MODE_INTERSECT:
case EuclidianConstants.MODE_JOIN:
case EuclidianConstants.MODE_SEGMENT:
case EuclidianConstants.MODE_RAY:
case EuclidianConstants.MODE_CIRCLE_THREE_POINTS:
case EuclidianConstants.MODE_SPHERE_POINT_RADIUS:
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
case EuclidianConstants.MODE_CONE_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_CYLINDER_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_TETRAHEDRON:
case EuclidianConstants.MODE_CUBE:
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
return true;
default:
return false;
}
} else {
switch (mode) {
// modes where point can be created on path/region
case EuclidianConstants.MODE_POINT:
case EuclidianConstants.MODE_POINT_ON_OBJECT:
case EuclidianConstants.MODE_JOIN:
case EuclidianConstants.MODE_SEGMENT:
case EuclidianConstants.MODE_RAY:
case EuclidianConstants.MODE_VECTOR:
case EuclidianConstants.MODE_POLYGON:
case EuclidianConstants.MODE_POLYLINE:
case EuclidianConstants.MODE_CIRCLE_THREE_POINTS:
case EuclidianConstants.MODE_CIRCLE_ARC_THREE_POINTS:
case EuclidianConstants.MODE_PLANE_THREE_POINTS:
case EuclidianConstants.MODE_SPHERE_TWO_POINTS:
case EuclidianConstants.MODE_SPHERE_POINT_RADIUS:
case EuclidianConstants.MODE_CONE_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_CYLINDER_TWO_POINTS_RADIUS:
case EuclidianConstants.MODE_VIEW_IN_FRONT_OF:
return true;
case EuclidianConstants.MODE_VECTOR_FROM_POINT:
Hits hits = view3D.getHits();
if (!hits.isEmpty() && hits.get(0).isGeoVector()) {
return false; // no cursor if on a vector
}
return true;
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
return (selPolygons() == 1) || (!polygonForPyramidBasis);
case EuclidianConstants.MODE_TETRAHEDRON:
case EuclidianConstants.MODE_CUBE:
// show cursor when direction has been selected
if (selCS2D() == 1 || selPoints() != 0) {
return true;
}
hits = view3D.getHits();
if (hits.isEmpty()) {
return true;
}
GeoPoint3D point = view3D.getCursor3D();
if (point.isPointOnPath()) {
return true;
}
if (point.hasRegion()) {
if (point.getRegion() == kernel.getXOYPlane()) {
return true;
}
}
return false;
case EuclidianConstants.MODE_ANGLE:
point = view3D.getCursor3D();
if (point.isPointOnPath()) {
return false;
}
if (point.hasRegion()) {
return false;
}
return true;
default:
return false;
}
}
}
// //////////////////////////////////////
// HANDLING PARTS OF PREVIEWABLES
// //////////////////////////////////////
private GeoElement handledGeo;
/**
* sets the geo as an handled geo (for previewables)
*
* @param geo
*/
public void setHandledGeo(GeoElement geo) {
handledGeo = geo;
if (handledGeo == null) {
return;
}
setStartPointLocation();
handledGeo.recordChangeableCoordParentNumbers(view3D);
}
@Override
protected boolean viewHasHitsForMouseDragged() {
// Application.debug(moveMode);
if (moveMode == MOVE_POINT && view3D
.getCursor3DType() == EuclidianView3D.PREVIEW_POINT_ALREADY) {
return getView().getHits().containsGeoPoint(); // if a point is
// under the
// mouse, don't try to
// find another hit
}
Hits hits = getView().getHits();
if (hits.isEmpty()) {
return false;
}
if (hits.get(0) == kernel.getXOYPlane()) {
return false;
}
return true;
}
@Override
public void wrapMouseDragged(AbstractEvent event, boolean startCapture) {
if (handledGeo != null) {
setMouseLocation(event);
event.release();
updateTranslationVector();
handledGeo.moveFromChangeableCoordParentNumbers(translationVec3D,
startPoint3D, view3D.getViewDirection(), null, null,
view3D);
// view3D.updatePreviewable();
kernel.notifyRepaint();
return;
}
setMouseMovedEvent(event);
wrapMouseDraggedND(event, startCapture);
}
// //////////////////////////////////////
// MOVE OBJECTS
// //////////////////////////////////////
private Coords startPoint3D = new Coords(0, 0, 0, 1);
private Coords startPoint3DxOy = new Coords(0, 0, 0, 1);
protected Coords translationVec3D = new Coords(4);
/**
* update translation vector
*/
protected void updateTranslationVector() {
Coords point = view3D.getPickPoint(mouseLoc);
view3D.toSceneCoords3D(point);
updateTranslationVector(point);
}
/**
* update translation vector from start point to current mouse pos
*
* @param point
* current mouse pos
*/
protected void updateTranslationVector(Coords point) {
point.sub(startPoint3D, translationVec3D);
}
@Override
public void setStartPointLocation() {
udpateStartPoint();
super.setStartPointLocation();
}
/**
* update start point to current mouse coords
*/
protected void udpateStartPoint() {
if (mouseLoc == null) {
return;
}
updateStartPoint(view3D.getPickPoint(mouseLoc));
}
/**
* update start point to p coords
*
* @param p
* coords
*/
final protected void updateStartPoint(Coords p) {
startPoint3D.set(p);
view3D.toSceneCoords3D(startPoint3D);
// Log.debug("\n"+startPoint3D);
// project on xOy
startPoint3D.projectPlaneThruVIfPossible(CoordMatrix4x4.IDENTITY,
view3D.getHittingDirection(), startPoint3DxOy);
}
@Override
protected void setTranslateStart(GeoElement geo, GeoVectorND vec) {
super.setTranslateStart(geo, vec);
startPoint3D.set(view3D.getCursor3D().getInhomCoordsInD3());
translationVec3D.set(vec.getCoordsInD3());
if (geo.isGeoPlane()) {
translateDirection = geo.getMainDirection();
} else {
translateDirection = null;
}
}
private void setTranslateFromPointStart(GeoElement geo, GeoPointND point) {
startPoint3D.set(view3D.getCursor3D().getInhomCoordsInD3());
translationVec3D.setSub(point.getInhomCoordsInD3(), startPoint3D);
if (geo.isGeoPlane()) {
translateDirection = geo.getMainDirection();
if (point.isGeoElement3D()) {
((GeoPoint3D) point).setMoveMode(GeoPointND.MOVE_MODE_Z);
}
} else {
translateDirection = null;
if (point.isGeoElement3D()) {
((GeoPoint3D) point)
.setMoveMode(GeoPointND.MOVE_MODE_TOOL_DEFAULT);
}
}
}
/**
*
* @return current normal translation direction
*/
public Coords getNormalTranslateDirection() {
if (translateDirection == null) {
return Coords.VZ;
}
return translateDirection;
}
@Override
protected void moveVector() {
Coords o = view3D.getPickPoint(mouseLoc);
view3D.toSceneCoords3D(o);
if (translateDirection == null) {
o.projectPlaneThruVIfPossible(Coords.VX, Coords.VY, Coords.VZ,
startPoint3D, view3D.getHittingDirection(), tmpCoords);
} else {
startPoint3D.projectNearLine(o, view3D.getHittingDirection(),
translateDirection, tmpCoords);
}
GeoPointND P = movedGeoVector.getStartPoint();
if (P == null) {
tmpCoords.setSub(tmpCoords, startPoint3D);
} else {
tmpCoords.setSub(tmpCoords, P.getInhomCoordsInD3());
}
tmpCoords.setAdd(tmpCoords, translationVec3D);
// snap to grid
((EuclidianController3DCompanion) companion)
.checkPointCapturingXYThenZ(tmpCoords);
if (movedGeoVector.isGeoElement3D()) {
((GeoVector3D) movedGeoVector).setCoords(tmpCoords);
} else {
moveVector(tmpCoords.getX(), tmpCoords.getY());
}
}
private Coords translateDirection;
@Override
public void setStartPointLocationWithOrigin(double x, double y) {
udpateStartPoint();
// sub origin
startPoint3DxOy.setX(startPoint3DxOy.getX() - x);
startPoint3DxOy.setY(startPoint3DxOy.getY() - y);
super.setStartPointLocationWithOrigin(x, y);
}
@Override
protected void calcRWcoords() {
Coords point = view3D.getPickPoint(mouseLoc);
view3D.toSceneCoords3D(point);
xRW = point.getX();
yRW = point.getY();
}
@Override
protected void moveDependent(boolean repaint) {
updateTranslationVector();
Coords end = startPoint3D;
if (translateableGeos.size() > 0
&& translateableGeos.get(0) instanceof GeoPointND) {
GeoPointND g3d = (GeoPointND) translateableGeos.get(0).copy();
if (g3d.getMoveMode() == GeoPointND.MOVE_MODE_Z || (g3d
.getMoveMode() == GeoPointND.MOVE_MODE_TOOL_DEFAULT
&& this.getPointMoveMode() == GeoPointND.MOVE_MODE_Z)) { // moves
((EuclidianController3DCompanion) companion)
.moveAlongZAxis(g3d);
} else {
getCurrentPlane().set(g3d.getCoordsInD3(), 4);
movePointOnCurrentPlane(g3d, false);
}
end = g3d.getInhomCoordsInD3();
}
GeoElement.moveObjects(translateableGeos, translationVec3D, end,
view3D.getHittingDirection(), view3D);
kernel.notifyRepaint();
}
@Override
protected void handleMovedElementMultiple() {
// TODO
}
@Override
final protected void handleMovedElementFree(PointerEventType type) {
if (handleMovedElementFreePoint()) {
translateDirection = null;
return;
}
if (handleMovedElementFreePlane()) {
return;
}
handleMovedElementFreeText();
}
/**
*
* @return true if there is a free plane to move
*/
final private boolean handleMovedElementFreePlane() {
boolean ret = getCompanion()
.handleMovedElementFreePlane(movedGeoElement);
if (ret) {
moveMode = MOVE_PLANE;
}
return ret;
}
@Override
final protected void handleMovedElementDependent() {
if (movedGeoElement.isTranslateable()) {
AlgoElement algo = movedGeoElement.getParentAlgorithm();
if (algo instanceof AlgoTranslate) {
GeoElement[] input = algo.getInput();
GeoElement in = input[1];
if (in instanceof GeoVectorND) {
if (in.isIndependent()) {
movedGeoVector = (GeoVectorND) input[1];
moveMode = MOVE_VECTOR_NO_GRID;
setTranslateStart(movedGeoElement, movedGeoVector);
} else if (in
.getParentAlgorithm() instanceof AlgoVectorPoint) {
AlgoVectorPoint algoVector = (AlgoVectorPoint) in
.getParentAlgorithm();
moveMode = MOVE_POINT_WITH_OFFSET;
setMovedGeoPoint(algoVector.getP());
setTranslateFromPointStart(movedGeoElement,
movedGeoPoint);
}
}
return;
}
}
translateableGeos = null;
handleMovedElementDependentWithChangeableCoordParentNumbers();
handleMovedElementDependentInitMode();
}
@Override
protected void movePointWithOffset(boolean repaint) {
companion.movePoint(repaint, null);
}
@Override
final protected GeoElementND[] orthogonal(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
boolean hitPoint = (addSelectedPoint(hits, 1, false, selPreview) != 0);
if (!hitPoint) {
if (selCS2D() == 0) {
addSelectedLine(hits, 1, false, selPreview);
}
if (selLines() == 0) {
addSelectedCS2D(hits, 1, false, selPreview);
}
}
if (selPoints() == 1) {
if (selCS2D() == 1) {
// fetch selected point and plane
GeoPointND[] points = getSelectedPointsND();
GeoCoordSys[] cs = getSelectedCS2D();
// create new line
return new GeoElementND[] { getKernel()
.getManager3D().OrthogonalLine3D(null, points[0],
(GeoCoordSys2D) cs[0]) };
} else if (selLines() == 1) {
// fetch selected point and line
GeoPointND[] points = getSelectedPointsND();
GeoLineND[] lines = getSelectedLinesND();
// create new line
return new GeoElementND[] {
getKernel()
.getManager3D().OrthogonalLine3D(null, points[0],
lines[0], kernel.getSpace()) };
}
}
return null;
}
private final GeoElement[] rotateAroundLine(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
// Transformable
int count = 0;
if (selGeos() == 0) {
Hits rotAbles = hits.getHits(Test.TRANSFORMABLE, tempArrayList);
count = addSelectedGeo(rotAbles, 1, false, selPreview);
}
// polygon
if (count == 0) {
count = addSelectedPolygon(hits, 1, false, selPreview);
}
// rotation axis
if (count == 0) {
addSelectedLine(hits, 1, false, selPreview);
}
// we got the rotation center point
if ((selLines() == 1) && (selGeos() > 0)) {
GeoElement[] selGeos = getSelectedGeos();
getDialogManager().showNumberInputDialogRotate(
l10n.getMenu(EuclidianConstants.getModeText(mode)),
getSelectedPolygons(), getSelectedLinesND(), selGeos, this);
return null;
}
return null;
}
/**
* @param geoRot
* rotated object
* @param phi
* angle
* @param line
* line
* @return rotated object
*/
public GeoElement[] rotateAroundLine(GeoElement geoRot, GeoNumberValue phi,
GeoLineND line) {
return kernel.getManager3D().Rotate3D(null, geoRot, phi, line);
}
/**
*
* @param clockwise
* user's choice
* @param line
* rotation axis
* @return correct clockwise orientation resp. view/line
*/
public boolean viewOrientationForClockwise(boolean clockwise,
GeoLineND line) {
if (line.getDirectionInD3().dotproduct(view3D.getViewDirection()) > 0) {
return !clockwise;
}
return clockwise;
}
private final GeoElement[] mirrorAtPlane(Hits hits, boolean selPreview) {
if (hits.isEmpty()) {
return null;
}
// Transformable
int count = 0;
if (selGeos() == 0) {
Hits mirAbles = hits.getHits(Test.TRANSFORMABLE, tempArrayList);
count = addSelectedGeo(mirAbles, 1, false, selPreview);
}
// plane = mirror
if (count == 0) {
addSelectedCS2D(hits, 1, false, selPreview);
}
// we got the mirror plane
if (selCS2D() == 1) {
if (selGeos() > 0) {
// mirror all selected geos
GeoElement[] geos = getSelectedGeos();
GeoCoordSys2D plane = (GeoCoordSys2D) getSelectedCS2D()[0];
GeoCoordSys2D mirror = plane;
if (plane.isGeoConic()) { // no override for
// mirror at circle
plane = kernel.getManager3D().Plane3D(mirror);
}
ArrayList<GeoElement> ret = new ArrayList<GeoElement>();
checkZooming();
for (int i = 0; i < geos.length; i++) {
if (geos[i] != mirror) {
if (geos[i] instanceof Transformable) {
ret.addAll(Arrays.asList(kernel.getManager3D()
.Mirror3D(null, geos[i], plane)));
} else if (geos[i].isGeoPolygon()) {
ret.addAll(Arrays.asList(kernel.getManager3D()
.Mirror3D(null, geos[i], plane)));
}
}
}
GeoElement[] retex = {};
return ret.toArray(retex);
}
}
return null;
}
/**
* show popup menu when no geo is selected
*
* @param hits
* hits on the mouse
*/
@Override
protected void showPopupMenuChooseGeo(ArrayList<GeoElement> selectedGeos1,
Hits hits) {
if (app.isUsingFullGui() && app.getGuiManager() != null) {
// if (geo != null) {
app.getGuiManager().showPopupChooseGeo(selectedGeos1, hits, view3D,
mouseLoc);
/*
* Now overriden } else { // for 3D : if the geo hitted is xOyPlane,
* then // chooseGeo return null //
* app.getGuiManager().showDrawingPadPopup((EuclidianView) // view,
* mouseLoc); showDrawingPadPopup(mouseLoc); }
*/
}
}
/**
* update all drawables now
*/
public void updateOwnDrawablesNow() {
for (IntersectionCurve intersectionCurve : intersectionCurveList) {
intersectionCurve.drawable.update();
}
}
@Override
public void setMode(int newMode, ModeSetter ms) {
// clear specific modes fields
// clear intersections
if (newMode != EuclidianConstants.MODE_INTERSECTION_CURVE) {
intersectionCurveList.clear();
}
// clear pyramid/prism basis
pyramidBasis = null;
super.setMode(newMode, ms);
if (!temporaryMode) {
initPointMoveMode();
}
}
@Override
protected void setDragCursorIfMoveView() {
// nothing to do, keep same cursor
}
@Override
protected final void processSelectionRectangle(boolean alt,
boolean isControlDown, boolean shift) {
// TODO implement this
}
@Override
protected int addSelectedPlanesForAngle(Hits hits, int count,
boolean selPreview) {
if (selVectors() == 0) {
if (selLines() == 0) { // angle between two planes
return addSelectedPlane(hits, 2, false, selPreview);
} else if (selLines() == 1) { // angle between line and plane
return addSelectedPlane(hits, 1, false, selPreview);
}
}
return count;
}
@Override
protected GeoAngle createAngle3D() {
if (selPlanes() == 2) {
GeoPlaneND[] planes = getSelectedPlanes();
return kernel.getManager3D().Angle3D(null, planes[0], planes[1]);
}
if (selPlanes() == 1 && selLines() == 1) {
GeoLineND[] lines = getSelectedLinesND();
GeoPlaneND[] planes = getSelectedPlanes();
return kernel.getManager3D().Angle3D(null, lines[0], planes[0]);
}
return null;
}
/**
*
* @return true if there is a 3D input
*/
public boolean hasInput3D() {
return false;
}
@Override
protected Coords getMouseLocRW() {
return view3D.getCursor3D().getInhomCoordsInD3();
}
public static void rotateObject(final App app, final String rawInput,
final boolean clockwise, final GeoPolygon[] polys,
final GeoLineND[] lines, final GeoElement[] selGeos,
final EuclidianController3D ec, final ErrorHandler eh,
final AsyncOperation<String> callback) {
final String angleText = rawInput;
Kernel kernel = app.getKernel();
// avoid labeling of num
final Construction cons = kernel.getConstruction();
final boolean oldVal = cons.isSuppressLabelsActive();
cons.setSuppressLabelCreation(true);
String inputText = rawInput;
// negative orientation ?
if (ec.viewOrientationForClockwise(clockwise, lines[0])) {
inputText = "-(" + inputText + ")";
}
kernel.getAlgebraProcessor().processAlgebraCommandNoExceptionHandling(
inputText, false, eh, true,
new AsyncOperation<GeoElementND[]>() {
@Override
public void callback(GeoElementND[] result) {
String defaultRotateAngle = Unicode.FORTY_FIVE_DEGREES;
cons.setSuppressLabelCreation(oldVal);
boolean success = result != null && result.length > 0
&& result[0] instanceof GeoNumberValue;
if (success) {
// GeoElement circle = kernel.Circle(null,
// geoPoint1,
// ((NumberInputHandler)inputHandler).getNum());
GeoNumberValue num = (GeoNumberValue) result[0];
// geogebra.gui.AngleInputDialog dialog =
// (geogebra.gui.AngleInputDialog) ob[1];
// keep angle entered if it ends with 'degrees'
if (angleText.endsWith(Unicode.DEGREE)) {
defaultRotateAngle = angleText;
}
if (polys.length == 1) {
GeoElement[] geos = ec.rotateAroundLine(
polys[0], num, lines[0]);
if (geos != null) {
app.storeUndoInfoAndStateForModeStarting();
ec.memorizeJustCreatedGeos(geos);
}
if (callback != null) {
callback.callback(defaultRotateAngle);
}
return;
}
ArrayList<GeoElement> ret = new ArrayList<GeoElement>();
for (int i = 0; i < selGeos.length; i++) {
if (selGeos[i] != lines[0]) {
if (selGeos[i] instanceof Transformable) {
ret.addAll(Arrays.asList(
ec.rotateAroundLine(selGeos[i],
num, lines[0])));
} else if (selGeos[i].isGeoPolygon()) {
ret.addAll(Arrays.asList(
ec.rotateAroundLine(selGeos[i],
num, lines[0])));
}
}
}
if (!ret.isEmpty()) {
app.storeUndoInfoAndStateForModeStarting();
ec.memorizeJustCreatedGeos(ret);
}
} else {
if (result != null && result.length > 0) {
eh.showError(app.getLocalization()
.getError("NumberExpected"));
}
}
if (callback != null) {
callback.callback(
success ? defaultRotateAngle : null);
}
}
});
}
@Override
protected GeoElement[] polygon() {
if (polygonMode == POLYGON_NORMAL) {
// cancel last switch
cancelSwitchPointMoveModeIfNeeded();
view3D.disposePreview();
}
return super.polygon();
}
@Override
protected GeoVectorND createVectorForTranslation() {
return ((AlgoDispatcher3D) getAlgoDispatcher()).Vector3D();
}
@Override
protected GeoVectorND createVectorForTranslation(String label) {
return ((AlgoDispatcher3D) getAlgoDispatcher()).Vector3D(label);
}
@Override
protected int getModeForShallMoveView(AbstractEvent event) {
if (event.isShiftDown() || app.isMiddleClick(event)) {
return EuclidianConstants.MODE_TRANSLATEVIEW;
}
return EuclidianConstants.MODE_ROTATEVIEW;
}
@Override
protected boolean hasNoHitsDisablingModeForShallMoveView(Hits hits,
AbstractEvent event) {
if (hits.isEmpty()) {
return true;
}
if (app.has(Feature.DRAGGING_NON_MOVEABLE_OBJECT_SPIN_THE_VIEW)) {
GeoElement geoLabel = getView().getLabelHitCheckRefresh(mouseLoc,
event.getType());
if (geoLabel != null) {
return false;
}
for (GeoElement geo : hits) {
if (isDraggable(geo, view3D)) {
return false;
}
}
// ok, let's spin the view
return true;
}
return hits.get(0) == kernel.getXOYPlane();
}
/**
*
* @param geo
* geo
* @param view
* view
* @return true if drag on this geo does something
*/
public static boolean isDraggable(GeoElement geo,
EuclidianViewInterfaceSlim view) {
// if geo is moveable
if (geo.isMoveable(view)) {
return true;
}
// if geo has translate parent algo
if (geo.isTranslateable()) {
AlgoElement algo = geo.getParentAlgorithm();
if (algo instanceof AlgoTranslate) {
return true;
}
}
// e.g. for extruded pyramid or polyhedron net
if (geo.hasChangeableCoordParentNumbers()) {
return true;
}
return false;
}
@Override
protected DrawDropDownList getComboBoxHit() {
return null;
}
@Override
protected boolean overComboBox(AbstractEvent event, GeoElement hit) {
return false;
}
@Override
public boolean textfieldJustFocused(int x, int y, PointerEventType type) {
return false;
}
/**
* exit use of 3D input
*/
public void exitInput3D() {
// use for 3D input
}
/**
*
* @return true if uses zSpace
*/
public boolean isZSpace() {
return false;
}
@Override
public void onPinchPhone(int x, int y, double scaleFactor) {
view3D.screenTranslateAndScale(x - twoTouchStartX, y - twoTouchStartY,
scaleFactor);
}
@Override
protected void hidePreviewForPhone() {
if (!(getView().getPreviewDrawable() instanceof DrawPolyLine3D)
&& !(getView().getPreviewDrawable() instanceof DrawPolygon3D)
&& !(getView().getPreviewDrawable() instanceof DrawPolyhedron3D)) {
getView().setPreview(null);
}
}
private Coords scaleAxisVector = new Coords(2), scaleOrigin = new Coords(2);
private double scaleOld, scaleDistanceInPixelsStart;
@Override
protected void setMoveModeIfAxis(Object hit) {
if (app.has(Feature.DIFFERENT_AXIS_RATIO_3D)) {
int newMode = -1;
if (hit == kernel.getXAxis()) {
newMode = MOVE_X_AXIS;
scaleAxisVector.set2(view3D.getToScreenMatrix().getVx());
scaleOld = view3D.getXscale();
} else if (hit == kernel.getYAxis()) {
newMode = MOVE_Y_AXIS;
scaleAxisVector.set2(view3D.getToScreenMatrix().getVy());
scaleOld = view3D.getYscale();
} else if (hit == kernel.getZAxis3D()) {
newMode = MOVE_Z_AXIS;
scaleAxisVector.set2(view3D.getToScreenMatrix().getVz());
scaleOld = view3D.getZscale();
}
if (newMode != -1) {
// an axis was hit
// check if axis is not quite orthogonal to screen
scaleAxisVector.calcNorm();
double norm = scaleAxisVector.getNorm();
// Log.debug(norm / scaleOld);
if (norm / scaleOld > 0.1) {
scaleAxisVector.mulInside(1 / norm);
scaleOrigin.set2(view3D.getToScreenMatrix().getOrigin());
tmpCoords.setMul(view3D.getToScreenMatrix(),
view3D.getCursor3D().getInhomCoordsInD3());
scaleDistanceInPixelsStart = getDistanceForScale(
tmpCoords.getX(), tmpCoords.getY());
if (Math.abs(
scaleDistanceInPixelsStart) > MIN_MOUSE_MOVE_FOR_AXIS_SCALE) {
moveMode = newMode;
}
}
}
}
}
private double getDistanceForScale(double x, double y) {
return (x - scaleOrigin.getX()) * scaleAxisVector.getX()
+ (y - scaleOrigin.getY()) * scaleAxisVector.getY();
}
@Override
protected void scaleXAxis(boolean repaint) {
scaleAxis(repaint);
}
@Override
protected void scaleYAxis(boolean repaint) {
scaleAxis(repaint);
}
@Override
protected void scaleZAxis(boolean repaint) {
scaleAxis(repaint);
}
final private void scaleAxis(boolean repaint) {
if (app.has(Feature.DIFFERENT_AXIS_RATIO_3D)) {
if (repaint) {
GPoint centeredMouse = new GPoint();
view3D.setCenteredPosition(mouseLoc, centeredMouse);
double distance = getDistanceForScale(centeredMouse.x,
centeredMouse.y);
// when mouse is close to origin
if (scaleDistanceInPixelsStart > 0) {
if (distance < MIN_MOUSE_MOVE_FOR_AXIS_SCALE) {
distance = MIN_MOUSE_MOVE_FOR_AXIS_SCALE;
}
} else {
if (distance > -MIN_MOUSE_MOVE_FOR_AXIS_SCALE) {
distance = -MIN_MOUSE_MOVE_FOR_AXIS_SCALE;
}
}
view3D.setCoordSystemFromAxisScale(
distance / scaleDistanceInPixelsStart, scaleOld,
moveMode);
}
}
}
@Override
public boolean penMode(int mode2) {
// no pen mode in 3D for now
return false;
}
@Override
protected void setCursorForTranslateView(Hits hits) {
view3D.setCursorForTranslateView(hits);
}
@Override
protected void setCursorForTranslateViewNoHit() {
view3D.setCursorForTranslateViewNoHit();
}
public void setViewRotationOccured(boolean flag) {
viewRotationOccured = flag;
}
public void setTimeOld(double time) {
timeOld = time;
}
public double getTimeOld() {
return timeOld;
}
public void setAnimatedRotSpeed(double speed) {
animatedRotSpeed = speed;
}
@Override
public EuclidianController3DCompanion getCompanion() {
createCompanionsIfNeeded();
return companion3D;
}
@Override
protected void createCompanionsIfNeeded() {
super.createCompanionsIfNeeded();
if (companion3D == null) {
companion3D = (EuclidianController3DCompanion) companion;
}
}
@Override
protected boolean modeTriggersUndoOnDragGeo(int mode2) {
switch (mode2) {
case EuclidianConstants.MODE_PYRAMID:
case EuclidianConstants.MODE_PRISM:
return pyramidBasis == null && selPolygons() == 0;
}
return super.modeTriggersUndoOnDragGeo(mode2);
}
}