Base
This commit is contained in:
341
utils/src/main/java/ru/delkom07/geometry/SpecificGeometry.java
Normal file
341
utils/src/main/java/ru/delkom07/geometry/SpecificGeometry.java
Normal 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};
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user