Commit 8fa13e0f authored by Catgolin's avatar Catgolin
Browse files

refactor(lineDistance): refactor of the line distances

parent 56cf652d
Pipeline #452712 passed with stage
in 22 seconds
......@@ -57,7 +57,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
\****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ DistanceInterface)\n/* harmony export */ });\n/* harmony import */ var _geometry_geometryInterface__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../geometry/geometryInterface */ \"./src/geometry/geometryInterface.js\");\n\n\n/**\n * @class DistanceInterface\n * @abstract\n *\n * @brief Measures the distance between an object and a point\n *\n * @version 2.0\n */\nclass DistanceInterface {\n\n /**\n * @param {GeometryInterface} object: The object in reference to which distances are measured\n */\n constructor(object){\n\tif(this.constructor == DistanceInterface)\n\t throw Error(\"DistanceInterface is abstract and should not be instanciated\");\n\tthis._object = object\n }\n\n /**\n * @brief The object in reference to which distances are measured\n * @type {GeometryInterface}\n */\n get object() {\n return this._object;\n }\n\n /**\n * @brief Distance between the destination and the object of reference\n * @see object\n *\n * @param {Point} destination\n *\n * @returns {number} The distance to the destination from the object of reference\n */\n to(destination){\n\tthrow Error(this.constructor.name+\" should implement to()\");\n }\n\n /**\n * @brief Square of the distance between the destination and the object of reference\n * @see to()\n *\n * This is meant to avoid calculating the square root when possible,\n * as calculating the square is cheaper as calculating the square root.\n *\n * @param {Point} destination\n *\n * @returns {number} Square of the distance to the destination from the object of reference\n *\n * @note This method should be override when the to() method is using a square root\n */\n squareTo(destination) {\n return this.to(destination)**2;\n }\n\n /**\n * @brief Checks if the object of reference contains the point\n *\n * The inclusion is understood in the large sense: borders are part of the object.\n *\n * @param {Point} destination\n *\n * @returns {boolean} Is the destination inside the object of reference?\n */\n contains(destination){\n throw Error(this.constructor.name+\" should implement contains\");\n }\n\n /**\n * @brief Checks if the object of rerefence strictly contains the point\n *\n * The inclusion is understood in the stric sense: borders are NOT part of the object.\n *\n * @param {Point} destination\n *\n * @returns {boolean} Is the destination strictly inside the object of reference?\n */\n containsStrict(destination){\n\treturn this.contains(destination);\n }\n}\n\n\n//# sourceURL=webpack://MCDG/./src/physics/distances/distanceInterface.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ DistanceInterface)\n/* harmony export */ });\n/* harmony import */ var _geometry_geometryInterface__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../geometry/geometryInterface */ \"./src/geometry/geometryInterface.js\");\n\n\n/**\n * @class DistanceInterface\n * @abstract\n *\n * @brief Measures the distance between an object and a point\n *\n * @version 2.0\n */\nclass DistanceInterface {\n\n /**\n * @param {GeometryInterface} object: The object in reference to which distances are measured\n */\n constructor(object){\n\tif(this.constructor == DistanceInterface)\n\t throw Error(\"DistanceInterface is abstract and should not be instanciated\");\n\tthis._object = object\n }\n\n /**\n * @brief The object in reference to which distances are measured\n * @type {GeometryInterface}\n */\n get object() {\n return this._object;\n }\n\n /**\n * @brief Distance between the destination and the object of reference\n * @see object\n *\n * @param {Point} destination\n *\n * @returns {number} The distance to the destination from the object of reference\n *\n * @throws {Error} If point is not a Point\n */\n to(destination){\n\tthrow Error(this.constructor.name+\" should implement to()\");\n }\n\n /**\n * @brief Square of the distance between the destination and the object of reference\n * @see to()\n *\n * This is meant to avoid calculating the square root when possible,\n * as calculating the square is cheaper as calculating the square root.\n *\n * @param {Point} destination\n *\n * @returns {number} Square of the distance to the destination from the object of reference\n *\n * @throws {Error} If point is not a Point\n *\n * @note This method should be override when the to() method is using a square root\n */\n squareTo(destination) {\n return this.to(destination)**2;\n }\n\n /**\n * @brief Checks if the object of reference contains the point\n *\n * The inclusion is understood in the large sense: borders are part of the object.\n *\n * @param {Point} destination\n *\n * @returns {boolean} Is the destination inside the object of reference?\n *\n * @throws {Error} If point is not a Point\n */\n contains(destination){\n throw Error(this.constructor.name+\" should implement contains\");\n }\n\n /**\n * @brief Checks if the object of rerefence strictly contains the point\n *\n * The inclusion is understood in the stric sense: borders are NOT part of the object.\n *\n * @param {Point} destination\n *\n * @returns {boolean} Is the destination strictly inside the object of reference?\n *\n * @throws {Error} If point is not a Point\n */\n containsStrict(destination){\n\treturn this.contains(destination);\n }\n}\n\n\n//# sourceURL=webpack://MCDG/./src/physics/distances/distanceInterface.js?");
/***/ }),
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -34,6 +34,8 @@ export default class DistanceInterface {
* @param {Point} destination
*
* @returns {number} The distance to the destination from the object of reference
*
* @throws {Error} If point is not a Point
*/
to(destination){
throw Error(this.constructor.name+" should implement to()");
......@@ -50,6 +52,8 @@ export default class DistanceInterface {
*
* @returns {number} Square of the distance to the destination from the object of reference
*
* @throws {Error} If point is not a Point
*
* @note This method should be override when the to() method is using a square root
*/
squareTo(destination) {
......@@ -64,6 +68,8 @@ export default class DistanceInterface {
* @param {Point} destination
*
* @returns {boolean} Is the destination inside the object of reference?
*
* @throws {Error} If point is not a Point
*/
contains(destination){
throw Error(this.constructor.name+" should implement contains");
......@@ -77,6 +83,8 @@ export default class DistanceInterface {
* @param {Point} destination
*
* @returns {boolean} Is the destination strictly inside the object of reference?
*
* @throws {Error} If point is not a Point
*/
containsStrict(destination){
return this.contains(destination);
......
......@@ -6,29 +6,45 @@ import Line from "../../geometry/curves/line";
export default class LineDistance extends DistanceInterface {
/**
* returns distance ( or angle ) from point ( or line ) to line
* @override
* @inheritdoc
*/
to( destination ){
const {a, b, c} = this.object.cartesianCoefficients
if( destination instanceof Point ){
return Math.abs( a*destination.x + b*destination.y + c)/ Math.sqrt(a**2 + b**2)
}
if( destination instanceof Line ){
const {a: e, b: f, c: g} = destination.cartesianCoefficients
return Math.acos( ( a*e + b*f )/( Math.sqrt( a**2 + b**2 )*Math.sqrt( e**2 + f**2 ) ) )
}
throw new Error(
"The destination should be a line or a point"
)
to(destination) {
return this.projectionOf(destination).distance.to(destination);
}
/**
* @override
* @inheritdoc
*/
contains(destination){
squareTo(destination) {
return this.projectionOf(destination).distance.squareTo(destination);
}
/**
* @override
* @inheritdoc
*/
contains(destination) {
return this.projectionOf(destination).distance.contains(destination);
}
/**
* @brief Returns the orthogonal projection of the point on the line
* @param {Point} point
* @return {Point}
* @throws {Error} If point is not a Point
*/
projectionOf(point) {
if(!point || typeof point !== 'object') {
throw new Error(`Expected destination to be a Point, got ${point}`);
} else if(!(point instanceof Point)) {
throw new Error(`Expected destination to be a Point, got ${point.constructor.name}`);
}
const {a, b, c} = this.object.cartesianCoefficients;
return Rounding.nullify(a*destination.x + b*destination.y + c);
const denum = a**2 + b**2;
const x = (b * (b*point.x - a*point.y) - a*c) / denum;
const y = (a * (a*point.y - b*point.x) - b*c) / denum;
return new Point(x, y);
}
}
import DistanceInterface from "./distanceInterface";
import Rounding from "../rounding";
import Point from "../../geometry/points/point";
import Line from "../../geometry/curves/line"
import Line from "../../geometry/curves/line";
import Segment from "../../geometry/curves/segment";
export default class SegmentDistance extends DistanceInterface {
......@@ -12,41 +12,39 @@ export default class SegmentDistance extends DistanceInterface {
* if it is, returns the distance from point to line,
* if not, returns the minimum distance from the point and the vertices of the linesegment
*/
to( destination ){
if( !(destination instanceof Point) )
throw new Error('destination should be a point')
const {a, b, c} = this.object.line.cartesianCoefficients
const projection = {x: (b * (b*destination.x - a*destination.y)-a*c)/(a**2+b**2),
y: (a * (-b*destination.x + a*destination.y)-b*c)/(a**2+b**2)}
if( this.contains( projection ) )
return this.object.line.to( destination )
return Math.min( this.object.vertices[0].distance.to( destination ),
this.object.vertices[1].distance.to( destination ) )
to(destination){
const projection = this.object.line.distance.projectionOf(destination);
if(this.contains(projection)) {
return projection.distance.to(destination);
}
return Math.min(
this.object.vertices[0].distance.to(destination),
this.object.vertices[1].distance.to(destination)
);
}
/**
*
* @param {GeometryInterface} destination
* @description For a point M, it first checks if the point lies on the line, then checks the sign of the scalar product AM.BM
* @returns
* @override
* @inheritdoc
*/
contains( destination ){
if(!this.object.line.distance.contains(destination))
contains(destination){
if(!this.object.line.distance.contains(destination)) {
return false;
let scalar = (destination.x - this.object.vertices[0].x)*(destination.x - this.object.vertices[1].x)
+(destination.y - this.object.vertices[0].y)*(destination.y - this.object.vertices[1].y)
if( Rounding.isNegative(scalar) )
return true
return false
}
if(this.object.vertices.find((point) => point.distance.contains(destination))) {
return true;
}
const A = this.object.vertices[0];
const B = this.object.vertices[1];
const P = destination;
const scalarProduct = (P.x - A.x) * (P.x - B.x) + (P.y - A.y) * (P.y - B.y);
return scalarProduct < 0;
}
containsStrict( destination ){
if( this.contains( destination ) ){
if( this.object.vertices[0].distance.contains(destination)
|| this.object.vertices[1].distance.contains(destination))
return false
return true
}
return false
containsStrict(destination){
if(!this.contains(destination)) {
return false;
}
return this.object.vertices.find((point) => point.distance.contains(destination)) == undefined;
}
}
......@@ -82,6 +82,18 @@ describe("Lines", function() {
});
describe("Lines distances", function() {
it("should return an error when we are measuring the distance to something else than a point",
function() {
const d = new Line(Math.random(), Math.random(), Math.random());
const e = new Line(Math.random(), Math.random(), Math.random());
expect(
() => d.distance.to(undefined)
).to.throw('Expected destination to be a Point, got undefined');
expect(
() => d.distance.to(e)
).to.throw('Expected destination to be a Point, got Line');
}
);
it("should get distance from point to line",
function() {
const A = new Point(2, 2);
......@@ -252,7 +264,7 @@ describe("Segments", function() {
});
describe("Segment distances", function() {
it("should give distance to the segment",
it("should give distance between a point and the segment",
function() {
const A = new Point(0, 0);
const B = new Point(1, 1);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment