package org.geogebra.common.geogebra3D.kernel3D.geos; import org.geogebra.common.euclidianForPlane.EuclidianViewForPlaneCompanionInterface; import org.geogebra.common.geogebra3D.kernel3D.transform.MirrorableAtPlane; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.Matrix.CoordMatrix4x4; import org.geogebra.common.kernel.Matrix.CoordSys; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.kernel.arithmetic.ValueType; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.kernelND.GeoConicND; 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.GeoLineND; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.kernel.kernelND.GeoSegmentND; import org.geogebra.common.kernel.kernelND.RotateableND; import org.geogebra.common.kernel.kernelND.ViewCreator; import org.geogebra.common.plugin.GeoClass; /** * @author ggb3D * */ public class GeoConic3D extends GeoConicND implements RotateableND, MirrorableAtPlane, ViewCreator { /** 2D coord sys where the conic exists */ private CoordSys coordSys; /** * Creates an empty 3D conic with 2D coord sys * * @param c * construction * @param cs * 2D coord sys */ public GeoConic3D(Construction c, CoordSys cs) { this(c); setCoordSys(cs); } /** * Copy constructor * * @param conic * original */ public GeoConic3D(GeoConicND conic) { this(conic.getConstruction()); set(conic); } /** * Creates an empty 3D conic with 2D coord sys * * @param c * construction */ public GeoConic3D(Construction c) { this(c, false); } /** * * @param c * construction * @param isIntersection * if this is an intersection curve */ public GeoConic3D(Construction c, boolean isIntersection) { super(c, 2, isIntersection); } @Override protected void createFields(int dimension) { midpoint3D = Coords.createInhomCoorsInD3(); super.createFields(dimension); } // /////////////////////////////////////// // link with the 2D coord sys /** * set the 2D coordinate system * * @param cs * the 2D coordinate system */ public void setCoordSys(CoordSys cs) { // Application.printStacktrace(cs.getMatrixOrthonormal().toString()); this.coordSys = cs; } @Override public CoordSys getCoordSys() { return coordSys; } /* * private Coords midpoint2D; * * /** sets the coords of the 2D midpoint * * @param coords * * public void setMidpoint2D(Coords coords){ midpoint2D=coords; } * * public Coords getMidpoint2D(){ return midpoint2D; } */ @Override public Coords getMainDirection() { return coordSys.getNormal(); } // /////////////////////////////////////// // GeoConicND /* * public Coords getMidpoint2D(){ return * coordSys.getPoint(super.getMidpoint2D()); * * } */ @Override public Coords getEigenvec3D(int i) { return coordSys.getVector(super.getEigenvec(i)); } @Override public Coords getMidpointND() { return getMidpoint3D(); } private Coords midpoint3D; @Override public Coords getMidpoint3D() { return coordSys.getPoint(super.getMidpoint2D(), midpoint3D); } @Override public Coords getDirection3D(int i) { return getCoordSys().getVector(lines[i].y, -lines[i].x); } @Override public Coords getOrigin3D(int i) { return getCoordSys().getPoint(startPoints[i].x, startPoints[i].y); } // /////////////////////////////////////// // GeoConic3D @Override public GeoClass getGeoClassType() { return GeoClass.CONIC3D; } /** * it's a 3D GeoElement. * * @return true */ @Override public boolean isGeoElement3D() { return true; } @Override public boolean hasFillType() { return false; } @Override public String toString(StringTemplate tpl) { StringBuilder sbToString = new StringBuilder(); switch (getType()) { case CONIC_CIRCLE: case CONIC_ELLIPSE: case CONIC_HYPERBOLA: case CONIC_PARABOLA: sbToString.setLength(0); sbToString.append(label); sbToString.append(": "); // GeoFunction.initStringBuilder(sbToString, tpl, label, "t", // isLabelSet(), false); break; default: sbToString.setLength(0); sbToString.append(label); sbToString.append(": "); break; } sbToString.append(buildValueString(tpl)); return sbToString.toString(); } @Override public boolean hasValueStringChangeableRegardingView() { return true; } @Override protected StringBuilder buildValueString(StringTemplate tpl) { return buildParametricValueString(tpl, 3); } @Override public void setSphereND(GeoPointND M, GeoSegmentND segment) { // TODO Auto-generated method stub } @Override public void setSphereND(GeoPointND M, GeoPointND P) { // TODO Auto-generated method stub } /** * set the conic as single point equal to m * * @param m * point */ public void setSinglePoint(GeoPointND m) { // coordSys.setSimpleCoordSysWithOrigin(m.getInhomCoordsInD3()); // set midpoint as projection of m on the current coord sys setMidpoint( coordSys.getNormalProjection(m.getInhomCoordsInD3())[1].get()); setSinglePointMatrix(); singlePoint(); } /** * set the conic as single point equal to coords * * @param coords * point */ public void setSinglePoint(Coords coords) { coordSys.setSimpleCoordSysWithOrigin(coords); // set midpoint as projection of m on the current coord sys setMidpoint(0, 0); setSinglePointMatrix(); singlePoint(); } private void setSinglePointMatrix() { for (int i = 0; i < matrix.length; i++) { matrix[i] = 0; } for (int i = 0; i < 3; i++) { matrix[i] = 1.0d; } } /** * set this to sigle point at m location * * @param conic * conic which will be single point * @param m * point */ static final public void setSinglePoint(GeoConic3D conic, Coords m) { CoordSys cs = conic.getCoordSys(); if (cs == null) { cs = new CoordSys(2); conic.setCoordSys(cs); } cs.resetCoordSys(); cs.addPoint(m); cs.completeCoordSys2D(); cs.makeOrthoMatrix(false, false); conic.setMidpoint(new double[] { 0, 0 }); conic.setSinglePointMatrix(); conic.singlePoint(); } @Override public GeoElement copy() { return new GeoConic3D(this); } /* * protected String getTypeString() { switch (type) { case * GeoConic.CONIC_CIRCLE: return "Circle"; default: return "Conic3D"; } * * * } */ @Override public boolean isEqual(GeoElementND Geo) { // TODO Auto-generated method stub return false; } @Override public void set(GeoElementND geo) { if (geo instanceof GeoConicND) { super.set(geo); if (coordSys == null) { coordSys = new CoordSys(2); } coordSys.set(((GeoConicND) geo).getCoordSys()); setIsEndOfQuadric(((GeoConicND) geo).isEndOfQuadric()); } } // ////////////////////////////////// // XML // ////////////////////////////////// /** * returns all class-specific xml tags for saveXML */ @Override protected void getXMLtags(StringBuilder sb) { if (getCoordSys() != null && isIndependent()) { Coords v0 = getCoordSys().getV(0); Coords v1 = getCoordSys().getV(1); Coords origin = getCoordSys().getOrigin(); sb.append("\t<coords ox=\""); sb.append(origin.get(1)); sb.append("\" oy=\""); sb.append(origin.get(2)); sb.append("\" oz=\""); sb.append(origin.get(3)); sb.append("\" ow=\""); sb.append(origin.get(4)); sb.append("\" vx=\""); sb.append(v0.get(1)); sb.append("\" vy=\""); sb.append(v0.get(2)); sb.append("\" vz=\""); sb.append(v0.get(3)); sb.append("\" wx=\""); sb.append(v1.get(1)); sb.append("\" wy=\""); sb.append(v1.get(2)); sb.append("\" wz=\""); sb.append(v1.get(3)); sb.append("\"/>\n"); } // curve thickness and type printed by conicND super.getXMLtags(sb); } // ////////////////////////////////// // GeoCoordSys2D // ////////////////////////////////// @Override public Coords getPoint(double x2d, double y2d, Coords coords) { return getCoordSys().getPoint(x2d, y2d, coords); } @Override public Coords[] getNormalProjection(Coords coords) { return getCoordSys().getNormalProjection(coords); } /** * @param coords * projected point * @param willingDirection * direction of projection * @return projected point */ public Coords[] getProjection(Coords coords, Coords willingDirection) { Coords[] result = new Coords[] { new Coords(4), new Coords(4) }; coords.projectPlaneThruV(getCoordSys().getMatrixOrthonormal(), willingDirection, result[0], result[1]); return result; } // ////////////////////////////////// // GeoCoordSys2D // ////////////////////////////////// /** * * @return true if is an intersection curve */ public boolean isIntersection() { return isIntersection; } @Override protected void doTranslate(Coords v) { coordSys.translate(v); } @Override public void matrixTransform(double a00, double a01, double a10, double a11) { if (tmpMatrix4x4 == null) { tmpMatrix4x4 = CoordMatrix4x4.Identity(); } else { tmpMatrix4x4.set(1, 3, 0); tmpMatrix4x4.set(1, 4, 0); tmpMatrix4x4.set(2, 3, 0); tmpMatrix4x4.set(2, 4, 0); tmpMatrix4x4.set(3, 1, 0); tmpMatrix4x4.set(3, 2, 0); tmpMatrix4x4.set(3, 3, 0); tmpMatrix4x4.set(3, 4, 0); tmpMatrix4x4.set(4, 1, 0); tmpMatrix4x4.set(4, 2, 0); tmpMatrix4x4.set(4, 3, 0); tmpMatrix4x4.set(4, 4, 1); } tmpMatrix4x4.set(1, 1, a00); tmpMatrix4x4.set(1, 2, a01); tmpMatrix4x4.set(2, 1, a10); tmpMatrix4x4.set(2, 2, a11); double[] ret = getCoordSys().matrixTransform(tmpMatrix4x4); super.matrixTransform(ret[0], ret[1], 0, ret[2]); } private CoordMatrix4x4 tmpMatrix4x4; @Override public void matrixTransform(double a00, double a01, double a02, double a10, double a11, double a12, double a20, double a21, double a22) { if (tmpMatrix4x4 == null) { tmpMatrix4x4 = CoordMatrix4x4.Identity(); } else { tmpMatrix4x4.set(1, 4, 0); tmpMatrix4x4.set(2, 4, 0); tmpMatrix4x4.set(3, 4, 0); tmpMatrix4x4.set(4, 1, 0); tmpMatrix4x4.set(4, 2, 0); tmpMatrix4x4.set(4, 3, 0); tmpMatrix4x4.set(4, 4, 1); } tmpMatrix4x4.set(1, 1, a00); tmpMatrix4x4.set(1, 2, a01); tmpMatrix4x4.set(1, 3, a02); tmpMatrix4x4.set(2, 1, a10); tmpMatrix4x4.set(2, 2, a11); tmpMatrix4x4.set(2, 3, a12); tmpMatrix4x4.set(3, 1, a20); tmpMatrix4x4.set(3, 2, a21); tmpMatrix4x4.set(3, 3, a22); double[] ret = getCoordSys().matrixTransform(tmpMatrix4x4); super.matrixTransform(ret[0], ret[1], 0, ret[2]); } @Override final public void rotate(NumberValue phiVal) { coordSys.rotate(phiVal.getDouble(), Coords.O); } @Override final public void rotate(NumberValue phiVal, GeoPointND Q) { coordSys.rotate(phiVal.getDouble(), Q.getInhomCoordsInD3()); } @Override public void rotate(NumberValue phiVal, GeoPointND Q, GeoDirectionND orientation) { rotate(phiVal, Q.getInhomCoordsInD3(), orientation.getDirectionInD3()); } @Override public void rotate(NumberValue phiVal, GeoLineND line) { rotate(phiVal, line.getStartInhomCoords(), line.getDirectionInD3()); } final private void rotate(NumberValue phiVal, Coords center, Coords direction) { coordSys.rotate(phiVal.getDouble(), center, direction.normalized()); } @Override public Coords getDirectionInD3() { switch (type) { case CONIC_LINE: case CONIC_EMPTY: case CONIC_SINGLE_POINT: return null; default: return getCoordSys().getVz(); } } // //////////////////////////////////////////// // TRANSLATE // //////////////////////////////////////////// @Override public void translate(Coords v) { getCoordSys().translate(v); } // ////////////////////// // MIRROR // ////////////////////// @Override public void mirror(Coords Q) { getCoordSys().mirror(Q); } @Override public void mirror(GeoLineND line) { Coords point = line.getStartInhomCoords(); Coords direction = line.getDirectionInD3().normalized(); getCoordSys().mirror(point, direction); } @Override public void mirror(GeoCoordSys2D plane) { getCoordSys().mirror(plane.getCoordSys()); } // ////////////////////// // DILATE // ////////////////////// @Override public void dilate(NumberValue rval, Coords S) { double r = rval.getDouble(); getCoordSys().dilate(r, S); if (r < 0) { // mirror was done in coord sys r = -r; } dilate(r); } // //////////////////////////////// // 2D VIEW private EuclidianViewForPlaneCompanionInterface euclidianViewForPlane; @Override public int getViewID() { return euclidianViewForPlane.getId(); } @Override public void createView2D() { euclidianViewForPlane = kernel.getApplication().getCompanion() .createEuclidianViewForPlane(this, true); euclidianViewForPlane.setTransformRegardingView(); } @Override public void removeView2D() { euclidianViewForPlane.doRemove(); } @Override public void doRemove() { if (euclidianViewForPlane != null) { removeView2D(); } super.doRemove(); } @Override public boolean hasView2DVisible() { return euclidianViewForPlane != null && kernel.getApplication() .getGuiManager().showView(euclidianViewForPlane.getId()); } @Override public void setView2DVisible(boolean flag) { if (euclidianViewForPlane == null) { if (flag) { createView2D(); } return; } kernel.getApplication().getGuiManager().setShowView(flag, euclidianViewForPlane.getId()); } @Override public void update(boolean drag) { super.update(drag); if (euclidianViewForPlane != null) { euclidianViewForPlane.updateMatrix(); updateViewForPlane(); } } private void updateViewForPlane() { euclidianViewForPlane.updateAllDrawables(true); } @Override public void setEuclidianViewForPlane( EuclidianViewForPlaneCompanionInterface view) { euclidianViewForPlane = view; } @Override public boolean isParametric() { return true; } @Override public ValueType getValueType() { return ValueType.PARAMETRIC3D; } @Override public void evaluateFirstDerivativeForParabola(double t, double[] result) { Coords eigenvec0 = getEigenvec(0); Coords eigenvec1 = getEigenvec(1); double x = p * (t * eigenvec0.getX() + eigenvec1.getX()); double y = p * (t * eigenvec0.getY() + eigenvec1.getY()); result[0] = x * coordSys.getVx().getX() + y * coordSys.getVy().getX(); result[1] = x * coordSys.getVx().getY() + y * coordSys.getVy().getY(); result[2] = x * coordSys.getVx().getZ() + y * coordSys.getVy().getZ(); } @Override public void evaluateSecondDerivativeForParabola(double t, double[] result) { Coords eigenvec0 = getEigenvec(0); double x = p * eigenvec0.getX(); double y = p * eigenvec0.getY(); result[0] = x * coordSys.getVx().getX() + y * coordSys.getVy().getX(); result[1] = x * coordSys.getVx().getY() + y * coordSys.getVy().getY(); result[2] = x * coordSys.getVx().getZ() + y * coordSys.getVy().getZ(); } @Override public boolean isRegion3D() { return true; } }