如果你需要在Javafx中进行实现
vv
AB是一条直线。
P是离直线很近的一个点。
M是离P最近的直线上的点。
public static Point findPointMOnLineClosestToGivenPointP(Point vector_A, Point vector_B, Point vector_P) {
Point vector_AB = vector_B.subtract(vector_A);
Point vector_AP = vector_P.subtract(vector_A);
double distance_AM = vector_AB.dotProduct(vector_AP) / vector_AB.magnitude();
Point vector_AM = vector_AB.normalize().multiply(distance_AM);
Point vector_M = vector_A.add(vector_AM);
return vector_M;
}
Point类与javafx.geometry.Point2D类完全相同,只是我将其重命名为Point...
(以下内容不重要)
测试案例和比较
(这个产生的结果与其他答案中的getNearestPointOnLine()相同,类似的数学公式。)
package com.redfrog.trafficsm;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Random;
import org.junit.jupiter.api.Test;
import com.redfrog.trafficsm.model.Point;
import com.redfrog.trafficsm.util.MathUtil;
import processing.core.PVector;
class SimpleTest {
Random random = new Random(111);
@Test
public void test_getNearestPointOnLine() {
float bound = 100;
for (int i = 0; i < 100; i++) {
float f_x;
float f_y;
f_x = random.nextFloat(-bound, bound);
f_y = random.nextFloat(-bound, bound);
Point point_A = new Point(f_x, f_y);
PVector pvector_A = new PVector(f_x, f_y);
f_x = random.nextFloat(-bound, bound);
f_y = random.nextFloat(-bound, bound);
Point point_B = new Point(f_x, f_y);
PVector pvector_B = new PVector(f_x, f_y);
PVector pvector_N = pvector_B.sub(pvector_A).normalize();
f_x = random.nextFloat(-bound, bound);
f_y = random.nextFloat(-bound, bound);
Point point_P = new Point(f_x, f_y);
PVector pvector_P = new PVector(f_x, f_y);
Point point_M = MathUtil.findPointMOnLineClosestToGivenPointP(point_A, point_B, point_P);
PVector pvector_M = MathUtil.getNearestPointOnLine(pvector_P, pvector_A, pvector_N);
System.out.println();
System.out.println(point_M);
System.out.println(pvector_M);
int scale = 2;
System.out.println(MathUtil.round(point_M.getX(), scale));
System.out.println(MathUtil.round(pvector_M.x, scale));
System.out.println(MathUtil.round(point_M.getY(), scale));
System.out.println(MathUtil.round(pvector_M.y, scale));
assertEquals(MathUtil.round(point_M.getX(), scale), MathUtil.round(pvector_M.x, scale));
assertEquals(MathUtil.round(point_M.getY(), scale), MathUtil.round(pvector_M.y, scale));
}
}
}
package com.redfrog.trafficsm.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import com.redfrog.trafficsm.model.Point;
import processing.core.PVector;
public class MathUtil {
public static double round(double value, int scale) {
return round(value, scale, RoundingMode.HALF_DOWN);
}
public static double round(double value, int scale, RoundingMode roundingMode) {
return new BigDecimal(value).setScale(scale, roundingMode).doubleValue();
}
public static Point findPointMOnLineClosestToGivenPointP(Point vector_A, Point vector_B, Point vector_P) {
Point vector_AB = vector_B.subtract(vector_A);
Point vector_AP = vector_P.subtract(vector_A);
double distance_AM = vector_AB.dotProduct(vector_AP) / vector_AB.magnitude();
Point vector_AM = vector_AB.normalize().multiply(distance_AM);
Point vector_M = vector_A.add(vector_AM);
return vector_M;
}
public static PVector getNearestPointOnLine(PVector p, PVector a, PVector n) {
PVector q = PVector.mult(n, -PVector.sub(a, p).dot(n));
q.add(a);
return q;
}
}
JavaFX中的可视化
package com.redfrog.note;
import java.util.Random;
import com.google.common.util.concurrent.AtomicDouble;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Bounds;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import processing.core.PVector;
public class TestAppJavafxBoot extends Application {
@Override
public void start(Stage primaryStage) {
AnchorPane pane_JfxRoot = new AnchorPane();
AnchorPane panel_SemanticRoot = new AnchorPane();
pane_JfxRoot.getChildren().add(panel_SemanticRoot);
final double opacity = 0.9;
panel_SemanticRoot.setLayoutX(350);
panel_SemanticRoot.setLayoutY(350);
Random random = new Random(111);
float bound = 100;
float f_x;
float f_y;
f_x = random.nextFloat(-bound, bound);
f_y = random.nextFloat(-bound, bound);
Point2D point_A = new Point2D(f_x, f_y);
PVector pvector_A = new PVector(f_x, f_y);
final Circle circle = new Circle();
panel_SemanticRoot.getChildren().add(circle);
circle.setRadius(3);
circle.setFill(Color.rgb(255, 0, 0, opacity));
circle.setCenterX(f_x);
circle.setCenterY(f_y);
f_x = random.nextFloat(-bound, bound);
f_y = random.nextFloat(-bound, bound);
Point2D point_B = new Point2D(f_x, f_y);
PVector pvector_B = new PVector(f_x, f_y);
PVector pvector_N = pvector_B.sub(pvector_A).normalize();
final Circle circle_02 = new Circle();
panel_SemanticRoot.getChildren().add(circle_02);
circle_02.setRadius(3);
circle_02.setFill(Color.rgb(0, 255, 0, opacity));
circle_02.setCenterX(f_x);
circle_02.setCenterY(f_y);
f_x = random.nextFloat(-bound, bound);
f_y = random.nextFloat(-bound, bound);
Point2D point_P = new Point2D(f_x, f_y);
PVector pvector_P = new PVector(f_x, f_y);
final Circle circle_03 = new Circle();
panel_SemanticRoot.getChildren().add(circle_03);
circle_03.setRadius(3);
circle_03.setFill(Color.rgb(0, 0, 255, opacity));
circle_03.setCenterX(f_x);
circle_03.setCenterY(f_y);
Point2D point_M = MathUtil.findPointMOnLineClosestToGivenPointP(point_A, point_B, point_P);
PVector pvector_M = MathUtil.getNearestPointOnLine(pvector_P, pvector_A, pvector_N);
System.out.println();
System.out.println(point_M);
final Circle circle_04 = new Circle();
panel_SemanticRoot.getChildren().add(circle_04);
circle_04.setRadius(3);
circle_04.setFill(Color.rgb(0, 255, 255, opacity));
circle_04.setCenterX(point_M.getX());
circle_04.setCenterY(point_M.getY());
final Circle circle_05 = new Circle();
panel_SemanticRoot.getChildren().add(circle_05);
circle_05.setRadius(3);
circle_05.setFill(Color.rgb(255, 255, 0, opacity));
circle_05.setCenterX(pvector_M.x);
circle_05.setCenterY(pvector_M.y);
Scene scene = new Scene(pane_JfxRoot, 950, 750);
primaryStage.setTitle("DDD");
primaryStage.setScene(scene);
primaryStage.show();
}
}