This commit is contained in:
Evgeniy
2024-05-16 15:41:59 +07:00
commit 2dfee5edbe
151 changed files with 17349 additions and 0 deletions

View File

@@ -0,0 +1,341 @@
package ru.delkom07.geometry;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import ru.delkom07.geometry.obj.LineFunction;
public class SpecificGeometry {
public static Point[] getTopLeftAndBottomRight(List<Point> points) {
double minX = Integer.MAX_VALUE;
double minY = Integer.MAX_VALUE;
double maxX = -1;
double maxY = -1;
for(Point point : points) {
if(point.x < minX) {
minX = point.x;
}
if(point.y < minY) {
minY = point.y;
}
if(point.x > maxX) {
maxX = point.x;
}
if(point.y > maxY) {
maxY = point.y;
}
}
return new Point[] {new Point(minX, minY), new Point(maxX, maxY)};
}
/**
* Разделение контура на два по линии представленной двумя точками данного контура.
* @param contour - исходный контур.
* @param point1 - первая точка линии деления.
* @param point2 - вторая точка линии деления.
* @return - два контура, замкнутые по линии деления.
*/
private static MatOfPoint[] devideCountour(MatOfPoint contour, Point point1, Point point2) {
MatOfPoint contour1 = new MatOfPoint();
MatOfPoint contour2 = new MatOfPoint();
List<Point> pointsOrdered = contour.toList();
List<Point> pointsOrdered1 = new LinkedList<Point>();
List<Point> pointsOrdered2 = new LinkedList<Point>();
// переключатель контура
boolean contourRelay = false;
for(Point point : pointsOrdered) {
// дошли до точки линии деления
if( point.equals(point1) || point.equals(point2)) {
contourRelay = !contourRelay;
// добавить все точки по линии деления для замыкания контура
if(point.equals(point1)) { // from point1 to point2
addMiddlePoints(contourRelay ? pointsOrdered1 : pointsOrdered2, point1, point2);
} else {
addMiddlePoints(contourRelay ? pointsOrdered1 : pointsOrdered2, point2, point1);
}
}
// добавить текущую точку исходного контура в соответствующий новый контур
if(contourRelay) {
pointsOrdered1.add(point);
} else {
pointsOrdered2.add(point);
}
}
contour1.fromList(pointsOrdered1);
contour2.fromList(pointsOrdered2);
return new MatOfPoint[]{contour1, contour2};
}
private static void addMiddlePoints(List<Point> pointsOrdered, Point point1, Point point2) {
double alfa;
int stepCount = (int) SimpleGeometry.distance(point1, point2) * 2;
double step = 1.0 / stepCount;
for(int i=0; i<stepCount; i++) {
alfa = step*i;
Point newPoint = new Point(point1.x*alfa + point2.x*(1.0-alfa), point1.y*alfa + point2.y*(1.0-alfa));
if(!pointsOrdered.contains(newPoint) && !newPoint.equals(point1) && !newPoint.equals(point2)) {
pointsOrdered.add(newPoint);
}
}
}
/**
* Method finds two points on middle normal with maximum distance.
* @param contour - mat of points on contour.
* @param p1 - top point.
* @param p2 - bottom point.
* @return two points on middle normal with maximum distance.
*/
private static double[][] findMaxDistancePointsOnMiddleNormal(MatOfPoint contour, final double[] p1, final double[] p2) {
double bigDistance = SimpleGeometry.distance(p1, p2)/3; // That distance is big for this contour
// Point : distance from point to middle normal
final Map<Double, double[]> distancesWithPoints = new HashMap <Double, double[]>();
// Find all distance for all point to middle normal
for(Point p: contour.toList()) {
double distance = distanceFromPointToMiddleNormal(new double[] {p.x, p.y}, new double[]{p1[0], p1[1], p2[0], p2[1]});
distancesWithPoints.put(distance, new double[] {p.x, p.y});
}
// Utils.forEach(contour,
// (double[] point) -> {
// double distance = distanceFromPointToMiddleNormal(point, new double[]{p1[0], p1[1], p2[0], p2[1]});
// distancesWithPoints.put(distance, point);
// }
// );
// new pair of points
double[][] pair = new double[2][2];
Set<Double> distances = distancesWithPoints.keySet();
pair[0] = distancesWithPoints.remove(Collections.min(distances));
while(!distancesWithPoints.isEmpty()) {
Double minDistance = Collections.min(distances);
double[] next = distancesWithPoints.get(minDistance);
if(SimpleGeometry.distance(pair[0], next) > bigDistance) {
pair[1] = next;
return pair;
}
distancesWithPoints.remove(minDistance);
}
return pair;
}
/**
* Calculate distance from point to middle normal of segment.
* @param p - point of reference.
* @return distance from point to middle normal of segment.
* @tested
*/
private static double distanceFromPointToMiddleNormal(double[] p, double[] line) {
LineFunction func = LineFunctions.getMiddleNormalLineFunction(
new double[]{line[0], line[1]}, new double[]{line[2], line[3]});
double A = func.getA();
double B = func.getB();
double C = func.getC();
double tmp = Math.sqrt(A*A + B*B);
if(0!=tmp) return Math.abs(A*p[0] + B*p[1] + C) / tmp;
else return SimpleGeometry.distance(p, new double[]{line[0], line[1]});
}
}
/**
* Вернить две точки лежащие наиболее близко к данной линии и нормали справа и слева от нормали соответственно.
* Функция сначала находит список точек претендентов: наиболее близкие к линии точки по pointBufferSize справа и слева.
* После этого для каждой стороны выбирается наиболее близкая точка к нормали.
* @param listOfPoints - списко точек.
* @param line - данная линия.
* @param normal - нормаль.
* @return две точки лежащие наиболее близко к данной линии и нормали справа и слева от нормали соответственно.
*/
//private static Point[] getTwoPointThatLayOnGivenLine(List<Point> listOfPoints, Vector line, Vector normal) {
//short pointBufferSize = 5;
//
//List<Pair<Point, Double>> leftPoints = new LinkedList<Pair<Point, Double>>();
//List<Pair<Point, Double>> rightPoints = new LinkedList<Pair<Point, Double>>();
//
//for(Point point : listOfPoints) {
// double xDiff = (line.x2() - line.x1());
// double yDiff = (line.y2() -line.y1());
//
// xDiff = xDiff == 0 ? 0.0001 : xDiff;
// yDiff = yDiff == 0 ? 0.0001 : yDiff;
//
// double closenessToLine = Math.abs((point.x - line.x1())/xDiff - (point.y - line.y1())/yDiff);
// //double closenessToLine = Math.abs((point.x - line.x1())/(line.x2() - line.x1()) - (point.y - line.y1())/(line.y2()-line.y1()));
//
// // position relative to the normal
// // (y1-y2)*x+(x2-x1)*y+(x1*y2-x2*y1) > or < 0
// double position = (normal.y1()-normal.y2())*point.x + (normal.x2()-normal.x1()) * point.y + (normal.x1()*normal.y2()-normal.x2()*normal.y1());
//
// Comparator<Pair<Point, Double>> comparator = new Comparator<Pair<Point, Double>>() {
//
// @Override
// public int compare(Pair<Point, Double> arg0, Pair<Point, Double> arg1) {
// if(arg0.getRight() > arg1.getRight()) {
// return 1;
// }
// if(arg0.getRight() < arg1.getRight()) {
// return -1;
// }
// return 0;
// }
// };
//
// if(position <= 0) { // right position
// if(rightPoints.size() < pointBufferSize && !Double.isNaN(closenessToLine) && Double.isFinite(closenessToLine)) {
// rightPoints.add(new Pair<Point, Double>(point, closenessToLine));
//
// if(rightPoints.size() == pointBufferSize) {
// rightPoints.sort(comparator);
// }
//
// } else {
// for(int j=0; j<rightPoints.size(); j++) {
// Pair<Point, Double> rightPoint = rightPoints.get(j);
//
// if(closenessToLine < rightPoint.getRight()) {
// rightPoints.add(rightPoints.indexOf(rightPoint), new Pair<Point, Double>(point, closenessToLine));
// rightPoints.remove(rightPoints.size()-1);
// break;
// }
// }
//
// }
//
// } else { // left position
// if(leftPoints.size() < pointBufferSize && !Double.isNaN(closenessToLine) && Double.isFinite(closenessToLine)) {
// leftPoints.add(new Pair<Point, Double>(point, closenessToLine));
//
// if(leftPoints.size() == pointBufferSize) {
// leftPoints.sort(comparator);
// }
// } else {
// for(int j=0; j<leftPoints.size(); j++) {
// Pair<Point, Double> leftPoint = leftPoints.get(j);
//
// if(closenessToLine < leftPoint.getRight()) {
// leftPoints.add(leftPoints.indexOf(leftPoint), new Pair<Point, Double>(point, closenessToLine));
// leftPoints.remove(leftPoints.size()-1);
// break;
// }
// }
//
// }
// }
//}
//
//
//Point rightPoint = null;
//double rightBestDist = Double.MAX_VALUE;
//for(Pair<Point, Double> rightPointPair : rightPoints) {
// Point point = rightPointPair.getLeft();
//
// double xDiff = (normal.x2() - normal.x1());
// double yDiff = (normal.y2() - normal.y1());
//
// xDiff = xDiff == 0 ? 0.0001 : xDiff;
// yDiff = yDiff == 0 ? 0.0001 : yDiff;
//
// double closenessToNormal = Math.abs((point.x - normal.x1())/xDiff - (point.y - normal.y1())/yDiff);
// //double closenessToNormal = Math.abs((point.x - normal.x1())/(normal.x2() - normal.x1()) - (point.y - normal.y1())/(normal.y2()-normal.y1()));
//
// if(closenessToNormal < rightBestDist) {
// rightPoint = point;
// rightBestDist = closenessToNormal;
// }
//
//}
//
//Point leftPoint = null;
//double leftBestDist = Double.MAX_VALUE;
//for(Pair<Point, Double> leftPointPair : leftPoints) {
// Point point = leftPointPair.getLeft();
//
// double xDiff = (normal.x2() - normal.x1());
// double yDiff = (normal.y2()- normal.y1());
//
// xDiff = xDiff == 0 ? 0.0001 : xDiff;
// yDiff = yDiff == 0 ? 0.0001 : yDiff;
//
// double closenessToNormal = Math.abs((point.x - normal.x1())/xDiff - (point.y - normal.y1())/yDiff);
// //double closenessToNormal = Math.abs((point.x - normal.x1())/(normal.x2() - normal.x1()) - (point.y - normal.y1())/(normal.y2()-normal.y1()));
//
// if(closenessToNormal < leftBestDist) {
// leftPoint = point;
// leftBestDist = closenessToNormal;
// }
//}
//
//return new Point[]{leftPoint, rightPoint};
//}
/*
*
* public static Point[] getTwoPointThatLayOnGivenLine_(List<Point> listOfPoints, Vector line) {
Point point1 = null;
Point point2 = null;
Point prevPoint = listOfPoints.get(0);
boolean rele = false;
double minEstimation = Double.MAX_VALUE;
for(Point point : listOfPoints) {
double estimation = Math.abs((point.x - line.x1())/(line.x2() - line.x1()) - (point.y - line.y1())/(line.y2()-line.y1()));
if(estimation < minEstimation && distance(prevPoint, point)>10) { // ?????? distance it is not good decision
minEstimation= estimation;
if(rele) {
point1 = point;
} else {
point2 = point;
}
rele = !rele;
prevPoint = point;
}
}
return new Point[]{point1, point2};
}
*/