@itwin/core-geometry 4.0.0-dev.23 → 4.0.0-dev.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -2
- package/lib/cjs/Geometry.d.ts +23 -0
- package/lib/cjs/Geometry.d.ts.map +1 -1
- package/lib/cjs/Geometry.js +25 -1
- package/lib/cjs/Geometry.js.map +1 -1
- package/lib/cjs/bspline/BSplineCurveOps.js +4 -5
- package/lib/cjs/bspline/BSplineCurveOps.js.map +1 -1
- package/lib/cjs/bspline/InterpolationCurve3d.js +7 -10
- package/lib/cjs/bspline/InterpolationCurve3d.js.map +1 -1
- package/lib/cjs/clipping/ClipPrimitive.js +2 -2
- package/lib/cjs/clipping/ClipPrimitive.js.map +1 -1
- package/lib/cjs/clipping/ClipUtils.js +4 -4
- package/lib/cjs/clipping/ClipUtils.js.map +1 -1
- package/lib/cjs/clipping/internalContexts/LineStringOffsetClipperContext.js +2 -2
- package/lib/cjs/clipping/internalContexts/LineStringOffsetClipperContext.js.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/cjs/curve/CurveCollection.js +1 -1
- package/lib/cjs/curve/CurveCollection.js.map +1 -1
- package/lib/cjs/curve/StrokeOptions.js +1 -2
- package/lib/cjs/curve/StrokeOptions.js.map +1 -1
- package/lib/cjs/curve/spiral/DirectSpiral3d.js +1 -2
- package/lib/cjs/curve/spiral/DirectSpiral3d.js.map +1 -1
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.js +1 -2
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.js.map +1 -1
- package/lib/cjs/geometry3d/BarycentricTriangle.d.ts +195 -8
- package/lib/cjs/geometry3d/BarycentricTriangle.d.ts.map +1 -1
- package/lib/cjs/geometry3d/BarycentricTriangle.js +459 -11
- package/lib/cjs/geometry3d/BarycentricTriangle.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableFloat64Array.js +2 -2
- package/lib/cjs/geometry3d/GrowableFloat64Array.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.d.ts +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.d.ts.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.js +2 -2
- package/lib/cjs/geometry3d/GrowableXYArray.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYZArray.js +1 -1
- package/lib/cjs/geometry3d/GrowableXYZArray.js.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYCollection.d.ts +22 -7
- package/lib/cjs/geometry3d/IndexedXYCollection.d.ts.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYCollection.js +41 -5
- package/lib/cjs/geometry3d/IndexedXYCollection.js.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts +58 -4
- package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYZCollection.js +102 -4
- package/lib/cjs/geometry3d/IndexedXYZCollection.js.map +1 -1
- package/lib/cjs/geometry3d/Point2dArrayCarrier.d.ts +10 -0
- package/lib/cjs/geometry3d/Point2dArrayCarrier.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Point2dArrayCarrier.js +14 -0
- package/lib/cjs/geometry3d/Point2dArrayCarrier.js.map +1 -1
- package/lib/cjs/geometry3d/Point2dVector2d.js +4 -6
- package/lib/cjs/geometry3d/Point2dVector2d.js.map +1 -1
- package/lib/cjs/geometry3d/Point3dArrayCarrier.d.ts +0 -6
- package/lib/cjs/geometry3d/Point3dArrayCarrier.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Point3dArrayCarrier.js +0 -6
- package/lib/cjs/geometry3d/Point3dArrayCarrier.js.map +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.d.ts +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.js +6 -8
- package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
- package/lib/cjs/geometry3d/PointHelpers.d.ts +14 -1
- package/lib/cjs/geometry3d/PointHelpers.d.ts.map +1 -1
- package/lib/cjs/geometry3d/PointHelpers.js +33 -1
- package/lib/cjs/geometry3d/PointHelpers.js.map +1 -1
- package/lib/cjs/geometry3d/PolygonOps.d.ts +120 -10
- package/lib/cjs/geometry3d/PolygonOps.d.ts.map +1 -1
- package/lib/cjs/geometry3d/PolygonOps.js +413 -13
- package/lib/cjs/geometry3d/PolygonOps.js.map +1 -1
- package/lib/cjs/geometry3d/Ray3d.js +1 -1
- package/lib/cjs/geometry3d/Ray3d.js.map +1 -1
- package/lib/cjs/polyface/AuxData.js +1 -1
- package/lib/cjs/polyface/AuxData.js.map +1 -1
- package/lib/cjs/polyface/FacetLocationDetail.d.ts +264 -0
- package/lib/cjs/polyface/FacetLocationDetail.d.ts.map +1 -0
- package/lib/cjs/polyface/FacetLocationDetail.js +376 -0
- package/lib/cjs/polyface/FacetLocationDetail.js.map +1 -0
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.d.ts +2 -5
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.d.ts.map +1 -1
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.js +5 -2
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceBuilder.d.ts +20 -14
- package/lib/cjs/polyface/PolyfaceBuilder.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceBuilder.js +21 -17
- package/lib/cjs/polyface/PolyfaceBuilder.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceClip.js +6 -7
- package/lib/cjs/polyface/PolyfaceClip.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceData.d.ts +1 -1
- package/lib/cjs/polyface/PolyfaceData.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceData.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.d.ts +22 -1
- package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.js +52 -2
- package/lib/cjs/polyface/PolyfaceQuery.js.map +1 -1
- package/lib/cjs/serialization/BGFBReader.js +4 -4
- package/lib/cjs/serialization/BGFBReader.js.map +1 -1
- package/lib/cjs/serialization/IModelJsonSchema.js +1 -2
- package/lib/cjs/serialization/IModelJsonSchema.js.map +1 -1
- package/lib/cjs/solid/Sphere.d.ts +5 -5
- package/lib/cjs/solid/Sphere.js +5 -5
- package/lib/cjs/solid/Sphere.js.map +1 -1
- package/lib/cjs/solid/SweepContour.js +1 -1
- package/lib/cjs/solid/SweepContour.js.map +1 -1
- package/lib/cjs/topology/Triangulation.js +1 -1
- package/lib/cjs/topology/Triangulation.js.map +1 -1
- package/lib/esm/Geometry.d.ts +23 -0
- package/lib/esm/Geometry.d.ts.map +1 -1
- package/lib/esm/Geometry.js +24 -0
- package/lib/esm/Geometry.js.map +1 -1
- package/lib/esm/bspline/BSplineCurveOps.js +4 -5
- package/lib/esm/bspline/BSplineCurveOps.js.map +1 -1
- package/lib/esm/bspline/InterpolationCurve3d.js +7 -10
- package/lib/esm/bspline/InterpolationCurve3d.js.map +1 -1
- package/lib/esm/clipping/ClipPrimitive.js +2 -2
- package/lib/esm/clipping/ClipPrimitive.js.map +1 -1
- package/lib/esm/clipping/ClipUtils.js +4 -4
- package/lib/esm/clipping/ClipUtils.js.map +1 -1
- package/lib/esm/clipping/internalContexts/LineStringOffsetClipperContext.js +2 -2
- package/lib/esm/clipping/internalContexts/LineStringOffsetClipperContext.js.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.js +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/esm/curve/CurveCollection.js +1 -1
- package/lib/esm/curve/CurveCollection.js.map +1 -1
- package/lib/esm/curve/StrokeOptions.js +1 -2
- package/lib/esm/curve/StrokeOptions.js.map +1 -1
- package/lib/esm/curve/spiral/DirectSpiral3d.js +1 -2
- package/lib/esm/curve/spiral/DirectSpiral3d.js.map +1 -1
- package/lib/esm/curve/spiral/IntegratedSpiral3d.js +1 -2
- package/lib/esm/curve/spiral/IntegratedSpiral3d.js.map +1 -1
- package/lib/esm/geometry3d/BarycentricTriangle.d.ts +195 -8
- package/lib/esm/geometry3d/BarycentricTriangle.d.ts.map +1 -1
- package/lib/esm/geometry3d/BarycentricTriangle.js +459 -12
- package/lib/esm/geometry3d/BarycentricTriangle.js.map +1 -1
- package/lib/esm/geometry3d/GrowableFloat64Array.js +2 -2
- package/lib/esm/geometry3d/GrowableFloat64Array.js.map +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.d.ts +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.d.ts.map +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.js +2 -2
- package/lib/esm/geometry3d/GrowableXYArray.js.map +1 -1
- package/lib/esm/geometry3d/GrowableXYZArray.js +1 -1
- package/lib/esm/geometry3d/GrowableXYZArray.js.map +1 -1
- package/lib/esm/geometry3d/IndexedXYCollection.d.ts +22 -7
- package/lib/esm/geometry3d/IndexedXYCollection.d.ts.map +1 -1
- package/lib/esm/geometry3d/IndexedXYCollection.js +41 -5
- package/lib/esm/geometry3d/IndexedXYCollection.js.map +1 -1
- package/lib/esm/geometry3d/IndexedXYZCollection.d.ts +58 -4
- package/lib/esm/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
- package/lib/esm/geometry3d/IndexedXYZCollection.js +103 -5
- package/lib/esm/geometry3d/IndexedXYZCollection.js.map +1 -1
- package/lib/esm/geometry3d/Point2dArrayCarrier.d.ts +10 -0
- package/lib/esm/geometry3d/Point2dArrayCarrier.d.ts.map +1 -1
- package/lib/esm/geometry3d/Point2dArrayCarrier.js +14 -0
- package/lib/esm/geometry3d/Point2dArrayCarrier.js.map +1 -1
- package/lib/esm/geometry3d/Point2dVector2d.js +4 -6
- package/lib/esm/geometry3d/Point2dVector2d.js.map +1 -1
- package/lib/esm/geometry3d/Point3dArrayCarrier.d.ts +0 -6
- package/lib/esm/geometry3d/Point3dArrayCarrier.d.ts.map +1 -1
- package/lib/esm/geometry3d/Point3dArrayCarrier.js +0 -6
- package/lib/esm/geometry3d/Point3dArrayCarrier.js.map +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.d.ts +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.js +6 -8
- package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
- package/lib/esm/geometry3d/PointHelpers.d.ts +14 -1
- package/lib/esm/geometry3d/PointHelpers.d.ts.map +1 -1
- package/lib/esm/geometry3d/PointHelpers.js +33 -1
- package/lib/esm/geometry3d/PointHelpers.js.map +1 -1
- package/lib/esm/geometry3d/PolygonOps.d.ts +120 -10
- package/lib/esm/geometry3d/PolygonOps.d.ts.map +1 -1
- package/lib/esm/geometry3d/PolygonOps.js +412 -13
- package/lib/esm/geometry3d/PolygonOps.js.map +1 -1
- package/lib/esm/geometry3d/Ray3d.js +1 -1
- package/lib/esm/geometry3d/Ray3d.js.map +1 -1
- package/lib/esm/polyface/AuxData.js +1 -1
- package/lib/esm/polyface/AuxData.js.map +1 -1
- package/lib/esm/polyface/FacetLocationDetail.d.ts +264 -0
- package/lib/esm/polyface/FacetLocationDetail.d.ts.map +1 -0
- package/lib/esm/polyface/FacetLocationDetail.js +369 -0
- package/lib/esm/polyface/FacetLocationDetail.js.map +1 -0
- package/lib/esm/polyface/IndexedPolyfaceVisitor.d.ts +2 -5
- package/lib/esm/polyface/IndexedPolyfaceVisitor.d.ts.map +1 -1
- package/lib/esm/polyface/IndexedPolyfaceVisitor.js +5 -2
- package/lib/esm/polyface/IndexedPolyfaceVisitor.js.map +1 -1
- package/lib/esm/polyface/PolyfaceBuilder.d.ts +20 -14
- package/lib/esm/polyface/PolyfaceBuilder.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceBuilder.js +21 -17
- package/lib/esm/polyface/PolyfaceBuilder.js.map +1 -1
- package/lib/esm/polyface/PolyfaceClip.js +6 -7
- package/lib/esm/polyface/PolyfaceClip.js.map +1 -1
- package/lib/esm/polyface/PolyfaceData.d.ts +1 -1
- package/lib/esm/polyface/PolyfaceData.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceData.js.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.d.ts +22 -1
- package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.js +52 -2
- package/lib/esm/polyface/PolyfaceQuery.js.map +1 -1
- package/lib/esm/serialization/BGFBReader.js +4 -4
- package/lib/esm/serialization/BGFBReader.js.map +1 -1
- package/lib/esm/serialization/IModelJsonSchema.js +1 -2
- package/lib/esm/serialization/IModelJsonSchema.js.map +1 -1
- package/lib/esm/solid/Sphere.d.ts +5 -5
- package/lib/esm/solid/Sphere.js +5 -5
- package/lib/esm/solid/Sphere.js.map +1 -1
- package/lib/esm/solid/SweepContour.js +1 -1
- package/lib/esm/solid/SweepContour.js.map +1 -1
- package/lib/esm/topology/Triangulation.js +1 -1
- package/lib/esm/topology/Triangulation.js.map +1 -1
- package/package.json +4 -4
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
5
|
*--------------------------------------------------------------------------------------------*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.Point3dArrayPolygonOps = exports.IndexedXYZCollectionPolygonOps = exports.PolygonOps = exports.CutLoopMergeContext = exports.CutLoop = void 0;
|
|
7
|
+
exports.Point3dArrayPolygonOps = exports.IndexedXYZCollectionPolygonOps = exports.PolygonOps = exports.CutLoopMergeContext = exports.CutLoop = exports.PolygonLocationDetail = void 0;
|
|
8
8
|
/** @packageDocumentation
|
|
9
9
|
* @module CartesianGeometry
|
|
10
10
|
*/
|
|
11
|
+
const core_bentley_1 = require("@itwin/core-bentley");
|
|
11
12
|
const Geometry_1 = require("../Geometry");
|
|
12
13
|
const Matrix4d_1 = require("../geometry4d/Matrix4d");
|
|
13
14
|
const Point4d_1 = require("../geometry4d/Point4d");
|
|
@@ -15,11 +16,68 @@ const XYParitySearchContext_1 = require("../topology/XYParitySearchContext");
|
|
|
15
16
|
const FrameBuilder_1 = require("./FrameBuilder");
|
|
16
17
|
const GrowableXYZArray_1 = require("./GrowableXYZArray");
|
|
17
18
|
const IndexedXYZCollection_1 = require("./IndexedXYZCollection");
|
|
19
|
+
const Matrix3d_1 = require("./Matrix3d");
|
|
20
|
+
const Plane3dByOriginAndUnitNormal_1 = require("./Plane3dByOriginAndUnitNormal");
|
|
18
21
|
const Point2dVector2d_1 = require("./Point2dVector2d");
|
|
19
22
|
const Point3dArrayCarrier_1 = require("./Point3dArrayCarrier");
|
|
20
23
|
const Point3dVector3d_1 = require("./Point3dVector3d");
|
|
21
24
|
const Ray3d_1 = require("./Ray3d");
|
|
22
25
|
const SortablePolygon_1 = require("./SortablePolygon");
|
|
26
|
+
/**
|
|
27
|
+
* Carries data about a point in the plane of a polygon.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
class PolygonLocationDetail {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.point = new Point3dVector3d_1.Point3d();
|
|
33
|
+
this.a = 0.0;
|
|
34
|
+
this.v = new Point3dVector3d_1.Vector3d();
|
|
35
|
+
this.code = Geometry_1.PolygonLocation.Unknown;
|
|
36
|
+
this.closestEdgeIndex = 0;
|
|
37
|
+
this.closestEdgeParam = 0.0;
|
|
38
|
+
}
|
|
39
|
+
/** Invalidate this detail. */
|
|
40
|
+
invalidate() {
|
|
41
|
+
this.point.setZero();
|
|
42
|
+
this.a = 0.0;
|
|
43
|
+
this.v.setZero();
|
|
44
|
+
this.code = Geometry_1.PolygonLocation.Unknown;
|
|
45
|
+
this.closestEdgeIndex = 0;
|
|
46
|
+
this.closestEdgeParam = 0.0;
|
|
47
|
+
}
|
|
48
|
+
/** Create an invalid detail.
|
|
49
|
+
* @param result optional pre-allocated object to fill and return
|
|
50
|
+
*/
|
|
51
|
+
static create(result) {
|
|
52
|
+
if (undefined === result)
|
|
53
|
+
result = new PolygonLocationDetail();
|
|
54
|
+
else
|
|
55
|
+
result.invalidate();
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
/** Set the instance contents from the other detail.
|
|
59
|
+
* @param other detail to clone
|
|
60
|
+
*/
|
|
61
|
+
copyContentsFrom(other) {
|
|
62
|
+
this.point.setFrom(other.point);
|
|
63
|
+
this.a = other.a;
|
|
64
|
+
this.v.setFrom(other.v);
|
|
65
|
+
this.code = other.code;
|
|
66
|
+
this.closestEdgeIndex = other.closestEdgeIndex;
|
|
67
|
+
this.closestEdgeParam = other.closestEdgeParam;
|
|
68
|
+
}
|
|
69
|
+
/** Whether this detail is valid. */
|
|
70
|
+
get isValid() {
|
|
71
|
+
return this.code !== Geometry_1.PolygonLocation.Unknown;
|
|
72
|
+
}
|
|
73
|
+
/** Whether this instance specifies a location inside or on the polygon. */
|
|
74
|
+
get isInsideOrOn() {
|
|
75
|
+
return this.code === Geometry_1.PolygonLocation.InsidePolygon ||
|
|
76
|
+
this.code === Geometry_1.PolygonLocation.OnPolygonVertex || this.code === Geometry_1.PolygonLocation.OnPolygonEdgeInterior ||
|
|
77
|
+
this.code === Geometry_1.PolygonLocation.InsidePolygonProjectsToVertex || this.code === Geometry_1.PolygonLocation.InsidePolygonProjectsToEdgeInterior;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.PolygonLocationDetail = PolygonLocationDetail;
|
|
23
81
|
/**
|
|
24
82
|
* Carrier for a loop extracted from clip operation, annotated for sorting
|
|
25
83
|
* @internal
|
|
@@ -538,29 +596,27 @@ class PolygonOps {
|
|
|
538
596
|
}
|
|
539
597
|
}
|
|
540
598
|
/** Test the direction of turn at the vertices of the polygon, ignoring z-coordinates.
|
|
541
|
-
*
|
|
542
|
-
* *
|
|
543
|
-
* all
|
|
544
|
-
* * Beware that a polygon which turns through more than a full turn can cross itself and close, but is not convex
|
|
545
|
-
* * Returns 1 if all turns are to the left, -1 if all to the right, and 0 if there are any zero or reverse turns
|
|
599
|
+
* * For a polygon without self-intersections and successive colinear edges, this is a convexity and orientation test: all positive is convex and counterclockwise, all negative is convex and clockwise.
|
|
600
|
+
* * Beware that a polygon which turns through more than a full turn can cross itself and close, but is not convex.
|
|
601
|
+
* @returns 1 if all turns are to the left, -1 if all to the right, and 0 if there are any zero or reverse turns
|
|
546
602
|
*/
|
|
547
|
-
static testXYPolygonTurningDirections(
|
|
603
|
+
static testXYPolygonTurningDirections(points) {
|
|
548
604
|
// Reduce count by trailing duplicates; leaves iLast at final index
|
|
549
|
-
let numPoint =
|
|
605
|
+
let numPoint = points.length;
|
|
550
606
|
let iLast = numPoint - 1;
|
|
551
|
-
while (iLast > 1 &&
|
|
607
|
+
while (iLast > 1 && points[iLast].x === points[0].x && points[iLast].y === points[0].y) {
|
|
552
608
|
numPoint = iLast--;
|
|
553
609
|
}
|
|
554
610
|
if (numPoint > 2) {
|
|
555
|
-
let vector0 = Point2dVector2d_1.Point2d.create(
|
|
556
|
-
const vector1 = Point2dVector2d_1.Point2d.create(
|
|
611
|
+
let vector0 = Point2dVector2d_1.Point2d.create(points[iLast].x - points[iLast - 1].x, points[iLast].y - points[iLast - 1].y);
|
|
612
|
+
const vector1 = Point2dVector2d_1.Point2d.create(points[0].x - points[iLast].x, points[0].y - points[iLast].y);
|
|
557
613
|
const baseArea = vector0.x * vector1.y - vector0.y * vector1.x;
|
|
558
614
|
// In a convex polygon, all successive-vector cross products will
|
|
559
615
|
// have the same sign as the base area, hence all products will be
|
|
560
616
|
// positive.
|
|
561
617
|
for (let i1 = 1; i1 < numPoint; i1++) {
|
|
562
618
|
vector0 = vector1.clone();
|
|
563
|
-
Point2dVector2d_1.Point2d.create(
|
|
619
|
+
Point2dVector2d_1.Point2d.create(points[i1].x - points[i1 - 1].x, points[i1].y - points[i1 - 1].y, vector1);
|
|
564
620
|
const currArea = vector0.x * vector1.y - vector0.y * vector1.x;
|
|
565
621
|
if (currArea * baseArea <= 0.0)
|
|
566
622
|
return 0;
|
|
@@ -570,6 +626,36 @@ class PolygonOps {
|
|
|
570
626
|
}
|
|
571
627
|
return 0;
|
|
572
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* Determine whether the polygon is convex.
|
|
631
|
+
* @param polygon vertices, closure point optional
|
|
632
|
+
* @returns whether the polygon is convex.
|
|
633
|
+
*/
|
|
634
|
+
static isConvex(polygon) {
|
|
635
|
+
if (!(polygon instanceof IndexedXYZCollection_1.IndexedXYZCollection))
|
|
636
|
+
return this.isConvex(new Point3dArrayCarrier_1.Point3dArrayCarrier(polygon));
|
|
637
|
+
let n = polygon.length;
|
|
638
|
+
if (n > 1 && polygon.getPoint3dAtUncheckedPointIndex(0).isExactEqual(polygon.getPoint3dAtUncheckedPointIndex(n - 1)))
|
|
639
|
+
--n; // ignore closure point
|
|
640
|
+
const normal = Point3dVector3d_1.Vector3d.create();
|
|
641
|
+
if (!this.unitNormal(polygon, normal))
|
|
642
|
+
return false;
|
|
643
|
+
let positiveArea = 0.0;
|
|
644
|
+
let negativeArea = 0.0;
|
|
645
|
+
const vecA = this._vector0;
|
|
646
|
+
let vecB = Point3dVector3d_1.Vector3d.createStartEnd(polygon.getPoint3dAtUncheckedPointIndex(n - 1), polygon.getPoint3dAtUncheckedPointIndex(0), this._vector1);
|
|
647
|
+
for (let i = 1; i <= n; i++) {
|
|
648
|
+
// check turn through vertices i-1,i,i+1
|
|
649
|
+
vecA.setFromVector3d(vecB);
|
|
650
|
+
vecB = Point3dVector3d_1.Vector3d.createStartEnd(polygon.getPoint3dAtUncheckedPointIndex(i - 1), polygon.getPoint3dAtUncheckedPointIndex(i % n), vecB);
|
|
651
|
+
const signedArea = normal.tripleProduct(vecA, vecB);
|
|
652
|
+
if (signedArea >= 0.0)
|
|
653
|
+
positiveArea += signedArea;
|
|
654
|
+
else
|
|
655
|
+
negativeArea += signedArea;
|
|
656
|
+
}
|
|
657
|
+
return Math.abs(negativeArea) < Geometry_1.Geometry.smallMetricDistanceSquared * positiveArea;
|
|
658
|
+
}
|
|
573
659
|
/**
|
|
574
660
|
* Test if point (x,y) is IN, OUT or ON a polygon.
|
|
575
661
|
* @return (1) for in, (-1) for OUT, (0) for ON
|
|
@@ -690,7 +776,7 @@ class PolygonOps {
|
|
|
690
776
|
*/
|
|
691
777
|
static sortOuterAndHoleLoops(loops, defaultNormal) {
|
|
692
778
|
const localToWorld = FrameBuilder_1.FrameBuilder.createRightHandedFrame(defaultNormal, loops);
|
|
693
|
-
const worldToLocal = localToWorld
|
|
779
|
+
const worldToLocal = localToWorld?.inverse();
|
|
694
780
|
const xyLoops = [];
|
|
695
781
|
if (worldToLocal !== undefined) {
|
|
696
782
|
// transform into plane so we can ignore z in the sort
|
|
@@ -717,6 +803,320 @@ class PolygonOps {
|
|
|
717
803
|
}
|
|
718
804
|
return sortedLoopsArray;
|
|
719
805
|
}
|
|
806
|
+
/** Compute the closest point on the polygon boundary to the given point.
|
|
807
|
+
* @param polygon points of the polygon, closure point optional
|
|
808
|
+
* @param testPoint point p to project onto the polygon edges. Works best when p is in the plane of the polygon.
|
|
809
|
+
* @param tolerance optional distance tolerance to determine point-vertex and point-edge coincidence.
|
|
810
|
+
* @param result optional pre-allocated object to fill and return
|
|
811
|
+
* @returns details d of the closest point `d.point`:
|
|
812
|
+
* * `d.isValid()` returns true if and only if the polygon is nontrivial.
|
|
813
|
+
* * `d.edgeIndex` and `d.edgeParam` specify the location of the closest point, within `distTol`.
|
|
814
|
+
* * `d.code` classifies the closest point as a vertex (`PolygonLocation.OnPolygonVertex`) or as a point on an edge (`PolygonLocation.OnPolygonEdgeInterior`).
|
|
815
|
+
* * `d.a` is the distance from testPoint to the closest point.
|
|
816
|
+
* * `d.v` can be used to classify p (if p and polygon are coplanar): if n is the polygon normal then `d.v.dotProduct(n)` is +/-/0 if and only if p is inside/outside/on the polygon.
|
|
817
|
+
*/
|
|
818
|
+
static closestPointOnBoundary(polygon, testPoint, tolerance = Geometry_1.Geometry.smallMetricDistance, result) {
|
|
819
|
+
if (!(polygon instanceof IndexedXYZCollection_1.IndexedXYZCollection))
|
|
820
|
+
return this.closestPointOnBoundary(new Point3dArrayCarrier_1.Point3dArrayCarrier(polygon), testPoint, tolerance, result);
|
|
821
|
+
const distTol2 = tolerance * tolerance;
|
|
822
|
+
let numPoints = polygon.length;
|
|
823
|
+
while (numPoints > 1) {
|
|
824
|
+
if (polygon.distanceSquaredIndexIndex(0, numPoints - 1) > distTol2)
|
|
825
|
+
break;
|
|
826
|
+
--numPoints; // ignore closure point
|
|
827
|
+
}
|
|
828
|
+
result = PolygonLocationDetail.create(result);
|
|
829
|
+
if (0 === numPoints)
|
|
830
|
+
return result; // invalid
|
|
831
|
+
if (1 === numPoints) {
|
|
832
|
+
polygon.getPoint3dAtUncheckedPointIndex(0, result.point);
|
|
833
|
+
result.a = result.point.distance(testPoint);
|
|
834
|
+
result.v.setZero();
|
|
835
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonVertex;
|
|
836
|
+
result.closestEdgeIndex = 0;
|
|
837
|
+
result.closestEdgeParam = 0.0;
|
|
838
|
+
return result;
|
|
839
|
+
}
|
|
840
|
+
let iPrev = numPoints - 1;
|
|
841
|
+
let minDist2 = Geometry_1.Geometry.largeCoordinateResult;
|
|
842
|
+
for (let iBase = 0; iBase < numPoints; ++iBase) {
|
|
843
|
+
let iNext = iBase + 1;
|
|
844
|
+
if (iNext === numPoints)
|
|
845
|
+
iNext = 0;
|
|
846
|
+
const uDotU = polygon.distanceSquaredIndexIndex(iBase, iNext);
|
|
847
|
+
if (uDotU <= distTol2)
|
|
848
|
+
continue; // ignore trivial polygon edge (keep iPrev)
|
|
849
|
+
const vDotV = polygon.distanceSquaredIndexXYAndZ(iBase, testPoint);
|
|
850
|
+
const uDotV = polygon.dotProductIndexIndexXYAndZ(iBase, iNext, testPoint);
|
|
851
|
+
const edgeParam = uDotV / uDotU; // param of projection of testPoint onto this edge
|
|
852
|
+
if (edgeParam <= 0.0) { // testPoint projects to/before edge start
|
|
853
|
+
const distToStart2 = vDotV;
|
|
854
|
+
if (distToStart2 <= distTol2) {
|
|
855
|
+
// testPoint is at edge start; we are done
|
|
856
|
+
polygon.getPoint3dAtUncheckedPointIndex(iBase, result.point);
|
|
857
|
+
result.a = Math.sqrt(distToStart2);
|
|
858
|
+
result.v.setZero();
|
|
859
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonVertex;
|
|
860
|
+
result.closestEdgeIndex = iBase;
|
|
861
|
+
result.closestEdgeParam = 0.0;
|
|
862
|
+
return result;
|
|
863
|
+
}
|
|
864
|
+
if (distToStart2 < minDist2) {
|
|
865
|
+
if (polygon.dotProductIndexIndexXYAndZ(iBase, iPrev, testPoint) <= 0.0) {
|
|
866
|
+
// update candidate (to edge start) only if previous edge was NOOP
|
|
867
|
+
polygon.getPoint3dAtUncheckedPointIndex(iBase, result.point);
|
|
868
|
+
result.a = Math.sqrt(distToStart2);
|
|
869
|
+
polygon.crossProductIndexIndexIndex(iBase, iPrev, iNext, result.v);
|
|
870
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonVertex;
|
|
871
|
+
result.closestEdgeIndex = iBase;
|
|
872
|
+
result.closestEdgeParam = 0.0;
|
|
873
|
+
minDist2 = distToStart2;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
else if (edgeParam <= 1.0) { // testPoint projects inside edge, or to edge end
|
|
878
|
+
const projDist2 = vDotV - edgeParam * edgeParam * uDotU;
|
|
879
|
+
if (projDist2 <= distTol2) {
|
|
880
|
+
// testPoint is on edge; we are done
|
|
881
|
+
const distToStart2 = vDotV;
|
|
882
|
+
if (edgeParam <= 0.5 && distToStart2 <= distTol2) {
|
|
883
|
+
// testPoint is at edge start
|
|
884
|
+
polygon.getPoint3dAtUncheckedPointIndex(iBase, result.point);
|
|
885
|
+
result.a = Math.sqrt(distToStart2);
|
|
886
|
+
result.v.setZero();
|
|
887
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonVertex;
|
|
888
|
+
result.closestEdgeIndex = iBase;
|
|
889
|
+
result.closestEdgeParam = 0.0;
|
|
890
|
+
return result;
|
|
891
|
+
}
|
|
892
|
+
const distToEnd2 = projDist2 + (1.0 - edgeParam) * (1.0 - edgeParam) * uDotU;
|
|
893
|
+
if (edgeParam > 0.5 && distToEnd2 <= distTol2) {
|
|
894
|
+
// testPoint is at edge end
|
|
895
|
+
polygon.getPoint3dAtUncheckedPointIndex(iNext, result.point);
|
|
896
|
+
result.a = Math.sqrt(distToEnd2);
|
|
897
|
+
result.v.setZero();
|
|
898
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonVertex;
|
|
899
|
+
result.closestEdgeIndex = iNext;
|
|
900
|
+
result.closestEdgeParam = 0.0;
|
|
901
|
+
return result;
|
|
902
|
+
}
|
|
903
|
+
// testPoint is on edge interior
|
|
904
|
+
polygon.interpolateIndexIndex(iBase, edgeParam, iNext, result.point);
|
|
905
|
+
result.a = Math.sqrt(projDist2);
|
|
906
|
+
result.v.setZero();
|
|
907
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonEdgeInterior;
|
|
908
|
+
result.closestEdgeIndex = iBase;
|
|
909
|
+
result.closestEdgeParam = edgeParam;
|
|
910
|
+
return result;
|
|
911
|
+
}
|
|
912
|
+
if (projDist2 < minDist2) {
|
|
913
|
+
// update candidate (to edge interior)
|
|
914
|
+
polygon.interpolateIndexIndex(iBase, edgeParam, iNext, result.point);
|
|
915
|
+
result.a = Math.sqrt(projDist2);
|
|
916
|
+
polygon.crossProductIndexIndexXYAndZ(iBase, iNext, testPoint, result.v);
|
|
917
|
+
result.code = Geometry_1.PolygonLocation.OnPolygonEdgeInterior;
|
|
918
|
+
result.closestEdgeIndex = iBase;
|
|
919
|
+
result.closestEdgeParam = edgeParam;
|
|
920
|
+
minDist2 = projDist2;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
else { // edgeParam > 1.0
|
|
924
|
+
// NOOP: testPoint projects beyond edge end, handled by next edge
|
|
925
|
+
}
|
|
926
|
+
iPrev = iBase;
|
|
927
|
+
}
|
|
928
|
+
return result;
|
|
929
|
+
}
|
|
930
|
+
/** Compute the intersection of a line (parameterized as a ray) with the plane of this polygon.
|
|
931
|
+
* @param polygon points of the polygon, closure point optional
|
|
932
|
+
* @param ray infinite line to intersect, as a ray
|
|
933
|
+
* @param tolerance optional distance tolerance to determine point-vertex and point-edge coincidence.
|
|
934
|
+
* @param result optional pre-allocated object to fill and return
|
|
935
|
+
* @returns details d of the line-plane intersection `d.point`:
|
|
936
|
+
* * `d.isValid()` returns true if and only if the line intersects the plane.
|
|
937
|
+
* * `d.code` indicates where the intersection lies with respect to the polygon.
|
|
938
|
+
* * `d.a` is the ray intersection parameter. If `d.a` >= 0, the ray intersects the plane of the polygon.
|
|
939
|
+
* * `d.edgeIndex` and `d.edgeParam` specify the location of the closest point on the polygon to the intersection, within `distTol`.
|
|
940
|
+
*/
|
|
941
|
+
static intersectRay3d(polygon, ray, tolerance = Geometry_1.Geometry.smallMetricDistance, result) {
|
|
942
|
+
if (!(polygon instanceof IndexedXYZCollection_1.IndexedXYZCollection))
|
|
943
|
+
return this.intersectRay3d(new Point3dArrayCarrier_1.Point3dArrayCarrier(polygon), ray, tolerance, result);
|
|
944
|
+
if (!this.unitNormal(polygon, this._normal))
|
|
945
|
+
return PolygonLocationDetail.create(result); // invalid
|
|
946
|
+
this._workPlane = Plane3dByOriginAndUnitNormal_1.Plane3dByOriginAndUnitNormal.createXYZUVW(polygon.getXAtUncheckedPointIndex(0), polygon.getYAtUncheckedPointIndex(0), polygon.getZAtUncheckedPointIndex(0), this._normal.x, this._normal.y, this._normal.z, this._workPlane);
|
|
947
|
+
const intersectionPoint = Point3dVector3d_1.Point3d.createZero(this._workXYZ);
|
|
948
|
+
const rayParam = ray.intersectionWithPlane(this._workPlane, intersectionPoint);
|
|
949
|
+
if (undefined === rayParam)
|
|
950
|
+
return PolygonLocationDetail.create(result);
|
|
951
|
+
result = this.closestPointOnBoundary(polygon, intersectionPoint, tolerance, result);
|
|
952
|
+
if (result.isValid) {
|
|
953
|
+
result.point.setFrom(intersectionPoint);
|
|
954
|
+
result.a = rayParam;
|
|
955
|
+
const dot = result.v.dotProduct(this._normal);
|
|
956
|
+
if (dot === 0.0) {
|
|
957
|
+
// NOOP: intersectionPoint is on the polygon, so result.code already classifies it
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
// intersectionPoint is not on polygon, so result.code refers to the closest point. Update it to refer to intersectionPoint.
|
|
961
|
+
if (Geometry_1.PolygonLocation.OnPolygonVertex === result.code)
|
|
962
|
+
result.code = (dot > 0.0) ? Geometry_1.PolygonLocation.InsidePolygonProjectsToVertex : Geometry_1.PolygonLocation.OutsidePolygonProjectsToVertex;
|
|
963
|
+
else if (Geometry_1.PolygonLocation.OnPolygonEdgeInterior === result.code)
|
|
964
|
+
result.code = (dot > 0.0) ? Geometry_1.PolygonLocation.InsidePolygonProjectsToEdgeInterior : Geometry_1.PolygonLocation.OutsidePolygonProjectsToEdgeInterior;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
return result;
|
|
968
|
+
}
|
|
969
|
+
/** Compute the intersection of a line (parameterized as a line segment) with the plane of this polygon.
|
|
970
|
+
* @param polygon points of the polygon, closure point optional
|
|
971
|
+
* @param point0 start point of segment on line to intersect
|
|
972
|
+
* @param point1 end point of segment on line to intersect
|
|
973
|
+
* @param tolerance optional distance tolerance to determine point-vertex and point-edge coincidence.
|
|
974
|
+
* @param result optional pre-allocated object to fill and return
|
|
975
|
+
* @returns details d of the line-plane intersection `d.point`:
|
|
976
|
+
* * `d.isValid()` returns true if and only if the line intersects the plane.
|
|
977
|
+
* * `d.code` indicates where the intersection lies with respect to the polygon.
|
|
978
|
+
* * `d.a` is the segment intersection parameter. If `d.a` is in [0,1], the segment intersects the plane of the polygon.
|
|
979
|
+
* * `d.edgeIndex` and `d.edgeParam` specify the location of the closest point on the polygon to the intersection, within `distTol`.
|
|
980
|
+
* @see intersectRay3d
|
|
981
|
+
*/
|
|
982
|
+
static intersectSegment(polygon, point0, point1, tolerance = Geometry_1.Geometry.smallMetricDistance, result) {
|
|
983
|
+
this._workRay = Ray3d_1.Ray3d.createStartEnd(point0, point1, this._workRay);
|
|
984
|
+
return this.intersectRay3d(polygon, this._workRay, tolerance, result);
|
|
985
|
+
}
|
|
986
|
+
/** Compute edge data for the barycentric coordinate computation, ignoring all z-coordinates.
|
|
987
|
+
* @param polygon points of the polygon (without closure point)
|
|
988
|
+
* @param edgeStartVertexIndex index of start vertex of the edge (unchecked)
|
|
989
|
+
* @param point point to project to the edge
|
|
990
|
+
* @param edgeOutwardUnitNormal pre-allocated vector to be populated on return with the unit perpendicular to the edge, facing outward, in xy-plane
|
|
991
|
+
* @param tolerance used to clamp outputs
|
|
992
|
+
* @param result optional pre-allocated result
|
|
993
|
+
* @returns x: signed projection distance of `point` to the edge, y: edge parameter of the projection
|
|
994
|
+
*/
|
|
995
|
+
static computeEdgeDataXY(polygon, edgeStartVertexIndex, point, edgeOutwardUnitNormal, tolerance = Geometry_1.Geometry.smallMetricDistance, result) {
|
|
996
|
+
const i0 = edgeStartVertexIndex % polygon.length;
|
|
997
|
+
const i1 = (i0 + 1) % polygon.length;
|
|
998
|
+
polygon.vectorIndexIndex(i0, i1, edgeOutwardUnitNormal).unitPerpendicularXY(edgeOutwardUnitNormal).negate(edgeOutwardUnitNormal); // z is zero
|
|
999
|
+
const hypDeltaX = polygon.getXAtUncheckedPointIndex(i0) - point.x;
|
|
1000
|
+
const hypDeltaY = polygon.getYAtUncheckedPointIndex(i0) - point.y;
|
|
1001
|
+
let projDist = Geometry_1.Geometry.dotProductXYXY(hypDeltaX, hypDeltaY, edgeOutwardUnitNormal.x, edgeOutwardUnitNormal.y);
|
|
1002
|
+
const edgeDist = Geometry_1.Geometry.crossProductXYXY(hypDeltaX, hypDeltaY, edgeOutwardUnitNormal.x, edgeOutwardUnitNormal.y);
|
|
1003
|
+
const edgeLength = Geometry_1.Geometry.distanceXYXY(polygon.getXAtUncheckedPointIndex(i0), polygon.getYAtUncheckedPointIndex(i0), polygon.getXAtUncheckedPointIndex(i1), polygon.getYAtUncheckedPointIndex(i1));
|
|
1004
|
+
let edgeParam = Geometry_1.Geometry.safeDivideFraction(edgeDist, edgeLength, 0.0);
|
|
1005
|
+
if (Geometry_1.Geometry.isSameCoordinate(0.0, projDist, tolerance))
|
|
1006
|
+
projDist = 0.0;
|
|
1007
|
+
if (Geometry_1.Geometry.isSameCoordinate(0.0, edgeParam, tolerance))
|
|
1008
|
+
edgeParam = 0.0;
|
|
1009
|
+
else if (Geometry_1.Geometry.isSameCoordinate(1.0, edgeParam, tolerance))
|
|
1010
|
+
edgeParam = 1.0;
|
|
1011
|
+
return Point2dVector2d_1.Point2d.create(projDist, edgeParam, result);
|
|
1012
|
+
}
|
|
1013
|
+
/** Compute the barycentric coordinates for a point on either of a pair of adjacent edges of a convex polygon.
|
|
1014
|
+
* @param polygon points of the polygon, assumed to be convex. Assumed to have no closure point.
|
|
1015
|
+
* @param iPrev start index of previous edge
|
|
1016
|
+
* @param prevNormal outward unit normal of previous edge
|
|
1017
|
+
* @param prevProj x = signed distance from point to previous edge; y = edge parameter of this projection in [0,1]
|
|
1018
|
+
* @param i start index of current edge
|
|
1019
|
+
* @param normal outward unit normal of current edge
|
|
1020
|
+
* @param proj x = signed distance from point to current edge; y = edge parameter of this projection in [0,1]
|
|
1021
|
+
* @param coords pre-allocated barycentric coordinate array to return, assumed to have length at least `polygon.length`
|
|
1022
|
+
* @returns barycentric coordinates, or undefined if not on either edge
|
|
1023
|
+
*/
|
|
1024
|
+
static convexBarycentricCoordinatesOnEdge(polygon, iPrev, prevNormal, prevProj, i, normal, proj, coords) {
|
|
1025
|
+
// ignore degenerate edges
|
|
1026
|
+
const pointIsOnPrevEdge = !prevNormal.isZero && (0.0 === prevProj.x) && Geometry_1.Geometry.isIn01(prevProj.y);
|
|
1027
|
+
const pointIsOnEdge = !normal.isZero && (0.0 === proj.x) && Geometry_1.Geometry.isIn01(proj.y);
|
|
1028
|
+
if (pointIsOnPrevEdge && pointIsOnEdge) { // the point is at vertex i
|
|
1029
|
+
coords.fill(0);
|
|
1030
|
+
coords[i] = 1.0;
|
|
1031
|
+
return coords;
|
|
1032
|
+
}
|
|
1033
|
+
const n = polygon.length;
|
|
1034
|
+
if (pointIsOnPrevEdge) { // the point is on the previous edge
|
|
1035
|
+
coords.fill(0);
|
|
1036
|
+
const i0 = iPrev;
|
|
1037
|
+
const i1 = i;
|
|
1038
|
+
const edgeParam = prevProj.y;
|
|
1039
|
+
coords[i0] = 1.0 - edgeParam;
|
|
1040
|
+
coords[i1] = edgeParam;
|
|
1041
|
+
return coords;
|
|
1042
|
+
}
|
|
1043
|
+
if (pointIsOnEdge) { // the point is on the edge starting at the i_th vertex
|
|
1044
|
+
coords.fill(0);
|
|
1045
|
+
const i0 = i;
|
|
1046
|
+
const i1 = (i + 1) % n;
|
|
1047
|
+
const edgeParam = proj.y;
|
|
1048
|
+
coords[i0] = 1.0 - edgeParam;
|
|
1049
|
+
coords[i1] = edgeParam;
|
|
1050
|
+
return coords;
|
|
1051
|
+
}
|
|
1052
|
+
return undefined; // not on edge
|
|
1053
|
+
}
|
|
1054
|
+
// cspell:word CAGD
|
|
1055
|
+
/** Compute the barycentric coordinates for a point inside a convex polygon.
|
|
1056
|
+
* @param polygon points of the polygon, assumed to be convex. Closure point optional.
|
|
1057
|
+
* @param point point assumed to be inside or on polygon
|
|
1058
|
+
* @param tolerance distance tolerance for point to be considered on a polygon edge
|
|
1059
|
+
* @return barycentric coordinates of the interior point, or undefined if invalid polygon or exterior point. Length is same as `polygon.length`.
|
|
1060
|
+
* @see BarycentricTriangle.pointToFraction
|
|
1061
|
+
*/
|
|
1062
|
+
static convexBarycentricCoordinates(polygon, point, tolerance = Geometry_1.Geometry.smallMetricDistance) {
|
|
1063
|
+
// cf. "Barycentric Coordinates for Convex Sets", by Warren et al., CAGD (2003)
|
|
1064
|
+
if (Array.isArray(polygon))
|
|
1065
|
+
return this.convexBarycentricCoordinates(new Point3dArrayCarrier_1.Point3dArrayCarrier(polygon), point);
|
|
1066
|
+
let n = polygon.length;
|
|
1067
|
+
while (n > 1 && polygon.getPoint3dAtUncheckedPointIndex(0).isExactEqual(polygon.getPoint3dAtUncheckedPointIndex(n - 1)))
|
|
1068
|
+
--n; // ignore closure point(s)
|
|
1069
|
+
if (n < 3 || !PolygonOps.unitNormal(polygon, this._normal))
|
|
1070
|
+
return undefined;
|
|
1071
|
+
const localToWorld = this._workMatrix3d = Matrix3d_1.Matrix3d.createRigidHeadsUp(this._normal, Geometry_1.AxisOrder.ZXY, this._workMatrix3d);
|
|
1072
|
+
const polygonXY = new GrowableXYZArray_1.GrowableXYZArray(n);
|
|
1073
|
+
for (let i = 0; i < n; ++i)
|
|
1074
|
+
polygonXY.push(localToWorld.multiplyInverseXYZAsPoint3d(polygon.getXAtUncheckedPointIndex(i), polygon.getYAtUncheckedPointIndex(i), polygon.getZAtUncheckedPointIndex(i), this._workXYZ));
|
|
1075
|
+
const pointXY = this._workXYZ = localToWorld.multiplyInverseXYZAsPoint3d(point.x, point.y, point.z, this._workXYZ);
|
|
1076
|
+
// now we know polygon orientation is ccw, its last edge has positive length, and we can ignore z-coords
|
|
1077
|
+
let iPrev = n - 1;
|
|
1078
|
+
const outwardUnitNormalOfLastEdge = this._vector0;
|
|
1079
|
+
const projToLastEdge = this._workXY0 = this.computeEdgeDataXY(polygonXY, iPrev, pointXY, outwardUnitNormalOfLastEdge, tolerance, this._workXY0);
|
|
1080
|
+
// we can compare to exact zero because computeEdgeDataXY has chopped small distances to zero
|
|
1081
|
+
if (projToLastEdge.x < 0.0)
|
|
1082
|
+
return undefined; // point is outside polygon, or polygon is nonconvex
|
|
1083
|
+
const outwardUnitNormalOfPrevEdge = Point3dVector3d_1.Vector3d.createFrom(outwardUnitNormalOfLastEdge, this._vector1);
|
|
1084
|
+
const projToPrevEdge = this._workXY1 = Point2dVector2d_1.Point2d.createFrom(projToLastEdge, this._workXY1);
|
|
1085
|
+
const coords = Array(polygon.length).fill(0); // use original length
|
|
1086
|
+
const largestResult = (tolerance > 0.0) ? 1.0 / (tolerance * tolerance) : Geometry_1.Geometry.largeCoordinateResult;
|
|
1087
|
+
let coordSum = 0.0;
|
|
1088
|
+
for (let i = 0; i < n; ++i) {
|
|
1089
|
+
const outwardUnitNormalOfEdge = Point3dVector3d_1.Vector3d.createFrom(outwardUnitNormalOfLastEdge, this._vector2);
|
|
1090
|
+
const projToEdge = this._workXY2 = (i < n - 1) ? this.computeEdgeDataXY(polygonXY, i, pointXY, outwardUnitNormalOfEdge, tolerance, this._workXY2) : Point2dVector2d_1.Point2d.createFrom(projToLastEdge, this._workXY2);
|
|
1091
|
+
if (projToEdge.x < 0.0)
|
|
1092
|
+
return undefined; // point is outside polygon, or polygon is nonconvex
|
|
1093
|
+
if (undefined !== this.convexBarycentricCoordinatesOnEdge(polygonXY, iPrev, outwardUnitNormalOfPrevEdge, projToPrevEdge, i, outwardUnitNormalOfEdge, projToEdge, coords))
|
|
1094
|
+
return coords; // point is on vertex or edge; we are done
|
|
1095
|
+
if (outwardUnitNormalOfEdge.x === 0.0 && outwardUnitNormalOfEdge.y === 0.0)
|
|
1096
|
+
continue; // edge is degenerate; coords[i] = 0; keep previous edge data
|
|
1097
|
+
if (0.0 === projToPrevEdge.x || 0.0 === projToEdge.x)
|
|
1098
|
+
continue; // point is on subsequent colinear edge (ASSUMING interior point, convex polygon!); coords[i] = 0; keep previous edge data
|
|
1099
|
+
const areaOfNormalParallelogram = Math.abs(outwardUnitNormalOfPrevEdge.crossProductXY(outwardUnitNormalOfEdge));
|
|
1100
|
+
const coord = Geometry_1.Geometry.conditionalDivideCoordinate(areaOfNormalParallelogram, projToPrevEdge.x * projToEdge.x, largestResult);
|
|
1101
|
+
if (undefined === coord) {
|
|
1102
|
+
(0, core_bentley_1.assert)(!"unexpectedly small projection distance to an edge");
|
|
1103
|
+
return undefined; // shouldn't happen due to chopping in computeEdgeDataXY: area/(dist*dist) <= 1/tol^2 = largestResult
|
|
1104
|
+
}
|
|
1105
|
+
coords[i] = coord;
|
|
1106
|
+
coordSum += coord;
|
|
1107
|
+
outwardUnitNormalOfPrevEdge.setFrom(outwardUnitNormalOfEdge);
|
|
1108
|
+
projToPrevEdge.setFrom(projToEdge);
|
|
1109
|
+
iPrev = i;
|
|
1110
|
+
}
|
|
1111
|
+
const scale = Geometry_1.Geometry.conditionalDivideCoordinate(1.0, coordSum);
|
|
1112
|
+
if (undefined === scale) {
|
|
1113
|
+
(0, core_bentley_1.assert)(!"unexpected zero barycentric coordinate sum");
|
|
1114
|
+
return undefined;
|
|
1115
|
+
}
|
|
1116
|
+
for (let i = 0; i < n; ++i)
|
|
1117
|
+
coords[i] *= scale; // normalized
|
|
1118
|
+
return coords;
|
|
1119
|
+
}
|
|
720
1120
|
}
|
|
721
1121
|
exports.PolygonOps = PolygonOps;
|
|
722
1122
|
/** These values are the integrated area moment products [xx,xy,xz, x]
|