Base
This commit is contained in:
39
utils/build.gradle
Normal file
39
utils/build.gradle
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Java library project to get you started.
|
||||
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
|
||||
* User Manual available at https://docs.gradle.org/7.5/userguide/building_java_projects.html
|
||||
*/
|
||||
|
||||
plugins {
|
||||
// Apply the java-library plugin for API and implementation separation.
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
compileTestJava.options.encoding = 'UTF-8'
|
||||
|
||||
|
||||
repositories {
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Use JUnit Jupiter for testing.
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
|
||||
|
||||
implementation("org.openpnp:opencv:3.4.2-0")
|
||||
|
||||
// This dependency is exported to consumers, that is to say found on their compile classpath.
|
||||
//api 'org.apache.commons:commons-math3:3.6.1'
|
||||
|
||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
||||
//implementation 'com.google.guava:guava:31.0.1-jre'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
// Use JUnit Platform for unit tests.
|
||||
useJUnitPlatform()
|
||||
}
|
||||
10
utils/src/main/java/ru/delkom07/Library.java
Normal file
10
utils/src/main/java/ru/delkom07/Library.java
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package ru.delkom07;
|
||||
|
||||
public class Library {
|
||||
public boolean someLibraryMethod() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
104
utils/src/main/java/ru/delkom07/fileutils/FileUtilities.java
Normal file
104
utils/src/main/java/ru/delkom07/fileutils/FileUtilities.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package ru.delkom07.fileutils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FileUtilities {
|
||||
public static FileFilter imageFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.getName().matches(".+\\.(png|PNG|jpg|JPG|bmp|BMP)")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static FileFilter jpgImageFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.getName().matches(".+\\.(jpg|JPG)")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static FileFilter pngImageFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.getName().matches(".+\\.(png|PNG)")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static FileFilter bmpImageFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.getName().matches(".+\\.(bmp|BMP)")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static FileFilter fileFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.isFile()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public static FileFilter dirFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.isDirectory()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Получить все файлы, соответствующие fileFilter, из директории и поддиректорий рекурсивно.
|
||||
* @param folder - корневая директория.
|
||||
* @param fileFilter (can be null) - фильтр файлов.
|
||||
* @return
|
||||
*/
|
||||
public static List<File> getFilesRecursively(File folder, FileFilter fileFilter) {
|
||||
if(null == fileFilter) {
|
||||
fileFilter = FileUtilities.fileFilter;
|
||||
}
|
||||
|
||||
List<File> imagesList = new ArrayList<File>(Arrays.asList(folder.listFiles(fileFilter)));
|
||||
|
||||
File[] subFolders = folder.listFiles(new FileFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
if(pathname.isDirectory())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
for(File subFolder : subFolders) {
|
||||
imagesList.addAll(getFilesRecursively(subFolder, fileFilter));
|
||||
}
|
||||
|
||||
return imagesList;
|
||||
}
|
||||
}
|
||||
25
utils/src/main/java/ru/delkom07/fileutils/Main.java
Normal file
25
utils/src/main/java/ru/delkom07/fileutils/Main.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package ru.delkom07.fileutils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
//FileUtils.compareTwoFouldersIgnoreFileNames(new File("../../wwork/2018_09_10_"), new File("../../wwork/2018_09_10_renamed_"));
|
||||
|
||||
//FileUtils.searchRepeatsInFolderIgnoreFileNames(new File("../data/img_renaming/renamed"));
|
||||
|
||||
//FileUtils.checkFilesForAnnotations(new File("../data/img_renaming/annotations.txt"), new File("../data/img_renaming/renamed"));
|
||||
|
||||
//FileUtils.checkAnnotationsForFiles(new File("../data/img_renaming/renamed"), new File[] {new File("../data/img_renaming/annotations.txt")});
|
||||
|
||||
//FileUtils.removeFileWithDoublecatesNames();
|
||||
|
||||
//FileUtils.renameFilesForAnnotations(new File("../data/img_renaming/annotations.csv"), new File("../data/img_renaming/renamed"));
|
||||
|
||||
|
||||
//FileUtils.findAndCopyImgsFromList(new File("c:\\Users\\KomyshevEG\\Downloads\\renamed_19.12.18"), new File("d:\\workspace\\data\\wheat_ears\\input\\calibrated_problem"), new File("d:\\workspace\\data\\wheat_ears\\input\\calibrated_problem\\list.txt"));
|
||||
}
|
||||
|
||||
}
|
||||
185
utils/src/main/java/ru/delkom07/geometry/AdditionalIndexies.java
Normal file
185
utils/src/main/java/ru/delkom07/geometry/AdditionalIndexies.java
Normal file
@@ -0,0 +1,185 @@
|
||||
package ru.delkom07.geometry;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.Core.MinMaxLocResult;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.MatOfInt;
|
||||
import org.opencv.core.MatOfPoint;
|
||||
import org.opencv.core.MatOfPoint2f;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Rect;
|
||||
import org.opencv.core.RotatedRect;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import ru.delkom07.geometry.obj.Circle;
|
||||
|
||||
|
||||
public class AdditionalIndexies {
|
||||
|
||||
public static double circularityIndex(MatOfPoint contour) {
|
||||
double area = Imgproc.contourArea(contour);
|
||||
|
||||
MatOfPoint2f contour2f = new MatOfPoint2f( contour.toArray() );
|
||||
double perimeter = Imgproc.arcLength(contour2f, true);
|
||||
|
||||
return ( 4*Math.PI * area ) / (perimeter*perimeter);
|
||||
}
|
||||
|
||||
|
||||
public static double roundness(MatOfPoint contour) {
|
||||
MatOfPoint2f forFillEllipse = new MatOfPoint2f();
|
||||
contour.convertTo(forFillEllipse, CvType.CV_32FC2);
|
||||
RotatedRect rotatedRect = Imgproc.fitEllipse(forFillEllipse);
|
||||
double majorAxis = Math.max(rotatedRect.size.height, rotatedRect.size.width);
|
||||
|
||||
double area = Imgproc.contourArea(contour);
|
||||
|
||||
return (4*area) / (Math.PI * majorAxis*majorAxis); // (4*area) / (pi*[Major axis]^2)
|
||||
}
|
||||
|
||||
|
||||
public static double solidity(MatOfPoint contour) {
|
||||
double area = Imgproc.contourArea(contour);
|
||||
|
||||
Point[] contourArr = contour.toArray();
|
||||
MatOfInt hull = new MatOfInt();
|
||||
Imgproc.convexHull(contour, hull);
|
||||
int[] hullIntArr = hull.toArray();
|
||||
|
||||
Point[] hullArr = new Point[hullIntArr.length];
|
||||
for(int i=0; i<hullIntArr.length; i++) {
|
||||
hullArr[i] = contourArr[hullIntArr[i]];
|
||||
}
|
||||
|
||||
MatOfPoint2f hull2f = new MatOfPoint2f(hullArr);
|
||||
MatOfPoint2f approxContour = new MatOfPoint2f();
|
||||
Imgproc.approxPolyDP(hull2f, approxContour, 0.001, true);
|
||||
double hullArea = Imgproc.contourArea(approxContour);
|
||||
|
||||
return area/hullArea;
|
||||
}
|
||||
|
||||
|
||||
public static double rugosity(MatOfPoint contour) {
|
||||
// perimeter
|
||||
MatOfPoint2f contour2f = new MatOfPoint2f( contour.toArray() );
|
||||
double perimeter = Imgproc.arcLength(contour2f, true);
|
||||
|
||||
MatOfInt hull = new MatOfInt();
|
||||
Imgproc.convexHull(contour, hull);
|
||||
|
||||
// hull perimeter:
|
||||
double hullPerimeter = 0;
|
||||
int[] hullArr = hull.toArray();
|
||||
Point[] contourArr = contour.toArray();
|
||||
for(int i=0; i<hullArr.length-1; i++) {
|
||||
Point curPoint = contourArr[hullArr[i]];
|
||||
Point nextPoint = contourArr[hullArr[i+1]];
|
||||
|
||||
hullPerimeter += SimpleGeometry.distance(curPoint, nextPoint);
|
||||
}
|
||||
hullPerimeter += SimpleGeometry.distance(contourArr[contourArr.length-1], contourArr[0]);
|
||||
|
||||
|
||||
return perimeter/hullPerimeter;
|
||||
}
|
||||
|
||||
|
||||
private static double maxInscribedMinCircumscribedCirclesDiametersRatio(MatOfPoint contour) {
|
||||
Point center = new Point();
|
||||
float[] enclosedCircleRadius = new float[1];
|
||||
|
||||
MatOfPoint2f contour2f = new MatOfPoint2f();
|
||||
contour.convertTo(contour2f, CvType.CV_32FC2);
|
||||
Imgproc.minEnclosingCircle(contour2f, center, enclosedCircleRadius);
|
||||
|
||||
Circle inscribedCircle = getMaxInscribedCircle(contour);
|
||||
double inscribedCircleRadius = inscribedCircle.radius();
|
||||
|
||||
return enclosedCircleRadius[0]/inscribedCircleRadius;
|
||||
}
|
||||
|
||||
|
||||
public static Circle getMinCircumscribedCircle(MatOfPoint contour) {
|
||||
Point center = new Point();
|
||||
float[] enclosedCircleRadius = new float[1];
|
||||
|
||||
MatOfPoint2f contour2f = new MatOfPoint2f();
|
||||
contour.convertTo(contour2f, CvType.CV_32FC2);
|
||||
Imgproc.minEnclosingCircle(contour2f, center, enclosedCircleRadius);
|
||||
|
||||
return new Circle(center, (double)enclosedCircleRadius[0]);
|
||||
}
|
||||
|
||||
|
||||
public static Circle getMaxInscribedCircle(MatOfPoint contour) {
|
||||
Rect rect = Imgproc.boundingRect(contour);
|
||||
|
||||
Mat imprint = Mat.zeros(rect.height, rect.width, CvType.CV_8UC1);
|
||||
Imgproc.drawContours(imprint, Arrays.asList(contour), -1, new Scalar(255), -1);
|
||||
|
||||
Circle circle = getInscribedCircle(contour, imprint);
|
||||
|
||||
imprint.release();
|
||||
|
||||
return circle;
|
||||
}
|
||||
|
||||
|
||||
private static Circle getInscribedCircle(MatOfPoint contour, Mat imprint) {
|
||||
Mat distTransform = new Mat();
|
||||
Imgproc.distanceTransform(imprint, distTransform, Imgproc.CV_DIST_L2, 0);
|
||||
|
||||
MinMaxLocResult result = Core.minMaxLoc(distTransform);
|
||||
Point maxLoc = result.maxLoc;
|
||||
//double[] maxLocD = new double[] {maxLoc.x, maxLoc.y};
|
||||
Point closestPoint = getClosestPoint(contour, maxLoc);
|
||||
double radius = SimpleGeometry.distance(closestPoint, maxLoc);
|
||||
|
||||
return new Circle(maxLoc, radius);
|
||||
}
|
||||
|
||||
|
||||
private static Point getClosestPoint(MatOfPoint contour, Point point) {
|
||||
double[] bestPoint = contour.get(0, 0);
|
||||
double bestDist = SimpleGeometry.distance(point, bestPoint);
|
||||
|
||||
for(int i=0; i<contour.rows(); i++) {
|
||||
for(int j=0; j<contour.cols(); j++) {
|
||||
double[] curPoint = contour.get(i, j);
|
||||
|
||||
double curDist = SimpleGeometry.distance(point, curPoint);
|
||||
if(curDist < bestDist) {
|
||||
bestPoint = curPoint;
|
||||
bestDist = curDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Point(bestPoint[0], bestPoint[1]);
|
||||
}
|
||||
|
||||
|
||||
// private static double[] getClosestPoint(MatOfPoint contour, double[] point) {
|
||||
// double[] bestPoint = contour.get(0, 0);
|
||||
// double bestDist = SimpleGeometry.distance(bestPoint, point);
|
||||
//
|
||||
// for(int i=0; i<contour.rows(); i++) {
|
||||
// for(int j=0; j<contour.cols(); j++) {
|
||||
// double[] curPoint = contour.get(i, j);
|
||||
//
|
||||
// double curDist = SimpleGeometry.distance(curPoint, point);
|
||||
// if(curDist < bestDist) {
|
||||
// bestPoint = curPoint;
|
||||
// bestDist = curDist;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return bestPoint;
|
||||
// }
|
||||
}
|
||||
336
utils/src/main/java/ru/delkom07/geometry/ContoursFunctions.java
Normal file
336
utils/src/main/java/ru/delkom07/geometry/ContoursFunctions.java
Normal file
@@ -0,0 +1,336 @@
|
||||
package ru.delkom07.geometry;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.MatOfPoint;
|
||||
import org.opencv.core.MatOfPoint2f;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.RotatedRect;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
import ru.delkom07.geometry.obj.Vector;
|
||||
import ru.delkom07.util.Pair;
|
||||
|
||||
public class ContoursFunctions {
|
||||
|
||||
/**
|
||||
* Obtain a contour with the maximum area among the given ones.
|
||||
* @param contours - list of contours.
|
||||
* @return contour with the maximum area.
|
||||
*/
|
||||
public static MatOfPoint getMaxAreaContour(List<MatOfPoint> contours) {
|
||||
if(null != contours && 0 != contours.size()) {
|
||||
double maxArea = Imgproc.contourArea(contours.get(0));
|
||||
MatOfPoint bestContour = contours.get(0);
|
||||
|
||||
for(MatOfPoint contour : contours) {
|
||||
double area = Imgproc.contourArea(contour);
|
||||
|
||||
if(area > maxArea) {
|
||||
maxArea = area;
|
||||
bestContour = contour;
|
||||
}
|
||||
}
|
||||
|
||||
return bestContour;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get linear sizes of object with elliptic contour.
|
||||
* @param contour - object contour.
|
||||
* @return linear sizes.
|
||||
*/
|
||||
private static double[] getLengthAndWidth(MatOfPoint contour) {
|
||||
// length and width
|
||||
MatOfPoint2f forFillEllipse = new MatOfPoint2f();
|
||||
contour.convertTo(forFillEllipse, CvType.CV_32FC2);
|
||||
RotatedRect rotatedRect = Imgproc.fitEllipse(forFillEllipse);
|
||||
Point[] points = new Point[4];
|
||||
rotatedRect.points(points);
|
||||
double length = 0;
|
||||
double width = 0;
|
||||
length = SimpleGeometry.distance(points[0], points[1]);
|
||||
width = SimpleGeometry.distance(points[1], points[2]);
|
||||
|
||||
if(length<width) {
|
||||
double dd = length;
|
||||
length = width;
|
||||
width = dd;
|
||||
}
|
||||
|
||||
return new double[]{length, width};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get center point of MatOfPoint that is point with (middleX, middleY) coordinates.
|
||||
* @param contour - matrix of point.
|
||||
* @return center point of given matrix of point.
|
||||
*/
|
||||
public static double[] massCenter(MatOfPoint contour) {
|
||||
double[] acc = new double[] {0.0, 0.0};
|
||||
|
||||
List<Point> points = contour.toList();
|
||||
for(Point p : points) {
|
||||
acc[0] += p.x;
|
||||
acc[1] += p.y;
|
||||
}
|
||||
|
||||
return new double[]{acc[0]/points.size(), acc[1]/points.size()};
|
||||
}
|
||||
|
||||
|
||||
// **Obsolete version
|
||||
// public static double[] massCenter(MatOfPoint contour) {
|
||||
// double[] massCenter = new double[2];
|
||||
// massCenter[0] = 0.0;
|
||||
// massCenter[1] = 0.0;
|
||||
// int count = 0;
|
||||
// for(int i=0; i<contour.rows(); i++) {
|
||||
// for(int j=0; j<contour.cols(); j++) {
|
||||
// double[] point = contour.get(i, j);
|
||||
// massCenter[0] += point[0];
|
||||
// massCenter[1] += point[1];
|
||||
// count++;
|
||||
// }
|
||||
// }
|
||||
// massCenter[0] = massCenter[0]/(double)count;
|
||||
// massCenter[1] = massCenter[1]/(double)count;
|
||||
//
|
||||
// return massCenter;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param contour
|
||||
* @return
|
||||
*/
|
||||
private static Vector[] mainComponents(MatOfPoint contour) {
|
||||
double[] massCenter = massCenter(contour);
|
||||
|
||||
Vector minAxis = new Vector(massCenter[0], massCenter[1], contour.get(0, 0)[0], contour.get(0, 0)[1]);
|
||||
double[] minInertionMoment = new double[2];
|
||||
minInertionMoment[0] = Double.MAX_VALUE;
|
||||
minInertionMoment[1] = Double.MAX_VALUE;
|
||||
|
||||
for(int i=0; i<contour.rows(); i++) {
|
||||
for(int j=0; j<contour.cols(); j++) {
|
||||
Vector potentialAxis = new Vector(massCenter[0], massCenter[1], contour.get(i, j)[0], contour.get(i, j)[1]);
|
||||
|
||||
double A = potentialAxis.y1()-potentialAxis.y2();
|
||||
double B = potentialAxis.x2()-potentialAxis.x1();
|
||||
double C = potentialAxis.x1()*potentialAxis.y2() - potentialAxis.x2()*potentialAxis.y1();
|
||||
|
||||
double[] inertionMoment = new double[2];
|
||||
for(int ii=0; ii<contour.rows(); ii++) {
|
||||
for(int jj=0; jj<contour.cols(); jj++) {
|
||||
double[] point = contour.get(ii, jj);
|
||||
|
||||
double[] pointOnAxis = new double[2];
|
||||
pointOnAxis[0] = ( B*(B*point[0]-A*point[1] )-A*C) / (A*A+B*B);
|
||||
pointOnAxis[1] = ( A*(-1*B*point[0]+A*point[1] )-B*C) / (A*A+B*B);
|
||||
|
||||
double d = Math.abs(A*point[0] + B*point[1] + C) / Math.sqrt(A*A + B*B);
|
||||
|
||||
inertionMoment[0] += d*d*pointOnAxis[0];
|
||||
inertionMoment[1] += d*d*pointOnAxis[1];
|
||||
}
|
||||
}
|
||||
|
||||
if(Math.sqrt(inertionMoment[0]*inertionMoment[0]+inertionMoment[1]*inertionMoment[1])
|
||||
< Math.sqrt(minInertionMoment[0]*minInertionMoment[0]+minInertionMoment[1]*minInertionMoment[1])) {
|
||||
minAxis = potentialAxis;
|
||||
minInertionMoment[0] = inertionMoment[0];
|
||||
minInertionMoment[1] = inertionMoment[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Vector[]{minAxis, new Vector(minAxis.x1(), minAxis.y1(), minAxis.x1()+minAxis.y(), minAxis.y1()-minAxis.x())};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Вычислить вектора, идущие вдоль контура в заданным (GLOB_VECT_SIZE) шагом.
|
||||
* @param contour - контур, полученный из функции findContours::Imgproc::OpenCV (матрица точек).
|
||||
* @return - список векторов, образующих (почти) замкнутый контур.
|
||||
*/
|
||||
public static List<Vector> getVectors(MatOfPoint contour, int vectSize) {
|
||||
List<Vector> vectList = new LinkedList<Vector>(); // список векторов (только направление, без привязки к координатам)
|
||||
//List<Double[]> vectEndList = new LinkedList<Double[]>(); // список концов векторов (для привязки к координатам)
|
||||
double[] prevPoint = contour.get(0, 0);
|
||||
int step = 0;
|
||||
for(int i=0; i<contour.size().width; i++) {
|
||||
for(int j=0; j<contour.size().height; j++) {
|
||||
step++;
|
||||
|
||||
if(i==0 && j==0) // пропуск первой точки
|
||||
continue;
|
||||
|
||||
if(step>=vectSize) { // шаг увеличивается пока не достигнет необходимой длины вектора
|
||||
step=0;
|
||||
|
||||
double[] curPoint = contour.get(j, i);
|
||||
|
||||
vectList.add(new Vector(prevPoint[0], prevPoint[1], curPoint[0], curPoint[1]));
|
||||
|
||||
prevPoint = curPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Последнй вектор замыкает контур:
|
||||
double[] curPoint = contour.get(0, 0);
|
||||
vectList.add(new Vector(prevPoint[0], prevPoint[1], curPoint[0], curPoint[1]));
|
||||
|
||||
return vectList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Вычисление перегибов
|
||||
* @param vectors - список векторов, идущих друг за другим (каждый последующий выходит из конца предидущего),
|
||||
* и образующих замкнутый контур.
|
||||
* @return - списк векторов, на конце которых обнаружился перегиб.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static List<Pair<Point, Vector>> getBendsIndxs(List<Vector> vectors) {
|
||||
// общая сумма направлений необходима, чтобы определить в какую сторону производится обход контура
|
||||
double courseSum = 0.0;
|
||||
|
||||
// список направлений векторов относительно предыдущего вектора: правее или левее
|
||||
List<Pair<Double, Double>> courseList = new LinkedList<Pair<Double, Double>>();
|
||||
Vector prevVector = vectors.get(vectors.size()-1);
|
||||
for(int i=0; i<vectors.size(); i++) { // only if vectList.size > 1;
|
||||
Vector curVector = vectors.get(i);
|
||||
|
||||
// направление текущего вектора относительно предидущего: правее (course<0) или левее (course>0)
|
||||
Double relativeCourse = prevVector.x()*curVector.y()-prevVector.y()*curVector.x();
|
||||
|
||||
courseList.add(new Pair<Double, Double>(relativeCourse, SimpleGeometry.angle(prevVector, curVector)));
|
||||
|
||||
courseSum += relativeCourse;
|
||||
|
||||
prevVector = curVector;
|
||||
}
|
||||
|
||||
// выбор индексов векторов, где обнаружен перегиб в обратную сторону относительно направления обхода контура
|
||||
|
||||
|
||||
List<Pair<Point, Vector>> bendListIndxs = new LinkedList<Pair<Point, Vector>>();
|
||||
for(int i=0; i<courseList.size(); i++) {
|
||||
Pair<Double, Double> coursePair = courseList.get(i);
|
||||
double course = coursePair.getLeft();
|
||||
double angle = coursePair.getRight();
|
||||
|
||||
double thresAngle = 0.7;
|
||||
if(courseSum > 0) {
|
||||
if(course < 0 && angle > thresAngle) { // Math.abs(course)>thres
|
||||
Vector v1 = i>0 ? vectors.get(i-1) : vectors.get(vectors.size()-1);
|
||||
Vector v2 = i<vectors.size() ? vectors.get(i) : vectors.get(0);
|
||||
|
||||
Vector inverse = v2.inverse();
|
||||
Vector deposition = v1.deposition(v1.x2(), v1.y2());
|
||||
Vector v3 = new Vector(inverse.x1(), inverse.y1(), (inverse.x2()+deposition.x2())/2.0, (inverse.y2()+deposition.y2())/2.0);
|
||||
|
||||
|
||||
bendListIndxs.add(new Pair<Point, Vector>(new Point(vectors.get(i).x1(), vectors.get(i).y1()), v3 ));
|
||||
}
|
||||
} else {
|
||||
if(course > 0 && angle > thresAngle) { // Math.abs(course)>thres
|
||||
Vector v1 = i>0 ? vectors.get(i-1) : vectors.get(vectors.size()-1);
|
||||
Vector v2 = i<vectors.size() ? vectors.get(i) : vectors.get(0);
|
||||
|
||||
Vector inverse = v2.inverse();
|
||||
Vector deposition = v1.deposition(v1.x2(), v1.y2());
|
||||
Vector v3 = new Vector(inverse.x1(), inverse.y1(), (inverse.x2()+deposition.x2())/2.0, (inverse.y2()+deposition.y2())/2.0);
|
||||
|
||||
bendListIndxs.add(new Pair<Point, Vector>(new Point(vectors.get(i).x1(), vectors.get(i).y1()), v3 ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bendListIndxs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TO CHECK
|
||||
//private static double[] getMassCenter(MatOfPoint contour) {
|
||||
//// mass center
|
||||
//double[] massCenter = new double[2];
|
||||
//massCenter[0] = 0.0;
|
||||
//massCenter[1] = 0.0;
|
||||
//int count = 0;
|
||||
//for(int i=0; i<contour.rows(); i++) {
|
||||
// for(int j=0; j<contour.cols(); j++) {
|
||||
// double[] point = contour.get(i, j);
|
||||
// massCenter[0] += point[0];
|
||||
// massCenter[1] += point[1];
|
||||
// count++;
|
||||
// }
|
||||
//}
|
||||
//massCenter[0] = massCenter[0]/(double)count;
|
||||
//massCenter[1] = massCenter[1]/(double)count;
|
||||
//
|
||||
//return massCenter;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//
|
||||
//private static Vector[] getMainComponents(MatOfPoint contour) {
|
||||
//double[] massCenter = getMassCenter(contour);
|
||||
//
|
||||
//Vector minAxis = new Vector(massCenter[0], massCenter[1], contour.get(0, 0)[0], contour.get(0, 0)[1]);
|
||||
//double[] minInertionMoment = new double[2];
|
||||
//minInertionMoment[0] = Double.MAX_VALUE;
|
||||
//minInertionMoment[1] = Double.MAX_VALUE;
|
||||
//
|
||||
//for(int i=0; i<contour.rows(); i++) {
|
||||
// for(int j=0; j<contour.cols(); j++) {
|
||||
// Vector potentialAxis = new Vector(massCenter[0], massCenter[1], contour.get(i, j)[0], contour.get(i, j)[1]);
|
||||
//
|
||||
// double A = potentialAxis.y1()-potentialAxis.y2();
|
||||
// double B = potentialAxis.x2()-potentialAxis.x1();
|
||||
// double C = potentialAxis.x1()*potentialAxis.y2() - potentialAxis.x2()*potentialAxis.y1();
|
||||
//
|
||||
// double[] inertionMoment = new double[2];
|
||||
// for(int ii=0; ii<contour.rows(); ii++) {
|
||||
// for(int jj=0; jj<contour.cols(); jj++) {
|
||||
// double[] point = contour.get(ii, jj);
|
||||
//
|
||||
// double[] pointOnAxis = new double[2];
|
||||
// pointOnAxis[0] = ( B*(B*point[0]-A*point[1] )-A*C) / (A*A+B*B);
|
||||
// pointOnAxis[1] = ( A*(-1*B*point[0]+A*point[1] )-B*C) / (A*A+B*B);
|
||||
//
|
||||
// double d = Math.abs(A*point[0] + B*point[1] + C) / Math.sqrt(A*A + B*B);
|
||||
//
|
||||
// inertionMoment[0] += d*d*pointOnAxis[0];
|
||||
// inertionMoment[1] += d*d*pointOnAxis[1];
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(Math.sqrt(inertionMoment[0]*inertionMoment[0]+inertionMoment[1]*inertionMoment[1])
|
||||
// < Math.sqrt(minInertionMoment[0]*minInertionMoment[0]+minInertionMoment[1]*minInertionMoment[1])) {
|
||||
// minAxis = potentialAxis;
|
||||
// minInertionMoment[0] = inertionMoment[0];
|
||||
// minInertionMoment[1] = inertionMoment[1];
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//return new Vector[]{minAxis, new Vector(minAxis.x1(), minAxis.y1(), minAxis.x1()+minAxis.y(), minAxis.y1()-minAxis.x())};
|
||||
//}
|
||||
145
utils/src/main/java/ru/delkom07/geometry/LineFunctions.java
Normal file
145
utils/src/main/java/ru/delkom07/geometry/LineFunctions.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package ru.delkom07.geometry;
|
||||
|
||||
import ru.delkom07.geometry.obj.LineFunction;
|
||||
|
||||
public class LineFunctions {
|
||||
|
||||
/**
|
||||
* Returns line function of given segment.
|
||||
* @param p1 - first point of segment.
|
||||
* @param p2 - second point of segment.
|
||||
* @return line function of given segment.
|
||||
* @tested
|
||||
*/
|
||||
public static LineFunction getLineFunction(double[] p1, double[] p2) {
|
||||
final double A = -(p2[1]-p1[1]); // -(y2-y1)
|
||||
final double B = (p2[0]-p1[0]); // (x2-x1)
|
||||
final double C = -p1[1]*p2[0] + p1[0]*p2[1]; // -y1x2 + x1y2
|
||||
|
||||
final double k = (p2[1]-p1[1])/(p2[0]-p1[0]); // (y2-y1)/(x2-x1)
|
||||
final double b = (p1[1]*p2[0]-p1[0]*p2[1])/(p2[0]-p1[0]); // (y1x2-x1y2)/(x2-x1)
|
||||
|
||||
return new LineFunction() {
|
||||
@Override
|
||||
public double value(double x) {
|
||||
return k*(double)x + b;
|
||||
}
|
||||
@Override
|
||||
public double getA() {return A;}
|
||||
@Override
|
||||
public double getB() {return B;}
|
||||
@Override
|
||||
public double getC() {return C;}
|
||||
@Override
|
||||
public double getk() {return k;}
|
||||
@Override
|
||||
public double getb() {return b;}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns perpendicular line function of given segment.
|
||||
* @param p1 - first point of segment.
|
||||
* @param p2 - second point of segment.
|
||||
* @return line function of given segment.
|
||||
* @tested
|
||||
*/
|
||||
public static LineFunction getNormalLineFunction(double[] p1, double[] p2, double[] pM) {
|
||||
final double k = -(p2[0]-p1[0])/(p2[1]-p1[1]); // -(x2-x1)/(y2-y1)
|
||||
final double b = pM[1]+(-k)*pM[0]; // y0+(x2-x1)/(y2-y1)*x0
|
||||
|
||||
final double A = k;
|
||||
final double B = -1;
|
||||
final double C = b;
|
||||
|
||||
return new LineFunction() {
|
||||
@Override
|
||||
public double value(double x) {
|
||||
return k*(double)x + b;
|
||||
}
|
||||
@Override
|
||||
public double getA() {return A;}
|
||||
@Override
|
||||
public double getB() {return B;}
|
||||
@Override
|
||||
public double getC() {return C;}
|
||||
@Override
|
||||
public double getk() {return k;}
|
||||
@Override
|
||||
public double getb() {return b;}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns middle normal line function of given segment.
|
||||
* @param p1 - first point of segment.
|
||||
* @param p2 - second point of segment.
|
||||
* @return middle normal line function of given segment.
|
||||
* @tested
|
||||
*/
|
||||
public static LineFunction getMiddleNormalLineFunction(double[] p1, double[] p2) {
|
||||
// Middle point
|
||||
double xMdl = (p1[0]+p2[0])/2.0;
|
||||
double yMdl = (p1[1]+p2[1])/2.0;
|
||||
|
||||
final double k = -(p2[0]-p1[0])/(p2[1]-p1[1]); // -(x2-x1)/(y2-y1)
|
||||
final double b = yMdl+(-k)*xMdl; // y0+(x2-x1)/(y2-y1)*x0
|
||||
|
||||
final double A = k;
|
||||
final double B = -1;
|
||||
final double C = b;
|
||||
|
||||
return new LineFunction() {
|
||||
@Override
|
||||
public double value(double x) {
|
||||
return k*(double)x + b;
|
||||
}
|
||||
@Override
|
||||
public double getA() {return A;}
|
||||
@Override
|
||||
public double getB() {return B;}
|
||||
@Override
|
||||
public double getC() {return C;}
|
||||
@Override
|
||||
public double getk() {return k;}
|
||||
@Override
|
||||
public double getb() {return b;}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculates distance from point to line.
|
||||
* @param point - given point.
|
||||
* @param func - function of line.
|
||||
* @return distance from point to line.
|
||||
* @tested
|
||||
*/
|
||||
private static double distanceFromPointToLine(double[] point, LineFunction func) {
|
||||
double A = func.getA();
|
||||
double B = func.getB();
|
||||
double C = func.getC();
|
||||
|
||||
double tmp = Math.sqrt(A*A + B*B);
|
||||
return Math.abs(A*point[0] + B*point[1] + C) / tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates distance from point to line.
|
||||
* @param point - given point.
|
||||
* @param line - given line.
|
||||
* @return distance from point to line.
|
||||
* @tested
|
||||
*/
|
||||
private static double distanceFromPointToLine(double[] point, double[] line) {
|
||||
double A = (line[3]-line[1]);
|
||||
double B = -(line[2]-line[0]);
|
||||
double C = (line[1]*line[2] - line[1]*line[0] - line[0]*line[3] + line[0]*line[1]);
|
||||
|
||||
double tmp = Math.sqrt(A*A + B*B);
|
||||
if(0!=tmp) return Math.abs(A*point[0] + B*point[1] + C) / tmp;
|
||||
return SimpleGeometry.distance(point, new double[]{line[0], line[1]});
|
||||
}
|
||||
|
||||
}
|
||||
469
utils/src/main/java/ru/delkom07/geometry/SimpleGeometry.java
Normal file
469
utils/src/main/java/ru/delkom07/geometry/SimpleGeometry.java
Normal file
@@ -0,0 +1,469 @@
|
||||
package ru.delkom07.geometry;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.opencv.core.Point;
|
||||
|
||||
import ru.delkom07.geometry.obj.Vector;
|
||||
import ru.delkom07.util.Pair;
|
||||
|
||||
public class SimpleGeometry {
|
||||
// === Distance ===
|
||||
|
||||
/**
|
||||
* Calculate euclidean distance from point p1 to point p2.
|
||||
* @param p1 - fisrt point.
|
||||
* @param p2 - second point.
|
||||
* @return numerical, unscaled distance.
|
||||
*/
|
||||
public static double distance(Point p1, Point p2) {
|
||||
double dx = Math.abs(p1.x-p2.x);
|
||||
double dy = Math.abs(p1.y-p2.y);
|
||||
return Math.sqrt(dx*dx+dy*dy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate euclidean distance from point p1 to point p2.
|
||||
* @param p1 - fisrt point.
|
||||
* @param p2 - second point.
|
||||
* @return numerical, unscaled distance.
|
||||
*/
|
||||
public static double distance(double[] p1, double[] p2) {
|
||||
double sum = 0;
|
||||
for(int i=0; i<p1.length || i<p2.length; i++) {
|
||||
sum += Math.pow(p1[i]-p2[i], 2);
|
||||
}
|
||||
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate euclidean distance from point p1 to point p2.
|
||||
* @param p1 - fisrt point.
|
||||
* @param p2 - second point.
|
||||
* @return numerical, unscaled distance.
|
||||
*/
|
||||
public static double distance(Point p1, double[] p2) {
|
||||
double dx = Math.abs(p1.x-p2[0]);
|
||||
double dy = Math.abs(p1.y-p2[1]);
|
||||
return Math.sqrt(dx*dx+dy*dy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate a new normalized vector from the given one.
|
||||
* @param vector - given vector.
|
||||
* @return a new normalized vector.
|
||||
*/
|
||||
public static Vector normalize(Vector vector) {
|
||||
double length = vector.length();
|
||||
|
||||
double newX = vector.x()/length;
|
||||
double newY = vector.y()/length;
|
||||
|
||||
return new Vector(vector.x1(), vector.y1(), vector.x1()+newX, vector.y1()+newY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// === Angles ===
|
||||
|
||||
/**
|
||||
* Calculate of angle between given vectors in radians.
|
||||
* To calculate degree: *180 / pi.
|
||||
* @param vect1 - first vector.
|
||||
* @param vect2 - second vector.
|
||||
* @return angle between given vectors.
|
||||
*/
|
||||
public static double angle(Vector vect1, Vector vect2) {
|
||||
return Math.acos((vect1.x()*vect2.x()+vect1.y()*vect2.y())/(vect1.length()*vect2.length()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate of angle between given vectors in degrees.
|
||||
* To calculate radians: *pi/180.
|
||||
* @param vect1 - first vector.
|
||||
* @param vect2 - second vector.
|
||||
* @return angle between given vector.
|
||||
*/
|
||||
public static double angleInDegree(Vector vect1, Vector vect2) {
|
||||
return angle(vect1, vect2) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Angle between two lines (without mean directions).
|
||||
* @param vect1 - first line.
|
||||
* @param vect2 - second line.
|
||||
* @return Angle between two lines.
|
||||
*/
|
||||
private static double lineAngle(Vector vect1, Vector vect2) {
|
||||
double val = angle(vect1, vect2);
|
||||
return val < Math.PI/2.0 ? val : Math.PI - val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle between two lines (without mean directions).
|
||||
* @param vect1 - first line.
|
||||
* @param vect2 - second line.
|
||||
* @return Angle between two lines.
|
||||
*/
|
||||
private static double lineAngleInDegree(Vector vect1, Vector vect2) {
|
||||
return lineAngle(vect1, vect2) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate of angle between given lines in radians.
|
||||
* To calculate degrees: * 180 / pi.
|
||||
* @param line1 - first line.
|
||||
* @param line2 - second line.
|
||||
* @return angle between given lines.
|
||||
*/
|
||||
private static double lineAngle(double[] line1, double[] line2) {
|
||||
double dx1 = Math.abs(line1[0]-line1[2]); // |x1 - x2|
|
||||
double dy1 = Math.abs(line1[1]-line1[3]); // |y1 - y2|
|
||||
double l1 = Math.sqrt(dx1*dx1 + dy1*dy1);
|
||||
|
||||
double dx2 = Math.abs(line2[0]-line2[2]); // |x1 - x2|
|
||||
double dy2 = Math.abs(line2[1]-line2[3]); // |y1 - y2|
|
||||
double l2 = Math.sqrt(dx2*dx2 + dy2*dy2);
|
||||
|
||||
double val = Math.acos((dx1*dx2+dy1*dy2)/(l1*l2));
|
||||
return val < Math.PI/2.0 ? val : Math.PI - val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate of angle between given lines in degrees.
|
||||
* To calculate radians: * pi / 180.
|
||||
* @param line1 - first line.
|
||||
* @param line2 - second line.
|
||||
* @return angle between given lines.
|
||||
*/
|
||||
private static double angleInDegree(double[] line1, double[] line2) {
|
||||
return lineAngle(line1, line2) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compute intersection of lines.
|
||||
* @param line1 - first line.
|
||||
* @param line2 - second line.
|
||||
* @return point of intersection of given lines.
|
||||
*/
|
||||
private static double[] computeIntersect(double[] line1, double[] line2) {
|
||||
double x1 = line1[0], y1 = line1[1], x2 = line1[2], y2 = line1[3];
|
||||
double x3 = line2[0], y3 = line2[1], x4 = line2[2], y4 = line2[3];
|
||||
|
||||
double d = ((x1-x2) * (y3-y4)) - ((y1-y2) * (x3-x4));
|
||||
if (0 != d) {
|
||||
double[] pt = new double[2];
|
||||
pt[0] = ((x1*y2 - y1*x2) * (x3-x4) - (x1-x2) * (x3*y4 - y3*x4)) / d;
|
||||
pt[1] = ((x1*y2 - y1*x2) * (y3-y4) - (y1-y2) * (x3*y4 - y3*x4)) / d;
|
||||
return pt;
|
||||
} else
|
||||
return new double[]{-1, -1};
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute intersection of lines.
|
||||
* @param p1Line1 - first point of first line.
|
||||
* @param p2Line1 - second point of first line.
|
||||
* @param p1Line2 - first point of second line.
|
||||
* @param p2Line2 - second point of second line.
|
||||
* @return point of intersection of given lines.
|
||||
*/
|
||||
public static double[] computeIntersect(double[] p1Line1, double[] p2Line1, double[] p1Line2, double[] p2Line2) {
|
||||
double x1 = p1Line1[0], y1 = p1Line1[1], x2 = p2Line1[0], y2 = p2Line1[1];
|
||||
double x3 = p1Line2[0], y3 = p1Line2[1], x4 = p2Line2[0], y4 = p2Line2[1];
|
||||
|
||||
double d = ((x1-x2) * (y3-y4)) - ((y1-y2) * (x3-x4));
|
||||
if (0 != d) {
|
||||
double[] pt = new double[2];
|
||||
pt[0] = ((x1*y2 - y1*x2) * (x3-x4) - (x1-x2) * (x3*y4 - y3*x4)) / d;
|
||||
pt[1] = ((x1*y2 - y1*x2) * (y3-y4) - (y1-y2) * (x3*y4 - y3*x4)) / d;
|
||||
return pt;
|
||||
} else
|
||||
return new double[]{-1, -1};
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute intersection of lines.
|
||||
* @param line1 - first line.
|
||||
* @param line2 - second line.
|
||||
* @return point of intersection of given lines.
|
||||
*/
|
||||
private static Point computeIntersect(Point[] line1, Point[] line2) {
|
||||
double x1 = line1[0].x, y1 = line1[0].y, x2 = line1[1].x, y2 = line1[1].y;
|
||||
double x3 = line2[0].x, y3 = line2[0].y, x4 = line2[1].x, y4 = line2[1].y;
|
||||
|
||||
double d = ((x1-x2) * (y3-y4)) - ((y1-y2) * (x3-x4));
|
||||
if (0 != d) {
|
||||
Point pt = new Point();
|
||||
pt.x = ((x1*y2 - y1*x2) * (x3-x4) - (x1-x2) * (x3*y4 - y3*x4)) / d;
|
||||
pt.y = ((x1*y2 - y1*x2) * (y3-y4) - (y1-y2) * (x3*y4 - y3*x4)) / d;
|
||||
return pt;
|
||||
} else
|
||||
return new Point(-1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute intersection of lines and return Point instance.
|
||||
* @param line1 - first line.
|
||||
* @param line2 - second line.
|
||||
* @return point of intersection of given lines.
|
||||
*/
|
||||
private static Point computeIntersectPoint(double[] line1, double[] line2) {
|
||||
return new Point(computeIntersect(line1, line2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static double fromLineToPointDistance(double[] line, double[] point) {
|
||||
return Math.abs((line[3]-line[1])*point[0] - (line[2]-line[0])*point[1] + line[2]*line[1] - line[3]*line[0])
|
||||
/ Math.sqrt((line[3]-line[1])*(line[3]-line[1]) + (line[2]-line[0])*(line[2]-line[0]));
|
||||
}
|
||||
|
||||
public static double fromLineToPointDistance(Vector line, double[] point) {
|
||||
return Math.abs((line.y2()-line.y1())*point[0] - (line.x2()-line.x1())*point[1] + line.x2()*line.y1() - line.y2()*line.x1())
|
||||
/ Math.sqrt((line.y2()-line.y1())*(line.y2()-line.y1()) + (line.x2()-line.x1())*(line.x2()-line.x1()));
|
||||
}
|
||||
|
||||
public static double fromLineToPointDistance(Vector line, Point point) {
|
||||
return Math.abs((line.y2()-line.y1())*point.x - (line.x2()-line.x1())*point.y + line.x2()*line.y1() - line.y2()*line.x1())
|
||||
/ Math.sqrt((line.y2()-line.y1())*(line.y2()-line.y1()) + (line.x2()-line.x1())*(line.x2()-line.x1()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param points
|
||||
* @return
|
||||
*/
|
||||
private 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 pointArr
|
||||
* @return
|
||||
*/
|
||||
private static Point[] findMaxDistantPoints(Point[] pointArr) {
|
||||
Point maxP1 = pointArr[0];
|
||||
Point maxP2 = pointArr[0];
|
||||
double maxDistance = 0;
|
||||
|
||||
for(Point p1: pointArr) {
|
||||
for(Point p2: pointArr) {
|
||||
if(distance(p1, p2) > maxDistance) {
|
||||
maxP1 = p1;
|
||||
maxP2 = p2;
|
||||
maxDistance = distance(p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new Point[]{maxP1, maxP2};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Вернить две точки лежащие наиболее близко к данной линии и нормали справа и слева от нормали соответственно.
|
||||
* Функция сначала находит список точек претендентов: наиболее близкие к линии точки по 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);
|
||||
Collections.sort(rightPoints, 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);
|
||||
Collections.sort(leftPoints, 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};
|
||||
}
|
||||
|
||||
|
||||
private static double distanceBetweenPointsOfElongatedVectors(Vector v1, Vector v2, double len) {
|
||||
Vector v1Direction = v1.normalizedDirection();
|
||||
Vector v2Direction = v2.normalizedDirection();
|
||||
|
||||
Point p1 = new Point(v1.x1() + v1Direction.x()*len, v1.y1() + v1Direction.y()*len);
|
||||
Point p2 = new Point(v2.x1() + v2Direction.x()*len, v2.y1() + v2Direction.y()*len);
|
||||
|
||||
return distance(p1, p2);
|
||||
}
|
||||
}
|
||||
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};
|
||||
}
|
||||
*/
|
||||
23
utils/src/main/java/ru/delkom07/geometry/obj/Circle.java
Normal file
23
utils/src/main/java/ru/delkom07/geometry/obj/Circle.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package ru.delkom07.geometry.obj;
|
||||
|
||||
import org.opencv.core.Point;
|
||||
|
||||
public class Circle {
|
||||
//private double[] center;
|
||||
private Point center;
|
||||
private double radius;
|
||||
|
||||
public Circle(Point center, double raduis) {
|
||||
this.center = center;
|
||||
this.radius = raduis;
|
||||
}
|
||||
|
||||
public Point getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
public double radius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package ru.delkom07.geometry.obj;
|
||||
|
||||
public interface LineFunction {
|
||||
double value(double x);
|
||||
double getA();
|
||||
double getB();
|
||||
double getC();
|
||||
double getk();
|
||||
double getb();
|
||||
}
|
||||
150
utils/src/main/java/ru/delkom07/geometry/obj/Vector.java
Normal file
150
utils/src/main/java/ru/delkom07/geometry/obj/Vector.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package ru.delkom07.geometry.obj;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
|
||||
public class Vector {
|
||||
private Double x;
|
||||
private Double y;
|
||||
|
||||
private Double x1;
|
||||
private Double y1;
|
||||
private Double x2;
|
||||
private Double y2;
|
||||
|
||||
boolean coordinateAssigned = false;
|
||||
|
||||
|
||||
|
||||
public Vector(double x, double y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
coordinateAssigned = false;
|
||||
}
|
||||
|
||||
|
||||
public Vector(double x1, double y1, double x2, double y2) {
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
|
||||
this.x = x2-x1;
|
||||
this.y = y2-y1;
|
||||
|
||||
coordinateAssigned = true;
|
||||
}
|
||||
|
||||
|
||||
public Vector(Point p1, Point p2) {
|
||||
this.x1 = p1.x;
|
||||
this.y1 = p1.y;
|
||||
this.x2 = p2.x;
|
||||
this.y2 = p2.y;
|
||||
|
||||
this.x = x2-x1;
|
||||
this.y = y2-y1;
|
||||
|
||||
coordinateAssigned = true;
|
||||
}
|
||||
|
||||
public Double x() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Double y() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Double x1() {
|
||||
if(!coordinateAssigned)
|
||||
throw new RuntimeException("Coordinate not assigned");
|
||||
|
||||
return x1;
|
||||
}
|
||||
|
||||
public Double y1() {
|
||||
if(!coordinateAssigned)
|
||||
throw new RuntimeException("Coordinate not assigned");
|
||||
|
||||
return y1;
|
||||
}
|
||||
|
||||
public Double x2() {
|
||||
if(!coordinateAssigned)
|
||||
throw new RuntimeException("Coordinate not assigned");
|
||||
|
||||
return x2;
|
||||
}
|
||||
|
||||
public Double y2() {
|
||||
if(!coordinateAssigned)
|
||||
throw new RuntimeException("Coordinate not assigned");
|
||||
|
||||
return y2;
|
||||
}
|
||||
|
||||
public Point p1() {
|
||||
return new Point(x1, y1);
|
||||
}
|
||||
|
||||
public Point p2() {
|
||||
return new Point(x2, y2);
|
||||
}
|
||||
|
||||
public void setPoint1(Point p1) {
|
||||
coordinateAssigned = true;
|
||||
this.x1 = p1.x;
|
||||
this.y1 = p1.y;
|
||||
|
||||
this.x = x2-x1;
|
||||
this.y = y2-y1;
|
||||
}
|
||||
|
||||
public void setPoint2(Point p2) {
|
||||
coordinateAssigned = true;
|
||||
|
||||
this.x2 = p2.x;
|
||||
this.y2 = p2.y;
|
||||
|
||||
this.x = x2-x1;
|
||||
this.y = y2-y1;
|
||||
}
|
||||
|
||||
public Double length() {
|
||||
return Math.sqrt(x*x+y*y);
|
||||
}
|
||||
|
||||
public Vector normalizedDirection() {
|
||||
double len = length();
|
||||
return new Vector(x/len, y/len);
|
||||
}
|
||||
|
||||
public Vector inverse() {
|
||||
return new Vector(x1, y1, x1-x, y1-y);
|
||||
}
|
||||
|
||||
public Vector deposition(double newX, double newY) {
|
||||
return new Vector(newX, newY, newX+x, newY+y);
|
||||
}
|
||||
|
||||
public void draw(Mat img, Scalar color) {
|
||||
double len = length()/15;
|
||||
Imgproc.line(img, new Point(x1(), y1()), new Point(x2(), y2()), color, 1);
|
||||
|
||||
double dxL = (-y + x2 + x1)/2.0 - x2();
|
||||
double dyL = (x + y2 + y1)/2.0 - y2();
|
||||
|
||||
double dxR = (y + x2 + x1)/2.0 - x2();
|
||||
double dyR = (-x + y2+y1)/2.0 - y2();
|
||||
|
||||
Imgproc.line(img, new Point(x2(), y2()), new Point(x2 + dxL/len, y2 + dyL/len), color, 1);
|
||||
Imgproc.line(img, new Point(x2(), y2()), new Point(x2 + dxR/len, y2 + dyR/len), color, 1);
|
||||
|
||||
//Imgproc.line(img, new Point(x2(), y2()), new Point((-y + x2 + x1)/(2.0), (x + y2 + y1)/(2.0)), color, 1);
|
||||
//Imgproc.line(img, new Point(x2(), y2()), new Point((y + x2 + x1)/(2.0), (-x + y2+y1)/(2.0)), color, 1);
|
||||
}
|
||||
}
|
||||
51
utils/src/main/java/ru/delkom07/util/ArgOption.java
Normal file
51
utils/src/main/java/ru/delkom07/util/ArgOption.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package ru.delkom07.util;
|
||||
|
||||
public class ArgOption {
|
||||
private String name;
|
||||
private String shortName;
|
||||
private String value;
|
||||
private boolean isNullValue;
|
||||
|
||||
public ArgOption(String name, String shortName, boolean isNullValue) {
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
this.isNullValue = isNullValue;
|
||||
}
|
||||
|
||||
void assign(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean isNullValue() {
|
||||
return isNullValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ArgOption other = (ArgOption) obj;
|
||||
if (name != other.name)
|
||||
return false;
|
||||
if (shortName != other.shortName) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
223
utils/src/main/java/ru/delkom07/util/CommandRepresentation.java
Normal file
223
utils/src/main/java/ru/delkom07/util/CommandRepresentation.java
Normal file
@@ -0,0 +1,223 @@
|
||||
package ru.delkom07.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Парсер параметров командной строки.
|
||||
* Формат строки: [--opt1 [--opt2...]] [arg1 [arg2...]]
|
||||
* Цикл использования: в конструктор передается командная строка, список допустимых опций,
|
||||
* а так же лимиты по количеству опций и аргументов.
|
||||
* После:
|
||||
* - вызов getAcceptedOptions вернет список всех переданных опций.
|
||||
* - вызовы nextOpt и nextArg вернут следующие переданные по списку опцию и аргумент.
|
||||
* - вызов flush - позволит сбросить перебор опций и аргументов и начать заново.
|
||||
* - вызовы getNumOpt и getNumArg возвращают размеры соответствующих списков.
|
||||
* @author Komyshev
|
||||
* v.1.0 (B)
|
||||
*/
|
||||
public class CommandRepresentation {
|
||||
// Списки принятых опций и аргументов
|
||||
private List<ArgOption> acceptedOptions = new LinkedList<ArgOption>();
|
||||
private List<String> acceptedArguments = new ArrayList<String>();
|
||||
|
||||
// Итераторы для быстрого извлечения опций и аргументов методами nextOpt, nextArg.
|
||||
private Iterator<ArgOption> optionIter;
|
||||
private Iterator<String> argumentIter;
|
||||
|
||||
/**
|
||||
* Разбор аргументов и опций командной строки.
|
||||
* @param args - командная строка.
|
||||
* @param optList - список названий принимаемых опций.
|
||||
* @param maxOptNum - максимальное количество опций.
|
||||
* @param minOptNum - минимальное количество опций.
|
||||
* @param maxArgNum - максимальное количество аргументов.
|
||||
* @param minArgNum - минимальносе количество аргументов.
|
||||
* @throws IncorrectCmdException - исключение некорректной команды.
|
||||
*/
|
||||
public CommandRepresentation(String[] args, List<ArgOption> optList, int maxOptNum, int minOptNum, int maxArgNum, int minArgNum) throws IncorrectCmdException{
|
||||
// Проверка на допустимость команды по количеству аргументов;
|
||||
if ( (minOptNum + minArgNum > args.length) ||
|
||||
maxOptNum + maxArgNum < args.length){
|
||||
throw new IncorrectCmdException("Incorrect count of argument.");
|
||||
}
|
||||
|
||||
//Получение параметров
|
||||
for(int i=0; i<args.length; i++) {
|
||||
String current = args[i];
|
||||
|
||||
if(current.startsWith("-")){ // Параметр опция
|
||||
if(current.startsWith("--")) { // полная
|
||||
|
||||
ArgOption accepted = getOptionFromList(optList, current, true);
|
||||
if(null != accepted) {
|
||||
if(!accepted.isNullValue()) {
|
||||
if(i!=args.length-1)
|
||||
accepted.assign(args[++i]);
|
||||
else
|
||||
throw new IncorrectCmdException("Option "+ accepted.getName()+ "has not value!");
|
||||
}
|
||||
|
||||
acceptedOptions.add(accepted);
|
||||
}
|
||||
else
|
||||
throw new IncorrectCmdException("Incorrect option in command line!");
|
||||
|
||||
} else { // сокращение
|
||||
// опция должна быть не длиннее 4х символов: -x
|
||||
if(current.length()>4)
|
||||
throw new IncorrectCmdException("Incorrect short option name.");
|
||||
|
||||
ArgOption accepted = getOptionFromList(optList, current, false);
|
||||
if(null != accepted) {
|
||||
if(!accepted.isNullValue()) {
|
||||
if(i!=args.length-1)
|
||||
accepted.assign(args[++i]);
|
||||
else
|
||||
throw new IncorrectCmdException("Option "+ accepted.getName()+ "has not value!");
|
||||
}
|
||||
|
||||
acceptedOptions.add(accepted);
|
||||
}
|
||||
else
|
||||
throw new IncorrectCmdException("Incorrect option in command line!");
|
||||
}
|
||||
|
||||
|
||||
} else { // Параметр - аргумент
|
||||
acceptedArguments.add(current.trim());
|
||||
}
|
||||
}
|
||||
|
||||
optionIter = acceptedOptions.iterator();
|
||||
argumentIter = acceptedArguments.iterator();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Получить список принятых опций.
|
||||
* @return список принятых опций.
|
||||
*/
|
||||
public List<ArgOption> getAcceptedOptions() {
|
||||
return acceptedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить список принятых аргументов.
|
||||
* @return список принятых опций.
|
||||
*/
|
||||
public List<String> getAcceptedArguments() {
|
||||
return acceptedArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить список принятых аргументов.
|
||||
* @return список принятых аргументов.
|
||||
*/
|
||||
public String[] getAcceptedArgs() {
|
||||
String[] acceptedArgs = new String[acceptedArguments.size()];
|
||||
for(int i=0; i<acceptedArguments.size(); i++) {
|
||||
acceptedArgs[i] = acceptedArguments.get(i);
|
||||
}
|
||||
return acceptedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить количество полученных опций.
|
||||
* @return количество полученных опций.
|
||||
*/
|
||||
public int getNumOfOpt() {
|
||||
return acceptedOptions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить количество полученных аргументов.
|
||||
* @return количество полученных аргументов.
|
||||
*/
|
||||
public int getNumOfArgs() {
|
||||
return acceptedArguments.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Если ли ещё опции по текущему итератору.
|
||||
*/
|
||||
public boolean hasNextOpt() {
|
||||
return optionIter.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Есть ли ещё аргументы по текущему итератору.
|
||||
*/
|
||||
public boolean hasNextArg() {
|
||||
return argumentIter.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод итерации по опциям командной строки.
|
||||
* Итератор сбрасывается методом flush.
|
||||
* @return - следующая опция командной строки.
|
||||
*/
|
||||
public ArgOption nextOpt() {
|
||||
return optionIter.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод итерации по аргументам командной строки.
|
||||
* Итератор сбрасывается методом flush.
|
||||
* @return - следующий аргумент командной строки.
|
||||
*/
|
||||
public String nextArg() {
|
||||
return argumentIter.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Сбросить итераторы по опциям и аргументам командной строки.
|
||||
*/
|
||||
public void flush() {
|
||||
optionIter = acceptedOptions.iterator();
|
||||
argumentIter = acceptedArguments.iterator();
|
||||
}
|
||||
|
||||
public boolean containsOptionByName(String name) {
|
||||
if(null!=getOptionFromList(acceptedOptions, name, true))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public ArgOption getOptionByName(String name) {
|
||||
return getOptionFromList(acceptedOptions, name, true);
|
||||
}
|
||||
|
||||
public boolean containsOptionByShortName(String shortName) {
|
||||
if(null!=getOptionFromList(acceptedOptions, shortName, false))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public ArgOption getOptionByShortName(String shortName) {
|
||||
return getOptionFromList(acceptedOptions, shortName, false);
|
||||
}
|
||||
|
||||
private ArgOption getOptionFromList(List<ArgOption> optList, String option, boolean fullName) {
|
||||
if(fullName) {
|
||||
for(ArgOption argOpt : optList) {
|
||||
if(argOpt.getName().equals(option)) {
|
||||
return argOpt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(ArgOption argOpt : optList) {
|
||||
if(argOpt.getShortName().equals(option)) {
|
||||
return argOpt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
77
utils/src/main/java/ru/delkom07/util/CyclicStack.java
Normal file
77
utils/src/main/java/ru/delkom07/util/CyclicStack.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package ru.delkom07.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class CyclicStack<T> implements Iterable<T> {
|
||||
private T[] container;
|
||||
private int pointer = -1;
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public CyclicStack(int size) {
|
||||
container = (T[]) new Object[size];
|
||||
}
|
||||
|
||||
|
||||
public void put(T obj) {
|
||||
pointer++;
|
||||
if(pointer == container.length) {
|
||||
pointer = 0;
|
||||
}
|
||||
|
||||
container[pointer] = obj;
|
||||
}
|
||||
|
||||
public T pull() {
|
||||
T obj = container[pointer];
|
||||
container[pointer--] = null;
|
||||
|
||||
if(pointer == -1) {
|
||||
pointer = container.length-1;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public T get(int i) {
|
||||
return container[i];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new CyclicStackIterator();
|
||||
}
|
||||
|
||||
|
||||
class CyclicStackIterator implements Iterator<T> {
|
||||
int iPointer = pointer;
|
||||
int iteration = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if(iteration < container.length && iPointer != -1 && container[iPointer] != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
T obj = container[iPointer--];
|
||||
|
||||
if(iPointer == -1) {
|
||||
iPointer = container.length-1;
|
||||
}
|
||||
|
||||
iteration++;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ru.delkom07.util;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Komyshev
|
||||
* v.1.0 (C)
|
||||
*/
|
||||
public class IncorrectCmdException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public IncorrectCmdException(){}
|
||||
|
||||
public IncorrectCmdException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
33
utils/src/main/java/ru/delkom07/util/Pair.java
Normal file
33
utils/src/main/java/ru/delkom07/util/Pair.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package ru.delkom07.util;
|
||||
|
||||
public class Pair<L,R> {
|
||||
|
||||
private final L left;
|
||||
private final R right;
|
||||
|
||||
public Pair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public L getLeft() { return left; }
|
||||
public R getRight() { return right; }
|
||||
|
||||
@Override
|
||||
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if(o instanceof Pair) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Pair<L, R> pairo = (Pair<L, R>) o;
|
||||
|
||||
return this.left.equals(pairo.getLeft()) &&
|
||||
this.right.equals(pairo.getRight());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ru.delkom07.workspaces;
|
||||
|
||||
public interface FileNameReplacer {
|
||||
public String replaceFileName(String fileName);
|
||||
}
|
||||
139
utils/src/main/java/ru/delkom07/workspaces/SimpleWorkspace.java
Normal file
139
utils/src/main/java/ru/delkom07/workspaces/SimpleWorkspace.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package ru.delkom07.workspaces;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.delkom07.fileutils.FileUtilities;
|
||||
import ru.delkom07.util.Pair;
|
||||
|
||||
/**
|
||||
* Простая рабочая среда.
|
||||
* Создает список операционных единиц (OpUnit) на основе входного/выходного каталогов,
|
||||
* которые связывают имена и пути входных и выходных файлов текущей сессии выполнения.
|
||||
* Способен создавать рабочую среду из подкаталогов входного каталога с древовидной структурой.
|
||||
* Для этого в выходном каталоге создается аналогичная входному каталогу структура подкаталогов и соответствующие файлы в них связываются через OpUnit.
|
||||
* Выходные файлы при этом не создаются. Вместо этого для них формируются имена и пути (экземпляры класса File).
|
||||
* В результате каждый OpUnit может обрабатываться независимо друг от друга.
|
||||
* @author Komyshev
|
||||
*
|
||||
*/
|
||||
public class SimpleWorkspace {
|
||||
protected File inputDir; // директория входных файлов
|
||||
protected File outputDir; // директория выходных файлов
|
||||
|
||||
protected List<OpUnit> operationUnits = new LinkedList<OpUnit>(); // единицы обработки
|
||||
private boolean treeStrtucture = false;
|
||||
|
||||
|
||||
public SimpleWorkspace(File inputDir, File outputDir, boolean treeStructure, FileFilter fileFilter, FileNameReplacer fileNameReplacer) throws IOException {
|
||||
this.inputDir = inputDir;
|
||||
this.outputDir = outputDir;
|
||||
|
||||
this.treeStrtucture = treeStructure;
|
||||
|
||||
if(treeStrtucture) {
|
||||
init(prepareAppropriateTreeOutputs(inputDir, outputDir, fileFilter, fileNameReplacer));
|
||||
} else {
|
||||
init(prepareAppropriateFlatOutputs(inputDir, outputDir, fileFilter, fileNameReplacer));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Подготовить список пар файлов (входной-выходной) с соответствующей структурой.
|
||||
* Для этого считать все входные файлы, соответствующие fileFilter, из директории inputDir а также её поддиректорий, и подготовить пути выходных файлов
|
||||
* с соответствующей структурой поддиректорий в outputDir.
|
||||
* @param inputDir - директория входных файлов.
|
||||
* @param outputDir - директория выходных файлов.
|
||||
* @param fileFilter - фильтр файлов.
|
||||
* @return - список пар (входной файл - выходной файл), где путь в поддиректориях в ouputDir выходного файла совпадает с соответствующим путем
|
||||
* входного файла в поддиректориях inputDir.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<Pair<File, File>> prepareAppropriateTreeOutputs(File inputDir, File outputDir, FileFilter fileFilter, FileNameReplacer fileNameReplacer) throws IOException {
|
||||
List<Pair<File, File>> inputsAndOutputs = new ArrayList<Pair<File, File>>();
|
||||
|
||||
List<File> inputFiles = FileUtilities.getFilesRecursively(inputDir, fileFilter);
|
||||
|
||||
for(File inputFile : inputFiles) {
|
||||
File outputImgDir = new File(outputDir, inputFile.getParentFile().getCanonicalPath().replace(inputDir.getCanonicalPath(), ""));
|
||||
|
||||
if(!outputImgDir.exists()) {
|
||||
outputImgDir.mkdirs();
|
||||
}
|
||||
|
||||
File outputImgFile = new File(outputImgDir, (null == fileNameReplacer) ? inputFile.getName() : fileNameReplacer.replaceFileName(inputFile.getName()));
|
||||
|
||||
inputsAndOutputs.add(new Pair<File, File>(inputFile, outputImgFile));
|
||||
}
|
||||
|
||||
return inputsAndOutputs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Подготовить список пар файлов (входной-выходной) без учета поддиректорий.
|
||||
* @param inputImgsDir - директория входных файлов.
|
||||
* @param outputImgsDir - директория выходных файлов.
|
||||
* @param filter - фильтр файлов.
|
||||
* @param fileNameReplacer - объект, заменяющие (изменяющее) названия входных файлов при создании выходных файлов.
|
||||
* @return список пар файлов.
|
||||
*/
|
||||
public static List<Pair<File, File>> prepareAppropriateFlatOutputs(File inputImgsDir, File outputImgsDir, FileFilter filter, FileNameReplacer fileNameReplacer) {
|
||||
List<Pair<File, File>> imgPairs = new ArrayList<Pair<File, File>>();
|
||||
|
||||
File[] files = inputImgsDir.listFiles(filter != null ? filter : FileUtilities.fileFilter);
|
||||
|
||||
// link source image
|
||||
for(int i=0; i<files.length; i++) {
|
||||
File sourceImgFile = files[i];
|
||||
|
||||
String name = (null == fileNameReplacer) ? sourceImgFile.getName() : fileNameReplacer.replaceFileName(sourceImgFile.getName());
|
||||
File outputImgFile = new File(outputImgsDir, name);
|
||||
|
||||
imgPairs.add(new Pair<File, File>(sourceImgFile, outputImgFile));
|
||||
}
|
||||
|
||||
return imgPairs;
|
||||
}
|
||||
|
||||
|
||||
void init(List<Pair<File, File>> insAndOuts) throws IOException {
|
||||
for(Pair<File, File> inAndOut : insAndOuts) {
|
||||
operationUnits.add(new OpUnit(inAndOut.getLeft(), inAndOut.getRight()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<OpUnit> getOpUnits() {
|
||||
return operationUnits;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Единица операции.
|
||||
* @author Komyshev
|
||||
*
|
||||
*/
|
||||
public class OpUnit {
|
||||
protected File in;
|
||||
protected File out;
|
||||
|
||||
OpUnit(File in, File out) {
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public File getIn() {
|
||||
return in;
|
||||
}
|
||||
|
||||
public File getOut() {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
utils/src/main/java/ru/delkom07/workspaces/StatusWorkspace.java
Normal file
110
utils/src/main/java/ru/delkom07/workspaces/StatusWorkspace.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package ru.delkom07.workspaces;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Подкласс класса SimpleWorkspace с дополнительной фукнциональностью - отслеживанием и сохранением статуса обработки операционных единиц.
|
||||
* @author Komyshev
|
||||
*
|
||||
*/
|
||||
public class StatusWorkspace extends SimpleWorkspace {
|
||||
private boolean[] statuses;
|
||||
private File statusFile;
|
||||
|
||||
public StatusWorkspace(File inputDir, File outputDir, boolean treeStructure, FileFilter fileFilter, FileNameReplacer fileNameReplacer) throws IOException {
|
||||
super(inputDir, outputDir, treeStructure, fileFilter, fileNameReplacer);
|
||||
|
||||
initStatus();
|
||||
}
|
||||
|
||||
|
||||
private void initStatus() throws IOException {
|
||||
statuses = new boolean[operationUnits.size()]; // False by default ???
|
||||
|
||||
statusFile = new File(outputDir, "status.txt");
|
||||
|
||||
if(!statusFile.exists()) {
|
||||
statusFile.createNewFile();
|
||||
} else {
|
||||
loadStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadStatus() {
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(statusFile))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
setProcessed(line);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void setProcessed(String identificationPath) {
|
||||
boolean success = false;
|
||||
|
||||
for(int i=0; i<operationUnits.size(); i++) {
|
||||
OpUnit opUnit = operationUnits.get(i);
|
||||
try {
|
||||
if(opUnit.getIn().getCanonicalPath().equals(identificationPath)) {
|
||||
statuses[i] = true;
|
||||
success = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(!success) {
|
||||
System.err.println("File: " + identificationPath + " is'nt found in workspace.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Записать операционную единицу как обработанную.
|
||||
* @param opUnit - обработанная операционная единица.
|
||||
*/
|
||||
public void saveProcessedOpUnit(OpUnit opUnit) {
|
||||
int ind = operationUnits.indexOf(opUnit);
|
||||
statuses[ind] = true;
|
||||
|
||||
try (PrintWriter pw = new PrintWriter(new FileWriter(statusFile, true))) {
|
||||
pw.println(opUnit.getIn().getCanonicalPath());
|
||||
pw.flush();
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выдать необработанные операционные единицы.
|
||||
* @return необработанные операционные единицы.
|
||||
*/
|
||||
public List<OpUnit> getRawOpUnits() {
|
||||
List<OpUnit> rawOpUnits = new LinkedList<OpUnit>();
|
||||
|
||||
for(int i=0; i<operationUnits.size(); i++) {
|
||||
if(statuses[i]==false) {
|
||||
rawOpUnits.add(operationUnits.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return rawOpUnits;
|
||||
}
|
||||
}
|
||||
14
utils/src/test/java/ru/delkom07/LibraryTest.java
Normal file
14
utils/src/test/java/ru/delkom07/LibraryTest.java
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package ru.delkom07;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class LibraryTest {
|
||||
@Test void someLibraryMethodReturnsTrue() {
|
||||
Library classUnderTest = new Library();
|
||||
assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user