Commit 67945d92 authored by MarkG's avatar MarkG Committed by TIGERs GitLab
Browse files

Resolve "Performance tuning"

Closes #1619

See merge request main/Sumatra!1360

sumatra-commit: f7972214e6da520a46d6d184f3d33d539c6c5daa
parent 59a0ab58
Pipeline #8861 passed with stage
in 4 minutes and 48 seconds
......@@ -119,8 +119,8 @@ public final class SumatraMath
/**
* Checks two double values for equality with a small tolerance value
*
* @param a first value
* @param b second value
* @param a first value
* @param b second value
* @param tolerance to use for comparison
* @return true, if absolute difference between both values is smaller than or equal to tolerance
*/
......@@ -146,23 +146,18 @@ public final class SumatraMath
/**
* Checks if x is a Number between to values (inclusive)
*
* @param x a value
* @param x a value
* @param min smaller value
* @param max larger value
* @return true, if min <= x <= max
*/
public static boolean isBetween(final double x, final double min, final double max)
{
boolean result;
if (max > min)
{
result = (x >= min) && (x <= max);
} else
{
result = (x >= max) && (x <= min);
return (x >= min) && (x <= max);
}
return result;
return (x >= max) && (x <= min);
}
......@@ -180,8 +175,8 @@ public final class SumatraMath
* Project value to a relative values between 0 and 1
*
* @param value the value
* @param from the value that corresponds to 0
* @param to the value that corresponds to 1
* @param from the value that corresponds to 0
* @param to the value that corresponds to 1
* @return value in range [0..1]
*/
public static double relative(final double value, final double from, final double to)
......@@ -214,11 +209,10 @@ public final class SumatraMath
/**
* Solves for the real roots of a quadratic equation with real
* coefficients. The quadratic equation is of the form
* <P>
* <p>
* <I>ax</I><SUP>2</SUP> + <I>bx</I> + <I>c</I> = 0
* <P>
* <p>
*
* @author AndreR <andre@ryll.cc>
* @param a Coefficient of <I>x</I><SUP>2</SUP>.
* @param b Coefficient of <I>x</I>.
* @param c Constant coefficient.
......@@ -272,12 +266,11 @@ public final class SumatraMath
/**
* Solves for the real roots of a cubic equation with real
* coefficients. The cubic equation is of the form
* <P>
* <p>
* <I>ax</I><SUP>3</SUP> + <I>bx</I><SUP>2</SUP> + <I>cx</I> + <I>d</I> = 0
* <P>
* <p>
* Source taken from: https://github.com/davidzof/wattzap/blob/master/src/com/wattzap/model/power/Cubic.java
*
* @author AndreR <andre@ryll.cc>
* @param a3 Coefficient of <I>x</I><SUP>3</SUP>.
* @param b2 Coefficient of <I>x</I><SUP>2</SUP>.
* @param c1 Coefficient of <I>x</I>.
......
......@@ -202,7 +202,7 @@ public final class CircleMath
*/
public static boolean isPointInCircle(ICircular circle, IVector2 point, double margin)
{
return point.distanceToSqr(circle.center()) <= Math.pow(circle.radius() + margin, 2);
return point.distanceToSqr(circle.center()) <= SumatraMath.square(circle.radius() + margin);
}
......
......@@ -81,4 +81,11 @@ abstract class ALine implements ILineBase
IVector2 closestPointOnLine = closestPointOnLine(point);
return point.distanceTo(closestPointOnLine);
}
@Override
public double distanceToSqr(final IVector2 point)
{
IVector2 closestPointOnLine = closestPointOnLine(point);
return point.distanceToSqr(closestPointOnLine);
}
}
......@@ -19,7 +19,7 @@ import edu.tigers.sumatra.math.vector.IVector2;
* {@link Optional} to convey an invalid line while other methods such as {@link #closestPointOnLine(IVector2)} will do
* a best-effort job to return a meaningful value. The method comments specify how the individual methods handle invalid
* line instances.
*
*
* @author Lukas Magel
*/
public interface ILineBase extends IEuclideanDistance
......@@ -30,95 +30,87 @@ public interface ILineBase extends IEuclideanDistance
* A half-line requires a non-zero direction vector to be valid, whereas a line segment must be defined through two
* non-equal support points to be properly defined.
*
* @return
* {@code true} if the line instance is properly defined, {@code false} otherwise
* @return {@code true} if the line instance is properly defined, {@code false} otherwise
*/
boolean isValid();
/**
* Creates a legacy line to use old functions
*
* @return a new legacy line with same bias and slope
*/
edu.tigers.sumatra.math.line.Line toLegacyLine();
/**
* Returns the direction vector of this line. It represents the direction in which this line points. Please note that
* even a bounded line segment has a direction vector which points from start to end. Since the different line types
* are zero-vector tolerant, the direction vector can also be zero.
*
* @return
* The direction vector of this line instance which can have a length of zero
*
* @return The direction vector of this line instance which can have a length of zero
*/
IVector2 directionVector();
/**
* Returns the support vector of this line. The support vector represents the starting point of the line, i.e. where
* it is anchored. Please note that even a bounded line segment has a support vector which equals the start vector.
*
* @return
* The support vector of this line instance which can have a length of zero
* @return The support vector of this line instance which can have a length of zero
*/
IVector2 supportVector();
/**
* Returns the slope of this line. Considering the regular definition {@code y = m * x + b} of a line, this method
* returns the parameter {@code m} of this instance.
*
* @return
* The slope value, or an empty optional if the line is not valid, or the line is parallel
* to the y axis and the slope therefore unbounded.
*
* @return The slope value, or an empty optional if the line is not valid, or the line is parallel
* to the y axis and the slope therefore unbounded.
*/
Optional<Double> getSlope();
/**
* Returns the angle bounded by the direction vector of this line and the x-axis. Considering the regular definition
* {@code y = m * x + b} of a line, this method returns arctan(m).
*
* @return
* The angle in radiant with a range of [-Pi, Pi] or an empty optional if this line is not valid
*
* @return The angle in radiant with a range of [-Pi, Pi] or an empty optional if this line is not valid
* @see IVector2#getAngle()
*/
Optional<Double> getAngle();
/**
* Create a deep copy of the {@code line} instance. The resulting instance does not share its variables with the
* current instance.
*
* @return
* A new line instance which is equal to the other one
* @return A new line instance which is equal to the other one
*/
ILineBase copy();
/**
* Returns true if this line is horizontal, i.e. its direction vector is parallel to the x axis. Please note that a
* line can only be considered horizontal if it is valid.
*
* @return
* {@code true} if the line is valid and the direction vector is parallel to the x axis
*
* @return {@code true} if the line is valid and the direction vector is parallel to the x axis
* @see IVector2#isHorizontal()
*/
boolean isHorizontal();
/**
* Returns true if this line is vertical, i.e. its direction vector is parallel to the y axis. Please note that a
* line can only be considered vertical if it is valid.
*
* @return
* {@code true} if the line is valid and the direction vector is parallel to the y axis
*
* @return {@code true} if the line is valid and the direction vector is parallel to the y axis
* @see IVector2#isVertical()
*/
boolean isVertical();
/**
* Returns {@code true} if the specified point is located on this line. The check uses a small margin value and
* verifies if the specified point is located inside this margin around the line. Please note that the result can
......@@ -127,103 +119,95 @@ public interface ILineBase extends IEuclideanDistance
* If the line instance is not properly defined (i.e. a line segment with to identical points or a half-line with
* zero direction vector) then this method only returns true if the point is located on the line origin (for a line
* or half-line) or on one of the segment points (for a line segment).
*
* @param point
* The point for which this check is to be performed
* @return
* {@code true} if the line is valid and the point is located on it
*
* @param point The point for which this check is to be performed
* @return {@code true} if the line is valid and the point is located on it
*/
boolean isPointOnLine(IVector2 point);
/**
* Returns a point on the line which is located closest to the specified point. For an unbounded line this is always
* the lead point. For a half-line or a line segment this is either the lead point or one of the bounding points if
* the lead point is not located on the segment.
* If the line instance is not valid, this method returns the line origin (for a line or half-line) or one of the
* segment points (for a line segment).
*
* @param point
* The point for which to find the closest point on the line
* @return
* A point on the line located closest to the specified point
*
* @param point The point for which to find the closest point on the line
* @return A point on the line located closest to the specified point
*/
IVector2 closestPointOnLine(IVector2 point);
/**
* Returns {@code true} if the specified {@code line} is parallel to this instance, i.e. the direction vectors of
* both lines are linear dependent. This is only the case if both lines are valid and the method will always return
* {@code false} if at least one of them is not valid.
*
* @param line
* The line which to compare to this instance
* @return
* {@code true} if both lines are valid according to {@link #isValid()} and parallel to each other
*
* @param line The line which to compare to this instance
* @return {@code true} if both lines are valid according to {@link #isValid()} and parallel to each other
* @see IVector2#isParallelTo(IVector2)
*/
boolean isParallelTo(final ILineBase line);
/**
* Converts this instance into an unbounded line. The resulting line uses the same support and direction vector as
* this line instance. Please note that the resulting {@link ILine} instance is only valid if this instance is also
* valid.
*
* @return
* A line instance which uses the same support and direction vector as the current instance
*
* @return A line instance which uses the same support and direction vector as the current instance
*/
ILine toLine();
/**
* Intersect this line instance with the specified unbounded {@code line} and return the intersection vector.
*
* @param line
* The line for which to calculate an intersection with this instance
* @return
* The intersection point of both lines or an empty {@link Optional} if at least one of the two lines is not
* valid, the lines are parallel or this line instance is not unbounded and the intersection would be
* located outside the range.
* @param line The line for which to calculate an intersection with this instance
* @return The intersection point of both lines or an empty {@link Optional} if at least one of the two lines is not
* valid, the lines are parallel or this line instance is not unbounded and the intersection would be
* located outside the range.
*/
Optional<IVector2> intersectLine(ILine line);
/**
* Intersect this line instance with the specified {@code halfLine} and return the intersection point.
*
* @param halfLine
* The half-line for which to calculate an intersection with this instance
* @return
* The intersection point of both lines r an empty {@link Optional} if at least one of the two lines is not
* valid, the lines are parallel or the intersection point was located outside their bounds.
* @param halfLine The half-line for which to calculate an intersection with this instance
* @return The intersection point of both lines r an empty {@link Optional} if at least one of the two lines is not
* valid, the lines are parallel or the intersection point was located outside their bounds.
*/
Optional<IVector2> intersectHalfLine(IHalfLine halfLine);
/**
* Intersect this line instance with the specified line {@code segment} and return the intersection point.
*
* @param segment
* The line segment for which to calculate an intersection with this instance
* @return
* The intersection point of both lines r an empty {@link Optional} if at least one of the two lines is not
* valid, the lines are parallel or the intersection point was located outside their bounds.
*
* @param segment The line segment for which to calculate an intersection with this instance
* @return The intersection point of both lines r an empty {@link Optional} if at least one of the two lines is not
* valid, the lines are parallel or the intersection point was located outside their bounds.
*/
Optional<IVector2> intersectSegment(ILineSegment segment);
/**
* Calculate the distance between the specified {@code point} and the line instance. This value is not defined for an
* invalid line instance and the method will consequently throw a {@code RuntimeException}.
*
* @param point
* target point
* @return
* The distance between the specified {@code point} and this line instance
* @throws IllegalArgumentException
* If this line is not valid according to the {@link #isValid()} method
*
* @param point target point
* @return The distance between the specified {@code point} and this line instance
* @throws IllegalArgumentException If this line is not valid according to the {@link #isValid()} method
*/
@Override
double distanceTo(IVector2 point);
/**
* Same as {@link #distanceTo(IVector2)}, but returns the squared distance to avoid sqrt calculation.
*
* @param point
* @return
*/
double distanceToSqr(IVector2 point);
}
......@@ -86,7 +86,7 @@ final class LineSegment extends ALine implements ILineSegment
@Override
public boolean isValid()
{
return !directionVector().isZeroVector();
return !start.equals(end);
}
......
......@@ -30,7 +30,7 @@ import edu.tigers.sumatra.math.vector.Vector2f;
/**
* This abstract class represents a rectangle. It is used i. e. to describe a part-rectangle of the field.
*
*
* @author Oliver Steinbrecher <OST1988@aol.com>, MalteM
*/
@Persistent
......@@ -39,36 +39,36 @@ abstract class ARectangle implements IRectangle
ARectangle()
{
}
@Override
public double maxX()
{
return center().x() + (xExtent() / 2.0);
}
@Override
public double minX()
{
return center().x() - (xExtent() / 2.0);
}
@Override
public double maxY()
{
return center().y() + (yExtent() / 2.0);
}
@Override
public double minY()
{
return center().y() - (yExtent() / 2.0);
}
@Override
public List<IVector2> getCorners()
{
......@@ -81,30 +81,35 @@ abstract class ARectangle implements IRectangle
corners.add(Vector2.fromXY(+halfWidth, -halfHeight).add(center()));
return corners;
}
@Override
public IVector2 getCorner(final ECorner pos)
{
return getCorners().get(pos.getIndex());
}
@Override
public boolean isPointInShape(final IVector2 point, final double margin)
{
return withMargin(margin).isPointInShape(point);
IVector2 relPoint = point.subtractNew(center());
double xw = xExtent() / 2.0 + margin;
double yw = yExtent() / 2.0 + margin;
return relPoint.x() >= -xw && relPoint.x() <= xw && relPoint.y() >= -yw && relPoint.y() <= yw;
}
@Override
public boolean isPointInShape(final IVector2 point)
{
return SumatraMath.isBetween(point.x(), minX(), maxX())
&& SumatraMath.isBetween(point.y(), minY(), maxY());
IVector2 relPoint = point.subtractNew(center());
double xw = xExtent() / 2.0;
double yw = yExtent() / 2.0;
return relPoint.x() >= -xw && relPoint.x() <= xw && relPoint.y() >= -yw && relPoint.y() <= yw;
}
@Override
public boolean isCircleInShape(final ICircle circle)
{
......@@ -113,8 +118,8 @@ abstract class ARectangle implements IRectangle
&& SumatraMath.isBetween(circle.center().y() + circle.radius(), minY(), maxY())
&& SumatraMath.isBetween(circle.center().y() - circle.radius(), minY(), maxY());
}
@Override
public IVector2 nearestPointOutside(final IVector2 point)
{
......@@ -122,39 +127,39 @@ abstract class ARectangle implements IRectangle
{
IVector2 nearestPoint;
double distance;
// left
distance = Math.abs(point.x() - minX());
nearestPoint = Vector2f.fromXY(minX(), point.y());
// right
if (distance > Math.abs(maxX() - point.x()))
{
distance = maxX() - point.x();
nearestPoint = Vector2f.fromXY(maxX(), point.y());
}
// top
if (distance > Math.abs(point.y() - minY()))
{
distance = point.y() - minY();
nearestPoint = Vector2f.fromXY(point.x(), minY());
}
// bottom
if (distance > Math.abs(maxY() - point.y()))
{
nearestPoint = Vector2f.fromXY(point.x(), maxY());
}
return nearestPoint;
}
// else return point
return point;
}
@Override
public IVector2 nearestPointInside(final IVector2 point)
{
......@@ -169,7 +174,7 @@ abstract class ARectangle implements IRectangle
{
x = point.x();
}
double y;
if (point.y() > maxY())
{
......@@ -181,18 +186,18 @@ abstract class ARectangle implements IRectangle
{
y = point.y();
}
return Vector2f.fromXY(x, y);
}
@Override
public IVector2 nearestPointInside(final IVector2 point, final double margin)
{
return withMargin(margin).nearestPointInside(point);
}
@Override
public IVector2 nearestPointInside(IVector2 point, IVector2 pointToBuildLine)
{
......@@ -203,8 +208,8 @@ abstract class ARectangle implements IRectangle
return point.nearestToOpt(lineIntersections(Line.fromPoints(point, pointToBuildLine)))
.orElse(point);
}