package org.geogebra.common.euclidian;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.awt.GPoint;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.Region;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.algos.AlgoArcLength;
import org.geogebra.common.kernel.algos.AlgoClosestPoint;
import org.geogebra.common.kernel.algos.AlgoPolygon;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPolyLine;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.geos.GeoText;
import org.geogebra.common.kernel.kernelND.GeoConicND;
import org.geogebra.common.kernel.kernelND.GeoConicPartND;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoLineND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.main.Localization;
import org.geogebra.common.util.StringUtil;
public class TextDispatcher {
protected Localization l10n;
protected Kernel kernel;
private EuclidianView view;
public TextDispatcher(Kernel kernel, EuclidianView view) {
this.kernel = kernel;
this.view = view;
this.l10n = kernel.getLocalization();
}
protected static String removeUnderscoresAndBraces(String label) {
// remove all subscripts
return label.replaceAll("_", "").replaceAll("\\{", "").replaceAll("\\}",
"");
}
protected void setNoPointLoc(GeoText text, GPoint loc) {
text.setAbsoluteScreenLocActive(true);
text.setAbsoluteScreenLoc(loc.x, loc.y);
}
public GeoElement[] getAreaText(GeoElement conic, GeoNumberValue area,
GPoint loc) {
// text
GeoText text = createDynamicTextForMouseLoc("AreaOfA", conic, area,
loc);
if (conic.isLabelSet()) {
if (!area.isLabelSet()) {
area.setLabel(removeUnderscoresAndBraces(
StringUtil.toLowerCase(l10n.getCommand("Area"))
+ conic.getLabelSimple()));
}
text.setLabel(removeUnderscoresAndBraces(
l10n.getPlain("Text") + conic.getLabelSimple()));
}
return new GeoElement[] { text };
}
private String descriptionPoints(String type, GeoPolygon poly) {
// build description text including point labels
StringBuilder descText = new StringBuilder();
// use points for polygon with static points (i.e. no list of points)
GeoPointND[] points = null;
if (poly.getParentAlgorithm() instanceof AlgoPolygon) {
points = ((AlgoPolygon) poly.getParentAlgorithm()).getPoints();
}
if (points != null) {
descText.append(" \"");
boolean allLabelsSet = true;
for (int i = 0; i < points.length; i++) {
if (points[i].isLabelSet()) {
descText.append(" + Name["
+ points[i].getLabel(StringTemplate.defaultTemplate)
+ "]");
} else {
allLabelsSet = false;
i = points.length;
}
}
if (allLabelsSet) {
descText.append(" + \"");
for (int i = 0; i < points.length; i++) {
points[i].setLabelVisible(true);
points[i].updateRepaint();
}
} else {
return l10n.getPlain(type,
"\" + Name["
+ poly.getLabel(StringTemplate.defaultTemplate)
+ "] + \"");
}
} else {
return l10n.getPlain(type, "\" + Name["
+ poly.getLabel(StringTemplate.defaultTemplate) + "] + \"");
}
return l10n.getPlain(type, descText.toString());
}
/**
* Creates a text that shows a number value of geo.
*/
private GeoText createDynamicText(String type, GeoElement object,
GeoElementND value) {
// create text that shows length
try {
// type might be eg "Area of %0" or "XXX %0 YYY"
String descText;
if (object.isGeoPolygon()) {
descText = descriptionPoints(type, (GeoPolygon) object);
} else {
descText = l10n.getPlain(type,
"\" + Name["
+ object.getLabel(
StringTemplate.defaultTemplate)
+ "] + \"");
}
// create dynamic text
String dynText = "\"" + descText + " = \" + "
+ value.getLabel(StringTemplate.defaultTemplate);
// checkZooming();
GeoText text = kernel.getAlgebraProcessor().evaluateToText(dynText,
true, true);
return text;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Creates a text that shows a number value of geo at the current mouse
* position.
*/
protected GeoText createDynamicTextForMouseLoc(String type,
GeoElement object, GeoElementND value, GPoint loc) {
GeoText text = createDynamicText(type, object, value);
if (text != null) {
GeoPointND P = null;
if (object.isRegion()) {
P = getPointForDynamicText((Region) object, loc);
} else if (object.isPath()) {
P = getPointForDynamicText((Path) object, loc);
} else {
P = getPointForDynamicText(loc);
}
if (P != null) {
P.setAuxiliaryObject(true);
P.setEuclidianVisible(false);
P.updateRepaint();
try {
text.setStartPoint(P);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else {
setNoPointLoc(text, loc);
}
text.checkVisibleIn3DViewNeeded();
text.setBackgroundColor(GColor.WHITE);
text.updateRepaint();
}
return text;
}
protected GeoPointND getPointForDynamicText(Region object, GPoint loc) {
double rwx = 0, rwy = 0;
if (loc != null) {
rwx = view.toRealWorldCoordX(loc.x);
rwy = view.toRealWorldCoordY(loc.y);
} else if (object instanceof GeoPolygon) {
GeoPointND[] pts = ((GeoPolygon) object).getPointsND();
for (GeoPointND pt : pts) {
rwx += pt.getCoordsInD2().getX();
rwy += pt.getCoordsInD2().getY();
}
rwx = rwx / pts.length;
rwy = rwy / pts.length;
} else if (object instanceof GeoConicND) {
rwx = ((GeoConicND) object).getTranslationVector().getX();
rwy = ((GeoConicND) object).getTranslationVector().getY();
}
return view.getEuclidianController().createNewPoint(
removeUnderscoresAndBraces(l10n.getPlain("Point")
+ object.getLabel(StringTemplate.defaultTemplate)),
false, object, rwx, rwy, 0, false, false);
}
protected GeoPointND getPointForDynamicText(Path object, GPoint loc) {
return view.getEuclidianController().getCompanion().createNewPoint(
removeUnderscoresAndBraces(l10n.getPlain("Point")
+ object.getLabel(StringTemplate.defaultTemplate)),
false, object, view.toRealWorldCoordX(loc.x),
view.toRealWorldCoordY(loc.y), 0, false, false);
}
protected GeoPointND getPointForDynamicText(GPoint loc) {
return null;
}
/**
* Creates a text that shows the distance length between geoA and geoB at
* the given startpoint.
*/
public GeoText createDistanceText(GeoElementND geoA, GeoElementND geoB,
GeoPointND textCorner, GeoNumeric length) {
StringTemplate tpl = StringTemplate.defaultTemplate;
// create text that shows length
try {
String strText = "";
boolean useLabels = geoA.isLabelSet() && geoB.isLabelSet();
if (useLabels) {
length.setLabel(removeUnderscoresAndBraces(
StringUtil.toLowerCase(l10n.getCommand("Distance"))
// .toLowerCase(Locale.US)
+ geoA.getLabel(tpl) + geoB.getLabel(tpl)));
// strText = "\"\\overline{\" + Name["+ geoA.getLabel()
// + "] + Name["+ geoB.getLabel() + "] + \"} \\, = \\, \" + "
// + length.getLabel();
// DistanceAB="\\overline{" + %0 + %1 + "} \\, = \\, " + %2
// or
// DistanceAB=%0+%1+" \\, = \\, "+%2
strText = "Name[" + geoA.getLabel(tpl) + "] + Name["
+ geoB.getLabel(tpl) + "] + \" = \" + "
+ length.getLabel(tpl);
// Application.debug(strText);
makeLabelNameVisible(geoA);
makeLabelNameVisible(geoB);
geoA.updateRepaint();
geoB.updateRepaint();
} else {
length.setLabel(removeUnderscoresAndBraces(
StringUtil.toLowerCase(l10n.getCommand("Distance"))));
// .toLowerCase(Locale.US)));
strText = "\"\"" + length.getLabel(tpl);
}
// create dynamic text
// checkZooming();
GeoText text = kernel.getAlgebraProcessor().evaluateToText(strText,
true, true);
if (useLabels) {
text.setLabel(removeUnderscoresAndBraces(l10n.getPlain("Text")
+ geoA.getLabel(tpl) + geoB.getLabel(tpl)));
}
text.checkVisibleIn3DViewNeeded();
text.setStartPoint(textCorner);
text.setBackgroundColor(GColor.WHITE);
text.updateRepaint();
return text;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static void makeLabelNameVisible(GeoElementND geo) {
// make sure that name of the geo will be visible
if (!geo.isLabelVisible()) {
if (geo.getLabelMode() != GeoElement.LABEL_NAME_VALUE) {
geo.setLabelMode(GeoElement.LABEL_NAME);
}
geo.setLabelVisible(true);
} else {
if (geo.getLabelMode() == GeoElement.LABEL_VALUE) {
geo.setLabelMode(GeoElement.LABEL_NAME_VALUE);
}
}
}
public GeoElement[] createCircumferenceText(GeoConicND conic, GPoint loc) {
if (conic.isGeoConicPart()) {
Construction cons = kernel.getConstruction();
AlgoArcLength algo = new AlgoArcLength(cons, null,
(GeoConicPartND) conic);
// cons.removeFromConstructionList(algo);
GeoNumeric arcLength = algo.getArcLength();
GeoText text = createDynamicTextForMouseLoc("ArcLengthOfA", conic,
arcLength, loc);
text.setLabel(removeUnderscoresAndBraces(
l10n.getPlain("Text") + conic.getLabelSimple()));
GeoElement[] ret = { text };
return ret;
}
// standard case: conic
// checkZooming();
GeoNumeric circumFerence = kernel.getAlgoDispatcher()
.Circumference(null, conic);
// text
GeoText text = createDynamicTextForMouseLoc("CircumferenceOfA", conic,
circumFerence, loc);
if (conic.isLabelSet()) {
circumFerence.setLabel(removeUnderscoresAndBraces(
StringUtil.toLowerCase(l10n.getCommand("Circumference"))
+ conic.getLabel(StringTemplate.defaultTemplate)));
text.setLabel(removeUnderscoresAndBraces(l10n.getPlain("Text")
+ conic.getLabel(StringTemplate.defaultTemplate)));
}
GeoElement[] ret = { text };
return ret;
}
public GeoElement[] createPerimeterText(GeoPolygon poly, GPoint mouseLoc) {
GeoNumeric perimeter = kernel.getAlgoDispatcher().Perimeter(null, poly);
// text
GeoText text = createDynamicTextForMouseLoc("PerimeterOfA", poly,
perimeter, mouseLoc);
if (poly.isLabelSet()) {
perimeter.setLabel(removeUnderscoresAndBraces(
StringUtil.toLowerCase(l10n.getCommand("Perimeter"))
+ poly.getLabelSimple()));
text.setLabel(removeUnderscoresAndBraces(
l10n.getPlain("Text") + poly.getLabelSimple()));
}
text.checkVisibleIn3DViewNeeded();
GeoElement[] ret = { text };
return ret;
}
public GeoElement[] createPerimeterText(GeoPolyLine poly, GPoint mouseLoc) {
// text
GeoText text = createDynamicTextForMouseLoc("PerimeterOfA", poly, poly,
mouseLoc);
if (poly.isLabelSet()) {
text.setLabel(removeUnderscoresAndBraces(
l10n.getPlain("Text") + poly.getLabelSimple()));
}
text.checkVisibleIn3DViewNeeded();
GeoElement[] ret = { text };
return ret;
}
public GeoElement[] createSlopeText(GeoLine line, GeoFunction f,
GPoint mouseLoc) {
GeoNumeric slope;
/*
* if ("de_AT".equals(strLocale)) { slope = kernel.Slope("k", line); }
* else { slope = kernel.Slope("m", line); }
*/
String label = l10n.getPlain("ExplicitLineGradient");
// make sure automatic naming goes m, m_1, m_2, ..., m_{10}, m_{11}
// etc
if (kernel.lookupLabel(label) != null) {
int i = 1;
while (kernel.lookupLabel(
i > 9 ? label + "_{" + i + "}" : label + "_" + i) != null) {
i++;
}
label = i > 9 ? label + "_{" + i + "}" : label + "_" + i;
}
// checkZooming();
slope = kernel.getAlgoDispatcher().Slope(label, line, f);
// show value
if (slope.isLabelVisible()) {
slope.setLabelMode(GeoElement.LABEL_NAME_VALUE);
} else {
slope.setLabelMode(GeoElement.LABEL_VALUE);
}
slope.setLabelVisible(true);
slope.updateRepaint();
GeoElement[] ret = { slope };
return ret;
}
public GeoElement createDistanceText(GeoPointND point1, GeoPointND point2) {
GeoNumeric length = kernel.getAlgoDispatcher().Distance(null, point1,
point2);
// set startpoint of text to midpoint of two points
GeoPointND midPoint = MidpointForDistance(point1, point2);
return this.createDistanceText(point1, point2, midPoint, length);
}
/**
* Creates Midpoint M = (P + Q)/2 without label (for use as e.g. start
* point)
*/
private final GeoPointND MidpointForDistance(GeoPointND P, GeoPointND Q) {
return (GeoPointND) view.getEuclidianController().getCompanion()
.midpoint(P, Q);
}
public GeoElement createDistanceText(GeoPointND point, GeoLineND line) {
GeoNumeric length = kernel.getAlgoDispatcher().Distance(null, point,
line);
// set startpoint of text to midpoint between point and line
GeoPointND midPoint = MidpointForDistance(point,
ClosestPoint(point, (Path) line));
return this.createDistanceText(point, line, midPoint, length);
}
/**
* Returns the projected point of P on line g (or nearest for a Segment)
*/
final private GeoPointND ClosestPoint(GeoPointND P, Path g) {
Construction cons = kernel.getConstruction();
boolean oldMacroMode = cons.isSuppressLabelsActive();
cons.setSuppressLabelCreation(true);
AlgoClosestPoint cp = kernel.getAlgoDispatcher()
.getNewAlgoClosestPoint(cons, g, P);
cons.setSuppressLabelCreation(oldMacroMode);
return cp.getP();
}
}