package org.geogebra.common.euclidian;
import java.util.ArrayList;
import org.geogebra.common.awt.GAffineTransform;
import org.geogebra.common.awt.GDimension;
import org.geogebra.common.awt.GGraphics2D;
import org.geogebra.common.euclidian.draw.DrawAngle;
import org.geogebra.common.euclidian.event.PointerEventType;
import org.geogebra.common.kernel.ModeSetter;
import org.geogebra.common.kernel.Matrix.CoordMatrix;
import org.geogebra.common.kernel.Matrix.CoordSys;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.geos.GeoAngle;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.kernelND.GeoConicND;
import org.geogebra.common.kernel.kernelND.GeoDirectionND;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPlaneND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.main.settings.AbstractSettings;
import org.geogebra.common.main.settings.EuclidianSettings;
/**
*
* @author mathieu
*
* view companion for methods that have to cross desktop/web
*
*/
public class EuclidianViewCompanion {
/** the view */
protected EuclidianView view;
/**
* constructor
*
* @param view
* view attached
*/
public EuclidianViewCompanion(EuclidianView view) {
setView(view);
}
/**
* @param view
* euclidian view
*/
protected void setView(EuclidianView view) {
this.view = view;
}
/**
*
* @return view attached
*/
public EuclidianView getView() {
return view;
}
/**
* Updates xmin, xmax, ... for updateSize()
*/
public void setXYMinMaxForUpdateSize() {
view.setXYMinMaxForSetCoordSystem();
}
/**
*
* @param geo
* angle
* @return drawable for this angle
*/
protected DrawAngle newDrawAngle(GeoAngle geo) {
return new DrawAngle(view, geo);
}
/**
* @return whether this is EV1/EV2 rather than view for plane
*/
public boolean isDefault2D() {
return true;
}
/**
* @param geo
* geo
* @return true if geo is visible in this view
*/
public boolean isVisibleInThisView(GeoElementND geo) {
return geo.isVisibleInView(view.getViewID());
}
/**
* tranform in view coords
*
* @param coords
* point
* @return the same coords for classic 2d view
*/
public Coords getCoordsForView(Coords coords) {
return coords;
}
/**
* return null if classic 2D view
*
* @return matrix representation of the plane shown by this view
*/
public CoordMatrix getMatrix() {
return null;
}
/**
* return null if classic 2D view
*
* @return matrix inverse representation of the plane shown by this view
*/
public CoordMatrix getInverseMatrix() {
return null;
}
/**
*
* @return string description of plane from the view was created
*/
public String getFromPlaneString() {
return "xOyPlane";
}
/**
*
* @return string translated description of plane from the view was created
*/
public String getTranslatedFromPlaneString() {
return view.getApplication().getLocalization().getMenu("xOyPlane");
}
/**
*
* @return null (for 2D) and xOyPlane (for 3D)
*/
public GeoPlaneND getPlaneContaining() {
return view.kernel.getDefaultPlane();
}
/**
*
* @return null (for 2D) and xOyPlane (for 3D)
*/
public GeoDirectionND getDirection() {
return getPlaneContaining();
}
/**
*
* @param v
* vector
* @return true if v is oriented to z+ direction
*/
public boolean goToZPlus(Coords v) {
return v.getZ() > 0;
}
/**
* @param geo
* element
* @return true if the element can be moved freely in this view
*/
public boolean isMoveable(GeoElement geo) {
return geo.isMoveable();
}
/**
* @param algo
* algorithm
* @return free input points of given algorithm
*/
public ArrayList<GeoPointND> getFreeInputPoints(AlgoElement algo) {
return algo.getFreeInputPoints();
}
/**
* add id to xml
*
* @param sbxml
* xml
*/
public void getXMLid(StringBuilder sbxml) {
if (view.evNo >= 2) {
getXMLidNoCheck(sbxml);
}
}
/**
* add id to xml
*
* @param sbxml
* xml
*/
protected void getXMLidNoCheck(StringBuilder sbxml) {
sbxml.append("\t<viewNumber ");
sbxml.append("viewNo=\"");
sbxml.append(view.evNo);
sbxml.append("\"");
sbxml.append("/>\n");
}
/**
* returns settings in XML format
*
* @param sbxml
* string builder
* @param asPreference
* true for preferences
*/
public void getXML(StringBuilder sbxml, boolean asPreference) {
view.startXML(sbxml, asPreference);
view.endXML(sbxml);
}
/**
* @param settings
* settings
*/
public void settingsChanged(AbstractSettings settings) {
EuclidianSettings evs = (EuclidianSettings) settings;
int viewDim = view.getDimension();
view.getKernel().getConstruction().setIgnoringNewTypes(true);
view.setXminObject(evs.getXminObject());
view.setXmaxObject(evs.getXmaxObject());
view.setYminObject(evs.getYminObject());
view.setYmaxObject(evs.getYmaxObject());
view.getKernel().getConstruction().setIgnoringNewTypes(false);
view.setBackground(evs.getBackground());
view.setAxesColor(evs.getAxesColor());
view.setGridColor(evs.getGridColor());
view.setAxesLineStyle(evs.getAxesLineStyle());
view.setGridLineStyle(evs.getGridLineStyle());
double[] d = evs.getGridDistances();
if (!evs.getAutomaticGridDistance() && (d == null)) {
view.setAutomaticGridDistance(false);
} else if (d == null) {
view.setAutomaticGridDistance(true);
} else {
view.setGridDistances(d);
}
for (int i = 0; i < viewDim; i++) {
view.setShowAxis(i, evs.getShowAxis(i), true);
}
String[] tempAxesLabels = evs.getAxesLabels();
// make sure <b>, <i> processed
for (int i = 0; i < viewDim; i++) {
view.setAxisLabel(i, tempAxesLabels[i]);
}
view.setAxesUnitLabels(evs.getAxesUnitLabels());
view.showAxesNumbers = evs.getShowAxisNumbers();
// might be Double.NaN, handled in setAxesNumberingDistance()
for (int i = 0; i < viewDim; i++) {
if (!evs.getAutomaticAxesNumberingDistance(i)
&& isNaN(evs.getAxisNumberingDistance(i))) {
view.setAutomaticAxesNumberingDistance(false, i);
} else {
view.setAxesNumberingDistance(evs.getAxisNumberingDistance(i),
i);
}
}
for (int i = 0; i < viewDim; i++) {
view.axesTickStyles[i] = evs.getAxesTickStyles()[i];
}
view.setDrawBorderAxes(evs.getDrawBorderAxes());
for (int i = 0; i < viewDim; i++) {
view.axisCross[i] = evs.getAxesCross()[i];
view.positiveAxes[i] = evs.getPositiveAxes()[i];
}
GDimension ps = evs.getPreferredSize();
if (ps != null) {
view.setPreferredSize(ps);
}
view.showGrid(evs.getShowGrid());
view.setGridIsBold(evs.getGridIsBold());
view.setGridType(evs.getGridType());
view.pointCapturingMode = evs.getPointCapturingMode();
view.setAllowShowMouseCoords(evs.getAllowShowMouseCoords());
view.setAllowToolTips(evs.getAllowToolTips());
view.synchronizeMenuBarAndEuclidianStyleBar(evs);
if (!evs.hasDynamicBounds()) {
// the xmin, xmax, ... we read from Settings are nulls;
// use the double values instead
double x0 = evs.getXZero();
double y0 = evs.getYZero();
if (view.getKeepCenter() && view.isShowing()) {
// we may need to shift center if windows/settings sizes
// don't match
int w = view.getWidth();
int h = view.getHeight();
if (w > EuclidianView.MIN_WIDTH
&& h > EuclidianView.MIN_HEIGHT) {
int sw = evs.getWidth();
int sh = evs.getHeight();
// Log.debug("x0:" + x0 + ", y0:" + y0 + ", " + sw + "x"
// + sh + ", view: " + w + "x" + h);
if (sw == 0) {
// no dimension from file: center the view
sw = (int) Math.round(x0 * 2);
sh = (int) Math.round(y0 * 2);
}
x0 += (w - sw) / 2.0;
y0 += (h - sh) / 2.0;
evs.setSize(w, h);
evs.setOriginNoUpdate(x0, y0);
}
// Log.debug(">> x0:" + x0 + ", y0:" + y0);
}
view.setCoordSystem(x0, y0, evs.getXscale(), evs.getYscale(), true);
evs.setXminObject(view.xminObject, false);
evs.setXmaxObject(view.xmaxObject, false);
evs.setYminObject(view.yminObject, false);
evs.setYmaxObject(view.ymaxObject, false);
} else {
// xmin, ... are OK; just update bounds
view.updateBounds(true, true);
}
// let's do this after other updates because this might override e.g.
// xmin
view.setLockedAxesRatio(evs.getLockedAxesRatio());
}
private static boolean isNaN(GeoNumberValue axisNumberingDistance) {
return axisNumberingDistance == null
|| Double.isNaN(axisNumberingDistance.getDouble());
}
/**
* Paints content of this view.
*
* @param g2
* graphics
*/
public void paint(GGraphics2D g2) {
view.paintTheBackground(g2);
g2.setAntialiasing();
// draw equations, checkboxes and all geo objects
view.drawObjects(g2);
if (view.selectionRectangle != null) {
view.drawZoomRectangle(g2);
}
// draw bounding box
if (view.getBoundingBox() != null) {
view.getBoundingBox().draw(g2);
}
// draw shape preview for shape tools
if (view.getShapeRectangle() != null) {
view.drawShape(g2, view.getShapeFillCol(), view.getShapeObjCol(),
view.getShapeStroke(),
view.getShapeRectangle());
}
if (view.getShapeEllipse() != null) {
view.drawShape(g2, view.getShapeFillCol(), view.getShapeObjCol(),
view.getShapeStroke(), view.getShapeEllipse());
}
if (view.getShapeLine() != null) {
view.drawShape(g2, view.getShapeFillCol(), view.getShapeObjCol(),
view.getShapeStroke(), view.getShapeLine());
}
if (view.getShapePolygon() != null) {
view.drawShape(g2, view.getShapeFillCol(), view.getShapeObjCol(),
view.getShapeStroke(),
view.getShapePolygon());
}
if (view.deletionRectangle != null) {
view.drawRect(g2, EuclidianView.colDeletionSquare,
EuclidianView.strokeDeletionSquare, view.deletionRectangle);
}
if (view.allowShowMouseCoords && view.showMouseCoords
&& (view.showAxes[0] || view.showAxes[1] || view.showGrid)) {
view.drawMouseCoords(g2);
}
if (view.showAxesRatio) {
view.drawAxesRatio(g2);
}
if (view.kernel.needToShowAnimationButton()) {
view.drawAnimationButtons(g2);
}
}
/**
* Attach this view to kernel and add all objects created so far
*/
public void attachView() {
view.kernel.notifyAddAll(view);
view.kernel.attach(view);
}
/**
* @param show
* true to show grid
* @return whether the setting changed
*/
public boolean showGrid(boolean show) {
if (show == view.showGrid) {
return false;
}
view.showGrid = show;
view.updateBackgroundImage();
return true;
}
/**
* @param geo
* geo
* @return new drawable for given geo
*/
public DrawableND newDrawable(GeoElement geo) {
return EuclidianDraw.newDrawable(view, geo);
}
/**
* Returns transform from eigenvector space to screen coords
*
* @param conic
* conic
* @param M
* conic's midpoint
* @param ev
* eigenvectors
* @return affine transform of the conic for this view
*/
public GAffineTransform getTransform(GeoConicND conic, Coords M,
Coords[] ev) {
return conic.getAffineTransform();
}
/**
* tranform point coords in view coords
*
* @param point
* point
* @return point coords in view coords
*/
public Coords getCoordsForView(GeoPointND point) {
return point.getInhomCoords();
}
/**
* Size changed, make sure our settings reflect that but do not update
* drawables
*/
protected void updateSizeKeepDrawables() {
view.updateSizeKeepDrawables();
}
/**
* @param sys
* coord system
* @return whether the coord system is in the plane of this view
*/
public boolean isInPlane(CoordSys sys) {
return sys.getEquationVector()
.isEqual(CoordSys.Identity3D.getEquationVector());
}
/**
* @param xRW
* real world x-coord
* @param yRW
* real world y-coord
* @param tmpCoordsL3
* target coordinates
*/
public void getCoordsFromView(double xRW, double yRW, Coords tmpCoordsL3) {
tmpCoordsL3.setX(xRW);
tmpCoordsL3.setY(yRW);
tmpCoordsL3.setZ(0);
}
/**
* set hits for current mouse loc
*
* @param type
* event type
*/
public void setHits(PointerEventType type) {
view.setHits(view.getEuclidianController().getMouseLoc(), type);
}
/**
* @return whether mouse is hovering over this view
*/
public boolean hasMouse() {
return view.hasMouse2D();
}
/**
* @param mode
* mode
* @param m
* mode setting event type
*/
public void setMode(int mode, ModeSetter m) {
// used for some input3D
}
}