package org.geogebra.common.main.settings;
import org.geogebra.common.awt.GFont;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.geogebra3D.euclidian3D.EuclidianView3D;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Feature;
import org.geogebra.common.plugin.EuclidianStyleConstants;
/**
* Settings for 3D view
*
* @author mathieu
*
*/
public class EuclidianSettings3D extends EuclidianSettings {
private double zscale;
private double zZero = EuclidianView3D.ZZERO_SCENE_STANDARD;
private double a = EuclidianView3D.ANGLE_ROT_OZ;
private double b = EuclidianView3D.ANGLE_ROT_XOY;// angles (in degrees)
public EuclidianSettings3D(App app) {
super(app);
setXscale(50);
setYscale(50);
setZscale(50);
xZero = EuclidianView3D.XZERO_SCENE_STANDARD;
yZero = EuclidianView3D.XZERO_SCENE_STANDARD;
}
private boolean hadSettingChanged = false;
/**
*
* @return true if some setting has been changed
*/
public boolean hadSettingChanged() {
return hadSettingChanged;
}
@Override
protected void settingChanged() {
super.settingChanged();
hadSettingChanged = true;
}
public void setZscale(double scale) {
if (this.zscale != scale) {
setZscaleValue(scale);
settingChanged();
}
}
public double getZscale() {
return zscale;
}
@Override
public void setXscaleValue(double scale) {
super.setXscaleValue(scale);
updateScaleHelpers();
}
@Override
public void setYscaleValue(double scale) {
super.setYscaleValue(scale);
updateScaleHelpers();
}
public void setZscaleValue(double scale) {
this.zscale = scale;
updateScaleHelpers();
}
private boolean hasSameScales = true;
private double xyScale, yzScale, zxScale, maxScale;
private void updateScaleHelpers() {
hasSameScales = true;
if (!Kernel.isEqual(xscale, yscale)) {
hasSameScales = false;
} else if (!Kernel.isEqual(xscale, zscale)) {
hasSameScales = false;
}
maxScale = xscale;
if (yscale > maxScale) {
maxScale = yscale;
}
if (zscale > maxScale) {
maxScale = zscale;
}
xyScale = xscale * yscale;
yzScale = yscale * zscale;
zxScale = zscale * xscale;
}
public double getMaxScale() {
return maxScale;
}
/**
*
* @return x scale * y scale
*/
public double getXYscale() {
return xyScale;
}
/**
*
* @return y scale * z scale
*/
public double getYZscale() {
return yzScale;
}
/**
*
* @return z scale * x scale
*/
public double getZXscale() {
return zxScale;
}
/**
*
* @return true if scales are equals on x,y,z
*/
public boolean hasSameScales() {
return hasSameScales;
}
public void setRotXYinDegrees(double a2, double b2) {
if (this.a != a2 || this.b != b2) {
this.a = a2;
this.b = b2;
settingChanged();
}
}
/**
* we won't call settingChanged() here since it's called from view
*
* @param a2
* @param b2
*/
public void setRotXYinDegreesFromView(double a2, double b2) {
this.a = a2;
this.b = b2;
}
public void updateRotXY(EuclidianView3D view) {
view.setRotXYinDegrees(a, b);
}
public void updateOrigin(double xZero2, double yZero2, double zZero2) {
if (this.xZero != xZero2 || this.yZero != yZero2
|| this.zZero != zZero2) {
this.xZero = xZero2;
this.yZero = yZero2;
this.zZero = zZero2;
settingChanged();
}
}
/**
* we won't call settingChanged() here since it's called from view
*
* @param xZero2
* @param yZero2
* @param zZero2
*/
public void updateOriginFromView(double xZero2, double yZero2,
double zZero2) {
this.xZero = xZero2;
this.yZero = yZero2;
this.zZero = zZero2;
}
public void updateOrigin(EuclidianView3D view) {
view.setXZero(getXZero());
view.setYZero(getYZero());
view.setZZero(getZZero());
}
public double getZZero() {
return zZero;
}
private boolean useClippingCube = false;
public void setUseClippingCube(boolean flag) {
if (useClippingCube != flag) {
useClippingCube = flag;
settingChanged();
}
}
public boolean useClippingCube() {
return useClippingCube;
}
private boolean showClippingCube = false;
public void setShowClippingCube(boolean flag) {
if (showClippingCube != flag) {
showClippingCube = flag;
settingChanged();
}
}
public boolean showClippingCube() {
return showClippingCube;
}
private int clippingReduction = 1;
public void setClippingReduction(int value) {
if (clippingReduction != value) {
clippingReduction = value;
settingChanged();
}
}
public int getClippingReduction() {
return clippingReduction;
}
private boolean showPlate = true;
public void setShowPlate(boolean flag) {
if (showPlate != flag) {
showPlate = flag;
settingChanged();
}
}
public boolean getShowPlate() {
return showPlate;
}
/**
* toggle visibility of the plane
*/
public void togglePlane() {
showPlate = !showPlate;
settingChanged();
}
private int projection;
public void setProjection(int projection) {
if (this.projection != projection) {
this.projection = projection;
settingChanged();
}
}
public int getProjection() {
return projection;
}
private int projectionPerspectiveEyeDistance = PROJECTION_PERSPECTIVE_EYE_DISTANCE_DEFAULT;
/**
* default value for eye distance to the screen for perspective
*/
public static final int PROJECTION_PERSPECTIVE_EYE_DISTANCE_DEFAULT = 2500;
/**
*
* @return eye distance to the screen for perspective
*/
public int getProjectionPerspectiveEyeDistance() {
return projectionPerspectiveEyeDistance;
}
/**
* set the near distance regarding eye distance to the screen for
* perspective (in pixels)
*
* @param distance
*/
public void setProjectionPerspectiveEyeDistance(int distance) {
if (projectionPerspectiveEyeDistance != distance) {
projectionPerspectiveEyeDistance = distance;
settingChanged();
}
}
public static final int EYE_SEP_DEFAULT = 200;
private int eyeSep = EYE_SEP_DEFAULT;
public void setEyeSep(int value) {
if (eyeSep != value) {
eyeSep = value;
settingChanged();
}
}
public int getEyeSep() {
return eyeSep;
}
public static final double PROJECTION_OBLIQUE_ANGLE_DEFAULT = 30;
public static final double PROJECTION_OBLIQUE_FACTOR_DEFAULT = 0.5;
private double projectionObliqueAngle = PROJECTION_OBLIQUE_ANGLE_DEFAULT;
private double projectionObliqueFactor = PROJECTION_OBLIQUE_FACTOR_DEFAULT;
public void setProjectionObliqueAngle(double value) {
if (projectionObliqueAngle != value) {
projectionObliqueAngle = value;
settingChanged();
}
}
public double getProjectionObliqueAngle() {
return projectionObliqueAngle;
}
public void setProjectionObliqueFactor(double value) {
if (projectionObliqueFactor != value) {
projectionObliqueFactor = value;
settingChanged();
}
}
public double getProjectionObliqueFactor() {
return projectionObliqueFactor;
}
private boolean yAxisVertical = false;
/**
*
* @return true if y axis is vertical (and not z axis)
*/
public boolean getYAxisVertical() {
return yAxisVertical;
}
public void setYAxisVertical(boolean flag) {
if (yAxisVertical != flag) {
yAxisVertical = flag;
settingChanged();
}
}
private boolean useLight = true;
private double rotSpeed;
public void setUseLight(boolean flag) {
if (useLight != flag) {
useLight = flag;
settingChanged();
}
}
public boolean getUseLight() {
return useLight;
}
@Override
public boolean is3D() {
return true;
}
@Override
protected void resetNoFire() {
super.resetNoFire();
xZero = EuclidianView3D.XZERO_SCENE_STANDARD;
yZero = EuclidianView3D.XZERO_SCENE_STANDARD;
zZero = EuclidianView3D.ZZERO_SCENE_STANDARD;
a = EuclidianView3D.ANGLE_ROT_OZ;
b = EuclidianView3D.ANGLE_ROT_XOY;
xscale = EuclidianView.SCALE_STANDARD;
yscale = EuclidianView.SCALE_STANDARD;
zscale = EuclidianView.SCALE_STANDARD;
maxScale = EuclidianView.SCALE_STANDARD;
yAxisVertical = false;
useLight = true;
clippingReduction = 1;
useClippingCube = false;
showClippingCube = false;
showPlate = true;
projection = 0;
eyeSep = EYE_SEP_DEFAULT;
projectionPerspectiveEyeDistance = PROJECTION_PERSPECTIVE_EYE_DISTANCE_DEFAULT;
projectionObliqueAngle = PROJECTION_OBLIQUE_ANGLE_DEFAULT;
projectionObliqueFactor = PROJECTION_OBLIQUE_FACTOR_DEFAULT;
}
/**
* set x, y, z scale, don't call settingsChanged()
*
* @param scale
* scale value
*/
public void setScaleNoCallToSettingsChanged(double scale) {
this.xscale = scale;
this.yscale = scale;
this.zscale = scale;
}
public void setRotSpeed(double d) {
this.rotSpeed = d;
}
public double getRotSpeed() {
return rotSpeed;
}
/**
* returns settings in XML format, read by xml handlers
*
* @return the XML description of 3D view settings
* @see org.geogebra.common.io.MyXMLHandler
* @see org.geogebra.common.geogebra3D.io.MyXMLHandler3D
*/
public void getXML(StringBuilder sb, boolean asPreference) {
// Application.debug("getXML: "+a+","+b);
// if (true) return "";
sb.append("<euclidianView3D>\n");
// coord system
sb.append("\t<coordSystem");
sb.append(" xZero=\"");
sb.append(getXZero());
sb.append("\"");
sb.append(" yZero=\"");
sb.append(getYZero());
sb.append("\"");
sb.append(" zZero=\"");
sb.append(getZZero());
sb.append("\"");
sb.append(" scale=\"");
sb.append(getXscale());
sb.append("\"");
if (app.has(Feature.DIFFERENT_AXIS_RATIO_3D) && !hasSameScales()) {
sb.append(" yscale=\"");
sb.append(getYscale());
sb.append("\"");
sb.append(" zscale=\"");
sb.append(getZscale());
sb.append("\"");
}
sb.append(" xAngle=\"");
sb.append(b);
sb.append("\"");
sb.append(" zAngle=\"");
sb.append(a);
sb.append("\"");
sb.append("/>\n");
// ev settings
sb.append("\t<evSettings axes=\"");
sb.append(getShowAxis(0) || getShowAxis(1) || getShowAxis(2));
sb.append("\" grid=\"");
sb.append(getShowGrid());
sb.append("\" gridIsBold=\""); //
sb.append(gridIsBold); // Michael Borcherds 2008-04-11
sb.append("\" pointCapturing=\"");
// make sure POINT_CAPTURING_STICKY_POINTS isn't written to XML
sb.append(
getPointCapturingMode() > EuclidianStyleConstants.POINT_CAPTURING_XML_MAX
? EuclidianStyleConstants.POINT_CAPTURING_DEFAULT
: getPointCapturingMode());
sb.append("\" rightAngleStyle=\"");
sb.append(app.rightAngleStyle);
// if (asPreference) {
// sb.append("\" allowShowMouseCoords=\"");
// sb.append(getAllowShowMouseCoords());
//
// sb.append("\" allowToolTips=\"");
// sb.append(getAllowToolTips());
//
// sb.append("\" deleteToolSize=\"");
// sb.append(getEuclidianController().getDeleteToolSize());
// }
// sb.append("\" checkboxSize=\"");
// sb.append(app.getCheckboxSize()); // Michael Borcherds
// 2008-05-12
sb.append("\" gridType=\"");
sb.append(getGridType()); // cartesian/isometric/polar
// if (lockedAxesRatio != null) {
// sb.append("\" lockedAxesRatio=\"");
// sb.append(lockedAxesRatio);
// }
sb.append("\"/>\n");
// end ev settings
// axis settings
for (int i = 0; i < 3; i++) {
addAxisXML(i, sb);
}
// xOy plane settings
sb.append("\t<plate show=\"");
sb.append(showPlate);
sb.append("\"/>\n");
//
// sb.append("\t<grid show=\"");
// sb.append(getxOyPlane().isGridVisible());
// sb.append("\"/>\n");
// background color
sb.append("\t<bgColor r=\"");
sb.append(backgroundColor.getRed());
sb.append("\" g=\"");
sb.append(backgroundColor.getGreen());
sb.append("\" b=\"");
sb.append(backgroundColor.getBlue());
sb.append("\"/>\n");
// y axis is up
if (getYAxisVertical()) {
sb.append("\t<yAxisVertical val=\"true\"/>\n");
}
// use light
if (!getUseLight()) {
sb.append("\t<light val=\"false\"/>\n");
}
// clipping cube
sb.append("\t<clipping use=\"");
sb.append(useClippingCube());
sb.append("\" show=\"");
sb.append(showClippingCube());
sb.append("\" size=\"");
sb.append(getClippingReduction());
sb.append("\"/>\n");
// projection
sb.append("\t<projection type=\"");
sb.append(getProjection());
getXMLForStereo(sb);
if (!Kernel.isEqual(projectionObliqueAngle,
EuclidianSettings3D.PROJECTION_OBLIQUE_ANGLE_DEFAULT)) {
sb.append("\" obliqueAngle=\"");
sb.append(projectionObliqueAngle);
}
if (!Kernel.isEqual(projectionObliqueFactor,
EuclidianSettings3D.PROJECTION_OBLIQUE_FACTOR_DEFAULT)) {
sb.append("\" obliqueFactor=\"");
sb.append(projectionObliqueFactor);
}
sb.append("\"/>\n");
// axes label style
int style = getAxisFontStyle();
if (style == GFont.BOLD || style == GFont.ITALIC
|| style == GFont.BOLD + GFont.ITALIC) {
sb.append("\t<labelStyle axes=\"");
sb.append(style);
sb.append("\"/>\n");
}
// end
sb.append("</euclidianView3D>\n");
}
private void getXMLForStereo(StringBuilder sb) {
int eyeDistance = projectionPerspectiveEyeDistance;
if (eyeDistance != EuclidianSettings3D.PROJECTION_PERSPECTIVE_EYE_DISTANCE_DEFAULT) {
sb.append("\" distance=\"");
sb.append(eyeDistance);
}
int sep = getEyeSep();
if (sep != EuclidianSettings3D.EYE_SEP_DEFAULT) {
sb.append("\" separation=\"");
sb.append(sep);
}
}
}