/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
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.
*/
/*
* RelationNumerical.java
*
* Created on 27 June 2014, 14:17
*
* based on Relation.java by Markus
* created on 12 December 2001, 12:37
*/
package org.geogebra.common.kernel;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.geogebra.common.kernel.RelationNumerical.Report.RelationCommand;
import org.geogebra.common.kernel.algos.AlgoIntersectConics;
import org.geogebra.common.kernel.algos.AlgoIntersectLineConic;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.geos.GeoConic;
import org.geogebra.common.kernel.geos.GeoConicPart;
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.GeoList;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.geos.GeoPolygon;
import org.geogebra.common.kernel.geos.GeoVec3D;
import org.geogebra.common.kernel.geos.GeoVector;
import org.geogebra.common.kernel.kernelND.GeoConicNDConstants;
import org.geogebra.common.kernel.kernelND.GeoSegmentND;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Localization;
/**
* Markus' original code has been extensively rewritten. On the other hand, the
* new behavior is backward compatible and the basic design is still the same.
*
* @author Zoltan Kovacs <zoltan@geogebra.org>
*/
public class RelationNumerical {
/**
* Stores information about geometric facts being computed numerically.
*
*/
public static class Report {
/**
* True if the numerical computation resulted in "yes". False if the
* computation resulted in "no". Null if computation was not done due to
* some error.
*/
public Boolean boolResult;
/**
* The internal name of the symbolic check, mostly the name of the Are*
* command.
*/
public enum RelationCommand {
/**
* equality
*/
AreEqual,
/**
* parallelism
*/
AreParallel,
/**
* orthogonality
*/
ArePerpendicular,
/**
* member of a path
*/
IsOnPath,
/**
* congruent segments
*/
AreCongruent,
/** collinear points */
AreCollinear,
/** concyclic points */
AreConcyclic,
/** concurrent lines */
AreConcurrent
}
/**
* Null if no further symbolic check is proposed. (Sometimes there are
* no suitable checks.) Otherwise the name of the symbolic check (mostly
* AreEqual).
*/
public RelationCommand symbolicCheck;
/**
* Localized version of the numerical computation check.
*/
public String stringResult;
/**
* Creates a numerical computation report.
*
* @param boolres
* Boolean result.
* @param command
* GeoGebra's Are... command to be done for further symbolic
* checking.
* @param stringres
* Localized string result.
*/
Report(Boolean boolres, RelationCommand command, String stringres) {
boolResult = boolres;
symbolicCheck = command;
stringResult = stringres;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Report)) {
return false;
}
// This does not work in GWT, maybe there is something equivalent.
// if (!Report.class.isAssignableFrom(obj.getClass())) {
// return false;
// }
// Maybe this is not really required at all...
return this.stringResult
.equalsIgnoreCase(((Report) obj).stringResult);
}
@Override
public int hashCode() {
return stringResult.hashCode();
}
}
/**
* Sort the relation reports alphabetically
*
* @param reports
* unsorted relation reports
* @return alphabetically sorted relation reports
*/
public static SortedSet<Report> sortAlphabetically(Set<Report> reports) {
Comparator<Report> myComparator = new Comparator<Report>() {
@Override
public int compare(Report r1, Report r2) {
return r1.stringResult.compareTo(r2.stringResult);
}
};
TreeSet<Report> sortedReports = new TreeSet<Report>(myComparator);
sortedReports.addAll(reports);
return sortedReports;
}
private void register(Boolean boolres, RelationCommand command,
String stringres) {
Report r = new Report(boolres, command, stringres);
reports.add(r);
}
private App app;
private Localization loc;
private Construction cons;
private Set<Report> reports;
/**
* Creates new relation
*
* @param kernel
* kernel
*/
public RelationNumerical(Kernel kernel) {
app = kernel.getApplication();
loc = app.getLocalization();
cons = kernel.getConstruction();
reports = new HashSet<Report>();
}
/**
* Description of the relation between three GeoElements a, b and c (equal,
* incident, intersect, parallel, linear dependent, tangent of, ...)
*
* @param a
* first geo
* @param b
* second geo
* @param c
* third geo (optional)
* @return string describing relation between these two
*/
final public Set<Report> relation(GeoElement a, GeoElement b,
GeoElement c) {
// check defined state
if (!a.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", a.getColoredLabel()));
return reports;
} else if (!b.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", b.getColoredLabel()));
return reports;
} else if (!c.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", c.getColoredLabel()));
return reports;
}
// decide what relation method can be used
// point, point, point
if (a instanceof GeoPoint && b instanceof GeoPoint
&& c instanceof GeoPoint) {
return relation((GeoPoint) a, (GeoPoint) b, (GeoPoint) c);
} else if (a instanceof GeoSegmentND && b instanceof GeoSegmentND
&& c instanceof GeoSegmentND) {
return relation((GeoSegmentND) a, (GeoSegmentND) b,
(GeoSegmentND) c);
} else if (a instanceof GeoLine && b instanceof GeoLine
&& c instanceof GeoLine) {
return relation((GeoLine) a, (GeoLine) b, (GeoLine) c);
}
register(null, null, loc.getPlain("ComparisonNotPossible"));
return reports;
}
/**
* description of the relation between two GeoElements a, b (equal,
* incident, intersect, parallel, linear dependent, tangent of, ...)
*
* @param a
* first geo
* @param b
* second geo
* @param c
* third geo (optional)
* @param d
* forth geo (optional)
* @return string describing relation between these two
*/
final public Set<Report> relation(GeoElement a, GeoElement b, GeoElement c,
GeoElement d) {
if (d == null) {
if (c == null) {
return relation(a, b);
}
return relation(a, b, c);
}
// check defined state
if (!a.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", a.getColoredLabel()));
return reports;
} else if (!b.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", b.getColoredLabel()));
return reports;
} else if (!c.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", c.getColoredLabel()));
return reports;
} else if (!d.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", d.getColoredLabel()));
return reports;
}
// decide what relation method can be used
// point, point, point, point
if (a instanceof GeoPoint && b instanceof GeoPoint
&& c instanceof GeoPoint && d instanceof GeoPoint) {
return relation((GeoPoint) a, (GeoPoint) b, (GeoPoint) c,
(GeoPoint) d);
}
register(null, null, loc.getPlain("ComparisonNotPossible"));
return reports;
}
/**
* description of the relation between two GeoElements a, b (equal,
* incident, intersect, parallel, linear dependent, tangent of, ...)
*
* @param a
* first geo
* @param b
* second geo
* @return string describing relation between these two
*/
final public Set<Report> relation(GeoElement a, GeoElement b) {
// check defined state
if (!a.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", a.getColoredLabel()));
return reports;
} else if (!b.isDefined()) {
register(null, null,
loc.getPlain("AisNotDefined", b.getColoredLabel()));
return reports;
}
// decide what relation method can be used
// point, point
if (a instanceof GeoPoint && b instanceof GeoPoint) {
return relation((GeoPoint) a, (GeoPoint) b);
} else if (a instanceof GeoVector && b instanceof GeoVector) {
return relation((GeoVector) a, (GeoVector) b);
} else if (a instanceof GeoSegmentND && b instanceof GeoSegmentND) {
return relation((GeoSegmentND) a, (GeoSegmentND) b);
} else if (a instanceof GeoLine && b instanceof GeoLine) {
return relation((GeoLine) a, (GeoLine) b);
} else if (a instanceof GeoConicPart && b instanceof GeoConicPart) {
return relation((GeoConicPart) a, (GeoConicPart) b);
} else if (a instanceof GeoConic && b instanceof GeoConic) {
return relation((GeoConic) a, (GeoConic) b);
} else if (a instanceof GeoFunction && b instanceof GeoFunction) {
return relation((GeoFunction) a, (GeoFunction) b);
} else if (a instanceof GeoPoint && b instanceof GeoPolygon) {
return relation((GeoPoint) a, (GeoPolygon) b);
} else if (a instanceof GeoPolygon && b instanceof GeoPoint) {
return relation((GeoPoint) b, (GeoPolygon) a);
} else if (a instanceof GeoPolygon && b instanceof GeoPolygon) {
return relation((GeoPolygon) a, (GeoPolygon) b);
} else if (a instanceof GeoPoint && b instanceof Path) {
return relation((GeoPoint) a, (Path) b);
} else if (a instanceof Path && b instanceof GeoPoint) {
return relation((GeoPoint) b, (Path) a);
} else if (a instanceof GeoConic && b instanceof GeoLine) {
return relation((GeoLine) b, (GeoConic) a);
} else if (a instanceof GeoLine && b instanceof GeoConic) {
return relation((GeoLine) a, (GeoConic) b);
} else if (a instanceof GeoNumberValue && b instanceof GeoNumberValue) {
return relation((GeoNumberValue) a, (GeoNumberValue) b);
} else if (a instanceof GeoList && b instanceof GeoList) {
return relation((GeoList) a, (GeoList) b);
} else {
register(null, null, loc.getPlain("AandBcannotBeCompared",
a.getColoredLabel(), b.getColoredLabel()));
return reports;
}
}
/**
* description of the relation between two lists a, b (equal, unequal)
*/
final private Set<Report> relation(GeoList a, GeoList b) {
Boolean bool = a.isEqual(b);
String str = equalityString(a.toGeoElement(), b.toGeoElement(), bool);
register(bool, RelationCommand.AreEqual, str);
return reports;
}
/**
* description of the relation between two numbers a, b (equal, unequal)
*/
final private Set<Report> relation(GeoNumberValue a, GeoNumberValue b) {
Boolean bool = Kernel.isEqual(a.getDouble(), b.getDouble());
String str = equalityString(a.toGeoElement(), b.toGeoElement(), bool);
register(bool, RelationCommand.AreEqual, str);
return reports;
}
/**
* description of the relation between segment a and segment b (equal,
* unequal)
*/
final private Set<Report> relation(GeoSegmentND a, GeoSegmentND b) {
Boolean bool;
String str;
if (Kernel.isEqual(((NumberValue) a).getDouble(),
((NumberValue) b).getDouble())) {
if (a.isEqual(b)) {
register(true, RelationCommand.AreEqual,
equalityString((GeoElement) a, (GeoElement) b, true));
} else {
register(true, RelationCommand.AreCongruent,
congruentSegmentString((GeoElement) a, (GeoElement) b,
true, loc));
}
} else {
register(false, null, congruentSegmentString((GeoElement) a,
(GeoElement) b, false, loc));
}
// Checking parallelism:
bool = ((GeoLine) a).isParallel((GeoLine) b);
if (bool) {
str = parallelString((GeoLine) a, (GeoLine) b);
register(true, RelationCommand.AreParallel, str);
}
// Checking orthogonality:
bool = ((GeoLine) a).isPerpendicular((GeoLine) b);
if (bool) {
str = perpendicularString((GeoLine) a, (GeoLine) b, true);
register(true, RelationCommand.ArePerpendicular, str);
}
return reports;
}
/**
* description of the relation among segments a, b and c (equal, unequal)
*/
final private Set<Report> relation(GeoSegmentND a, GeoSegmentND b,
GeoSegmentND c) {
/* Checking if the objects/lengths are equal. */
if (Kernel.isEqual(a.getDouble(), b.getDouble())
&& Kernel.isEqual(b.getDouble(), c.getDouble())) {
if (a.isEqual(b) && b.isEqual(c)) {
register(true, null, equalityString((GeoElement) a,
(GeoElement) b, (GeoElement) c, true));
return reports;
}
register(true, null, congruentSegmentString((GeoElement) a,
(GeoElement) b, (GeoElement) c));
return reports;
}
/*
* As segments there is no relation among them. Maybe there is positive
* result when they are considered as lines.
*/
return relation((GeoLine) a, (GeoLine) b, (GeoLine) c);
}
/**
* description of the relation between two points A, B (equal, unequal)
*/
final private Set<Report> relation(GeoPoint A, GeoPoint B) {
Boolean bool = A.isEqual(B);
String str = equalityString(A, B, bool);
register(bool, RelationCommand.AreEqual, str);
return reports;
}
/**
* description of the relation of three points A, B, C (equal, unequal,
* collinear)
*/
final private Set<Report> relation(GeoPoint A, GeoPoint B, GeoPoint C) {
if (A.isEqual(B) && A.isEqual(C)) {
String str = equalityString(A, B, C, true);
// consider implementing Prove[A==B==C]
register(true, null, str);
} else if (GeoPoint.collinear(A, B, C)) {
String str = collinearityString(A, B, C);
register(true, RelationCommand.AreCollinear, str);
} else {
String str = equalityString(A, B, C, false);
register(false, null, str);
}
return reports;
}
/**
* description of the relation of three points A, B, C, D (equal, unequal,
* collinear, concyclic)
*/
final private Set<Report> relation(GeoPoint A, GeoPoint B, GeoPoint C,
GeoPoint D) {
if (A.isEqual(B) && A.isEqual(C) && A.isEqual(D)) {
String str = equalityString(A, B, C, D, true);
// consider implementing Prove[A==B==C==D]
register(true, null, str);
} else if (GeoPoint.collinear(A, B, C) && GeoPoint.collinear(A, B, D)) {
String str = collinearityString(A, B, C, D);
// consider implementing Prove[AreCollinear[A,B,C,D]]
register(true, null, str);
} else if (GeoPoint.concyclic(A, B, C, D)) {
String str = concyclicityString(A, B, C, D);
register(true, RelationCommand.AreConcyclic, str);
} else {
String str = equalityString(A, B, C, D, false);
register(false, null, str);
}
return reports;
}
/**
* description of the relation between two vectors a, b (equal, linear
* dependent, linear independent)
*/
final private Set<Report> relation(GeoVector a, GeoVector b) {
String str;
Boolean bool;
if (a.isEqual(b)) {
str = equalityString(a, b, true);
bool = true;
} else {
str = linDependencyString(a, b, a.linDep(b));
bool = false;
}
register(bool, RelationCommand.AreEqual, str);
return reports;
}
/**
* description of the relation between point A and a polygon ((not) on
* perimeter)
*/
final private Set<Report> relation(GeoPoint A, GeoPolygon p) {
Boolean bool = p.isOnPath(A, Kernel.STANDARD_PRECISION);
String str = incidencePerimeterString(A, p.toGeoElement(), bool);
register(bool, null, str);
// TODO: Symbolically we cannot decide this yet.
return reports;
}
/**
* description of the relation between point A and a path (incident, not
* incident)
*/
final private Set<Report> relation(GeoPoint A, Path path) {
Boolean bool = path.isOnPath(A, Kernel.STANDARD_PRECISION);
String str = incidenceString(A, path.toGeoElement(), bool);
register(bool, RelationCommand.IsOnPath, str);
return reports;
}
/**
* description of the relation between polygons a and b
*/
final private Set<Report> relation(GeoPolygon a, GeoPolygon b) {
Boolean bool = a.hasSameArea(b);
String str = equalAreaString(a, b, bool, loc);
register(bool, RelationCommand.AreEqual, str);
return reports;
}
/**
* description of the relation between lines g and h (equal, parallel or
* intersecting)
*/
final private Set<Report> relation(GeoLine g, GeoLine h) {
String str;
// check for equality
if (g.isEqual(h)) {
str = equalityString(g, h, true);
register(true, RelationCommand.AreEqual, str);
} else {
if (g.isParallel(h)) {
str = parallelString(g, h);
register(true, RelationCommand.AreParallel, str);
} else if (g.isPerpendicular(h)) {
str = perpendicularString(g, h, true);
register(true, RelationCommand.ArePerpendicular, str);
} else {
// check if intersection point really lies on both objects (e.g.
// segments)
// TODO: This cannot be done with the current symbolic methods
// yet.
GeoPoint tempPoint = new GeoPoint(g.cons);
GeoVec3D.cross(g, h, tempPoint);
boolean isIntersection = g.isIntersectionPointIncident(
tempPoint, Kernel.STANDARD_PRECISION)
&& h.isIntersectionPointIncident(tempPoint,
Kernel.STANDARD_PRECISION);
str = intersectString(g, h, isIntersection);
register(isIntersection, null, str);
}
}
return reports;
}
/**
* description of the relation between lines g, h and i (concurrency)
*/
final private Set<Report> relation(GeoLine g, GeoLine h, GeoLine i) {
String str;
// check for equality
if (g.isEqual(h) && g.isEqual(i)) {
str = equalityString(g, h, i, true);
// consider implementing Prove[g==h==i]
register(true, null, str);
} else if (g.isParallel(h) && g.isParallel(i)) {
str = parallelString(g, h, i);
// consider implementing Prove[g||h||i]
register(true, null, str);
} else if (GeoLine.concurrent(g, h, i)) {
str = concurrentString(g, h, i);
register(true, RelationCommand.AreConcurrent, str);
} else {
str = equalityString(g, h, i, false);
// consider implementing Prove[g==h==i]
register(false, null, str);
}
return reports;
}
/**
* description of the relation between line g and conic c (intersection
* type: tangent, secant, ...)
*/
final private Set<Report> relation(GeoLine g, GeoConic c) {
int type;
String str;
// limited paths have to handled differently (e.g. segments, arcs)
if (g.isLimitedPath() || c.isLimitedPath()) {
// intersect line and conic
// precision setting is not needed here (done by algorithm)
AlgoIntersectLineConic algo = new AlgoIntersectLineConic(cons, g,
c);
GeoPoint[] points = algo.getIntersectionPoints();
cons.removeFromConstructionList(algo);
// check for defined intersection points
boolean intersect = false;
for (int i = 0; i < points.length; i++) {
if (points[i].isDefined()) {
intersect = true;
break;
}
}
// build relation string
str = intersectString(g, c, intersect);
// remove algorithm by removing one of its points
points[0].remove();
register(intersect, null, str);
// TODO: Unsupported symbolically.
return reports;
}
// is line defined as tangent or asymptote of c?
if (g.isDefinedTangent(c)) {
str = lineConicString(g, c,
AlgoIntersectLineConic.INTERSECTION_TANGENT_LINE);
} else if (g.isDefinedAsymptote(c)) {
str = lineConicString(g, c,
AlgoIntersectLineConic.INTERSECTION_ASYMPTOTIC_LINE);
} else {
// intersect line and conic
GeoPoint[] points = { new GeoPoint(cons), new GeoPoint(cons) };
type = AlgoIntersectLineConic.intersectLineConic(g, c, points,
Kernel.STANDARD_PRECISION);
str = lineConicString(g, c, type);
}
register(null, null, str); // TODO: Completely unsupported symbolically.
return reports;
}
/**
* description of the relation between conic parts a, b (equal, intersecting
* or not intersecting)
*/
final private Set<Report> relation(GeoConicPart a, GeoConicPart b) {
Boolean bool = a.isEqual(b);
String str = equalityString(a, b, bool);
register(bool, null, str);
// TODO: No prover support for conic equality yet.
bool = Kernel.isEqual(((NumberValue) a).getDouble(),
((NumberValue) b).getDouble());
int type = a.getConicPartType();
if (type == b.getConicPartType()) {
if (type == GeoConicNDConstants.CONIC_PART_ARC) {
str = congruentSegmentString(a, b, bool, loc);
register(bool, null, str); // TODO: No symbolic support.
} else {
str = equalAreaString(a, b, bool, loc);
register(bool, null, str); // TODO: No symbolic support.
}
// sb.append(": ");
// sb.append(relation((NumberValue) a, (NumberValue) b));
}
return reports;
}
/**
* description of the relation between conics a, b (equal, intersecting or
* not intersecting)
*/
final private Set<Report> relation(GeoConic a, GeoConic b) {
String str;
if (a.isEqual(b)) {
str = equalityString(a, b, true);
register(true, null, str); // TODO: No symbolically supported.
} else {
// intersect conics
// precision setting is not needed here (done by algorithm)
AlgoIntersectConics algo = new AlgoIntersectConics(cons, a, b);
GeoPoint[] points = algo.getIntersectionPoints();
cons.removeFromConstructionList(algo);
// check for defined intersection points
boolean intersect = false;
for (int i = 0; i < points.length; i++) {
if (points[i].isDefined()) {
intersect = true;
break;
}
}
boolean touch = false;
// check if we have one intersection point
if (points[0].isEqual(points[1])) {
touch = true;
}
// build relation string
// case one intersection point
if (touch) {
str = touchString(a, b, touch);
}
// case more than one intersection point
else {
str = intersectString(a, b, intersect);
}
register(true, null, str); // TODO: No symbolically supported.
// remove algorithm by removing one of its points
points[0].remove();
}
return reports;
}
/**
* description of the relation between functions
*/
final private Set<Report> relation(GeoFunction a, GeoFunction b) {
Boolean bool = a.isEqual(b);
String str = equalityString(a, b, bool); // This was equalityStringExact
// originally.
register(bool, null, str); // No symbolically supported.
return reports;
}
/***************************
* private methods
***************************/
// "Relation of a and b: equal"
// "Relation of a and b: unequal"
final private String equalityString(GeoElement a, GeoElement b,
boolean equal) {
return equalityString(a, b, equal, loc);
}
/**
* Internationalized string of "a and b are equal" (or not)
*
* @param a
* first object
* @param b
* second object
* @param equal
* yes or no
* @param loc
* locale
* @return internationalized string
*/
final static public String equalityString(GeoElement a, GeoElement b,
boolean equal, Localization loc) {
if (equal) {
return loc.getPlain("AandBareEqual", a.getColoredLabel(),
b.getColoredLabel());
}
return loc.getPlain("AandBareNotEqual", a.getColoredLabel(),
b.getColoredLabel());
}
/**
* Internationalized string of "a, b and c are equal" (or not)
*
* @param a
* first object
* @param b
* second object
* @param c
* third object
* @param equal
* if objects are equal
*
* @return internationalized string
*/
final public String equalityString(GeoElement a, GeoElement b,
GeoElement c, boolean equal) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = a.getColoredLabel() + ", " + b.getColoredLabel() + " "
+ and + " " + c.getColoredLabel();
if (equal) {
return loc.getPlain("TheFollowingAreEqualA", pars);
}
return loc.getPlain("TheFollowingAreNotEqualA", pars);
}
/**
* Internationalized string of "a, b and c are congruent" (or not)
*
* @param a
* first object
* @param b
* second object
* @param c
* third object
*
* @return internationalized string
*/
final public String congruentSegmentString(GeoElement a, GeoElement b,
GeoElement c) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = a.getColoredLabel() + ", " + b.getColoredLabel() + " "
+ and + " " + c.getColoredLabel();
return loc.getPlain("TheFollowingAreCongruentA", pars);
}
/**
* Internationalized string of "a, b, c and d are equal" (or not)
*
* @param a
* first object
* @param b
* second object
* @param c
* third object
* @param d
* forth object
* @param equal
* if the objects are equal
*
* @return internationalized string
*/
final public String equalityString(GeoElement a, GeoElement b, GeoElement c,
GeoElement d, boolean equal) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = a.getColoredLabel() + ", " + b.getColoredLabel() + ", "
+ c.getColoredLabel() + " " + and + " " + d.getColoredLabel();
if (equal) {
return loc.getPlain("TheFollowingAreEqualA", pars);
}
return loc.getPlain("TheFollowingAreNotEqualA", pars);
}
/**
* Internationalized string of "a and b are congruent" (or not)
*
* @param a
* first object
* @param b
* second object
* @param equal
* yes or no
* @param loc
* locale
* @return internationalized string
*/
final static public String congruentSegmentString(GeoElement a,
GeoElement b, boolean equal, Localization loc) {
if (equal) {
return loc.getPlain("AhasTheSameLengthAsB", a.getColoredLabel(),
b.getColoredLabel());
}
return loc.getPlain("AdoesNothaveTheSameLengthAsB", a.getColoredLabel(),
b.getColoredLabel());
}
/**
* Internationalized string of "a and b have the same area" (or not)
*
* @param a
* first object
* @param b
* second object
* @param equal
* yes or no
* @param loc
* locale
* @return internationalized string
*/
final static public String equalAreaString(GeoElement a, GeoElement b,
boolean equal, Localization loc) {
if (equal) {
return loc.getPlain("AhasTheSameAreaAsB", a.getColoredLabel(),
b.getColoredLabel());
}
return loc.getPlain("AdoesNothaveTheSameAreaAsB", a.getColoredLabel(),
b.getColoredLabel());
}
/**
* Internationalized string of "A, B and C are collinear"
*
* @param A
* first object
* @param B
* second object
* @param C
* third object
*
* @return internationalized string
*/
final public String collinearityString(GeoElement A, GeoElement B,
GeoElement C) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = A.getColoredLabel() + ", " + B.getColoredLabel() + " "
+ and + " " + C.getColoredLabel();
return loc.getPlain("TheFollowingAreCollinearA", pars);
}
/**
* Internationalized string of "A, B, C and D are collinear"
*
* @param A
* first object
* @param B
* second object
* @param C
* third object
* @param D
* forth object
*
* @return internationalized string
*/
final public String collinearityString(GeoElement A, GeoElement B,
GeoElement C, GeoElement D) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = A.getColoredLabel() + ", " + B.getColoredLabel() + ", "
+ C.getColoredLabel() + " " + and + " " + D.getColoredLabel();
return loc.getPlain("TheFollowingAreCollinearA", pars);
}
/**
* Internationalized string of "a, b and c are concurrent"
*
* @param a
* first object
* @param b
* second object
* @param c
* third object
*
* @return internationalized string
*/
final public String concurrentString(GeoElement a, GeoElement b,
GeoElement c) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = a.getColoredLabel() + ", " + b.getColoredLabel() + " "
+ and + " " + c.getColoredLabel();
return loc.getPlain("TheFollowingAreConcurrentA", pars);
}
/**
* Internationalized string of "A, B, C and D are concyclic"
*
* @param A
* first object
* @param B
* second object
* @param C
* third object
* @param D
* forth object
*
* @return internationalized string
*/
final public String concyclicityString(GeoElement A, GeoElement B,
GeoElement C, GeoElement D) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = A.getColoredLabel() + ", " + B.getColoredLabel() + ", "
+ C.getColoredLabel() + " " + and + " " + D.getColoredLabel();
return loc.getPlain("TheFollowingAreConcyclicA", pars);
}
// "Relation of a and b: linear dependent"
// "Relation of a and b: linear independent"
final private String linDependencyString(GeoElement a, GeoElement b,
boolean dependent) {
if (dependent) {
return loc.getPlain("AandBareLinearlyDependent",
a.getColoredLabel(), b.getColoredLabel());
}
return loc.getPlain("AandBareLinearlyIndependent", a.getColoredLabel(),
b.getColoredLabel());
}
// "a lies on b"
// "a does not lie on b"
final private String incidenceString(GeoPoint a, GeoElement b,
boolean incident) {
if (incident) {
return loc.getPlain("AliesOnB", a.getColoredLabel(),
b.getColoredLabel());
}
return loc.getPlain("AdoesNotLieOnB", a.getColoredLabel(),
b.getColoredLabel());
}
// "a lies on the perimeter of b"
// "a does not lie on the perimeter of b"
final private String incidencePerimeterString(GeoPoint a, GeoElement b,
boolean incident) {
if (incident) {
return loc.getPlain("AliesOnThePerimeterOfB", a.getColoredLabel(),
b.getColoredLabel());
}
return loc.getPlain("AdoesNotLieOnThePerimeterOfB", a.getColoredLabel(),
b.getColoredLabel());
}
// "Relation of a and b: parallel"
final private String parallelString(GeoLine a, GeoLine b) {
return parallelString(a, b, loc);
}
// "Relation of a and b and c: parallel"
final private String parallelString(GeoLine a, GeoLine b, GeoLine c) {
return parallelString(a, b, c, loc);
}
/**
* Internationalized string of "a and b are parallel"
*
* @param a
* first line
* @param b
* second line
* @param loc
* locale
* @return internationalized string
*/
final public static String parallelString(GeoLine a, GeoLine b,
Localization loc) {
return loc.getPlain("AandBareParallel", a.getColoredLabel(),
b.getColoredLabel());
}
/**
* Internationalized string of "a, b and c are parallel"
*
* @param a
* first line
* @param b
* second line
* @param c
* second line
* @param loc
* locale
* @return internationalized string
*/
final public static String parallelString(GeoLine a, GeoLine b, GeoLine c,
Localization loc) {
String and = loc.getMenu("Symbol.And").toLowerCase();
String pars = a.getColoredLabel() + ", " + b.getColoredLabel() + " "
+ and + " " + c.getColoredLabel();
return loc.getPlain("TheFollowingAreParallelA", pars);
}
/*
* This is not used yet. It requires support for 3 points in the Relation
* Tool.
*/
// final private String triangleNonDegenerateString(GeoPoint A, GeoPoint B,
// GeoPoint C) {
// return triangleNonDegenerateString(A, B, C, loc);
// }
/**
* Internationalized string of "Triangle ABC is non-degenerate"
*
* @param A
* first vertex
* @param B
* second vertex
* @param C
* third vertex
* @param loc
* locale
* @return internationalized string
*/
final public static String triangleNonDegenerateString(GeoPoint A,
GeoPoint B, GeoPoint C, Localization loc) {
return loc.getPlain("TriangleABCnonDegenerate", A.getColoredLabel()
+ B.getColoredLabel() + C.getColoredLabel());
}
final private String perpendicularString(GeoLine a, GeoLine b,
boolean perp) {
return perpendicularString(a, b, perp, loc);
}
/**
* Internationalized string of "a and b are perpendicular" (or not)
*
* @param a
* first line
* @param b
* second line
* @param perp
* yes or no
* @param loc
* locale
* @return internationalized string
*/
final static public String perpendicularString(GeoLine a, GeoLine b,
boolean perp, Localization loc) {
if (perp) {
return loc.getPlain("AandBarePerpendicular", a.getColoredLabel(),
b.getColoredLabel());
}
return loc.getPlain("AandBareNotPerpendicular", a.getColoredLabel(),
b.getColoredLabel());
}
// "a intersects with b"
final private String intersectString(GeoElement a, GeoElement b,
boolean intersects) {
return intersectString(a, b, intersects, loc);
}
/**
* Internationalized string of "a intersects with b" (or not)
*
* @param a
* first object
* @param b
* second object
* @param intersects
* yes or no
* @param loc
* locale
* @return internationalized string
*/
final public static String intersectString(GeoElement a, GeoElement b,
boolean intersects, Localization loc) {
StringBuilder sb = new StringBuilder();
// Michael Borcherds 2008-05-14
// updated for better translation
if (intersects) {
sb.append(loc.getPlain("AIntersectsWithB", a.getColoredLabel(),
b.getColoredLabel()));
} else {
sb.append(loc.getPlain("ADoesNotIntersectWithB",
a.getColoredLabel(), b.getColoredLabel()));
}
return sb.toString();
}
// "a touches b"
final private String touchString(GeoElement a, GeoElement b,
boolean touches) {
return touchString(a, b, touches, loc);
}
/**
* Internationalized string of "a touches b" (or not)
*
* @param a
* first object
* @param b
* second object
* @param touches
* yes or no
* @param loc
* locale
* @return internationalized string
*/
final public static String touchString(GeoElement a, GeoElement b,
boolean touches, Localization loc) {
StringBuilder sb = new StringBuilder();
if (touches) {
sb.append(loc.getPlain("ATouchesB", a.getColoredLabel(),
b.getColoredLabel()));
} else {
sb.append(loc.getPlain("ADoesNotIntersectWithB",
a.getColoredLabel(), b.getColoredLabel()));
}
return sb.toString();
}
// e.g "a is tangent of b"
// types are defined in AlgoIntersectLineConic
final private String lineConicString(GeoLine a, GeoConic b, int type) {
switch (type) {
case AlgoIntersectLineConic.INTERSECTION_PRODUCING_LINE:
// strType = getPlain("producingLine");
return loc.getPlain("AisaDegenerateBranchOfB", a.getColoredLabel(),
b.getColoredLabel());
// break;
case AlgoIntersectLineConic.INTERSECTION_ASYMPTOTIC_LINE:
// strType = getPlain("asymptoticLine");
return loc.getPlain("AisAnAsymptoteToB", a.getColoredLabel(),
b.getColoredLabel());
// break;
case AlgoIntersectLineConic.INTERSECTION_MEETING_LINE:
// strType = getPlain("meetingLine");
return loc.getPlain("AintersectsWithBOnce", a.getColoredLabel(),
b.getColoredLabel());
// break;
case AlgoIntersectLineConic.INTERSECTION_TANGENT_LINE:
// strType = getPlain("tangentLine");
return loc.getPlain("AisaTangentToB", a.getColoredLabel(),
b.getColoredLabel());
// break;
case AlgoIntersectLineConic.INTERSECTION_SECANT_LINE:
// strType = getPlain("secantLine");
return loc.getPlain("AintersectsWithBTwice", a.getColoredLabel(),
b.getColoredLabel());
// break;
default:
// case AlgoIntersectLineConic.INTERSECTION_PASSING_LINE:
// strType = getPlain("passingLine");
return loc.getPlain("ADoesNotIntersectWithB", a.getColoredLabel(),
b.getColoredLabel());
// break;
}
}
}