/*
This file is part of GeoGebra.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation.
*/
package org.geogebra.common.export.pstricks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.geogebra.common.awt.GAffineTransform;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.awt.GFont;
import org.geogebra.common.awt.GPathIterator;
import org.geogebra.common.awt.GShape;
import org.geogebra.common.euclidian.DrawableND;
import org.geogebra.common.euclidian.draw.DrawPoint;
import org.geogebra.common.export.UnicodeTeX;
import org.geogebra.common.factories.AwtFactory;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.MyPoint;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoAngleLines;
import org.geogebra.common.kernel.algos.AlgoAnglePoints;
import org.geogebra.common.kernel.algos.AlgoAngleVector;
import org.geogebra.common.kernel.algos.AlgoAngleVectors;
import org.geogebra.common.kernel.algos.AlgoBoxPlot;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.algos.AlgoFunctionAreaSums;
import org.geogebra.common.kernel.algos.AlgoSlope;
import org.geogebra.common.kernel.arithmetic.ExpressionNodeConstants.StringType;
import org.geogebra.common.kernel.arithmetic.Function;
import org.geogebra.common.kernel.arithmetic.FunctionalNVar;
import org.geogebra.common.kernel.arithmetic.Inequality;
import org.geogebra.common.kernel.cas.AlgoIntegralDefinite;
import org.geogebra.common.kernel.cas.AlgoIntegralFunctions;
import org.geogebra.common.kernel.geos.GeoAngle;
import org.geogebra.common.kernel.geos.GeoAngle.AngleStyle;
import org.geogebra.common.kernel.geos.GeoConic;
import org.geogebra.common.kernel.geos.GeoConicPart;
import org.geogebra.common.kernel.geos.GeoCurveCartesian;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoElement.FillType;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoLocus;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.geos.GeoPolyLine;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.geos.GeoRay;
import org.geogebra.common.kernel.geos.GeoSegment;
import org.geogebra.common.kernel.geos.GeoText;
import org.geogebra.common.kernel.geos.GeoTransferFunction;
import org.geogebra.common.kernel.geos.GeoVec3D;
import org.geogebra.common.kernel.geos.GeoVector;
import org.geogebra.common.kernel.implicit.GeoImplicit;
import org.geogebra.common.kernel.kernelND.GeoConicND;
import org.geogebra.common.kernel.kernelND.GeoConicNDConstants;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.kernelND.GeoVectorND;
import org.geogebra.common.main.App;
import org.geogebra.common.plugin.EuclidianStyleConstants;
import org.geogebra.common.util.StringTokenizer;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.debug.Log;
import org.geogebra.common.util.lang.Unicode;
/*
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject; */
/**
* @author Andy Zhu
*/
public abstract class GeoGebraToAsymptote extends GeoGebraExport {
// Use euro symbol, compact code and cse5 code, respectively; and
// black-and-white vs color
private boolean eurosym = false, compact = false, compactcse5 = false,
grayscale = false, dotColors = false,
// refer to pairs by a name
pairName = false;
// Indexes number of parabolas and hyperbolas and arcs and functions
private int parabolaCount = 0, // number of functions used by parabolas
hyperbolaCount = 0, // number of functions used by hyperbolas
arcCount = 0, // number of arcs drawn
functionCount = 0, // number of functions drawn
implicitFuncCount = 0, // number of implicit functions drawn
fillType = 0, // FILL_OPACITY, etc
fontsize; // font size
// Code for beginning of picture, for points, for Colors, and for background
// fill
private StringBuilder codeBeginPic, codePointDecl, codeColors, codeEndDoc;
// Contains list of points
private ArrayList<GeoPoint> pointList;
// Maps unicode expressions to text equivalents
private Map<String, String> pairNameTable;
// Maps function return expressions to function #
private Map<String, Integer> implicitPolyTable;
// use the following packages for Asymptote and LaTeX commands
// importContour = false, importMath = false, importGraph = false,
// usepackage_amssymb = false, usepackage_amsmath = false,
// usepackage_mathrsfs = false;
private Set<String> usepackage;
/** packages to import */
public Set<String> importpackage;
/** whether to fill inequality */
public boolean fillInequality = false;
/**
* @param app
* application
*/
public GeoGebraToAsymptote(final App app) {
super(app);
}
/**
* generateAllCode: generate Asymptote output by assembling snippets and
* sanitizing
*/
@Override
public void generateAllCode() {
// reset global variables
parabolaCount = 0;
hyperbolaCount = 0;
arcCount = 0;
functionCount = 0;
implicitFuncCount = 0;
fillType = 0;
/*
* importContour = false; importMath = false; importGraph = false;
* usepackage_amssymb = false; usepackage_amsmath = false;
* usepackage_mathrsfs = false;
*/
usepackage = new TreeSet<String>();
importpackage = new TreeSet<String>();
pointList = new ArrayList<GeoPoint>(); // list of pairs, for cse5
pairNameTable = new HashMap<String, String>(); // map of coordinates ->
// point's name
implicitPolyTable = new HashMap<String, Integer>(); // function(x,y)
// return value to
// function #
customColor = new HashMap<GColor, String>(); // map
// of
// rgb
// ->
// alphabet
// pen
// names
// retrieve flags from frame
format = frame.getFormat();
compact = frame.getAsyCompact() || frame.getAsyCompactCse5();
compactcse5 = frame.getAsyCompactCse5();
fillType = frame.getFillType();
fontsize = frame.getFontSize();
grayscale = frame.isGrayscale();
pairName = frame.getUsePairNames();
dotColors = frame.getKeepDotColors();
// initialize unit variables, scale ratio = yunit/xunit;
try {
xunit = frame.getXUnit();
yunit = frame.getYUnit();
} catch (NullPointerException e2) {
xunit = 1;
yunit = 1;
}
// initialize new StringBuilders for Asymptote code
// overall output
code = new StringBuilder();
// beginning statements/comments
codePreamble = new StringBuilder();
// beginning statements/comments
codeBeginPic = new StringBuilder();
// definition of pairs, for cse5 mode
codePointDecl = new StringBuilder();
// pens corresponding to certain rgb values
codeColors = new StringBuilder();
// dots and labels
codePoint = new StringBuilder();
// all major geometric constructions
codeFilledObject = new StringBuilder();
// axes, grid, and so forth
codeBeginPic = new StringBuilder();
// ending code, odds and ends
codeEndDoc = new StringBuilder();
// generate point list
if (pairName) {
for (int step = 0; step < construction.steps(); step++) {
GeoElementND[] geos = construction.getConstructionElement(step)
.getGeoElements();
for (int j = 0; j < geos.length; j++) {
GeoElementND g = geos[j];
if (g.isEuclidianVisible() && g.isGeoPoint()) {
pointList.add((GeoPoint) g);
}
}
}
}
// In cse5, initialize pair definitions.
initPointDeclarations();
// get all objects from construction and "draw" by creating Asymptote
// code
// **Run this before generating other code in case it causes other
// changes
// such as which packages should be imported.**
drawAllElements();
// Write preamble. If compact option unchecked, include liberal
// documentation.
if (!compact) {
codePreamble.append(" /* Geogebra to Asymptote conversion, ");
// userscripts.org/scripts/show/72997
codePreamble.append(
"documentation at artofproblemsolving.com/Wiki, go to User:Azjps/geogebra */\n");
}
importpackage.add("graph");
for (String s : importpackage) {
codePreamble.append("import " + s + "; ");
}
for (String s : usepackage) {
codePreamble.append("usepackage(\"" + s + "\"); ");
}
/*
* if (usepackage_amssymb) codePreamble.append(
* "usepackage(\"amssymb\"); "); if (usepackage_amsmath)
* codePreamble.append("usepackage(\"amsmath\"); "); if (importContour)
* codePreamble.append("import contour; "); if (importMath)
* codePreamble.append("import math; ");
*/
codePreamble.append("size(" + format(frame.getLatexWidth()) + "cm); ");
initUnitAndVariable();
// Draw grid
if (euclidianView.getShowGrid() && frame.getShowAxes()) {
drawGrid();
}
// Draw axis
if ((euclidianView.getShowXaxis() || euclidianView.getShowYaxis())
&& frame.getShowAxes()) {
drawAxis();
}
// Clip frame
codeEndDoc.append(
"\nclip((xmin,ymin)--(xmin,ymax)--(xmax,ymax)--(xmax,ymin)--cycle); ");
// Background color
if (!euclidianView.getBackgroundCommon().equals(GColor.WHITE)) {
if (!compact) {
codeEndDoc.append("\n");
}
codeEndDoc.append("shipout(bbox(");
colorCode(euclidianView.getBackgroundCommon(), codeEndDoc);
codeEndDoc.append(",Fill)); ");
}
// Re-scale
if (format(yunit).compareTo(format(xunit)) != 0) {
if (!compact) {
codeEndDoc.append("\n /* re-scale y/x */\n");
}
packSpaceBetween(codeEndDoc, "currentpicture", "=",
"yscale(" + format(yunit / xunit) + ")", "*",
"currentpicture; ");
}
if (!compact) {
codeEndDoc.append("\n /* end of picture */");
}
// add code for Points and Labels
code.append("\n");
if (!compact) {
code.append(" /* dots and labels */");
}
code.append(codePoint);
/*
* String formatFont=resizeFont(app.getFontSize()); if
* (null!=formatFont){ codeBeginPic.insert(0,formatFont+"\n");
* code.append("}\n"); }
*/// Order: TODO
// Preamble, Colors, Points, Fills, Pic, Objects, regular code,
// EndDoc
if (!compact) {
code.insert(0, " /* draw figures */");
}
code.insert(0, "\n");
code.insert(0, codeBeginPic);
code.insert(0, codeFilledObject);
if (codeFilledObject.length() != 0) {
code.insert(0, "\n");
}
code.insert(0, codePointDecl);
if (!compact) {
code.insert(0, codeColors);
} else if (codeColors.length() != 0) {
code.insert(0, "\npen" + codeColors.substring(1) + "; ");
}
code.insert(0, codePreamble);
code.append(codeEndDoc); // clip frame, background fill, re-scaling
// code to temporarily remove pi from code, other unicode issues
convertUnicodeToText(code);
frame.write(code);
}
@Override
protected void drawLocus(GeoLocus geo) {
ArrayList<MyPoint> ll = geo.getPoints();
Iterator<MyPoint> it = ll.iterator();
boolean first = true, first2 = true; // whether to write join operators
// afterwards
if (!compact) {
code.append(" /* locus construction */\n");
}
startDraw();
while (it.hasNext()) {
MyPoint mp = it.next();
if (mp.x > xmin && mp.x < xmax && mp.y > ymin && mp.y < ymax) {
String x = format(mp.x), y = format(mp.y);
if (first && first2) {
code.append("(");
first = false;
first2 = false;
} else if (first) { // don't draw connecting line
code.append("^^(");
first = false;
} else if (mp.getLineTo()) {
code.append("--(");
} else {
code.append("^^(");
}
code.append(x + "," + y + ")");
} else {
first = true;
}
}
endDraw(geo);
}
@Override
protected void drawBoxPlot(GeoNumeric geo) {
AlgoBoxPlot algo = ((AlgoBoxPlot) geo.getParentAlgorithm());
double y = algo.getA().getDouble();
double height = algo.getB().getDouble();
double[] lf = algo.getLeftBorders();
double min = lf[0];
double q1 = lf[1];
double med = lf[2];
double q3 = lf[3];
double max = lf[4];
// Min vertical bar
drawLine(min, y - height, min, y + height, geo);
// Max vertical bar
drawLine(max, y - height, max, y + height, geo);
// Med vertical bar
drawLine(med, y - height, med, y + height, geo);
// Min-q1 horizontal
drawLine(min, y, q1, y, geo);
// q3-max
drawLine(q3, y, max, y, geo);
// Rectangle q1-q3
startTransparentFill(codeFilledObject);
codeFilledObject.append("box(");
addPoint(format(q1), format(y - height), codeFilledObject);
codeFilledObject.append(",");
addPoint(format(q3), format(y + height), codeFilledObject);
codeFilledObject.append(")");
endTransparentFill(geo, codeFilledObject);
}
@Override
protected void drawHistogramOrBarChartBox(double[] y, double[] x,
int length, double width, GeoNumeric g) {
String command = g.getDefinition(StringTemplate.noLocalDefault);
if (command.contains("Binomial") && command.contains("true")) {
startTransparentFill(codeFilledObject);
codeFilledObject.append("(" + format(x[0] + width / 2));
codeFilledObject.append(",0) -- (");
codeFilledObject.append(format(x[0] + width / 2));
codeFilledObject.append(",");
codeFilledObject.append(format(y[0]) + ")");
endTransparentFill(g, codeFilledObject);
for (int i = 0; i < length - 1; i++) {
startTransparentFill(codeFilledObject);
codeFilledObject.append("(" + format(x[i] + width / 2));
codeFilledObject.append("," + format(y[i]) + ") -- (");
codeFilledObject.append(format(x[i + 1] + width / 2));
codeFilledObject.append(",");
codeFilledObject.append(format(y[i]) + ")");
endTransparentFill(g, codeFilledObject);
startTransparentFill(codeFilledObject);
codeFilledObject.append("(" + format(x[i + 1] + width / 2));
codeFilledObject.append("," + format(y[i]) + ") -- (");
codeFilledObject.append(format(x[i + 1] + width / 2));
codeFilledObject.append(",");
codeFilledObject.append(format(y[i + 1]) + ")");
endTransparentFill(g, codeFilledObject);
}
} else {
for (int i = 0; i < length; i++) {
barNumber = i + 1;
startTransparentFill(codeFilledObject);
codeFilledObject.append("box((");
codeFilledObject.append(format(x[i]));
codeFilledObject.append(",0),(");
if (x.length == length) {
codeFilledObject.append(format(x[i] + width));
} else {
codeFilledObject.append(format(x[i + 1]));
}
codeFilledObject.append(",");
codeFilledObject.append(format(y[i]));
codeFilledObject.append("))");
endTransparentFill(g, codeFilledObject);
}
}
}
@Override
protected void drawSumTrapezoidal(GeoNumeric geo) {
AlgoFunctionAreaSums algo = (AlgoFunctionAreaSums) geo
.getParentAlgorithm();
int n = algo.getIntervals();
double[] y = algo.getValues();
double[] x = algo.getLeftBorder();
for (int i = 0; i < n; i++) {
startTransparentFill(codeFilledObject);
codeFilledObject.append("(");
codeFilledObject.append(format(x[i]));
codeFilledObject.append(",0)--(");
codeFilledObject.append(format(x[i + 1]));
codeFilledObject.append(",0)--(");
codeFilledObject.append(format(x[i + 1]));
codeFilledObject.append(",");
codeFilledObject.append(format(y[i + 1]));
codeFilledObject.append(")--(");
codeFilledObject.append(format(x[i]));
codeFilledObject.append(",");
codeFilledObject.append(format(y[i]));
codeFilledObject.append(")--cycle");
endTransparentFill(geo, codeFilledObject);
}
}
@Override
protected void drawSumUpperLower(GeoNumeric geo) {
AlgoFunctionAreaSums algo = (AlgoFunctionAreaSums) geo
.getParentAlgorithm();
int n = algo.getIntervals();
double step = algo.getStep();
double[] y = algo.getValues();
double[] x = algo.getLeftBorder();
for (int i = 0; i < n; i++) {
startTransparentFill(codeFilledObject);
codeFilledObject.append("box((");
codeFilledObject.append(format(x[i]));
codeFilledObject.append(",0),(");
codeFilledObject.append(format(x[i] + step));
codeFilledObject.append(",");
codeFilledObject.append(format(y[i]));
codeFilledObject.append("))");
endTransparentFill(geo, codeFilledObject);
}
}
@Override
protected void drawIntegralFunctions(GeoNumeric geo) {
importpackage.add("graph");
AlgoIntegralFunctions algo = (AlgoIntegralFunctions) geo
.getParentAlgorithm();
GeoFunction f = algo.getF(), // function f
g = algo.getG(); // function g
// double a and b
double a = algo.getA().getDouble(), b = algo.getB().getDouble();
// String output for a and b
String sa = format(a), sb = format(b);
// String Expression of f and g
String valueF = f.toValueString(getStringTemplate()),
valueG = g.toValueString(getStringTemplate());
valueF = parseFunction(valueF);
valueG = parseFunction(valueG);
// String expressions for f(a) and g(b)
// String fa = format(f.evaluate(a));
// String gb = format(g.evaluate(b));
if (!compact) {
codeFilledObject.append("\n");
}
// write functions for f and g if they do not already exist.
int indexFunc = -1;
String tempFunctionCountF = "f" + Integer.toString(functionCount + 1);
String returnCode = "(real x){return " + valueF + ";} ";
// search for previous occurrences of function
// TODO Hashtable rewrite?
if (compact) {
indexFunc = codeFilledObject.indexOf(returnCode);
if (indexFunc != -1) {
// retrieve name of previously used function
int indexFuncStart = codeFilledObject.lastIndexOf(" ",
indexFunc);
tempFunctionCountF = codeFilledObject
.substring(indexFuncStart + 1, indexFunc);
}
}
// write function
if (indexFunc == -1) {
functionCount++;
packSpaceBetween(codeFilledObject, "real f" + functionCount,
"(real x)", "{", "return " + valueF + ";", "} ");
}
indexFunc = -1;
String tempFunctionCountG = "f" + Integer.toString(functionCount + 1);
returnCode = "(real x){return " + valueG + ";} ";
// search for previous occurrences of function
if (compact) {
indexFunc = codeFilledObject.indexOf(returnCode);
if (indexFunc != -1) {
// retrieve name of previously used function
int indexFuncStart = codeFilledObject.lastIndexOf(" ",
indexFunc);
tempFunctionCountG = codeFilledObject
.substring(indexFuncStart + 1, indexFunc);
}
} // write function
if (indexFunc == -1) {
functionCount++;
packSpaceBetween(codeFilledObject, "real f" + functionCount,
"(real x)", "{", "return " + valueG + ";", "} ");
}
// draw graphs of f and g
startTransparentFill(codeFilledObject);
packSpaceBetween(codeFilledObject, "graph(" + tempFunctionCountF + ",",
sa + ",", sb + ")", "--", "graph(" + tempFunctionCountG + ",",
sb + ",", sa + ")", "--cycle");
endTransparentFill(geo, codeFilledObject);
}
@Override
protected void drawIntegral(GeoNumeric geo) {
importpackage.add("graph");
AlgoIntegralDefinite algo = (AlgoIntegralDefinite) geo
.getParentAlgorithm();
GeoFunction f = algo.getFunction(); // function f between a and b
String a = format(algo.getA().getDouble());
String b = format(algo.getB().getDouble());
if (algo.getA().getDouble() == Double.NEGATIVE_INFINITY) {
a = format(xmin);
}
if (algo.getB().getDouble() == Double.POSITIVE_INFINITY) {
b = format(xmax);
}
String value = f.toValueString(getStringTemplate());
value = parseFunction(value);
if (!isLatexFunction(f.toValueString(StringTemplate.noLocalDefault))) {
double af = xmin;
double bf = xmax;
if (f.hasInterval()) {
af = f.getIntervalMin();
bf = f.getIntervalMax();
}
f.setInterval(algo.getA().getDouble(), algo.getB().getDouble());
drawFunction(f, true, geo, true);
drawFunction(f, true, geo, false);
f.setInterval(af, bf);
if (f.isEuclidianVisible()) {
drawFunction(f, false, geo, false);
}
} else {
int indexFunc = -1;
String tempFunctionCount = "f"
+ Integer.toString(functionCount + 1);
String returnCode = "(real x){return (" + value + ");} ";
// search for previous occurrences of function
if (compact) {
indexFunc = codeFilledObject.indexOf(returnCode);
if (indexFunc != -1) {
// retrieve name of previously used function
int indexFuncStart = codeFilledObject.lastIndexOf(" ",
indexFunc);
tempFunctionCount = codeFilledObject
.substring(indexFuncStart + 1, indexFunc);
}
} // write function
if (indexFunc == -1) {
functionCount++;
if (!compact) {
codeFilledObject.append("\n");
}
codeFilledObject.append("real f");
codeFilledObject.append(functionCount);
packSpace(codeFilledObject, "(real x)");
codeFilledObject.append("{return ");
codeFilledObject.append(value);
codeFilledObject.append(";} ");
}
startTransparentFill(codeFilledObject);
codeFilledObject.append("graph(");
codeFilledObject.append(tempFunctionCount);
codeFilledObject.append(",");
codeFilledObject.append(a);
codeFilledObject.append(",");
codeFilledObject.append(b);
codeFilledObject.append(")--");
addPoint(b, "0", codeFilledObject);
codeFilledObject.append("--");
addPoint(a, "0", codeFilledObject);
codeFilledObject.append("--cycle");
endTransparentFill(geo, codeFilledObject);
}
}
@Override
protected void drawSlope(GeoNumeric geo) { // TODO: label bug?
int slopeTriangleSize = geo.getSlopeTriangleSize();
double rwHeight = geo.getValue() * slopeTriangleSize;
double height = euclidianView.getYscale() * rwHeight;
double[] coords = new double[2];
if (Math.abs(height) > Float.MAX_VALUE) {
return;
}
// get point on line g
((AlgoSlope) geo.getParentAlgorithm()).getInhomPointOnLine(coords);
// draw slope triangle
double x = coords[0];
double y = coords[1];
double xright = x + slopeTriangleSize;
startTransparentFill(codeFilledObject);
addPoint(format(x), format(y), codeFilledObject);
codeFilledObject.append("--");
addPoint(format(xright), format(y), codeFilledObject);
codeFilledObject.append("--");
addPoint(format(xright), format(y + rwHeight), codeFilledObject);
codeFilledObject.append("--cycle");
endTransparentFill(geo, codeFilledObject);
// draw Label
double xLabelHor = (x + xright) / 2;
double yLabelHor = y - ((euclidianView.getFont().getSize() + 2)
/ euclidianView.getYscale());
GColor geocolor = geo.getObjectColor();
if (!compact) {
codePoint.append("\n");
}
packSpaceAfter(codePoint, "label(\"$" + slopeTriangleSize + "$\",",
"(" + format(xLabelHor) + ",", format(yLabelHor) + "),", "NE",
"*");
if (compact) {
codePoint.append("lsf");
} else {
codePoint.append("labelscalefactor");
}
if (!geocolor.equals(GColor.BLACK)) {
codePoint.append(",");
colorCode(geocolor, codePoint);
}
codePoint.append("); ");
}
@Override
protected void drawAngle(GeoAngle geo) {
int arcSize = geo.getArcSize();
AlgoElement algo = geo.getParentAlgorithm();
GeoPointND vertex, point;
GeoVectorND v;
GeoPoint tempPoint = new GeoPoint(construction);
tempPoint.setCoords(0.0, 0.0, 1.0);
double[] firstVec = new double[2];
double[] m = new double[2];
// angle defines with three points
if (algo instanceof AlgoAnglePoints) {
AlgoAnglePoints pa = (AlgoAnglePoints) algo;
vertex = pa.getB();
point = pa.getA();
vertex.getInhomCoords(m);
// first vec
Coords coords = point.getInhomCoordsInD3();
firstVec[0] = coords.getX() - m[0];
firstVec[1] = coords.getY() - m[1];
}
// angle between two vectors
else if (algo instanceof AlgoAngleVectors) {
AlgoAngleVectors va = (AlgoAngleVectors) algo;
v = va.getv();
// vertex
vertex = v.getStartPoint();
if (vertex == null) {
vertex = tempPoint;
}
vertex.getInhomCoords(m);
// first vec
v.getInhomCoords(firstVec);
}
// angle between two lines
else if (algo instanceof AlgoAngleLines) {
AlgoAngleLines la = (AlgoAngleLines) algo;
vertex = tempPoint;
la.updateDrawInfo(m, firstVec, null);
}
// angle of a single vector or a single point
else if (algo instanceof AlgoAngleVector) {
AlgoAngleVector va = (AlgoAngleVector) algo;
GeoVec3D vec = va.getVec3D();
if (vec instanceof GeoVector) {
v = (GeoVector) vec;
// vertex
vertex = v.getStartPoint();
if (vertex == null) {
vertex = tempPoint;
}
vertex.getInhomCoords(m);
} else if (vec instanceof GeoPoint) {
vertex = tempPoint;
// vertex
vertex.getInhomCoords(m);
}
firstVec[0] = 1;
firstVec[1] = 0;
}
tempPoint.remove(); // Michael Borcherds 2008-08-20
double angSt = Math.atan2(firstVec[1], firstVec[0]);
// Michael Borcherds 2007-10-21 BEGIN
// double angExt = geo.getValue();
double angExt = geo.getRawAngle();
if (angExt > Math.PI * 2) {
angExt -= Math.PI * 2;
}
// if (geo.getAngleStyle() == GeoAngle.ANGLE_ISCLOCKWISE) {
// angSt += angExt;
// angExt = 2.0*Math.PI-angExt;
// }
if (geo.getAngleStyle() == AngleStyle.NOTREFLEX) {
if (angExt > Math.PI) {
angSt += angExt;
angExt = 2.0 * Math.PI - angExt;
}
}
if (geo.getAngleStyle() == AngleStyle.ISREFLEX) {
if (angExt < Math.PI) {
angSt += angExt;
angExt = 2.0 * Math.PI - angExt;
}
}
// if (geo.changedReflexAngle()) {
// angSt = angSt - angExt;
// }
// Michael Borcherds 2007-10-21 END
angExt += angSt;
double r = arcSize / euclidianView.getXscale();
// StringBuilder tempsb = new StringBuilder();
startTransparentFill(codeFilledObject);
// if right angle and decoration is a little square
if (Kernel.isEqual(geo.getValue(), Kernel.PI_HALF)
&& geo.isEmphasizeRightAngle() && euclidianView
.getRightAngleStyle() == EuclidianStyleConstants.RIGHT_ANGLE_STYLE_SQUARE) {
r = r / Math.sqrt(2);
double[] x = new double[8];
x[0] = m[0] + r * Math.cos(angSt);
x[1] = m[1] + r * Math.sin(angSt);
x[2] = m[0]
+ r * Math.sqrt(2) * Math.cos(angSt + Kernel.PI_HALF / 2);
x[3] = m[1]
+ r * Math.sqrt(2) * Math.sin(angSt + Kernel.PI_HALF / 2);
x[4] = m[0] + r * Math.cos(angSt + Kernel.PI_HALF);
x[5] = m[1] + r * Math.sin(angSt + Kernel.PI_HALF);
x[6] = m[0];
x[7] = m[1];
for (int i = 0; i < 4; i++) {
addPoint(format(x[2 * i]), format(x[2 * i + 1]),
codeFilledObject);
codeFilledObject.append("--");
}
codeFilledObject.append("cycle");
// transparent fill options
endTransparentFill(geo, codeFilledObject);
} else { // draw arc for the angle.
codeFilledObject.append("arc(");
addPoint(format(m[0]), format(m[1]), codeFilledObject);
codeFilledObject.append(",");
codeFilledObject.append(format(r));
codeFilledObject.append(",");
codeFilledObject.append(format(Math.toDegrees(angSt)));
codeFilledObject.append(",");
codeFilledObject.append(format(Math.toDegrees(angExt)));
codeFilledObject.append(")--(");
codeFilledObject.append(format(m[0]));
codeFilledObject.append(",");
codeFilledObject.append(format(m[1]));
codeFilledObject.append(")--cycle");
// transparent fill options
endTransparentFill(geo, codeFilledObject);
// draw the [circular?] dot if right angle and decoration is dot
if (Kernel.isEqual(geo.getValue(), Kernel.PI_HALF)
&& geo.isEmphasizeRightAngle() && euclidianView
.getRightAngleStyle() == EuclidianStyleConstants.RIGHT_ANGLE_STYLE_DOT) {
double diameter = geo.getLineThickness()
/ euclidianView.getXscale();
double radius = arcSize / euclidianView.getXscale() / 1.7;
double labelAngle = (angSt + angExt) / 2.0;
double x1 = m[0] + radius * Math.cos(labelAngle);
double x2 = m[1] + radius * Math.sin(labelAngle);
startDraw();
if (compactcse5) {
code.append("CR(");
} else {
code.append("circle(");
}
addPoint(format(x1), format(x2), code);
code.append(",");
code.append(format(diameter));
code.append(")");
endDraw(geo);
}
if (geo.getDecorationType() != GeoElement.DECORATION_NONE) {
markAngle(geo, r, m, angSt, angExt);
}
}
}
@Override
protected void drawArrowArc(GeoAngle geo, double[] vertex, double angSt,
double angEnd0, double r, boolean anticlockwise) {
// The arrow head goes away from the line.
// Arrow Winset=0.25, see PStricks spec for arrows
double arrowHeight = (geo.getLineThickness() * 0.8 + 3) * 1.4 * 3 / 4;
double angle = Math
.asin(arrowHeight / 2 / euclidianView.getXscale() / r);
double angEnd = angEnd0 - angle;
startDraw();
code.append("arc(");
addPoint(format(vertex[0]), format(vertex[1]), code);
code.append(",");
code.append(format(r));
code.append(",");
code.append(format(Math.toDegrees(angSt)));
code.append(",");
code.append(format(Math.toDegrees(angEnd)));
code.append(")");
if (lineOptionCode(geo, true) != null) {
packSpaceAfter(code, ",");
code.append(lineOptionCode(geo, true));
} // TODO: resize?
if (anticlockwise) {
code.append(",EndArcArrow(6)");
} else {
code.append(",BeginArcArrow(6)");
}
code.append("); ");
}
// angSt, angEnd in degrees. r = radius.
@Override
protected void drawArc(GeoAngle geo, double[] vertex, double angSt,
double angEnd, double r) {
startDraw();
code.append("arc(");
addPoint(format(vertex[0]), format(vertex[1]), code);
code.append(",");
code.append(format(r));
code.append(",");
code.append(format(Math.toDegrees(angSt)));
code.append(",");
code.append(format(Math.toDegrees(angEnd)));
code.append(")");
endDraw(geo);
}
@Override
protected void drawTick(GeoAngle geo, double[] vertex, double angle0) {
double cos = Math.cos(angle0);
double sin = Math.sin(-angle0);
double radius = geo.getArcSize();
double diff = 2.5 + geo.getLineThickness() / 4d;
double x1 = euclidianView.toRealWorldCoordX(
vertex[0] + (radius - diff) * cos);
double x2 = euclidianView.toRealWorldCoordX(
vertex[0] + (radius + diff) * cos);
double y1 = euclidianView.toRealWorldCoordY(vertex[1] + (radius - diff)
* sin * euclidianView.getScaleRatio());
double y2 = euclidianView.toRealWorldCoordY(vertex[1] + (radius + diff)
* sin * euclidianView.getScaleRatio());
startDraw();
addPoint(format(x1), format(y1), code);
code.append("--");
addPoint(format(x2), format(y2), code);
endDraw(geo);
}
@Override
protected void drawSlider(GeoNumeric geo) {
boolean horizontal = geo.isSliderHorizontal();
double max = geo.getIntervalMax();
double min = geo.getIntervalMin();
double value = geo.getValue();
double width = geo.getSliderWidth();
double x = geo.getSliderX();
double y = geo.getSliderY();
// start point of horizontal line for slider
if (geo.isAbsoluteScreenLocActive()) {
x = euclidianView.toRealWorldCoordX(x);
y = euclidianView.toRealWorldCoordY(y);
width = horizontal ? width / euclidianView.getXscale()
: width / euclidianView.getYscale();
}
// create point for slider
GeoPoint geoPoint = new GeoPoint(construction);
geoPoint.setObjColor(geo.getObjectColor());
String label = StringUtil.toLaTeXString(geo.getLabelDescription(),
true);
geoPoint.setLabel(label);
double param = (value - min) / (max - min);
geoPoint.setPointSize(2 + (geo.getLineThickness() + 1) / 3);
geoPoint.setLabelVisible(geo.isLabelVisible());
if (horizontal) {
geoPoint.setCoords(x + width * param, y, 1.0);
} else {
geoPoint.setCoords(x, y + width * param, 1.0);
}
DrawPoint drawPoint = new DrawPoint(euclidianView, geoPoint);
drawPoint.setGeoElement(geo);
if (geo.isLabelVisible()) {
if (horizontal) {
drawPoint.xLabel -= 15;
drawPoint.yLabel -= 5;
} else {
drawPoint.xLabel += 5;
drawPoint.yLabel += 2 * geoPoint.getPointSize() + 4;
}
}
drawGeoPoint(geoPoint);
drawLabel(geoPoint, drawPoint);
geoPoint.remove(); // Michael Borcherds 2008-08-20
// draw Line for Slider
startDraw();
addPoint(format(x), format(y), code);
code.append("--");
if (horizontal) {
x += width;
} else {
y += width;
}
addPoint(format(x), format(y), code);
endDraw(geo);
}
@Override
protected void drawPolygon(GeoPolygon geo) {
GeoPointND[] points = geo.getPoints();
// StringBuilder tempsb = new StringBuilder();
startTransparentFill(codeFilledObject);
for (int i = 0; i < points.length; i++) {
Coords coords = points[i].getCoordsInD2();
double x = coords.getX(), y = coords.getY(), z = coords.getZ();
x = x / z;
y = y / z;
addPoint(format(x), format(y), codeFilledObject);
codeFilledObject.append("--");
}
codeFilledObject.append("cycle");
endTransparentFill(geo, codeFilledObject);
}
@Override
protected void drawText(GeoText geo) {
boolean isLatex = geo.isLaTeX();
String st = geo.getTextString();
if (isLatex) {
st = StringUtil.toLaTeXString(st, true);
}
// try to replace euro symbol
if (st.indexOf("\u20ac") != -1) {
st = st.replace("\\u20ac", "\\\\euro{}");
if (!eurosym) {
codePreamble.append("usepackage(\"eurosym\"); ");
}
}
GColor geocolor = geo.getObjectColor();
int style = geo.getFontStyle();
int size = (int) (geo.getFontSizeMultiplier() * getApp().getFontSize());
GeoPoint gp;
double x, y;
// compute location of text
if (geo.isAbsoluteScreenLocActive()) {
x = geo.getAbsoluteScreenLocX();
y = geo.getAbsoluteScreenLocY();
} else {
gp = (GeoPoint) geo.getStartPoint();
if (gp == null) {
x = (int) euclidianView.getXZero();
y = (int) euclidianView.getYZero();
} else {
if (!gp.isDefined()) {
return;
}
x = euclidianView.toScreenCoordX(gp.inhomX);
y = euclidianView.toScreenCoordY(gp.inhomY);
}
x += geo.labelOffsetX;
y += geo.labelOffsetY;
}
x = euclidianView.toRealWorldCoordX(x);
y = euclidianView
.toRealWorldCoordY(y - euclidianView.getFont().getSize());
int id = st.indexOf("\n");
boolean comma = false;
// One line
if (id == -1 || isLatex) {
if (!compact) {
code.append("\n");
}
code.append("label(\"");
addText(st, isLatex, style);
code.append("\",");
addPoint(format(x), format(y), code);
code.append(",SE*");
if (compact) {
code.append("lsf");
} else {
code.append("labelscalefactor");
}
if (!geocolor.equals(GColor.BLACK)) { // color
code.append(",");
comma = true;
colorCode(geocolor, code);
}
if (size != getApp().getFontSize()) { // fontsize
if (!comma) {
code.append(",");
} else {
packSpace(code, "+");
}
code.append("fontsize(");
code.append(fontsize + (size - getApp().getFontSize()));
code.append(")");
} else if (compactcse5) { // use default font pen for cse5
if (!comma) {
code.append(",");
} else {
packSpace(code, "+");
}
code.append("fp");
}
code.append("); ");
}
// MultiLine
else {
StringBuilder sb = new StringBuilder();
StringTokenizer stk = new StringTokenizer(st, "\n");
int width = 0;
GFont font = AwtFactory.getPrototype().newFont(
geo.isSerifFont() ? "Serif" : "SansSerif", style, size);
while (stk.hasMoreTokens()) {
String line = stk.nextToken();
width = Math.max(width, (int) Math.ceil(
StringUtil.getPrototype().estimateLength(line, font)));
sb.append(line);
if (stk.hasMoreTokens()) {
sb.append(" \\\\ ");
}
}
if (!compact) {
code.append("\n");
}
code.append("label(\"$");
code.append("\\parbox{");
code.append(format(
width * (xmax - xmin) * xunit / euclidianView.getWidth()
+ 1));
code.append(" cm}{");
addText(sb.toString(), isLatex, style);
code.append("}$\",");
addPoint(format(x), format(y), code);
code.append(",SE*");
if (compact) {
code.append("lsf");
} else {
code.append("labelscalefactor");
}
if (!geocolor.equals(GColor.BLACK)) { // color
code.append(",");
comma = true;
colorCode(geocolor, code);
}
if (size != getApp().getFontSize()) { // fontsize
if (!comma) {
code.append(",");
} else {
packSpace(code, "+");
}
code.append("fontsize(");
code.append(fontsize + (size - getApp().getFontSize()));
code.append(")");
} else if (compactcse5) { // use default font pen for cse5
if (!comma) {
code.append(",");
} else {
packSpace(code, "+");
}
code.append("fp");
}
code.append("); ");
}
}
@Override
protected void drawGeoConicPart(GeoConicPart geo) {
StringBuilder tempsb = new StringBuilder();
double r1 = geo.getHalfAxes()[0], r2 = geo.getHalfAxes()[1];
double startAngle = geo.getParameterStart();
double endAngle = geo.getParameterEnd();
// Get all coefficients form the transform matrix
GAffineTransform af = geo.getAffineTransform();
double m11 = af.getScaleX();
double m22 = af.getScaleY();
double m12 = af.getShearX();
double m21 = af.getShearY();
double tx = af.getTranslateX();
double ty = af.getTranslateY();
if (startAngle > endAngle) {
startAngle -= Math.PI * 2;
}
// Fill if: SECTOR and fill type not set to FILL_NONE
if (m11 == 1 && m22 == 1 && m12 == 0 && m21 == 0) {
if (geo.getConicPartType() == GeoConicNDConstants.CONIC_PART_SECTOR
&& fillType != ExportSettings.FILL_NONE) {
startTransparentFill(tempsb);
} else {
startDraw(tempsb);
}
tempsb.append("shift(");
addPoint(format(tx), format(ty), tempsb);
tempsb.append(")*xscale(");
tempsb.append(format(r1));
tempsb.append(")*yscale(");
tempsb.append(format(r2));
tempsb.append(")*arc((0,0),1,");
tempsb.append(format(Math.toDegrees(startAngle)));
tempsb.append(",");
tempsb.append(format(Math.toDegrees(endAngle)));
tempsb.append(")");
} else {
StringBuilder sb1 = new StringBuilder(), sb2 = new StringBuilder();
sb1.append(format(r1));
sb1.append("*cos(t)");
sb2.append(format(r2));
sb2.append("*sin(t)");
arcCount++;
if (!compact) {
tempsb.append("\n");
}
tempsb.append("pair arc");
tempsb.append(arcCount);
packSpace(tempsb, "(real t)");
tempsb.append("{return (");
tempsb.append(format(m11));
tempsb.append("*");
tempsb.append(sb1);
tempsb.append("+");
tempsb.append(format(m12));
tempsb.append("*");
tempsb.append(sb2);
tempsb.append("+");
tempsb.append(format(tx));
tempsb.append(",");
tempsb.append(format(m21));
tempsb.append("*");
tempsb.append(sb1);
tempsb.append("+");
tempsb.append(format(m22));
tempsb.append("*");
tempsb.append(sb2);
tempsb.append("+");
tempsb.append(format(ty));
tempsb.append(");} ");
if (geo.getConicPartType() == GeoConicNDConstants.CONIC_PART_SECTOR
&& fillType != ExportSettings.FILL_NONE) {
startTransparentFill(tempsb);
} else {
startDraw(tempsb);
}
tempsb.append("graph(arc");
tempsb.append(arcCount);
tempsb.append(",");
tempsb.append(format(startAngle));
tempsb.append(",");
tempsb.append(format(endAngle));
tempsb.append(")");
}
if (geo.getConicPartType() == GeoConicNDConstants.CONIC_PART_SECTOR) {
tempsb.append("--");
addPoint(format(tx), format(ty), tempsb);
tempsb.append("--cycle");
if (fillType == ExportSettings.FILL_NONE) {
endDraw(geo, tempsb);
} else {
endTransparentFill(geo, tempsb);
}
} else {
endDraw(geo, tempsb);
}
if (geo.getConicPartType() == GeoConicNDConstants.CONIC_PART_SECTOR
&& fillType != ExportSettings.FILL_NONE) {
codeFilledObject.append(tempsb);
} else {
code.append(tempsb);
}
}
@Override
protected void drawSingleCurveCartesian(GeoCurveCartesian geo,
boolean trasparency) {
importpackage.add("graph");
double start = geo.getMinParameter(), end = geo.getMaxParameter();
// boolean isClosed=geo.isClosedPath();
String fx = parseFunction(geo.getFunX(getStringTemplate()));
String fy = parseFunction(geo.getFunY(getStringTemplate()));
String variable = parseFunction(geo.getVarString(getStringTemplate()));
// boolean warning=!("t".equals(variable));
int indexFunc = -1;
String tempFunctionCount = "f" + Integer.toString(functionCount + 1);
String returnCode = "(real " + variable + "){return (" + fx + "," + fy
+ ");} ";
// search for previous occurrences of function
if (compact) {
indexFunc = codeFilledObject.indexOf(returnCode);
if (indexFunc != -1) {
// retrieve name of previously used function
int indexFuncStart = codeFilledObject.lastIndexOf(" ",
indexFunc);
tempFunctionCount = codeFilledObject
.substring(indexFuncStart + 1, indexFunc);
} else if (code.indexOf(returnCode) != -1) {
indexFunc = code.indexOf(returnCode);
int indexFuncStart = code.lastIndexOf(" ", indexFunc);
tempFunctionCount = code.substring(indexFuncStart + 1,
indexFunc);
indexFunc = code.indexOf(returnCode);
}
} // write function
if (indexFunc == -1) {
functionCount++;
if (!compact) {
code.append("\n");
}
code.append("pair f");
code.append(functionCount);
packSpace(code, "(real " + variable + ")");
code.append("{return (");
code.append(fx);
code.append(",");
code.append(fy);
code.append(");} ");
}
startDraw();
code.append("graph(");
code.append(tempFunctionCount);
code.append(",");
code.append(format(start));
code.append(",");
code.append(format(end));
code.append(")");
endDraw(geo);
}
@Override
protected void drawFunction(GeoFunction geo) {
drawFunction(geo, false, null, false);
}
/**
* @param geo
* function
* @param integral
* whether to fill below
* @param geo1
* used for color
* @param contour
* whether to show contour
*/
protected void drawFunction(GeoFunction geo, boolean integral,
GeoNumeric geo1, boolean contour) {
importpackage.add("graph");
Function f = geo.getFunction();
if (f == null) {
return;
}
String value = f.toValueString(getStringTemplate());
value = parseFunction(value);// killSpace(StringUtil.toLaTeXString(value,true));
value = value.replace("\\\\pi", "pi");
double a = xmin;
double b = xmax;
if (geo.hasInterval()) {
a = Math.max(a, geo.getIntervalMin());
b = Math.min(b, geo.getIntervalMax());
}
double xrangemax = a, xrangemin = a;
while (xrangemax < b) {
xrangemin = firstDefinedValue(geo, a, b);
// Application.debug("xrangemin "+xrangemin);
if (xrangemin == b) {
break;
}
xrangemax = maxDefinedValue(geo, xrangemin, b);
// Application.debug("xrangemax "+xrangemax);
int indexFunc = -1;
String tempFunctionCount = null;
String returnCode = null;
if (!isLatexFunction(
f.toValueString(StringTemplate.noLocalDefault))) {
StringBuilder sb = new StringBuilder();
StringBuilder lineBuilder;
if (integral) {
sb.append("path p" + (++functionCount) + ";\n");
sb.append("p" + functionCount + "=");
String template = "(%0,%1) -- (%2,%3) -- ";
lineBuilder = drawNoLatexFunction(geo, xrangemax, xrangemin,
400, template);
lineBuilder.append(
"(" + format(geo.getIntervalMax()) + ",0) -- ("
+ format(geo.getIntervalMin()) + ",0) -- ");
StringBuilder color = new StringBuilder();
colorCode(geo1.getObjectColor(), color);
String str = "cycle;\ndraw(p" + functionCount + "," + color;
if (!contour) {
str = "cycle;\nfill(p" + functionCount + "," + color;
str += "+opacity(0.05)";
}
lineBuilder.append(str);
lineBuilder.append(");\n");
sb.append(lineBuilder);
lineBuilder = sb;
} else {
colorCode(geo.getObjectColor(), sb);
String template = "draw( (%0,%1) -- (%2,%3)," + sb
+ "+linewidth(" + geo.getLineThickness() + "));\n";
lineBuilder = drawNoLatexFunction(geo, xrangemax, xrangemin,
400, template);
}
code.append(lineBuilder.toString() + ";\n");
} else {
tempFunctionCount = "f" + Integer.toString(functionCount + 1);
returnCode = "(real x){return " + value + ";} ";
// search for previous occurrences of function
if (compact) {
indexFunc = codeFilledObject.indexOf(returnCode);
if (indexFunc != -1) {
// retrieve name of previously used function
int indexFuncStart = codeFilledObject.lastIndexOf(" ",
indexFunc);
tempFunctionCount = codeFilledObject
.substring(indexFuncStart + 1, indexFunc);
} else if (code.indexOf(returnCode) != -1) {
indexFunc = code.indexOf(returnCode);
int indexFuncStart = code.lastIndexOf(" ", indexFunc);
tempFunctionCount = code.substring(indexFuncStart + 1,
indexFunc);
indexFunc = code.indexOf(returnCode);
}
} // write function
if (indexFunc == -1) {
functionCount++;
if (!compact) {
code.append("\n");
}
code.append("real ");
code.append(tempFunctionCount);
packSpace(code, "(real x)");
code.append("{return ");
code.append(value);
code.append(";} ");
}
startDraw();
code.append("graph(");
code.append(tempFunctionCount);
code.append(",");
// add/subtract 0.01 to prevent 1/x, log(x) undefined behavior
code.append(format(xrangemin + 0.01));
code.append(",");
code.append(format(xrangemax - 0.01));
code.append(")");
endDraw(geo);
}
// ? recycled code of sorts?*/
xrangemax += PRECISION_XRANGE_FUNCTION;
a = xrangemax;
}
}
// draw vector with EndArrow(6)
@Override
protected void drawGeoVector(GeoVector geo) {
GeoPointND pointStart = geo.getStartPoint();
String x1, y1;
if (pointStart == null) {
x1 = "0";
y1 = "0";
} else {
Coords c = pointStart.getCoords();
x1 = format(c.getX() / c.getZ());
y1 = format(c.getY() / c.getZ());
}
double[] coord = new double[3];
geo.getCoords(coord);
String x2 = format(
coord[0] + kernel.getAlgebraProcessor().evaluateToDouble(x1));
String y2 = format(
coord[1] + kernel.getAlgebraProcessor().evaluateToDouble(y1));
if (!compact) {
code.append("\n");
}
if (compactcse5) {
code.append("D(");
} else {
code.append("draw(");
}
addPoint(x1, y1, code);
code.append("--");
addPoint(x2, y2, code);
if (lineOptionCode(geo, true) != null) {
code.append(",");
if (!compact) {
code.append(" ");
}
code.append(lineOptionCode(geo, true));
}
code.append(",EndArrow(6)); ");
}
private void drawCircle(GeoConic geo) {
StringBuilder tempsb = new StringBuilder();
boolean nofill = geo.getAlphaValue() < 0.05;
if (xunit == yunit) {
// draw a circle
double x = geo.getTranslationVector().getX();
double y = geo.getTranslationVector().getY();
double r = geo.getHalfAxes()[0];
String tmpr = format(r); // removed *xunit, unsure of function
if (nofill) {
if (!compact) {
tempsb.append("\n");
}
if (compactcse5) {
tempsb.append("D(CR(");
} else {
tempsb.append("draw(circle(");
}
} else {
startTransparentFill(tempsb);
if (compactcse5) {
tempsb.append("CR(");
} else {
tempsb.append("circle(");
}
}
addPoint(format(x), format(y), tempsb);
packSpaceAfter(tempsb, ",");
if (kernel.getAlgebraProcessor().evaluateToDouble(tmpr) != 0) {
tempsb.append(tmpr);
} else {
tempsb.append(r);
}
tempsb.append(")");
if (nofill) {
endDraw(geo, tempsb);
} else {
endTransparentFill(geo, tempsb);
}
} else {
// draw an ellipse by scaling a circle
double x1 = geo.getTranslationVector().getX();
double y1 = geo.getTranslationVector().getY();
double r1 = geo.getHalfAxes()[0];
double r2 = geo.getHalfAxes()[1];
if (nofill) {
if (!compact) {
tempsb.append("\n");
}
if (compactcse5) {
tempsb.append("D(");
} else {
tempsb.append("draw(");
}
} else {
startTransparentFill(tempsb);
}
tempsb.append("shift(");
addPoint(format(x1), format(y1), tempsb);
packSpaceBetween(tempsb, ")", "*", "scale(" + format(r1) + ",",
format(r2) + ")*unitcircle");
if (nofill) {
endDraw(geo, tempsb);
} else {
endTransparentFill(geo, tempsb);
}
}
if (nofill) {
code.append(tempsb);
} else {
codeFilledObject.append(tempsb);
}
}
@Override
protected void drawGeoConic(GeoConic geo) {
switch (geo.getType()) {
// if conic is a circle
default:
// do nothing
break;
case GeoConicNDConstants.CONIC_CIRCLE:
drawCircle(geo);
break;
// if conic is an ellipse
case GeoConicNDConstants.CONIC_ELLIPSE:
GAffineTransform at = geo.getAffineTransform();
double eigenvecX = at.getScaleX();
double eigenvecY = at.getShearY();
double x1 = geo.getTranslationVector().getX();
double y1 = geo.getTranslationVector().getY();
double r1 = geo.getHalfAxes()[0];
double r2 = geo.getHalfAxes()[1];
double angle = Math.toDegrees(Math.atan2(eigenvecY, eigenvecX));
// use scale operator to draw ellipse
if (compactcse5) {
if (fillInequality) {
code.append("filldraw(shift(");
} else {
code.append("D(shift(");
}
} else if (fillInequality) {
code.append("filldraw(shift(");
} else {
code.append("draw(shift(");
}
addPoint(format(x1), format(y1), code);
code.append(")*rotate(");
code.append(format(angle));
code.append(")*xscale(");
code.append(format(r1));
code.append(")*yscale(");
code.append(format(r2));
code.append(")*unitcircle");
if (fillInequality) {
code.append(",pattern(\"hatch\"),border);\n");
}
endDraw(geo);
break;
// if conic is a parabola
case GeoConicNDConstants.CONIC_PARABOLA:
// parameter of the parabola
double p = geo.p;
at = geo.getAffineTransform();
// first eigenvector
eigenvecX = at.getScaleX();
eigenvecY = at.getShearY();
// vertex
x1 = geo.getTranslationVector().getX();
y1 = geo.getTranslationVector().getY();
// calculate the x range to draw the parabola
double x0 = Math.max(Math.abs(x1 - xmin), Math.abs(x1 - xmax));
x0 = Math.max(x0, Math.abs(y1 - ymin));
x0 = Math.max(x0, Math.abs(y1 - ymax));
// avoid sqrt by choosing x = k*p with
// i = 2*k is quadratic number
// make parabola big enough: k*p >= 2*x0 -> 2*k >= 4*x0/p
x0 = 4 * x0 / p;
int i = 4, k2 = 16;
while (k2 < x0) {
i += 2;
k2 = i * i;
}
// x0 = k2/2 * p; // x = k*p
x0 = i * p; // y = sqrt(2k p^2) = i p
angle = Math.toDegrees(Math.atan2(eigenvecY, eigenvecX)) - 90;
// write real parabola (real x) function
parabolaCount++;
if (!compact) {
code.append("\n");
}
code.append("real p");
if (!compact) {
code.append("arabola");
}
code.append(parabolaCount);
packSpace(code, "(real x)");
code.append("{return x^2/2/");
if (compact) {
code.append(format(p));
} else {
code.append(p);
}
code.append(";} ");
// use graph to plot parabola
if (!compact) {
code.append("\n");
}
if (compactcse5) {
code.append("D(shift(");
} else {
code.append("draw(shift(");
}
addPoint(format(x1), format(y1), code);
code.append(")*rotate(");
code.append(format(angle));
code.append(")*graph(p");
if (!compact) {
code.append("arabola");
}
code.append(parabolaCount);
code.append(",");
code.append(format(-x0));
code.append(",");
code.append(format(x0));
code.append(")");
endDraw(geo);
if (!compact) {
code.append("/* parabola construction */");
}
break;
case GeoConicNDConstants.CONIC_HYPERBOLA:
// parametric: (a(1+t^2)/(1-t^2), 2bt/(1-t^2))
at = geo.getAffineTransform();
eigenvecX = at.getScaleX();
eigenvecY = at.getShearY();
x1 = geo.getTranslationVector().getX();
y1 = geo.getTranslationVector().getY();
r1 = geo.getHalfAxes()[0];
r2 = geo.getHalfAxes()[1];
angle = Math.toDegrees(Math.atan2(eigenvecY, eigenvecX));
hyperbolaCount++;
if (!compact) {
code.append("\n");
}
if (!compact) {
code.append("pair hyperbolaLeft");
} else {
code.append("pair hl");
}
code.append(hyperbolaCount);
packSpace(code, "(real t)");
code.append("{return (");
code.append(format(r1));
code.append("*(1+t^2)/(1-t^2),");
code.append(format(r2));
code.append("*2*t/(1-t^2));} ");
if (!compact) {
code.append("pair hyperbolaRight");
} else {
code.append("pair hr");
}
code.append(hyperbolaCount);
packSpace(code, "(real t)");
code.append("{return (");
code.append(format(r1));
code.append("*(-1-t^2)/(1-t^2),");
code.append(format(r2));
code.append("*(-2)*t/(1-t^2));} ");
// use graph to plot both halves of hyperbola
if (!compact) {
code.append("\n");
}
if (compactcse5) {
code.append("D(shift(");
} else {
code.append("draw(shift(");
}
addPoint(format(x1), format(y1), code);
code.append(")*rotate(");
code.append(format(angle));
if (!compact) {
code.append(")*graph(hyperbolaLeft");
} else {
code.append(")*graph(hl");
}
code.append(hyperbolaCount);
code.append(",-0.99,0.99)"); // arbitrary to approach (-1,1)
endDraw(geo);
if (compactcse5) {
code.append("D(shift(");
} else {
code.append("draw(shift(");
}
addPoint(format(x1), format(y1), code);
code.append(")*rotate(");
code.append(format(angle));
if (!compact) {
code.append(")*graph(hyperbolaRight");
} else {
code.append(")*graph(hr");
}
code.append(hyperbolaCount);
code.append(",-0.99,0.99)");
endDraw(geo);
if (!compact) {
code.append("/* hyperbola construction */");
}
break;
}
}
// draws dot
@Override
protected void drawGeoPoint(GeoPoint gp) {
if (frame.getExportPointSymbol()) {
double x = gp.getX(), y = gp.getY(), z = gp.getZ();
x = x / z;
y = y / z;
gp.getNameDescription();
int dotstyle = gp.getPointStyle();
if (dotstyle == -1) { // default
dotstyle = EuclidianStyleConstants.POINT_STYLE_DOT;
} // draw special dot styles
if (dotstyle != EuclidianStyleConstants.POINT_STYLE_DOT) {
drawSpecialPoint(gp);
} else { // plain dot style
if (!compact) {
codePoint.append("\n");
}
if (compactcse5) {
codePoint.append("D(");
} else {
codePoint.append("dot(");
}
addPoint(format(x), format(y), codePoint);
PointOptionCode(gp, codePoint);
codePoint.append("); ");
}
}
}
/**
* Draws a point with a special point style (usually uses draw() or
* filldraw() command).
*
* @param geo
* GeoPoint with style not equal to the standard dot style.
*/
protected void drawSpecialPoint(GeoPoint geo) {
// radius = dotsize (pt) * (2.54 cm)/(72 pt per inch) * XUnit / cm
double dotsize = geo.getPointSize();
double radius = dotsize * (2.54 / 72) * (frame.getXUnit());
int dotstyle = geo.getPointStyle();
if (dotstyle == -1) { // default
dotstyle = EuclidianStyleConstants.POINT_STYLE_DOT;
}
double x = geo.getX(), y = geo.getY(), z = geo.getZ();
x = x / z;
y = y / z;
GColor dotcolor = geo.getObjectColor();
switch (dotstyle) {
case EuclidianStyleConstants.POINT_STYLE_CROSS:
startDraw();
code.append("shift((" + format(x) + "," + format(y) + "))*");
code.append("scale(");
code.append(format(radius));
code.append(")*(expi(pi/4)--expi(5*pi/4)");
if (compactcse5) {
// operator
code.append("--(0,0)--");
} else {
code.append("^^");
}
code.append("expi(3*pi/4)--expi(7*pi/4))");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_CIRCLE:
// use dot(..,UnFill(0)) command in lieu of filldraw
if (!compactcse5) {
codePoint.append("dot(");
addPoint(format(x), format(y), codePoint);
// 4.0 slightly arbitrary. 6.0 should be corrective factor, but
// too small.
PointOptionCode(geo, codePoint, geo.getPointSize() / 4.0);
codePoint.append(",UnFill(0)); ");
}
// use filldraw(CR) for cse5
else {
startDraw();
// if(compactcse5)
code.append("CR((");
// else
// code.append("circle((");
code.append(format(x) + "," + format(y) + "),");
code.append(format(radius));
code.append(")");
endPoint(dotcolor);
}
break;
case EuclidianStyleConstants.POINT_STYLE_EMPTY_DIAMOND:
startDraw();
code.append("shift((" + format(x) + "," + format(y) + "))*");
code.append("scale(");
code.append(format(radius));
code.append(")*((1,0)--(0,1)--(-1,0)--(0,-1)--cycle)");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_FILLED_DIAMOND:
if (!compact) {
code.append("\n");
}
packSpaceBetween(
"fill(shift((" + format(x) + "," + format(y) + "))", "*",
"scale(" + format(radius) + ")", "*",
"((1,0)--(0,1)--(-1,0)--(0,-1)--cycle)");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_PLUS:
startDraw();
packSpaceBetween("shift((" + format(x) + "," + format(y) + "))",
"*", "scale(" + format(radius) + ")", "*",
"((0,1)--(0,-1)");
if (compactcse5) {
// operator
code.append("--(0,0)--");
} else {
code.append("^^");
}
code.append("(1,0)--(-1,0))");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_TRIANGLE_EAST:
if (!compact) {
code.append("\n");
}
packSpaceBetween(
"fill(shift((" + format(x) + "," + format(y) + "))", "*",
"scale(" + format(radius) + ")", "*",
"((1,0)--expi(2*pi/3)--expi(4*pi/3)--cycle)");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_TRIANGLE_NORTH:
if (!compact) {
code.append("\n");
}
packSpaceBetween(
"fill(shift((" + format(x) + "," + format(y) + "))", "*",
"rotate(90)", "*", "scale(" + format(radius) + ")", "*",
"((1,0)--expi(2*pi/3)--expi(4*pi/3)--cycle)");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_TRIANGLE_SOUTH:
if (!compact) {
code.append("\n");
}
packSpaceBetween(
"fill(shift((" + format(x) + "," + format(y) + "))", "*",
"rotate(270)", "*", "scale(" + format(radius) + ")", "*",
"((1,0)--expi(2*pi/3)--expi(4*pi/3)--cycle)");
endPoint(dotcolor);
break;
case EuclidianStyleConstants.POINT_STYLE_TRIANGLE_WEST:
if (!compact) {
code.append("\n");
}
packSpaceBetween(
"fill(shift((" + format(x) + "," + format(y) + "))", "*",
"rotate(180)", "*", "scale(" + format(radius) + ")", "*",
"((1,0)--expi(2*pi/3)--expi(4*pi/3)--cycle)");
endPoint(dotcolor);
break;
default:
break;
}
if (!compact) {
code.append("/* special point */");
}
}
// draws line
@Override
protected void drawGeoLine(GeoLine geo) {
double x = geo.getX(), y = geo.getY(), z = geo.getZ();
if (y != 0) {
startDraw();
// new evaluation: [-x/y]*[xmin or xmax]-(z/y)
packSpaceAfter(code, "(xmin,");
code.append(format(-x / y));
code.append("*xmin");
if (z / y < 0 || format(-z / y).equals("0")) {
packSpace(code, "+");
}
code.append(format(-z / y));
code.append(")");
// String tmpy=format(y);
// if (Double.parseDouble(tmpy)!=0) code.append(tmpy);
// else code.append(y);
packSpaceAfter(code, "--(xmax,");
code.append(format(-x / y));
code.append("*xmax");
if (z / y < 0 || format(-z / y).equals("0")) {
packSpace(code, "+");
}
code.append(format(-z / y));
// if (Double.parseDouble(tmpy)!=0) code.append(tmpy);
// else code.append(y);
code.append(")");
endDraw(geo);
} else { // vertical line
if (!compact) {
code.append("\n");
}
if (compactcse5) {
code.append("D((");
} else {
code.append("draw((");
}
String s = format(-z / x);
code.append(s);
code.append(",ymin)--(");
code.append(s);
code.append(",ymax)");
endDraw(geo);
}
if (!compact) {
code.append("/* line */");
}
}
// draws segment
@Override
protected void drawGeoSegment(GeoSegment geo) {
double[] A = new double[2], B = new double[2];
GeoPoint pointStart = geo.getStartPoint();
GeoPoint pointEnd = geo.getEndPoint();
pointStart.getInhomCoords(A);
pointEnd.getInhomCoords(B);
String x1 = format(A[0]), y1 = format(A[1]), x2 = format(B[0]),
y2 = format(B[1]);
int deco = geo.getDecorationType();
if (!compact) {
code.append("\n");
}
if (!compactcse5) {
code.append("draw(");
} else {
code.append("D(");
}
addPoint(x1, y1, code);
code.append("--");
addPoint(x2, y2, code);
endDraw(geo);
if (deco != GeoElement.DECORATION_NONE) {
mark(A, B, deco, geo);
}
}
@Override
protected void drawLine(double x1, double y1, double x2, double y2,
GeoElement geo) {
String sx1 = format(x1);
String sy1 = format(y1);
String sx2 = format(x2);
String sy2 = format(y2);
startDraw();
addPoint(sx1, sy1, code);
code.append("--");
addPoint(sx2, sy2, code);
endDraw(geo);
}
@Override
protected void drawGeoRay(GeoRay geo) {
GeoPoint pointStart = geo.getStartPoint();
double x1 = pointStart.getX();
double z1 = pointStart.getZ();
x1 = x1 / z1;
String y1 = format(pointStart.getY() / z1);
double x = geo.getX(), y = geo.getY(), z = geo.getZ();
double yEndpoint; // records explicitly y-coordinate of endpoint
// String tmpy = format(y);
double inf = xmin, sup = xmax; // determine left and right bounds on x
// to draw ray
if (y > 0) {
inf = x1;
yEndpoint = (-z - x * inf) / y;
} else {
sup = x1;
yEndpoint = (-z - x * sup) / y;
}
// format: draw((inf,f(inf))--(xmax,f(xmax)));
// OR: draw((xmin,f(xmin))--(sup,f(sup)));
// old evaluation: (-(z)-(x)*[inf or sup])/y
// new evaluation: [-x/y]*[inf or sup]-(z/y)
startDraw();
if (y != 0) { // non-vertical line
if (y > 0) {
addPoint(format(inf), format(yEndpoint), code);
code.append("--");
packSpaceAfter(code, "(xmax,");
code.append(format(-x / y));
code.append("*xmax");
if (z / y < 0 || format(-z / y).equals("0")) {
packSpace(code, "+");
}
code.append(format(-z / y));
// code.append(")/");
// if (Double.parseDouble(tmpy)!=0) code.append(tmpy);
// else code.append(y);
code.append(")");
} else {
addPoint(format(sup), format(yEndpoint), code);
code.append("--");
packSpaceAfter(code, "(xmin,");
code.append(format(-x / y));
code.append("*xmin");
if (z / y < 0 || format(-z / y).equals("0")) {
packSpace(code, "+");
}
code.append(format(-z / y));
// code.append("/");
// if (Double.parseDouble(tmpy) != 0) code.append(tmpy);
// else code.append(y);
code.append(")");
}
endDraw(geo);
} else {
addPoint(format(x1), y1, code);
code.append("--(");
code.append(format(x1));
packSpaceAfter(code, ",");
if (-x > 0) {
code.append("ymax");
} else {
code.append("ymin");
}
code.append(")");
endDraw(geo);
}
if (!compact) {
code.append("/* ray */");
}
}
@Override
protected void drawImplicitPoly(GeoImplicit geo) {
// credit: help from Art of Problem Solving user fedja
importpackage.add("contour"); // importContour = true; flag for preamble
// to import contour package
// two-variable implicit function expression
String polynomial = parseFunction(getImplicitExpr(geo))
.replace("\\\\pi", "pi");
implicitFuncCount++;
int implicitFuncName = implicitFuncCount;
// if compact, retrieve previous instance of implicit polynomial
// expression, if exists
if (!compact || !implicitPolyTable.containsKey(polynomial)) {
if (compact) {
if (implicitPolyTable.isEmpty()) {
implicitPolyTable.put(polynomial, 1);
} else {
implicitFuncName = implicitPolyTable.size() + 1;
implicitPolyTable.put(polynomial, implicitFuncName);
}
}
// write implicitf# (real x, real y) is implicit polynomial function
// of two variables
if (!compact) {
code.append("\n");
}
code.append("real implicitf");
code.append(implicitFuncName);
packSpace("(real x, real y)", "{");
code.append("return " + polynomial);
packSpaceAfter(";");
code.append("} ");
} else {
implicitFuncName = implicitPolyTable.get(polynomial);
}
startDraw(); // code: draw(contour(f, (xmin,ymin), (xmax,ymax), new
// real[]{0}, 500));
code.append("contour(implicitf");
code.append(implicitFuncName);
packSpaceBetween(code, ",", "(xmin,ymin),", "(xmax,ymax),",
"new real[]{0},", "500)");
endDraw(geo.toGeoElement());
}
@Override
protected void drawPolyLine(GeoPolyLine geo) {
GeoPointND[] points = geo.getPoints();
StringBuilder str = new StringBuilder();
startDraw(str); // connect (by join --) all points within one draw
// statement
for (int i = 0; i < points.length; i++) {
Coords coords = points[i].getInhomCoords();
double x = coords.getX(), y = coords.getY();
addPoint(format(x), format(y), str);
if (i != points.length - 1) {
str.append("--");
}
}
endDraw(geo, str);
String s = str.toString();
StringBuilder sb = new StringBuilder();
if (lineOptionCode(geo, true) != null) {
packSpaceAfter(sb, ",");
sb.append(lineOptionCode(geo, true));
}
sb.append("); ");
StringBuilder sa = new StringBuilder();
if (!compact) {
sa.append("\n");
}
if (compactcse5) {
sa.append("D(");
} else {
sa.append("draw(");
}
s = s.replace("--\\(\\?,\\?\\)--", sb.toString() + sa.toString());
code.append(s);
}
private void initUnitAndVariable() {
// Initaialze units, dot style, dot size ....
/*
* codeBeginPic.append("\\psset{xunit=");
* codeBeginPic.append(sci2dec(xunit));
* codeBeginPic.append("cm,yunit=");
* codeBeginPic.append(sci2dec(yunit));
* codeBeginPic.append("cm,algebraic=true,dotstyle=o,dotsize=");
* codeBeginPic.append(EuclidianStyleConstants.DEFAULT_POINT_SIZE);
* codeBeginPic.append("pt 0"); codeBeginPic.append(",linewidth=");
* codeBeginPic
* .append(format(EuclidianStyleConstants.DEFAULT_LINE_THICKNESS
* /2*0.8)); codeBeginPic.append("pt,arrowsize=3pt 2,arrowinset=0.25}\n"
* );
*/
if (!compact) {
codePreamble.append(
"\nreal labelscalefactor = 0.5; /* changes label-to-point distance */");
codePreamble.append("\npen dps = linewidth(0.7) + fontsize(");
codePreamble.append(fontsize);
codePreamble.append("); defaultpen(dps); /* default pen style */ ");
if (!frame.getKeepDotColors()) {
codePreamble
.append("\npen dotstyle = black; /* point style */ \n");
}
} else if (!compactcse5) {
codePreamble
.append("real lsf=0.5; pen dps=linewidth(0.7)+fontsize(");
codePreamble.append(fontsize);
codePreamble.append("); defaultpen(dps); ");
if (!frame.getKeepDotColors()) {
codePreamble.append("pen ds=black; ");
}
} else {
codePreamble.append(
"real lsf=0.5; pathpen=linewidth(0.7); pointpen=black; pen fp=fontsize(");
codePreamble.append(fontsize);
codePreamble.append("); pointfontpen=fp; ");
}
boolean[] positiveOnly = euclidianView.getPositiveAxes();
double assignMinX = xmin;
double assignMinY = ymin;
if (positiveOnly[0]) {
assignMinX = -0.1;
}
if (positiveOnly[1]) {
assignMinY = -0.1;
}
packSpaceBetween(codePreamble, "real xmin", "=",
format(assignMinX) + ",", "xmax", "=", format(xmax) + ",",
"ymin", "=", format(assignMinY) + ",", "ymax", "=",
format(ymax) + "; ");
if (!compact) {
codePreamble.append(" /* image dimensions */\n");
} else { /* codePreamble.append("\n"); */
}
}
// Generate list of pairs for cse5 code to use
private void initPointDeclarations() {
if (!pairName) {
return;
}
Iterator<GeoPoint> it = pointList.iterator();
boolean comma = false; // flag for determining whether to add comma
// pre-defined pair names in base module plain. Do not re-write to save
// hassle
String predefinedNames[] = { "N", "S", "E", "W", "NE", "SE", "NW", "SW",
"NNE", "NNW", "SSE", "SSW", "ENE", "WNW", "ESE", "WSW", "left",
"right", "up", "down" };
while (it.hasNext()) {
GeoPoint gp = it.next();
if (gp.getPointStyle() == EuclidianStyleConstants.POINT_STYLE_DOT
|| gp.getPointStyle() == EuclidianStyleConstants.POINT_STYLE_CIRCLE) {
double x = gp.getX(), y = gp.getY(), z = gp.getZ();
x /= z;
y /= z;
String pairString = "(" + format(x) + "," + format(y) + ")";
String pointName = gp.getLabel(getStringTemplate());
boolean isVariable = true;
// Note: if problem with point name, simply discard and move on.
// check if characters of point names are valid, namely
// alphanumeric or underscore
for (int i = 0; i < pointName.length(); i++) {
if (!Character.isLetterOrDigit(pointName.charAt(i))
&& pointName.charAt(i) != '_') {
isVariable = false;
}
}
// check that point names don't re-write basic asymptote pairs
for (int i = 0; i < predefinedNames.length; i++) {
if (pointName.equals(predefinedNames[i])) {
isVariable = false;
}
}
// store pairString -> pairName, write asy declaration pair
// pairName = pairString;
if (!pairNameTable.containsKey(pairString) && isVariable) {
if (comma) {
codePointDecl.append(", ");
} else {
comma = true;
}
pairNameTable.put(pairString, pointName);
codePointDecl.append(pointName);
packSpace(codePointDecl, "=");
codePointDecl.append(pairString);
}
}
}
if (comma) {
codePointDecl.insert(0, "\npair ");
codePointDecl.append("; ");
}
}
// if label is visible, draw it
@Override
protected void drawLabel(GeoElement geo, DrawableND drawGeo0) {
try {
if (geo.isLabelVisible()) {
String name;
if (geo.getLabelMode() == GeoElement.LABEL_CAPTION) {
name = convertUnicodeToText(geo.getLabelDescription())
.replace("\\$", "dollar");
if (name.contains("_")) {
name = "$" + name + "$";
}
} else if (compactcse5) {
name = StringUtil.toLaTeXString(geo.getLabelDescription(),
true);
name = convertUnicodeToLatex(name);
} else {
name = "$" + StringUtil.toLaTeXString(
geo.getLabelDescription(), true) + "$";
name = convertUnicodeToLatex(name);
}
if (name.indexOf(Unicode.DEGREE) != -1) {
name = name.replace(Unicode.DEGREE, "^\\\\circ");
}
DrawableND drawGeo = drawGeo0;
if (drawGeo == null) {
drawGeo = euclidianView.getDrawableFor(geo);
}
double xLabel = drawGeo.getxLabel();
double yLabel = drawGeo.getyLabel();
xLabel = euclidianView.toRealWorldCoordX(Math.round(xLabel));
yLabel = euclidianView.toRealWorldCoordY(Math.round(yLabel));
boolean isPointLabel = false;
GColor geocolor = geo.getObjectColor();
if (!compact) {
codePoint.append("\n");
}
if (compactcse5
&& geo.getLabelMode() != GeoElement.LABEL_CAPTION) {
codePoint.append("MP(\"");
} else {
codePoint.append("label(\"");
}
codePoint.append(name);
packSpaceBetween(codePoint, "\",", "(");
codePoint.append(format(xLabel));
codePoint.append(",");
codePoint.append(format(yLabel));
codePoint.append("),");
if (!compact) {
codePoint.append(" ");
}
codePoint.append("NE");
packSpace(codePoint, "*");
if (compact) {
codePoint.append("lsf");
}
if (!compact) {
codePoint.append("labelscalefactor");
}
// check if label is of point
isPointLabel = (geocolor.equals(GColor.BLUE) || ColorEquals(
geocolor, GColor.newColor(124, 124, 255))) // xdxdff
// is of the form "A" or "$A$"
&& (((name.length() == 1)
&& Character.isUpperCase(name.charAt(0)))
|| (((name.length() == 3)
&& name.charAt(0) == '$' && name
.charAt(2) == '$'
&& Character
.isUpperCase(name.charAt(1)))));
isPointLabel = isPointLabel || geo.isGeoPoint();
// replaced with pointfontpen:
// if(compactcse5) {
// codePoint.append(",fp");
// }
if (isPointLabel && !frame.getKeepDotColors()) {
// configurable or default black?
// temp empty
} else if (!geocolor.equals(GColor.BLACK)) {
if (compactcse5) {
codePoint.append(",fp+");
} else {
codePoint.append(",");
}
colorCode(geocolor, codePoint);
}
codePoint.append("); ");
}
}
// For GeoElement that don't have a Label
// For example (created with geoList)
catch (NullPointerException e) {
Log.debug(e);
}
}
/**
* Returns whether or not c1 and c2 are equivalent colors, when rounded to
* the nearest hexadecimal integer.
*
* @param c1
* The first Color object.
* @param c2
* The second Color object to compare with.
* @return Whether c1 and c2 are equivalent colors, to rounding.
*/
boolean ColorEquals(GColor c1, GColor c2) {
return format(c1.getRed() / 255d).equals(format(c2.getRed() / 255d))
&& format(c1.getGreen() / 255d)
.equals(format(c2.getGreen() / 255d))
&& format(c1.getBlue() / 255d)
.equals(format(c2.getBlue() / 255d));
}
// Draw the grid
private void drawGrid() {
GColor GridCol = euclidianView.getGridColor();
double[] GridDist = euclidianView.getGridDistances();
boolean GridBold = euclidianView.getGridIsBold();
int GridLine = euclidianView.getGridLineStyle();
if (!compact) {
// draws grid using Asymptote loops
codeBeginPic
.append("\n /* draw grid of horizontal/vertical lines */");
codeBeginPic.append("\npen gridstyle = ");
if (GridBold) {
codeBeginPic.append("linewidth(1.0)");
} else {
codeBeginPic.append("linewidth(0.7)");
}
codeBeginPic.append(" + ");
colorCode(GridCol, codeBeginPic);
if (GridLine != EuclidianStyleConstants.LINE_TYPE_FULL) {
codeBeginPic.append(" + ");
LinestyleCode(GridLine, codeBeginPic);
}
codeBeginPic.append("; real gridx = ");
codeBeginPic.append(format(GridDist[0]));
codeBeginPic.append(", gridy = ");
codeBeginPic.append(format(GridDist[1]));
codeBeginPic.append("; /* grid intervals */"
+ "\nfor(real i = ceil(xmin/gridx)*gridx; "
+ "i <= floor(xmax/gridx)*gridx; i += gridx)");
codeBeginPic.append("\n draw((i,ymin)--(i,ymax), gridstyle);");
codeBeginPic.append("\nfor(real i = ceil(ymin/gridy)*gridy; "
+ "i <= floor(ymax/gridy)*gridy; i += gridy)");
codeBeginPic.append("\n draw((xmin,i)--(xmax,i), gridstyle);");
codeBeginPic.append("\n /* end grid */ \n");
return;
} else if (!compactcse5) {
codeBeginPic.append(
"\n/*grid*/ "); /*
* //// COMMENTED CODE - explicitly draw
* grid using for loops. ////
* codeBeginPic.append ("pen gs=");
* if(GridBold) codeBeginPic
* .append("linewidth(1.0)"); else
* codeBeginPic.append( "linewidth(0.7)");
* codeBeginPic.append("+"); ColorCode
* (GridCol,codeBeginPic); if(GridLine !=
* EuclidianStyleConstants .LINE_TYPE_FULL)
* { codeBeginPic.append("+");
* LinestyleCode(GridLine, codeBeginPic); }
* codeBeginPic.append("; "); codeBeginPic
* .append("real gx=" + format(GridDist[0])
* + ",gy=" + format(GridDist[1]) + "; ");
* codeBeginPic.append(
* "\nfor(real i=ceil(xmin/gx)*gx;" +
* "i<=floor(xmax/gx)*gx;i+=gx)" );
* codeBeginPic.append(
* " draw((i,ymin)--(i,ymax),gs);" );
* codeBeginPic.append(
* " for(real i=ceil(ymin/gy)*gy;" +
* "i<=floor(ymax/gy)*gy;i+=gy)" );
* codeBeginPic.append(
* " draw((xmin,i)--(xmax,i),gs); " );
*
* // USE math module defined method
* grid(Nx, Ny): real gx=1,gy=1;
* add(scale(gx,gy)*shift (floor(xmin
* /gx),floor(ymin/gy) )*grid(ceil
* (xmax-xmin)+1,ceil(
* ymax-ymin)+1,gridpen)); } else { // with
* cse5 shorthands if(GridBold) codeBeginPic
* .append("linewidth(1.0)"); else
* codeBeginPic.append( "linewidth(0.7)");
* codeBeginPic.append("+"); ColorCode
* (GridCol,codeBeginPic); if(GridLine !=
* EuclidianStyleConstants .LINE_TYPE_FULL)
* { codeBeginPic.append("+");
* LinestyleCode(GridLine, codeBeginPic); }
* codeBeginPic. append("; real gx=");
* codeBeginPic
* .append(format(GridDist[0]));
* codeBeginPic.append(",gy="); codeBeginPic
* .append(format(GridDist[1]));
* codeBeginPic.append(
* ";\nfor(real i=ceil(xmin/gx)*gx;" +
* "i<=floor(xmax/gx)*gx;i+=gx)" );
* codeBeginPic.append(
* " D((i,ymin)--(i,ymax),gs);" );
* codeBeginPic.append(
* " for(real i=ceil(ymin/gy)*gy;" +
* "i<=floor(ymax/gy)*gy;i+=gy)" );
* codeBeginPic.append(
* " D((xmin,i)--(xmax,i),gs); " ); }
*/
}
importpackage.add("math");
codeBeginPic.append("real gx=" + format(GridDist[0]) + ",gy="
+ format(GridDist[1]) + "; ");
codeBeginPic.append(
"add(scale(gx,gy)*shift(floor(xmin/gx),floor(ymin/gy))*grid(ceil(xmax-xmin)+1,ceil(ymax-ymin)+1,");
if (GridBold) {
codeBeginPic.append("linewidth(1.0)");
} else {
codeBeginPic.append("linewidth(0.7)");
}
codeBeginPic.append("+");
colorCode(GridCol, codeBeginPic);
if (GridLine != EuclidianStyleConstants.LINE_TYPE_FULL) {
codeBeginPic.append("+");
LinestyleCode(GridLine, codeBeginPic);
}
codeBeginPic.append(")); ");
}
// Draws Axis presuming shown
// TODO low priority: improve modularity of this function, repeated code for
// xaxis/yaxis.
// note: may shift around relative positions of certain labels.
private void drawAxis() {
boolean xAxis = euclidianView.getShowXaxis();
boolean yAxis = euclidianView.getShowYaxis();
boolean bx = euclidianView.getShowAxesNumbers()[0];
boolean by = euclidianView.getShowAxesNumbers()[1];
String Dx = format(euclidianView.getAxesNumberingDistances()[0]);
String Dy = format(euclidianView.getAxesNumberingDistances()[1]);
String[] label = euclidianView.getAxesLabels(false);
String[] units = euclidianView.getAxesUnitLabels();
int axisStyle = euclidianView.getAxesLineStyle();
int[] tickStyle = euclidianView.getAxesTickStyles();
GColor axisColor = euclidianView.getAxesColor();
boolean axisBold = (axisStyle & 2) == EuclidianStyleConstants.AXES_BOLD;
String lx = "", ly = ""; // axis labels
if (label[0] != null) {
lx = "$" + StringUtil.toLaTeXString(label[0], true) + "$";
}
if (label[1] != null) {
ly = "$" + StringUtil.toLaTeXString(label[1], true) + "$";
/*
* follow format: void xaxis(picture pic=currentpicture, Label L="",
* axis axis=YZero, real xmin=-infinity, real xmax=infinity, pen
* p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, bool
* above=false);
*/
}
// Note: code for xaxis and yaxis duplicated twice.
// When making changes, be sure to update both.
if (xAxis || yAxis) {
codeBeginPic.append("\n"); // create initial label
codeBeginPic.append("Label laxis; laxis.p");
packSpace(codeBeginPic, "=");
codeBeginPic.append("fontsize(" + fontsize + "); ");
if (!bx || !by) { // implement no number shown
if (!compact) {
codeBeginPic.append("\n");
}
codeBeginPic.append("string blank(real x) {return \"\";} ");
}
if (bx || by) { // implement unit labels
if (units[0] != null && !units[0].equals("")) {
codeBeginPic.append("string ");
if (compact) {
codeBeginPic.append("xlbl");
} else {
codeBeginPic.append("xaxislabel");
}
packSpace(codeBeginPic, "(real x)");
packSpaceAfter(codeBeginPic, "{");
// asymptote code for pi labels:
// string xlbl(real x){string s; int n=round(2*x/pi);
// if(abs(n-2*x/pi) > 1e-3) return string(x);
// if(abs(n)>2) s=string(round((n%2+1)*x/pi)); if(n%2==0)
// return "$"+s+"\pi$"; return "$"+s+"\pi/2$";}
// unit label is pi: format -1pi, -1pi/2, 0pi, 1pi/2, 1pi
if (units[0].equals(Unicode.PI_STRING)) {
// create labeling function for special labels if n =
// -1,0,1
packSpaceBetween(codeBeginPic, "string s; ", "int n",
"=", "round(2*x/pi); ");
if (!compact) {
codeBeginPic.append("\n");
}
packSpaceBetween(codeBeginPic, "if(abs(n-2*x/pi)", ">",
"1e-3) return string(x); ");
if (!compact) {
codeBeginPic.append("\n");
}
packSpaceBetween(codeBeginPic, "if(abs(n)", ">",
"2) s = string(round((n%2", "+", "1)*x/pi)); ");
if (!compact) {
codeBeginPic.append("\n");
}
packSpaceBetween(codeBeginPic, "if(n%2", "==",
"0) return \"$\"+s+\"\\pi$\"; ");
// codeBeginPic.append("int n=round(x/pi); ");
// codeBeginPic.append("if(n==-1) return \"$-\\pi$\";
// ");
// codeBeginPic.append("if(n==1) return \"$\\pi$\"; ");
// codeBeginPic.append("if(n==0) return \"$0$\"; ");
}
codeBeginPic.append("return \"$\"");
packSpace(codeBeginPic, "+");
// unit label is pi
if (units[0].equals(Unicode.PI_STRING)) {
packSpaceBetween(codeBeginPic, "s", "+", "\"\\pi/2");
} else if (units[0].equals(Unicode.DEGREE)) {
packSpaceBetween(codeBeginPic, "string(x)", "+",
"\"^\\circ");
} else {
codeBeginPic.append("string(x)");
packSpace(codeBeginPic, "+");
codeBeginPic.append("\"\\,\\mathrm{" + units[0] + "}");
}
codeBeginPic.append("$\";} ");
}
if (units[1] != null && !units[1].equals("")) {
codeBeginPic.append("string ");
if (compact) {
codeBeginPic.append("ylbl");
} else {
codeBeginPic.append("yaxislabel");
}
packSpace(codeBeginPic, "(real x)");
packSpaceAfter(codeBeginPic, "{");
// asymptote code for pi labels:
// string ylbl(real x){string s; int n=round(2*x/pi);
// if(abs(n-2*x/pi) > 1e-3) return string(x);
// if(abs(n)>2) s=string(round((n%2+1)*x/pi)); if(n%2==0)
// return "$"+s+"\pi$"; return "$"+s+"\pi/2$";}
// unit label is pi: format -1pi, -1pi/2, 0pi, 1pi/2, 1pi
if (units[1].equals(Unicode.PI_STRING)) {
// create labeling function for special labels if n =
// -1,0,1
packSpaceBetween(codeBeginPic, "string s; ", "int n",
"=", "round(2*x/pi); ");
if (!compact) {
codeBeginPic.append("\n");
}
packSpaceBetween(codeBeginPic, "if(abs(n-2*x/pi)", ">",
"1e-3) return string(x); ");
if (!compact) {
codeBeginPic.append("\n");
}
packSpaceBetween(codeBeginPic, "if(abs(n)", ">",
"2) s = string(round((n%2", "+", "1)*x/pi)); ");
if (!compact) {
codeBeginPic.append("\n");
}
packSpaceBetween(codeBeginPic, "if(n%2", "==",
"0) return \"$\"+s+\"\\pi$\"; ");
// codeBeginPic.append("int n=round(x/pi); ");
// codeBeginPic.append("if(n==-1) return \"$-\\pi$\";
// ");
// codeBeginPic.append("if(n==1) return \"$\\pi$\"; ");
// codeBeginPic.append("if(n==0) return \"$0$\"; ");
}
codeBeginPic.append("return \"$\"");
packSpace(codeBeginPic, "+");
// unit label is pi
if (units[1].equals(Unicode.PI_STRING)) {
packSpaceBetween(codeBeginPic, "s", "+", "\"\\pi/2");
} else if (units[1].equals(Unicode.DEGREE)) {
packSpaceBetween(codeBeginPic, "string(x)", "+",
"\"^\\circ");
} else {
codeBeginPic.append("string(x)");
packSpace(codeBeginPic, "+");
// put units in text form
codeBeginPic.append("\"\\,\\mathrm{" + units[1] + "}");
}
codeBeginPic.append("$\";} ");
}
}
codeBeginPic.append("\n");
}
if (xAxis) {
codeBeginPic.append("xaxis(");
if (label[0] != null) {
packSpaceBetween(codeBeginPic, "\"" + lx + "\",");
}
packSpaceBetween(codeBeginPic, "xmin,", "xmax"); // non-fixed axes?
// TODO: remove
// if !compact?
// priority:
// minor
// axis pen style
if (axisColor != GColor.BLACK) {
codeBeginPic.append(",");
// catch for other options not changing.
if (compactcse5) {
codeBeginPic.append("pathpen+");
} else {
codeBeginPic.append("defaultpen+");
}
colorCode(axisColor, codeBeginPic);
if (axisBold) {
codeBeginPic.append("+linewidth(1.2)");
}
} else if (axisBold) {
codeBeginPic.append(",linewidth(1.2)");
}
packSpaceAfter(codeBeginPic, ",");
if (tickStyle[0] == EuclidianStyleConstants.AXES_TICK_STYLE_MAJOR) {
packSpaceAfter(codeBeginPic, "Ticks(laxis,");
if (!bx) {
packSpaceAfter(codeBeginPic, "blank,");
} else if (units[0] != null && !units[0].equals("")) {
if (compact) {
packSpaceAfter(codeBeginPic, "xlbl,");
} else {
packSpaceAfter(codeBeginPic, "xaxislabel,");
}
}
// Step=Dx, Size=2, NoZero
packSpaceBetween(codeBeginPic, "Step", "=", Dx + ",", "Size",
"=", "2");
if (yAxis) {
packSpaceBetween(codeBeginPic, ",", "NoZero");
}
codeBeginPic.append(")");
} else if (tickStyle[0] == EuclidianStyleConstants.AXES_TICK_STYLE_MAJOR_MINOR) {
packSpaceAfter(codeBeginPic, "Ticks(laxis,");
if (!bx) {
packSpaceAfter(codeBeginPic, "blank,");
} else if (units[0] != null && !units[0].equals("")) {
if (compact) {
packSpaceAfter(codeBeginPic, "xlbl,");
} else {
packSpaceAfter(codeBeginPic, "xaxislabel,");
}
}
// n=2, Step=Dx, Size=2, size=1, NoZero
packSpaceBetween(codeBeginPic, "n", "=", "2,", "Step", "=",
Dx + ",", "Size", "=", "2,", "size", "=", "1");
codeBeginPic.append(")");
}
packSpaceBetween(codeBeginPic, ",", "above", "=", "true); ");
}
if (xAxis && yAxis && !compact) {
codeBeginPic.append("\n");
}
if (yAxis) {
codeBeginPic.append("yaxis(");
if (label[1] != null) {
packSpaceAfter(codeBeginPic, "\"" + ly + "\",");
}
packSpaceBetween(codeBeginPic, "ymin,", "ymax"); // non-fixed axes?
// axis pen style
if (axisColor != GColor.BLACK) {
if (compactcse5) {
codeBeginPic.append(",pathpen+");
} else {
codeBeginPic.append(",defaultpen+");
}
colorCode(axisColor, codeBeginPic);
if (axisBold) {
codeBeginPic.append("+linewidth(1.2)");
}
} else if (axisBold) {
codeBeginPic.append(",linewidth(1.2)");
}
packSpaceAfter(codeBeginPic, ",");
if (tickStyle[1] == EuclidianStyleConstants.AXES_TICK_STYLE_MAJOR) {
packSpaceAfter(codeBeginPic, "Ticks(laxis,");
if (!by) {
packSpaceAfter(codeBeginPic, "blank,");
} else if (units[1] != null && !units[1].equals("")) {
if (compact) {
packSpaceAfter(codeBeginPic, "ylbl,");
} else {
packSpaceAfter(codeBeginPic, "yaxislabel,");
}
}
// Step=Dy, Size=2, NoZero
packSpaceBetween(codeBeginPic, "Step", "=", Dy + ",", "Size",
"=", "2");
if (xAxis) {
packSpaceBetween(codeBeginPic, ",", "NoZero");
}
codeBeginPic.append(")");
} else if (tickStyle[1] == EuclidianStyleConstants.AXES_TICK_STYLE_MAJOR_MINOR) {
packSpaceAfter(codeBeginPic, "Ticks(laxis,");
if (!by) {
packSpaceAfter(codeBeginPic, "blank,");
} else if (units[1] != null && !units[1].equals("")) {
if (compact) {
packSpaceAfter(codeBeginPic, "ylbl,");
} else {
packSpaceAfter(codeBeginPic, "yaxislabel,");
}
}
// n=2, Step=Dy, Size=2, size=1, NoZero
packSpaceBetween(codeBeginPic, "n", "=", "2,", "Step", "=",
Dy + ",", "Size", "=", "2,", "size", "=", "1");
codeBeginPic.append(")");
}
packSpaceBetween(codeBeginPic, ",", "above", "=", "true); ");
}
if ((xAxis || yAxis) && !compact) {
codeBeginPic.append("/* draws axes; NoZero hides '0' label */ ");
}
drawArrows(axisStyle, axisBold);
}
private void drawArrows(int axisStyle, boolean axisBold) {
boolean axisLeftArrow = (axisStyle
& 4) == EuclidianStyleConstants.AXES_LEFT_ARROW;
boolean axisRightArrow = (axisStyle
& 1) == EuclidianStyleConstants.AXES_RIGHT_ARROW;
String arrow = null;
String pt = "6";
if (axisBold) {
pt = "9";
}
if (axisRightArrow && axisLeftArrow) {
arrow = "Arrows(" + pt + "),";
codeBeginPic.insert(codeBeginPic.indexOf("above") - 1, arrow);
codeBeginPic.insert(codeBeginPic.lastIndexOf("above") - 1, arrow);
} else {
if (axisRightArrow) {
arrow = "EndArrow(" + pt + "),";
codeBeginPic.insert(codeBeginPic.indexOf("above") - 1, arrow);
codeBeginPic.insert(codeBeginPic.lastIndexOf("above") - 1,
arrow);
}
if (axisLeftArrow) {
arrow = "BeginArrow(" + pt + "),";
codeBeginPic.insert(codeBeginPic.indexOf("above") - 1, arrow);
codeBeginPic.insert(codeBeginPic.lastIndexOf("above") - 1,
arrow);
}
}
}
// Returns point style code with size dotsize. Includes comma.
private void PointOptionCode(GeoPoint geo, StringBuilder sb,
double dotsize) {
GColor dotcolor = geo.getObjectColor();
int dotstyle = geo.getPointStyle();
if (dotstyle == -1) { // default
dotstyle = EuclidianStyleConstants.POINT_STYLE_DOT;
}
boolean comma = false; // add comma
if (dotsize != EuclidianStyleConstants.DEFAULT_POINT_SIZE) {
// comma needed
comma = true;
sb.append(",linewidth(");
// Note: Asymptote magnifies default dotsizes by a scale of 6 x
// linewidth,
// but it does not magnify passed-in arguments. So the dotsize here
// is approximately of the correct size.
sb.append(format(dotsize));
sb.append("pt)");
}
if (!dotcolor.equals(GColor.BLACK) && frame.getKeepDotColors()) {
if (comma) {
packSpace(sb, "+");
} else {
sb.append(",");
}
comma = true;
colorCode(dotcolor, sb);
} else if (!frame.getKeepDotColors() && !compactcse5) {
if (comma) {
packSpace(sb, "+");
} else {
sb.append(",");
}
comma = true;
/* cse5 has pointpen attribute */
if (!compact) {
sb.append("dotstyle");
} else if (!compactcse5) {
sb.append("ds");
}
}
// catch mistake
if (dotstyle != EuclidianStyleConstants.POINT_STYLE_DOT) {
if (comma) {
packSpace(sb, "+");
} else {
sb.append(",");
}
comma = true;
sb.append("invisible");
}
}
// Returns point style code. Includes comma.
private void PointOptionCode(GeoPoint geo, StringBuilder sb) {
PointOptionCode(geo, sb, geo.getPointSize());
}
// Line style code; does not include comma.
private String lineOptionCode(GeoElement geo, boolean transparency) {
StringBuilder sb = new StringBuilder();
int linethickness = geo.getLineThickness();
int linestyle = geo.getLineType();
Info info = new Info(geo);
boolean noPlus = true;
if (linethickness != EuclidianStyleConstants.DEFAULT_LINE_THICKNESS) {
// first parameter
noPlus = false;
sb.append("linewidth(");
sb.append(format(linethickness / 2.0 * 0.8));
sb.append(")");
}
if (linestyle != EuclidianStyleConstants.DEFAULT_LINE_TYPE) {
if (!noPlus) {
packSpace(sb, "+");
} else {
noPlus = false;
}
LinestyleCode(linestyle, sb);
}
if (!info.getLinecolor().equals(GColor.BLACK)) {
if (!noPlus) {
packSpace(sb, "+");
} else {
noPlus = false;
}
colorCode(info.getLinecolor(), sb);
}
if (transparency && geo.isFillable() && info.getAlpha() > 0.0f) {
/*
* TODO: write opacity code? if (!noPlus) packSpace("+",sb); else
* noPlus = false; sb.append("fillcolor="); ColorCode(linecolor,sb);
* sb.append(",fillstyle=solid,opacity=");
* sb.append(geo.getAlphaValue());
*/
}
if (noPlus) {
return null;
}
return sb.toString();
}
// Append the linestyle to PSTricks code
private static void LinestyleCode(int linestyle, StringBuilder sb) {
// note: removed 'pt' from linetype commands, seems to work better.
switch (linestyle) {
default:
// do nothing
break;
case EuclidianStyleConstants.LINE_TYPE_DOTTED:
sb.append("dotted");
break;
case EuclidianStyleConstants.LINE_TYPE_DASHED_SHORT:
sb.append("linetype(\"");
// int size = resizePt(3);
int size = 2;
sb.append(size);
sb.append(" ");
sb.append(size);
sb.append("\")");
break;
case EuclidianStyleConstants.LINE_TYPE_DASHED_LONG:
sb.append("linetype(\"");
// size = resizePt(6);
size = 4;
sb.append(size);
sb.append(" ");
sb.append(size);
sb.append("\")");
break;
case EuclidianStyleConstants.LINE_TYPE_DASHED_DOTTED:
sb.append("linetype(\"");
// int size1 = resizePt(2);
// int size2 = resizePt(8);
// int size3 = resizePt(10);
int size1 = 0, size2 = 3, size3 = 4;
sb.append(size1);
sb.append(" ");
sb.append(size2);
sb.append(" ");
sb.append(size3);
sb.append(" ");
sb.append(size2);
sb.append("\")");
break;
}
}
// Append the name color to StringBuilder sb
@Override
protected void colorCode(GColor c0, StringBuilder sb) {
int red = c0.getRed(), green = c0.getGreen(), blue = c0.getBlue();
if (grayscale) {
String colorname = "";
int grayscale1 = (red + green + blue) / 3;
GColor c = GColor.newColor(grayscale1, grayscale1, grayscale1);
if (customColor.containsKey(c)) {
colorname = customColor.get(c).toString();
} else {
// Not compact:
// "pen XXXXXX = rgb(0,0,0); pen YYYYYY = rgb(1,1,1);"
// Compact:
// "pen XXXXXX = rgb(0,0,0), YYYYYY = rgb(1,1,1);"
colorname = createCustomColor(grayscale1, grayscale1,
grayscale1);
if (!compact) {
codeColors.append("pen ");
} else {
codeColors.append(", ");
}
codeColors.append(colorname);
packSpace(codeColors, "=");
codeColors.append("rgb(" + format(grayscale1 / 255d) + ","
+ format(grayscale1 / 255d) + ","
+ format(grayscale1 / 255d) + ")");
if (!compact) {
codeColors.append("; ");
}
customColor.put(c, colorname);
}
if (c.equals(GColor.BLACK)) {
sb.append("black");
} else if (c.equals(GColor.GRAY)) {
sb.append("gray");
} else if (c.equals(GColor.WHITE)) {
sb.append("white");
} else {
sb.append(colorname);
}
} else {
if (c0.equals(GColor.BLACK)) {
sb.append("black");
} else if (c0.equals(GColor.GRAY)) {
sb.append("gray");
} else if (c0.equals(GColor.WHITE)) {
sb.append("white");
} else if (c0.equals(GColor.RED)) {
sb.append("red");
} else if (c0.equals(GColor.GREEN)) {
sb.append("green");
} else if (c0.equals(GColor.BLUE)) {
sb.append("blue");
} else if (c0.equals(GColor.YELLOW)) {
sb.append("yellow");
} else {
String colorname = "";
if (customColor.containsKey(c0)) {
colorname = customColor.get(c0).toString();
} else {
colorname = createCustomColor(red, green, blue);
if (!compact) {
codeColors.append("pen ");
} else {
codeColors.append(", ");
}
codeColors.append(colorname);
packSpace(codeColors, "=");
codeColors.append("rgb(" + format(red / 255d) + ","
+ format(green / 255d) + "," + format(blue / 255d)
+ ")");
if (!compact) {
codeColors.append("; ");
}
customColor.put(c0, colorname);
}
sb.append(colorname);
}
}
}
/**
* Equivalent to ColorCode, but dampens color based upon opacity. Appends
* the pen to codeColor.
*
* @param c
* The original color before transparency.
* @param opacity
* Double value from 0 to 1, with 0 being completely transparent.
* @param sb
* StringBuilder to attach code to.
*/
protected void colorLightCode(GColor c, double opacity, StringBuilder sb) {
// new Color object so that c is not overriden.
GColor tempc;
int red = c.getRed(), green = c.getGreen(), blue = c.getBlue();
red = (int) (255 * (1 - opacity) + red * opacity);
green = (int) (255 * (1 - opacity) + green * opacity);
blue = (int) (255 * (1 - opacity) + blue * opacity);
if (grayscale) {
String colorname = "";
int grayscale1 = (red + green + blue) / 3;
tempc = GColor.newColor(grayscale1, grayscale1, grayscale1);
if (customColor.containsKey(tempc)) {
colorname = customColor.get(tempc).toString();
} else {
colorname = createCustomColor(grayscale1, grayscale1,
grayscale1);
if (!compact) {
codeColors.append("pen ");
} else {
codeColors.append(", ");
}
codeColors.append(colorname);
packSpace(codeColors, "=");
codeColors.append("rgb(" + format(grayscale1 / 255d) + ","
+ format(grayscale1 / 255d) + ","
+ format(grayscale1 / 255d) + ")");
if (!compact) {
codeColors.append("; ");
}
customColor.put(tempc, colorname);
}
if (tempc.equals(GColor.BLACK)) {
sb.append("black");
} else if (tempc.equals(GColor.GRAY)) {
sb.append("gray");
} else if (tempc.equals(GColor.WHITE)) {
sb.append("white");
} else {
sb.append(colorname);
}
} else {
tempc = GColor.newColor(red, green, blue);
if (tempc.equals(GColor.BLACK)) {
sb.append("black");
} else if (tempc.equals(GColor.GRAY)) {
sb.append("gray");
} else if (tempc.equals(GColor.WHITE)) {
sb.append("white");
} else if (tempc.equals(GColor.RED)) {
sb.append("red");
} else if (tempc.equals(GColor.GREEN)) {
sb.append("green");
} else if (tempc.equals(GColor.BLUE)) {
sb.append("blue");
} else if (tempc.equals(GColor.YELLOW)) {
sb.append("yellow");
} else {
String colorname = "";
if (customColor.containsKey(tempc)) {
colorname = customColor.get(tempc).toString();
} else {
colorname = createCustomColor(red, green, blue);
if (!compact) {
codeColors.append("pen ");
} else {
codeColors.append(", ");
}
codeColors.append(colorname);
packSpace(codeColors, "=");
codeColors.append("rgb(" + format(red / 255d) + ","
+ format(green / 255d) + "," + format(blue / 255d)
+ ")");
if (!compact) {
codeColors.append("; ");
}
customColor.put(tempc, colorname);
}
sb.append(colorname);
}
}
}
/*
* // Resize text Keep the ratio between font size and picture height
* private String resizeFont(int fontSize){ int
* latexFont=frame.getFontSize(); double
* height_geogebra=euclidianView.getHeight()/30; double
* height_latex=frame.getLatexHeight(); double
* ratio=height_latex/height_geogebra; int
* theoric_size=(int)Math.round(ratio*fontSize); String st=null;
* switch(latexFont){ case 10: if (theoric_size<=5) st="\\tiny{"; else if
* (theoric_size<=7) st="\\scriptsize{"; else if (theoric_size<=8)
* st="\\footnotesize{"; else if (theoric_size<=9) st="\\small{"; else if
* (theoric_size<=10) ; else if (theoric_size<=12) st="\\large{"; else if
* (theoric_size<=14) st="\\Large{"; else if (theoric_size<=17)
* st="\\LARGE{"; else if (theoric_size<=20) st="\\huge{"; else
* st="\\Huge{"; break; case 11: if (theoric_size<=6) st="\\tiny{"; else if
* (theoric_size<=8) st="\\scriptsize{"; else if (theoric_size<=9)
* st="\\footnotesize{"; else if (theoric_size<=10) st="\\small{"; else if
* (theoric_size<=11) ; else if (theoric_size<=12) st="\\large{"; else if
* (theoric_size<=14) st="\\Large{"; else if (theoric_size<=17)
* st="\\LARGE{"; else if (theoric_size<=20) st="\\huge{"; else
* st="\\Huge{"; break; case 12: if (theoric_size<=6) st="\\tiny{"; else if
* (theoric_size<=8) st="\\scriptsize{"; else if (theoric_size<=10)
* st="\\footnotesize{"; else if (theoric_size<=11) st="\\small{"; else if
* (theoric_size<=12) ; else if (theoric_size<=14) st="\\large{"; else if
* (theoric_size<=17) st="\\Large{"; else if (theoric_size<=20)
* st="\\LARGE{"; else if (theoric_size<=25) st="\\huge{"; else
* st="\\Huge{"; break; } return st; }
*/
// private void defineTransparency(){}
private void addText(String st0, boolean isLatex, int style) {
if (isLatex) {
code.append("$");
}
String st = st0;
if (isLatex) {
st = st.replaceAll("\n", " ");
}
if (isLatex && st.charAt(0) == '$') {
st = st.substring(1);
}
// use packages
if (isLatex) {
/*
* too many commands to check, here's a partial list of more common
* ones: \begin \text \substack \tfrac \dfrac \cfrac \iint \iiint
* \iiiint \boldsymbol \pmb \dots \dddot \ddddot
*/
if (st.indexOf("\\") != -1) {
usepackage.add("amsmath");
}
if (st.indexOf("\\mathbb") != -1 || st.indexOf("\\mathfrak") != -1) {
usepackage.add("amssymb");
}
if (st.indexOf("\\mathscr") != -1) {
usepackage.add("mathrsfs");
}
}
// Convert Unicode symbols
if (isLatex) {
st = convertUnicodeToLatex(st);
} else {
st = convertUnicodeToText(st);
// Strip dollar signs. Questionable! TODO
st = st.replace("\\$", "dollar ");
// Replace all backslash symbol with \textbackslash, except for
// newlines
st = st.replace("\\\\", "\\\\textbackslash ").replace(
"\\\\textbackslash \\\\textbackslash ", "\\\\\\\\ ");
}
switch (style) {
default:
// do nothing
break;
case 1:
if (isLatex) {
code.append("\\mathbf{");
} else {
code.append("\\textbf{");
}
break;
case 2:
if (isLatex) {
code.append("\\mathit{");
} else {
code.append("\\textit{");
}
break;
case 3:
if (isLatex) {
code.append("\\mathit{\\mathbf{");
} else {
code.append("\\textit{\\textbf{");
}
break;
}
/*
* if (!geocolor.equals(Color.BLACK)){ ColorCode2(geocolor,code);
* code.append("{"); } // Colors moved to drawText()
*
* if (size!=app.getFontSize()) { String formatFont=resizeFont(size); if
* (null!=formatFont) code.append(formatFont); }
*/
// strip final '$'
code.append(st.substring(0, st.length() - 1));
if (!isLatex || st.charAt(st.length() - 1) != '$') {
code.append(st.charAt(st.length() - 1));
}
// if (size!=app.getFontSize()) code.append("}");
// if (!geocolor.equals(Color.BLACK)) code.append("}");
switch (style) {
default:
// do nothing
break;
case 1:
case 2:
code.append("}");
break;
case 3:
code.append("}}");
break;
}
if (isLatex) {
code.append("$");
}
}
/**
* Append spaces between list s to code if not in compact mode.
*
* @param s
* A string which can have spaces around it.
*/
protected void packSpaceBetween(String... s) {
packSpaceBetween(code, s);
}
/**
* Append spaces between list s to sb if not in compact mode.
*
* @param sb
* The StringBuilder to which s is attached.
* @param s
* A string which can have spaces around it.
*/
protected void packSpaceBetween(StringBuilder sb, String... s) {
sb.append(s[0]);
for (int i = 1; i < s.length; i++) {
if (!compact) {
sb.append(" ");
sb.append(s[i]);
} else {
sb.append(s[i]);
}
}
}
/**
* Append spaces after s to code if not in compact mode.
*
* @param s
* A string which can have spaces around it.
*/
protected void packSpaceAfter(String... s) {
packSpaceAfter(code, s);
}
/**
* Append spaces after s to sb if not in compact mode.
*
* @param sb
* The StringBuilder to which s is attached.
* @param s
* A string which can have spaces around it.
*/
protected void packSpaceAfter(StringBuilder sb, String... s) {
packSpaceBetween(sb, s);
if (!compact) {
sb.append(" ");
}
}
/**
* Append space around s to code if not in compact mode.
*
* @param s
* A string which can have spaces around it.
*/
protected void packSpace(String... s) {
packSpace(code, s);
}
/**
* Append spaces about s to sb if not in compact mode.
*
* @param sb
* The StringBuilder to which s is attached.
* @param s
* A string which can have spaces around it.
*/
protected void packSpace(StringBuilder sb, String... s) {
if (!compact) {
sb.append(" ");
}
packSpaceAfter(sb, s);
}
/**
* Default version of startDraw, appends the start of a draw() command to
* StringBuilder code.
*
*/
protected void startDraw() {
startDraw(code);
}
/**
* Appends the opening of a draw() command to sb.
*
* @param sb
* Code to attach to.
*/
protected void startDraw(StringBuilder sb) {
if (!compact) {
sb.append("\n");
}
if (compactcse5) {
sb.append("D(");
} else {
sb.append("draw(");
}
}
/**
* Appends line style code to end of StringBuilder code.
*
* @param geo
* contains line style code.
*/
protected void endDraw(GeoElement geo) {
endDraw(geo, code);
}
/**
* Appends line style code to end of StringBuilder code.
*
* @param geo
* contains line style code.
* @param sb
* code to attach to.
*/
protected void endDraw(GeoElement geo, StringBuilder sb) {
if (fillInequality) {
return;
}
if (lineOptionCode(geo, true) != null) {
packSpaceAfter(sb, ",");
sb.append(lineOptionCode(geo, true));
}
sb.append("); ");
}
/**
* Begins an object drawn by the filldraw() command.
*
* @param sb
* StringBuilder to which code added.
*/
protected void startTransparentFill(StringBuilder sb) {
if (!compact) {
sb.append("\n");
}
if (fillType != ExportSettings.FILL_NONE) {
sb.append("filldraw(");
} else if (compactcse5) {
sb.append("D(");
} else {
sb.append("draw(");
}
}
/**
* Closes an object drawn by the filldraw() command.
*
* @param geo
* Object that can be filled.
* @param sb
* StringBuilder to which code added.
*/
protected void endTransparentFill(GeoElement geo, StringBuilder sb) {
Info info = new Info(geo);
// transparent fill options
if (fillType == ExportSettings.FILL_OPAQUE) {
packSpaceAfter(sb, ",");
if (info.getAlpha() >= 0.9) {
colorCode(info.getLinecolor(), sb);
} else {
sb.append("invisible");
}
}
// use opacity(alpha value) pen
else if (fillType == ExportSettings.FILL_OPACITY_PEN) {
packSpaceAfter(sb, ",");
colorCode(info.getLinecolor(), sb);
packSpace(sb, "+");
sb.append("opacity(");
sb.append(info.getAlpha());
sb.append(")");
} else if (fillType == ExportSettings.FILL_LAYER) {
packSpaceAfter(sb, ",");
colorLightCode(info.getLinecolor(), info.getAlpha(), sb);
}
if (lineOptionCode(geo, true) != null) {
packSpaceAfter(sb, ",");
sb.append(lineOptionCode(geo, true));
}
sb.append("); ");
}
/**
* For use with drawSpecialPoint() function, appends dot styles
*
* @param c
* color
*/
protected void endPoint(GColor c) {
if (!c.equals(GColor.BLACK) && dotColors) {
code.append(",");
if (!compact) {
code.append(" ");
}
colorCode(c, code);
}
code.append("); ");
}
/**
* Adds a point in the format "(s1,s2)" to sb.
*
* @param s1
* format(x-coordinate)
* @param s2
* format(y-coordinate)
* @param sb
* StringBuilder object to append code to.
*/
protected void addPoint(String s1, String s2, StringBuilder sb) {
String pairString = "(" + s1 + "," + s2 + ")";
if (pairName && pairNameTable.containsKey(pairString)) {
sb.append(pairNameTable.get(pairString));
// retrieves point name from codePointDecl
// using string manipulations, unsafe
// int locPair = codePointDecl.indexOf("(" + s1 + "," + s2 + ")");
// if(locPair != -1 && compact) {
// String name = codePointDecl.substring(0,locPair);
// int locNameStart = name.lastIndexOf(" ")+1;
// int locNameEnd = name.lastIndexOf("=");
// name = codePointDecl.substring(locNameStart,locNameEnd);
// sb.append(name);
// return;
// }
// else {
// String name = codePointDecl.substring(0,locPair); // temporary re-use
// int locNameStart = Math.max(name.lastIndexOf(", ")+2,
// name.lastIndexOf("pair ")+5);
// int locNameEnd = name.lastIndexOf("=");
// name = codePointDecl.substring(locNameStart,locNameEnd);
// sb.append(name);
// return;
// }
} else {
sb.append(pairString);
}
}
/**
* Adds a point in the format "(s1,s2)" to sb.
*
* @param x
* real value of x-coordinate
* @param y
* real value of y-coordinate
* @param sb
* StringBuilder object to append code to.
*/
protected void addPoint(double x, double y, StringBuilder sb) {
addPoint(format(x), format(y), sb);
}
/**
* Converts unicode expressions ("\u03c0") to plain text ("pi").
*
* @param sb
* StringBuilder with code.
* @return Updated StringBuilder;
*/
protected StringBuilder convertUnicodeToText(StringBuilder sb) {
// import unicode;
String tempc = sb.toString();
tempc = convertUnicodeToText(tempc);
// override sb with tempc
sb.delete(0, sb.length());
sb.append(tempc);
return sb;
}
/**
* Converts unicode expressions ("\u03c0") to plain text ("pi").
*
* @param s
* Text to convert unicode symbols to text. Is not modified.
* @return Converted string.
*/
protected String convertUnicodeToText(String s) {
// import unicode;
String s1 = s;
Iterator<Character> it = UnicodeTeX.getMap().keySet().iterator();
while (it.hasNext()) {
char skey = it.next();
s1 = s1.replace(skey + "", UnicodeTeX.getMap().get(skey) + " ");
}
return s1.replace(Unicode.DEGREE, "o ")
// degree symbol
.replace("\u212f", "e ").replace("\u00b2", "2 ")
.replace("\u00b3", "3 ").replace("pi \\)", "pi\\)"); // eliminate
// unsightly
// spaces
}
/**
* Converts unicode expressions ("\u03c0") to LaTeX expressions ("\pi").
*
* @param s
* Text to convert unicode symbols to LaTeX. Is not modified.
* @return Converted string.
*/
protected String convertUnicodeToLatex(String s) {
// import unicode;
String s1 = s;
Iterator<Character> it = UnicodeTeX.getMap().keySet().iterator();
// look up unicodeTable conversions and replace with LaTeX commands
while (it.hasNext()) {
char skey = it.next();
s1 = s1.replace(skey + "",
"\\\\" + UnicodeTeX.getMap().get(skey) + " ");
}
// strip dollar signs
/*
* int locDollar = 0; while((locDollar = s1.indexOf('$',locDollar+1)) !=
* -1) { if(locDollar != 0 && locDollar != s1.length() &&
* s1.charAt(locDollar-1) != '\\') s1 = s1.substring(0,locDollar) + "\\"
* + s1.substring(locDollar); }
*/
StringBuilder sb = new StringBuilder();
// ignore first and last characters
// TODO check if odd number of dollar signs? No catch-all fix ..
sb.append(s1.charAt(0));
for (int i = 1; i < s1.length() - 1; i++) {
if (s1.charAt(i - 1) == '\\'
&& (i == 1 || s1.charAt(i - 2) != '\\')) {
sb.append(s1.charAt(i));
continue;
} else if (s1.charAt(i) == '$') {
sb.append("\\$");
} else {
sb.append(s1.charAt(i));
}
}
if (s1.length() > 1) {
sb.append(s1.charAt(s1.length() - 1));
}
s1 = sb.toString();
return s1.replace(Unicode.DEGREE, "^\\\\circ").replace("\u212f", " e")
.replace("\u00b2", "^2").replace("\u00b3", "^3")
.replace("\\\\questeq", "\\\\stackrel{?}{=}");
}
/**
* Formats a function string.
*
* @param s
* Code containing function.
* @return Parsed function string compatible with programming languages.
*/
protected String parseFunction(String s) {
// Unicode?
return killSpace(StringUtil.toLaTeXString(s, true));
}
/*
* Rewrite the function: TODO Kill spaces Add character * when needed: 2 x
* +3 ----> 2*x+3 Rename several functions: log(x) ---> ln(x) ceil(x) --->
* ceiling(x) exp(x) ---> 2.71828^(x)
*/
private static String killSpace(String name) {
StringBuilder sb = new StringBuilder();
boolean operand = false;
boolean space = false;
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if ("*/+-".indexOf(c) != -1) {
sb.append(c);
operand = true;
space = false;
} else if (c == ' ') {
if (!operand) {
space = true;
} else {
space = false;
operand = false;
}
} else {
if (space) {
sb.append("*");
}
sb.append(c);
space = false;
operand = false;
}
}
// following needs cleanup
// rename functions log, ceil and exp
renameFunc(sb, "\\\\pi", "pi");
renameFunc(sb, "EXP(", "exp(");
renameFunc(sb, "ln(", "log(");
// integers
renameFunc(sb, "ceiling(", "ceil(");
renameFunc(sb, "CEILING(", "ceil(");
renameFunc(sb, "FLOOR(", "floor(");
// de-capitalize trigonometric/hyperbolics
renameFunc(sb, "SIN(", "sin(");
renameFunc(sb, "COS(", "cos(");
renameFunc(sb, "TAN(", "tan(");
renameFunc(sb, "ASIN(", "asin(");
renameFunc(sb, "ACOS(", "acos(");
renameFunc(sb, "ATAN(", "atan(");
renameFunc(sb, "SINH(", "sinh(");
renameFunc(sb, "COSH(", "cosh(");
renameFunc(sb, "TANH(", "tanh(");
renameFunc(sb, "ASINH(", "asinh(");
renameFunc(sb, "ACOSH(", "acosh(");
renameFunc(sb, "ATANH(", "atanh(");
// for exponential in new Geogebra version.
renameFunc(sb, Unicode.EULER_STRING, "2.718"); /* 2.718281828 */
// temporary code: may be redundant, fail-safe
// upper letter greek symbols
renameFunc(sb, "\u0393", "Gamma");
renameFunc(sb, "\u0394", "Delta");
renameFunc(sb, "\u0398", "Theta");
renameFunc(sb, "\u039b", "Lambda");
renameFunc(sb, "\u039e", "Xi");
renameFunc(sb, "\u03a0", "Pi");
renameFunc(sb, "\u03a3", "Sigma");
renameFunc(sb, "\u03a6", "Phi");
renameFunc(sb, "\u03a8", "Psi");
renameFunc(sb, "\u03a9", "Omega");
// lower letter greek symbols
renameFunc(sb, "\u03b1", "alpha");
renameFunc(sb, "\u03b2", "beta");
renameFunc(sb, "\u03b3", "gamma");
renameFunc(sb, "\u03b4", "delta");
renameFunc(sb, "\u03b5", "epsilon");
renameFunc(sb, "\u03b6", "zeta");
renameFunc(sb, "\u03b7", "eta");
renameFunc(sb, "\u03b8", "theta");
renameFunc(sb, "\u03b9", "iota");
renameFunc(sb, "\u03ba", "kappa");
renameFunc(sb, "\u03bb", "lambda");
renameFunc(sb, "\u03bc", "mu");
renameFunc(sb, "\u03be", "xi");
renameFunc(sb, Unicode.PI_STRING, "pi");
renameFunc(sb, "\u03c1", "rho");
renameFunc(sb, "\u03c2", "varsigma");
renameFunc(sb, "\u03c3", "sigma");
renameFunc(sb, "\u03c4", "tau");
renameFunc(sb, "\u03c5", "upsilon");
renameFunc(sb, "\u03c6", "varphi");
renameFunc(sb, "\u03c7", "chi");
renameFunc(sb, "\u03c8", "psi");
renameFunc(sb, "\u03c9", "omega");
// remove greek letter escapes
String greekalpha[] = { "alpha", "beta", "gamma", "delta", "epsilon",
"zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "xi",
"pi", "rho", "varsigma", "sigma", "tau", "upsilon", "varphi",
"chi", "psi", "omega" };
for (int i = 0; i < greekalpha.length; i++) {
renameFunc(sb, "\\" + greekalpha[i], greekalpha[i]); // lower case
String temps = Character
.toString(Character.toUpperCase(greekalpha[i].charAt(0)))
+ greekalpha[i].substring(1);
renameFunc(sb, "\\" + temps, temps); // upper case
}
return sb.toString();
}
@Override
protected StringTemplate getStringTemplate() {
// Asymptote doesn't understand E notation ie 3E-10
return StringTemplate.fullFigures(StringType.PSTRICKS);
}
/**
* @param geo
* element
* @return stroke style
*/
public String penStyle(GeoElement geo) {
StringBuilder sb = new StringBuilder();
switch (geo.getLineType()) {
default:
case EuclidianStyleConstants.DEFAULT_LINE_TYPE:
sb.append("solid+");
break;
case EuclidianStyleConstants.LINE_TYPE_DASHED_LONG:
sb.append("longdashed+");
break;
case EuclidianStyleConstants.LINE_TYPE_DASHED_SHORT:
sb.append("dashed+");
break;
case EuclidianStyleConstants.LINE_TYPE_DASHED_DOTTED:
sb.append("dashdotted+");
break;
case EuclidianStyleConstants.LINE_TYPE_DOTTED:
sb.append("Dotted+");
break;
}
return sb.toString();
}
@Override
protected boolean isLatexFunction(String s) {
// used if there are other non-latex
return !s.toLowerCase().contains("csc(")
&& !s.toLowerCase().contains("csch(")
&& !s.toLowerCase().contains("sec(")
&& !s.toLowerCase().contains("cot(")
&& !s.toLowerCase().contains("coth(")
&& !s.toLowerCase().contains("sech(")
&& !s.toLowerCase().contains("if");
}
@Override
protected void drawNyquist(GeoTransferFunction g) {
StringBuilder sb = new StringBuilder();
colorCode(g.getObjectColor(), sb);
String template = "draw( (%0,%1) -- (%2,%3)," + sb + "+linewidth(1)"
+ Unicode.SECTION_SIGN + ",arrows" + Unicode.SECTION_SIGN
+ ");\n";
StringBuilder lineBuilder = drawNyquistDiagram(g, template,
Unicode.SECTION_SIGN + ",arrows" + Unicode.SECTION_SIGN,
",BeginArrow", ",EndArrow");
code.append(lineBuilder.toString() + ";\n");
}
@Override
protected String format(double d) {
return super.format(d).replace("E", "e");
}
@Override
protected boolean fillSpline(GeoCurveCartesian[] curves) {
if (curves[0].getAlphaValue() == 0
&& FillType.STANDARD == curves[0].getFillType()) {
return false;
}
String liopco = lineOptionCode(curves[0], true);
if (liopco == null) {
liopco = "";
} else {
liopco = "," + liopco;
}
for (int i = 0; i < curves.length; i++) {
drawSingleCurveCartesian(curves[i], false);
}
StringBuilder fill = new StringBuilder();
fill.append("\nfill(");
double p;
double y;
double x;
for (int i = 0; i < curves.length; i++) {
p = curves[i].getMinParameter();
y = curves[i].getFunY().value(curves[i].getMinParameter());
if (Math.abs(y) < 0.001) {
y = 0;
}
double step = (curves[i].getMaxParameter()
- curves[i].getMinParameter()) / 200;
for (; p <= curves[i].getMaxParameter(); p += step) {
y = curves[i].getFunY().value(p);
x = curves[i].getFunX().value(p);
if (Math.abs(y) < 0.001) {
y = 0;
}
if (Math.abs(x) < 0.001) {
x = 0;
}
fill.append("(" + x + "," + y + ") -- ");
}
}
fill.append("cycle" + liopco + ");");
code.append(fill);
return true;
}
/**
* @param s
* shape
* @param ineq
* inequality
* @param geo
* element
* @param ds
* bounds, see getViewBoundsForGeo
*/
public void superFill(GShape s, Inequality ineq, FunctionalNVar geo,
double[] ds) {
importpackage.add("patterns");
GColor c = ((GeoElement) geo).getObjectColor();
int lineType = ((GeoElement) geo).getLineType();
((GeoElement) geo).setLineType(ineq.getBorder().lineType);
code.append("\npen border=" + penStyle((GeoElement) geo));
colorCode(c, code);
((GeoElement) geo).setLineType(lineType);
code.append(";\npen fillstyle=" + penStyle((GeoElement) geo));
colorCode(c, code);
if (((GeoElement) geo).getFillType() != FillType.STANDARD) {
code.append(";\nadd(\"hatch\",hatch(2mm,NW,fillstyle));\n");
} else {
code.append(";\nadd(\"hatch\",hatch(0.5mm,NW,fillstyle));\n");
}
switch (ineq.getType()) {
default:
// do nothing
break;
case INEQUALITY_CONIC:
GeoConicND conic = ineq.getConicBorder();
if (conic.getType() == GeoConicNDConstants.CONIC_ELLIPSE
|| conic.getType() == GeoConicNDConstants.CONIC_CIRCLE) {
conic.setType(GeoConicNDConstants.CONIC_ELLIPSE);
((GeoElement) conic)
.setObjColor(((GeoElement) geo).getObjectColor());
conic.setType(GeoConicNDConstants.CONIC_ELLIPSE);
((GeoElement) conic)
.setAlphaValue(((GeoElement) geo).getAlphaValue());
conic.setType(GeoConicNDConstants.CONIC_ELLIPSE);
((GeoElement) conic).setHatchingAngle(
(int) ((GeoElement) geo).getHatchingAngle());
((GeoElement) conic).setHatchingDistance(
((GeoElement) geo).getHatchingDistance());
((GeoElement) conic)
.setFillType(((GeoElement) geo).getFillType());
fillInequality = true;
drawGeoConic((GeoConic) conic);
fillInequality = false;
break;
}
case INEQUALITY_PARAMETRIC_Y:
case INEQUALITY_PARAMETRIC_X:
case INEQUALITY_1VAR_X:
case INEQUALITY_1VAR_Y:
case INEQUALITY_LINEAR:
double[] coords = new double[2];
double zeroY = ds[5] * ds[3];
double zeroX = ds[4] * (-ds[0]);
GPathIterator path = s.getPathIterator(null);
code.append("filldraw(");
double precX = Integer.MAX_VALUE;
double precY = Integer.MAX_VALUE;
while (!path.isDone()) {
path.currentSegment(coords);
if (coords[0] == precX && coords[1] == precY) {
code.append("cycle,pattern(\"hatch\"),border);\n");
code.append("filldraw(");
} else {
code.append("(");
code.append(format((coords[0] - zeroX) / ds[4]));
code.append(",");
code.append(format(-(coords[1] - zeroY) / ds[5]));
code.append(")--");
}
precX = coords[0];
precY = coords[1];
path.next();
}
int i = code.lastIndexOf(")");
code.delete(i + 1, code.length());
code.append(";\n");
break;
}
}
}