@itwin/ecschema-rpcinterface-tests 4.4.0-dev.16 → 4.4.0-dev.17
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/lib/dist/_bea9.bundled-tests.js.map +1 -1
- package/lib/dist/bundled-tests.js +227 -193
- package/lib/dist/bundled-tests.js.map +1 -1
- package/lib/dist/core_frontend_lib_esm_ApproximateTerrainHeightsProps_js.bundled-tests.js.map +1 -1
- package/lib/dist/vendors-common_temp_node_modules_pnpm_loaders_gl_draco_3_1_6_node_modules_loaders_gl_draco_di-0642a6.bundled-tests.js.map +1 -1
- package/package.json +16 -16
|
@@ -250254,6 +250254,22 @@ class Sample {
|
|
|
250254
250254
|
}
|
|
250255
250255
|
}
|
|
250256
250256
|
}
|
|
250257
|
+
/** Create a point on the polar parametric curve r = cos(a * theta), aka "rose".
|
|
250258
|
+
* @param theta angle
|
|
250259
|
+
* @param a period multiplier. If odd, this is the petal count; if even, twice the number of petals.
|
|
250260
|
+
* @param z z-coordinate for output
|
|
250261
|
+
*/
|
|
250262
|
+
static createRosePoint3d(theta, a, z = 0) {
|
|
250263
|
+
const r = Math.cos(a * theta);
|
|
250264
|
+
return _geometry3d_Point3dVector3d__WEBPACK_IMPORTED_MODULE_1__.Point3d.create(r * Math.cos(theta), r * Math.sin(theta), z);
|
|
250265
|
+
}
|
|
250266
|
+
/** Create a point on the polar parametric curve r = cos(a * theta), aka "rose".
|
|
250267
|
+
* @param theta angle
|
|
250268
|
+
* @param a period multiplier. If odd, this is the petal count; if even, twice the number of petals.
|
|
250269
|
+
*/
|
|
250270
|
+
static createRosePoint2d(theta, a) {
|
|
250271
|
+
return _geometry3d_Point2dVector2d__WEBPACK_IMPORTED_MODULE_3__.Point2d.createFrom(Sample.createRosePoint3d(theta, a));
|
|
250272
|
+
}
|
|
250257
250273
|
/**
|
|
250258
250274
|
* Create a mesh surface from samples of a smooth function over [0,1]x[0,1].
|
|
250259
250275
|
* @param size grid size; the number of intervals on each side of the unit square domain.
|
|
@@ -254827,15 +254843,15 @@ var HalfEdgeMask;
|
|
|
254827
254843
|
* * A boundary edge with interior to one side, exterior to the other, will have EXTERIOR only on the outside.
|
|
254828
254844
|
* * An edge inserted "within a purely exterior face" can have EXTERIOR on both sides.
|
|
254829
254845
|
* * An interior edge (such as added during triangulation) will have no EXTERIOR bits.
|
|
254830
|
-
|
|
254831
|
-
|
|
254846
|
+
*/
|
|
254847
|
+
// Visualization can be found at geometry/internaldocs/Graph.md
|
|
254832
254848
|
HalfEdgeMask[HalfEdgeMask["EXTERIOR"] = 1] = "EXTERIOR";
|
|
254833
254849
|
/**
|
|
254834
254850
|
* Mask commonly set (on both sides) of original geometry edges that are transition from outside to inside.
|
|
254835
254851
|
* * At the moment of creating an edge from primary user boundary loop coordinates, the fact that an edge is BOUNDARY
|
|
254836
254852
|
* is often clear even though there is uncertainty about which side should be EXTERIOR.
|
|
254837
|
-
* * Visualization can be found at geometry/internaldocs/Graph.md
|
|
254838
254853
|
*/
|
|
254854
|
+
// Visualization can be found at geometry/internaldocs/Graph.md
|
|
254839
254855
|
HalfEdgeMask[HalfEdgeMask["BOUNDARY_EDGE"] = 2] = "BOUNDARY_EDGE";
|
|
254840
254856
|
/**
|
|
254841
254857
|
* Mask commonly set (on both sides) of original geometry edges, but NOT indicating that the edge is certainly a
|
|
@@ -256402,6 +256418,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
256402
256418
|
/* harmony export */ "HalfEdgeGraphSearch": () => (/* binding */ HalfEdgeGraphSearch),
|
|
256403
256419
|
/* harmony export */ "HalfEdgeMaskTester": () => (/* binding */ HalfEdgeMaskTester)
|
|
256404
256420
|
/* harmony export */ });
|
|
256421
|
+
/* harmony import */ var _geometry3d_Range__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../geometry3d/Range */ "../../core/geometry/lib/esm/geometry3d/Range.js");
|
|
256405
256422
|
/* harmony import */ var _Graph__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Graph */ "../../core/geometry/lib/esm/topology/Graph.js");
|
|
256406
256423
|
/* harmony import */ var _SignedDataSummary__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SignedDataSummary */ "../../core/geometry/lib/esm/topology/SignedDataSummary.js");
|
|
256407
256424
|
/* harmony import */ var _XYParitySearchContext__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./XYParitySearchContext */ "../../core/geometry/lib/esm/topology/XYParitySearchContext.js");
|
|
@@ -256415,11 +256432,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
256415
256432
|
|
|
256416
256433
|
|
|
256417
256434
|
|
|
256418
|
-
|
|
256419
|
-
*/
|
|
256435
|
+
|
|
256436
|
+
/** Class to test match of half edge mask. */
|
|
256420
256437
|
class HalfEdgeMaskTester {
|
|
256421
256438
|
/**
|
|
256422
|
-
*
|
|
256439
|
+
* Constructor
|
|
256423
256440
|
* @param mask mask to test in `testEdge` function
|
|
256424
256441
|
* @param targetValue value to match for true return
|
|
256425
256442
|
*/
|
|
@@ -256427,47 +256444,27 @@ class HalfEdgeMaskTester {
|
|
|
256427
256444
|
this._targetMask = mask;
|
|
256428
256445
|
this._targetValue = targetValue;
|
|
256429
256446
|
}
|
|
256430
|
-
/** Return true if the value of the targetMask matches the targetValue */
|
|
256447
|
+
/** Return true if the value of the targetMask matches the targetValue. */
|
|
256431
256448
|
testEdge(edge) {
|
|
256432
256449
|
return edge.isMaskSet(this._targetMask) === this._targetValue;
|
|
256433
256450
|
}
|
|
256434
256451
|
}
|
|
256435
|
-
|
|
256452
|
+
/** Class for different types of searches for HalfEdgeGraph. */
|
|
256436
256453
|
class HalfEdgeGraphSearch {
|
|
256437
256454
|
/**
|
|
256438
|
-
*
|
|
256439
|
-
* *
|
|
256440
|
-
*/
|
|
256441
|
-
static pushAndMaskAllNodesInFace(faceSeed, mask, allNodeStack, onePerFaceStack) {
|
|
256442
|
-
onePerFaceStack.push(faceSeed);
|
|
256443
|
-
faceSeed.collectAroundFace((node) => {
|
|
256444
|
-
node.setMask(mask);
|
|
256445
|
-
allNodeStack.push(node);
|
|
256446
|
-
});
|
|
256447
|
-
}
|
|
256448
|
-
/**
|
|
256449
|
-
* Search an array of faceSeed nodes for the face with the most negative area.
|
|
256450
|
-
* @param oneCandidateNodePerFace array containing one node from each face to be considered.
|
|
256451
|
-
* @returns node on the minimum area face, or undefined if no such face (e.g., all faces have zero area).
|
|
256452
|
-
*/
|
|
256453
|
-
static findMinimumAreaFace(oneCandidateNodePerFace, faceAreaFunction) {
|
|
256454
|
-
const summary = HalfEdgeGraphSearch.collectFaceAreaSummary(oneCandidateNodePerFace, false, faceAreaFunction);
|
|
256455
|
-
return summary.largestNegativeItem;
|
|
256456
|
-
}
|
|
256457
|
-
/**
|
|
256458
|
-
* static method for face area computation -- useful as function parameter in collect FaceAreaSummary.
|
|
256459
|
-
* * This simply calls `node.signedFaceArea ()`
|
|
256455
|
+
* Static method for face area computation -- useful as function parameter in `collectFaceAreaSummary`.
|
|
256456
|
+
* * This simply calls `node.signedFaceArea()`
|
|
256460
256457
|
* @param node instance for signedFaceArea call.
|
|
256461
256458
|
*/
|
|
256462
|
-
static signedFaceArea(node) {
|
|
256459
|
+
static signedFaceArea(node) {
|
|
256460
|
+
return node.signedFaceArea();
|
|
256461
|
+
}
|
|
256463
256462
|
/**
|
|
256464
|
-
*
|
|
256465
|
-
* Return a summary structure data about face (or other numeric quantity if the caller's areaFunction returns other value)
|
|
256466
|
-
* * The default areaFunction computes area of polygonal face.
|
|
256463
|
+
* Return a summary of face data (e.g., area) as computed by the callback on the faces of the graph.
|
|
256467
256464
|
* * Callers with curved edge graphs must supply their own area function.
|
|
256468
|
-
* @param source graph or array of nodes to examine
|
|
256469
|
-
* @param collectAllNodes flag to pass to the SignedDataSummary constructor to control collection of nodes.
|
|
256470
|
-
* @param areaFunction function to
|
|
256465
|
+
* @param source graph or array of nodes to examine.
|
|
256466
|
+
* @param collectAllNodes flag to pass to the `SignedDataSummary` constructor to control collection of nodes.
|
|
256467
|
+
* @param areaFunction function to obtain area (or other numeric value). Default computes polygonal face area.
|
|
256471
256468
|
*/
|
|
256472
256469
|
static collectFaceAreaSummary(source, collectAllNodes = false, areaFunction = (node) => HalfEdgeGraphSearch.signedFaceArea(node)) {
|
|
256473
256470
|
const result = new _SignedDataSummary__WEBPACK_IMPORTED_MODULE_0__.SignedDataSummary(collectAllNodes);
|
|
@@ -256483,10 +256480,19 @@ class HalfEdgeGraphSearch {
|
|
|
256483
256480
|
return result;
|
|
256484
256481
|
}
|
|
256485
256482
|
/**
|
|
256486
|
-
*
|
|
256487
|
-
*
|
|
256488
|
-
*
|
|
256489
|
-
|
|
256483
|
+
* Search the graph for the face with the most negative area.
|
|
256484
|
+
* @param oneCandidateNodePerFace graph or an array containing one node from each face to be considered.
|
|
256485
|
+
* @returns node on the negative area face with largest absolute area, or `undefined` if no negative area face.
|
|
256486
|
+
*/
|
|
256487
|
+
static findMinimumAreaFace(oneCandidateNodePerFace, faceAreaFunction) {
|
|
256488
|
+
const summary = HalfEdgeGraphSearch.collectFaceAreaSummary(oneCandidateNodePerFace, false, faceAreaFunction);
|
|
256489
|
+
return summary.largestNegativeItem;
|
|
256490
|
+
}
|
|
256491
|
+
/**
|
|
256492
|
+
* Test if the graph is triangulated.
|
|
256493
|
+
* * Return `false` if:
|
|
256494
|
+
* * number of positive area faces with more than 3 edges is larger than `numPositiveExceptionsAllowed`.
|
|
256495
|
+
* * graph has more than 1 negative area face when `allowMultipleNegativeAreaFaces` is `false`.
|
|
256490
256496
|
* * 2-edge faces are ignored.
|
|
256491
256497
|
*/
|
|
256492
256498
|
static isTriangulatedCCW(source, allowMultipleNegativeAreaFaces = true, numPositiveExceptionsAllowed = 0) {
|
|
@@ -256520,24 +256526,41 @@ class HalfEdgeGraphSearch {
|
|
|
256520
256526
|
return true;
|
|
256521
256527
|
}
|
|
256522
256528
|
/**
|
|
256523
|
-
*
|
|
256524
|
-
*
|
|
256525
|
-
*
|
|
256526
|
-
*
|
|
256527
|
-
*
|
|
256528
|
-
* * It is entirely clear on all faces that are an odd number of face-to-face steps away from the seed.
|
|
256529
|
-
* @param seedEdge first edge to search.
|
|
256530
|
-
* @param visitMask mask applied to all faces as visited.
|
|
256531
|
-
* @param parityMask mask to apply (a) to first face, (b) to faces with alternating parity during the search.
|
|
256529
|
+
* Process a face during graph traversal.
|
|
256530
|
+
* @param faceSeed a node in the face.
|
|
256531
|
+
* @param mask mask to set on each node of the face.
|
|
256532
|
+
* @param allNodeStack array appended with each node of the face.
|
|
256533
|
+
* @param onePerFaceStack array appended with `faceSeed`.
|
|
256532
256534
|
*/
|
|
256533
|
-
static
|
|
256535
|
+
static pushAndMaskAllNodesInFace(faceSeed, mask, allNodeStack, onePerFaceStack) {
|
|
256536
|
+
onePerFaceStack.push(faceSeed);
|
|
256537
|
+
faceSeed.collectAroundFace((node) => {
|
|
256538
|
+
node.setMask(mask);
|
|
256539
|
+
allNodeStack.push(node);
|
|
256540
|
+
});
|
|
256541
|
+
}
|
|
256542
|
+
/**
|
|
256543
|
+
* Traverse (via Depth First Search) to all accessible faces from the given seed.
|
|
256544
|
+
* @param faceSeed first node to start the traverse.
|
|
256545
|
+
* @param visitMask mask applied to all faces as visited.
|
|
256546
|
+
* @param parityEdgeTester function to test if an edge is adjacent to two faces of opposite parity, e.g., a boundary
|
|
256547
|
+
* edge that separates an "interior" face and an "exterior" face. If `parityEdgeTester` is not supplied and `parityMask`
|
|
256548
|
+
* is supplied, the default parity rule is to alternate parity state in a "bullseye" pattern starting at the seed face,
|
|
256549
|
+
* with each successive concentric ring of faces at constant topological distance from the seed face receiving the
|
|
256550
|
+
* opposite parity state of the previous ring.
|
|
256551
|
+
* @param parityMask mask to apply to the first face and faces that share the same parity as the first face, as
|
|
256552
|
+
* determined by the parity rule. If this is `NULL_MASK`, there is no record of parity. If (non-null) parity mask
|
|
256553
|
+
* is given, on return it is entirely set or entirely clear around each face.
|
|
256554
|
+
* @returns an array that contains one representative node in each face of the connected component.
|
|
256555
|
+
*/
|
|
256556
|
+
static parityFloodFromSeed(faceSeed, visitMask, parityEdgeTester, parityMask) {
|
|
256534
256557
|
const faces = [];
|
|
256535
|
-
if (
|
|
256536
|
-
return faces; // empty
|
|
256558
|
+
if (faceSeed.isMaskSet(visitMask))
|
|
256559
|
+
return faces; // empty array
|
|
256537
256560
|
const allMasks = parityMask | visitMask;
|
|
256538
256561
|
const stack = [];
|
|
256539
|
-
//
|
|
256540
|
-
HalfEdgeGraphSearch.pushAndMaskAllNodesInFace(
|
|
256562
|
+
// the seed face is arbitrarily assigned the parity mask
|
|
256563
|
+
HalfEdgeGraphSearch.pushAndMaskAllNodesInFace(faceSeed, allMasks, stack, faces);
|
|
256541
256564
|
while (stack.length > 0) {
|
|
256542
256565
|
const p = stack.pop();
|
|
256543
256566
|
const mate = p.edgeMate;
|
|
@@ -256553,113 +256576,123 @@ class HalfEdgeGraphSearch {
|
|
|
256553
256576
|
return faces;
|
|
256554
256577
|
}
|
|
256555
256578
|
/**
|
|
256556
|
-
* *
|
|
256557
|
-
* *
|
|
256579
|
+
* * Correct the parity mask in the faces of a component.
|
|
256580
|
+
* * It is assumed that the parity mask is applied _consistently_ throughout the supplied faces, but maybe
|
|
256581
|
+
* not _correctly_.
|
|
256582
|
+
* * A consistently applied parity mask is "correct" if it is set on the negative area ("exterior") face of
|
|
256583
|
+
* a connected component.
|
|
256584
|
+
* * This method finds a face with negative area and toggles the mask throughout the input faces if this face
|
|
256585
|
+
* lacks the parity mask.
|
|
256558
256586
|
* * In a properly merged planar subdivision there should be only one true negative area face per component.
|
|
256559
|
-
* @param graph parent graph
|
|
256560
|
-
* @param parityMask mask which was previously set with alternating parity, but with an arbitrary start face.
|
|
256561
|
-
* @param faces array of faces to search.
|
|
256562
256587
|
*/
|
|
256563
|
-
static correctParityInSingleComponent(
|
|
256588
|
+
static correctParityInSingleComponent(parityMask, faces) {
|
|
256564
256589
|
const exteriorHalfEdge = HalfEdgeGraphSearch.findMinimumAreaFace(faces);
|
|
256565
256590
|
if (!exteriorHalfEdge) {
|
|
256591
|
+
// graph has all degenerate faces; do nothing
|
|
256566
256592
|
}
|
|
256567
|
-
else if (exteriorHalfEdge.isMaskSet(
|
|
256568
|
-
// all should be well
|
|
256593
|
+
else if (exteriorHalfEdge.isMaskSet(parityMask)) {
|
|
256594
|
+
// all should be well; nothing to do
|
|
256569
256595
|
}
|
|
256570
256596
|
else {
|
|
256571
|
-
// TOGGLE around the face (assuming all are consistent with the seed)
|
|
256572
256597
|
for (const faceSeed of faces) {
|
|
256573
|
-
if (faceSeed.isMaskSet(
|
|
256574
|
-
faceSeed.clearMaskAroundFace(
|
|
256598
|
+
if (faceSeed.isMaskSet(parityMask)) {
|
|
256599
|
+
faceSeed.clearMaskAroundFace(parityMask);
|
|
256575
256600
|
}
|
|
256576
256601
|
else {
|
|
256577
|
-
faceSeed.setMaskAroundFace(
|
|
256602
|
+
faceSeed.setMaskAroundFace(parityMask);
|
|
256578
256603
|
}
|
|
256579
256604
|
}
|
|
256580
256605
|
}
|
|
256581
256606
|
}
|
|
256582
|
-
/** Apply correctParityInSingleComponent to each array in components
|
|
256583
|
-
static correctParityInComponentArrays(
|
|
256584
|
-
if (
|
|
256607
|
+
/** Apply `correctParityInSingleComponent` to each array in components (quick exit if `parityMask` is `NULL_MASK`). */
|
|
256608
|
+
static correctParityInComponentArrays(parityMask, components) {
|
|
256609
|
+
if (parityMask === _Graph__WEBPACK_IMPORTED_MODULE_1__.HalfEdgeMask.NULL_MASK)
|
|
256585
256610
|
return;
|
|
256586
256611
|
for (const facesInComponent of components)
|
|
256587
|
-
HalfEdgeGraphSearch.correctParityInSingleComponent(
|
|
256588
|
-
}
|
|
256589
|
-
/**
|
|
256590
|
-
* Collect
|
|
256591
|
-
* @param graph graph to inspect
|
|
256592
|
-
* @param parityEdgeTester (optional) function to test if an edge is
|
|
256593
|
-
*
|
|
256612
|
+
HalfEdgeGraphSearch.correctParityInSingleComponent(parityMask, facesInComponent);
|
|
256613
|
+
}
|
|
256614
|
+
/**
|
|
256615
|
+
* Collect connected components of the graph (via Depth First Search).
|
|
256616
|
+
* @param graph graph to inspect.
|
|
256617
|
+
* @param parityEdgeTester (optional) function to test if an edge is adjacent to two faces of opposite parity,
|
|
256618
|
+
* e.g., a boundary edge that separates an "interior" face and an "exterior" face. If `parityEdgeTester` is not
|
|
256619
|
+
* supplied and `parityMask` is supplied, the default parity rule is to alternate parity state in a "bullseye"
|
|
256620
|
+
* pattern starting at the seed face, with each successive concentric ring of faces at constant topological
|
|
256621
|
+
* distance from the seed face receiving the opposite parity state of the previous ring.
|
|
256622
|
+
* @param parityMask (optional) mask to apply to the first face and faces that share the same parity as the
|
|
256623
|
+
* first face, as determined by the parity rule. If this is `NULL_MASK`, there is no record of parity. If
|
|
256624
|
+
* (non-null) parity mask is given, on return it is entirely set or entirely clear around each face.
|
|
256625
|
+
* @returns the components of the graph, each component represented by an array of nodes, one node per face
|
|
256626
|
+
* of the component. In other words, entry [i][j] is a HalfEdge in the j_th face loop of the i_th component.
|
|
256594
256627
|
*/
|
|
256595
256628
|
static collectConnectedComponentsWithExteriorParityMasks(graph, parityEdgeTester, parityMask = _Graph__WEBPACK_IMPORTED_MODULE_1__.HalfEdgeMask.NULL_MASK) {
|
|
256629
|
+
// Illustration of the algorithm can be found at geometry/internaldocs/Graph.md
|
|
256596
256630
|
const components = [];
|
|
256597
256631
|
const visitMask = _Graph__WEBPACK_IMPORTED_MODULE_1__.HalfEdgeMask.VISITED;
|
|
256598
256632
|
const allMasks = parityMask | visitMask;
|
|
256599
256633
|
graph.clearMask(allMasks);
|
|
256600
256634
|
for (const faceSeed of graph.allHalfEdges) {
|
|
256601
|
-
if (!faceSeed.isMaskSet(
|
|
256635
|
+
if (!faceSeed.isMaskSet(visitMask)) {
|
|
256602
256636
|
const newFaces = HalfEdgeGraphSearch.parityFloodFromSeed(faceSeed, visitMask, parityEdgeTester, parityMask);
|
|
256637
|
+
// parityFloodFromSeed does not return an empty array because it is called on an unvisited faceSeed
|
|
256603
256638
|
components.push(newFaces);
|
|
256604
256639
|
}
|
|
256605
256640
|
}
|
|
256606
|
-
HalfEdgeGraphSearch.correctParityInComponentArrays(
|
|
256641
|
+
HalfEdgeGraphSearch.correctParityInComponentArrays(parityMask, components);
|
|
256607
256642
|
return components;
|
|
256608
256643
|
}
|
|
256609
256644
|
/**
|
|
256610
|
-
* Test if (
|
|
256611
|
-
* @param seedNode any node on the face loop
|
|
256612
|
-
* @param
|
|
256613
|
-
* @param
|
|
256645
|
+
* Test if test point (xTest,yTest) is inside/outside a face or on an edge.
|
|
256646
|
+
* @param seedNode any node on the face loop.
|
|
256647
|
+
* @param xTest x coordinate of the test point.
|
|
256648
|
+
* @param yTest y coordinate of the test point.
|
|
256649
|
+
* @returns 0 if ON, 1 if IN, -1 if OUT.
|
|
256614
256650
|
*/
|
|
256615
|
-
static pointInOrOnFaceXY(seedNode,
|
|
256616
|
-
const context = new _XYParitySearchContext__WEBPACK_IMPORTED_MODULE_2__.XYParitySearchContext(
|
|
256617
|
-
// walk around looking for an accepted node to start the search (seedNode is usually ok
|
|
256651
|
+
static pointInOrOnFaceXY(seedNode, xTest, yTest) {
|
|
256652
|
+
const context = new _XYParitySearchContext__WEBPACK_IMPORTED_MODULE_2__.XYParitySearchContext(xTest, yTest);
|
|
256653
|
+
// walk around looking for an accepted node to start the search (seedNode is usually ok)
|
|
256618
256654
|
let nodeA = seedNode;
|
|
256619
256655
|
let nodeB = seedNode.faceSuccessor;
|
|
256620
256656
|
for (;; nodeA = nodeB) {
|
|
256621
256657
|
if (context.tryStartEdge(nodeA.x, nodeA.y, nodeB.x, nodeB.y))
|
|
256622
256658
|
break;
|
|
256623
256659
|
if (nodeB === seedNode) {
|
|
256624
|
-
//
|
|
256625
|
-
|
|
256660
|
+
// the test point and the face are all on line "y = yTest"
|
|
256661
|
+
const range = _geometry3d_Range__WEBPACK_IMPORTED_MODULE_3__.Range1d.createXX(nodeB.x, nodeB.faceSuccessor.x);
|
|
256662
|
+
return range.containsX(xTest) ? 0 : -1;
|
|
256626
256663
|
}
|
|
256627
256664
|
nodeB = nodeA.faceSuccessor;
|
|
256628
256665
|
}
|
|
256629
|
-
// nodeB is the real start node for search
|
|
256630
|
-
|
|
256631
|
-
let node = nodeB.faceSuccessor;
|
|
256666
|
+
// nodeB is the real start node for search, so stop when we revisit it. For each edge, accumulate parity and hits
|
|
256667
|
+
let nodeC = nodeB.faceSuccessor;
|
|
256632
256668
|
for (;;) {
|
|
256633
|
-
if (!context.advance(
|
|
256669
|
+
if (!context.advance(nodeC.x, nodeC.y)) {
|
|
256634
256670
|
return context.classifyCounts();
|
|
256635
256671
|
}
|
|
256636
|
-
if (
|
|
256672
|
+
if (nodeC === nodeB)
|
|
256637
256673
|
break;
|
|
256638
|
-
|
|
256674
|
+
nodeC = nodeC.faceSuccessor;
|
|
256639
256675
|
}
|
|
256640
256676
|
return context.classifyCounts();
|
|
256641
256677
|
}
|
|
256642
256678
|
/**
|
|
256643
|
-
*
|
|
256644
|
-
* *
|
|
256645
|
-
* * "Around the vertex" from nodeA means
|
|
256646
|
-
* * First look at nodeA.faceSuccessor;
|
|
256647
|
-
* * Then look at vertexPredecessor around that vertex loop.
|
|
256648
|
-
* * Each accepted node is passed to announceNode, and marked with the visit mask.
|
|
256649
|
-
* * The counter of the announceEdge function is zero for the first edge, then increases with each edge.
|
|
256679
|
+
* Collect boundary edges starting from `seed`.
|
|
256680
|
+
* * If `seed` is not a boundary node or is already visited, the function exists early.
|
|
256650
256681
|
* @param seed start node.
|
|
256651
|
-
* @param
|
|
256652
|
-
* @param
|
|
256682
|
+
* @param visitMask mask to set on processed nodes.
|
|
256683
|
+
* @param isBoundaryEdge function to test if an edge in a boundary edge.
|
|
256684
|
+
* @param announceEdgeInBoundary callback invoked on each edge in the boundary loop in order. The counter is zero
|
|
256685
|
+
* for the first edge, and incremented with each successive edge.
|
|
256653
256686
|
*/
|
|
256654
|
-
static collectExtendedBoundaryLoopFromSeed(seed, visitMask, isBoundaryEdge,
|
|
256687
|
+
static collectExtendedBoundaryLoopFromSeed(seed, visitMask, isBoundaryEdge, announceEdgeInBoundary) {
|
|
256655
256688
|
let counter = 0;
|
|
256656
256689
|
while (!seed.getMask(visitMask) && isBoundaryEdge(seed)) {
|
|
256657
|
-
|
|
256690
|
+
announceEdgeInBoundary(seed, counter++);
|
|
256658
256691
|
seed.setMask(visitMask);
|
|
256659
256692
|
const vertexBase = seed.faceSuccessor;
|
|
256660
256693
|
let candidateAroundVertex = vertexBase;
|
|
256661
256694
|
for (;;) {
|
|
256662
|
-
if (candidateAroundVertex.getMask(visitMask))
|
|
256695
|
+
if (candidateAroundVertex.getMask(visitMask)) // end of boundary loop
|
|
256663
256696
|
return;
|
|
256664
256697
|
if (isBoundaryEdge(candidateAroundVertex)) {
|
|
256665
256698
|
seed = candidateAroundVertex;
|
|
@@ -256667,23 +256700,22 @@ class HalfEdgeGraphSearch {
|
|
|
256667
256700
|
}
|
|
256668
256701
|
candidateAroundVertex = candidateAroundVertex.vertexPredecessor;
|
|
256669
256702
|
if (candidateAroundVertex === vertexBase)
|
|
256670
|
-
break;
|
|
256703
|
+
break; // prevent infinite loop in case exteriorMask is not set on the edge mate of the boundary edge
|
|
256671
256704
|
}
|
|
256672
256705
|
}
|
|
256673
256706
|
}
|
|
256674
256707
|
/**
|
|
256675
|
-
* Collect
|
|
256676
|
-
* *
|
|
256677
|
-
* *
|
|
256678
|
-
*
|
|
256679
|
-
*
|
|
256680
|
-
*
|
|
256681
|
-
*
|
|
256682
|
-
* @
|
|
256683
|
-
* @param isBoundaryNode
|
|
256684
|
-
* @param announceNode
|
|
256708
|
+
* Collect boundary edges in the graph.
|
|
256709
|
+
* * A boundary edge is defined by `exteriorMask` being set on only its "exterior" edge mate.
|
|
256710
|
+
* * Each boundary edge is identified in the output by its edge mate that lacks `exteriorMask`.
|
|
256711
|
+
* * Each inner array is ordered in the output so that its boundary edges form a connected path. If `exteriorMask`
|
|
256712
|
+
* is preset consistently around each "exterior" face, these paths are loops.
|
|
256713
|
+
* @param graph the graph to query
|
|
256714
|
+
* @param exteriorMask mask preset on exactly one side of boundary edges
|
|
256715
|
+
* @returns array of boundary loops, each loop an array of the unmasked mates of boundary edges
|
|
256685
256716
|
*/
|
|
256686
256717
|
static collectExtendedBoundaryLoopsInGraph(graph, exteriorMask) {
|
|
256718
|
+
// Illustration of the algorithm can be found at geometry/internaldocs/Graph.md
|
|
256687
256719
|
const loops = [];
|
|
256688
256720
|
const visitMask = graph.grabMask(true);
|
|
256689
256721
|
const isBoundaryEdge = (edge) => {
|
|
@@ -259168,10 +259200,10 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
259168
259200
|
/**
|
|
259169
259201
|
* Class to accumulate statistics about a stream of signed numbers with tag items.
|
|
259170
259202
|
* * All sums, counts, extrema, and item values are initialized to zero in the constructor.
|
|
259171
|
-
* * Each call to `announceItem
|
|
259203
|
+
* * Each call to `announceItem(item, value)` updates the various sums, counts, and extrema.
|
|
259172
259204
|
*/
|
|
259173
259205
|
class SignedDataSummary {
|
|
259174
|
-
/**
|
|
259206
|
+
/** Setup with zero sums and optional arrays. */
|
|
259175
259207
|
constructor(createArrays) {
|
|
259176
259208
|
this.positiveSum = this.negativeSum = 0.0;
|
|
259177
259209
|
this.numPositive = this.numNegative = this.numZero = 0.0;
|
|
@@ -259182,7 +259214,7 @@ class SignedDataSummary {
|
|
|
259182
259214
|
this.zeroItemArray = [];
|
|
259183
259215
|
}
|
|
259184
259216
|
}
|
|
259185
|
-
/**
|
|
259217
|
+
/** Update with an item and its data value. */
|
|
259186
259218
|
announceItem(item, data) {
|
|
259187
259219
|
if (data < 0) {
|
|
259188
259220
|
this.numNegative++;
|
|
@@ -260407,127 +260439,129 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
260407
260439
|
* @module Topology
|
|
260408
260440
|
*/
|
|
260409
260441
|
/**
|
|
260410
|
-
*
|
|
260442
|
+
* `XYParitySearchContext` is an internal class for callers that can feed points (without extracting to array structures)
|
|
260411
260443
|
* * Most will be via static methods which handle a specific data source.
|
|
260412
|
-
* * PolygonOps.classifyPointInPolygon
|
|
260413
|
-
* * HalfEdgeGraphSearch.pointInOrOnFaceXY
|
|
260444
|
+
* * PolygonOps.classifyPointInPolygon(x,y,points: XAndY[])
|
|
260445
|
+
* * HalfEdgeGraphSearch.pointInOrOnFaceXY(halfEdgeOnFace, x, y)
|
|
260414
260446
|
* Use pattern:
|
|
260415
|
-
* * Caller must be able walk around polygon producing x,y coordinates (possibly transformed from actual polygon)
|
|
260447
|
+
* * Caller must be able to walk around polygon producing x,y coordinates (possibly transformed from actual polygon).
|
|
260416
260448
|
* * Caller announce edges to tryStartEdge until finding one acceptable to the search.
|
|
260417
260449
|
* * Caller then passes additional points up to and including both x0,y0 and x1, y1 of the accepted start edge.
|
|
260418
260450
|
* Call sequence is:
|
|
260419
|
-
*
|
|
260420
|
-
*
|
|
260421
|
-
*
|
|
260422
|
-
*
|
|
260451
|
+
* * `context = new XYParitySearchContext`
|
|
260452
|
+
* * `repeat { acquire edge (x0,y0) (x1,y1) } until context.tryStartEdge(x0,y0,x1,y1);`
|
|
260453
|
+
* * `for each (x,y) beginning AFTER x1,y1 and ending with (x1,y1) context.advance (x,y)`
|
|
260454
|
+
* * `return context.classifyCounts();`
|
|
260423
260455
|
*/
|
|
260424
260456
|
class XYParitySearchContext {
|
|
260425
260457
|
/**
|
|
260426
260458
|
* Create a new searcher for specified test point.
|
|
260427
|
-
* @param xTest x coordinate of test point
|
|
260428
|
-
* @param yTest y coordinate of test point
|
|
260459
|
+
* @param xTest x coordinate of test point.
|
|
260460
|
+
* @param yTest y coordinate of test point.
|
|
260429
260461
|
*/
|
|
260430
260462
|
constructor(xTest, yTest) {
|
|
260431
260463
|
this.xTest = xTest;
|
|
260432
260464
|
this.yTest = yTest;
|
|
260433
|
-
this.u0 = this.v0 = this.u1 = this.v1 = 0; //
|
|
260465
|
+
this.u0 = this.v0 = this.u1 = this.v1 = 0; // not valid for search; caller must satisfy tryStartEdge
|
|
260434
260466
|
this.numLeftCrossing = this.numRightCrossing = 0;
|
|
260435
260467
|
this.numHit = 0;
|
|
260436
260468
|
}
|
|
260437
|
-
/**
|
|
260438
|
-
* test if x,y is a safe first coordinate to start the search.
|
|
260439
|
-
* * safe start must have non-zero y so that final point test (return to x0,y0) does not need look back for exact crossing logic.
|
|
260440
|
-
* @param x
|
|
260441
|
-
* @param y
|
|
260442
|
-
*/
|
|
260469
|
+
/** Test if parity processing can begin with this edge. */
|
|
260443
260470
|
tryStartEdge(x0, y0, x1, y1) {
|
|
260444
260471
|
if (y0 !== this.yTest) {
|
|
260445
260472
|
this.u0 = x0 - this.xTest;
|
|
260446
260473
|
this.v0 = y0 - this.yTest;
|
|
260447
260474
|
this.u1 = x1 - this.xTest;
|
|
260448
260475
|
this.v1 = y1 - this.yTest;
|
|
260449
|
-
return true;
|
|
260476
|
+
return true; // we won't need wraparound logic to process the final edge ending at (x0,y0)
|
|
260450
260477
|
}
|
|
260451
260478
|
return false;
|
|
260452
260479
|
}
|
|
260453
|
-
/**
|
|
260454
|
-
|
|
260455
|
-
|
|
260456
|
-
|
|
260457
|
-
|
|
260458
|
-
|
|
260459
|
-
|
|
260480
|
+
/** Update local coordinates: the current edge becomes the previous edge. */
|
|
260481
|
+
updateUV01(u2, v2) {
|
|
260482
|
+
this.u0 = this.u1;
|
|
260483
|
+
this.v0 = this.v1;
|
|
260484
|
+
this.u1 = u2;
|
|
260485
|
+
this.v1 = v2;
|
|
260486
|
+
return true;
|
|
260487
|
+
}
|
|
260488
|
+
/**
|
|
260489
|
+
* Process the current edge ending at (x2,y2).
|
|
260490
|
+
* * Accumulate left/right parity of the test point wrt to the polygon. These counts track the number of polygon crossings
|
|
260491
|
+
* of the left and right horizontal rays emanating from the test point. After all edges are processed, if either count is
|
|
260492
|
+
* odd/even, the test point is inside/outside the polygon (see [[classifyCounts]]).
|
|
260493
|
+
* * Check whether the test point lies on the edge.
|
|
260494
|
+
* @returns whether caller should continue processing with the next edge. In particular, `false` if we have an exact hit.
|
|
260495
|
+
*/
|
|
260496
|
+
advance(x2, y2) {
|
|
260497
|
+
// In this method we use local u,v coordinates obtained by translating the test point to the origin.
|
|
260498
|
+
// This simplifies our computations:
|
|
260499
|
+
// * left (right) parity is incremented if the current edge crosses the u-axis at u<0 (u>0)
|
|
260500
|
+
// * we have an exact hit if the current edge crosses the u-axis at u=0
|
|
260501
|
+
const u2 = x2 - this.xTest;
|
|
260502
|
+
const v2 = y2 - this.yTest;
|
|
260503
|
+
const p = v2 * this.v1;
|
|
260460
260504
|
if (p > 0) {
|
|
260461
|
-
//
|
|
260462
|
-
this.
|
|
260463
|
-
this.v0 = this.v1;
|
|
260464
|
-
this.u1 = u;
|
|
260465
|
-
this.v1 = v;
|
|
260466
|
-
return true;
|
|
260505
|
+
// Current edge does not cross u-axis.
|
|
260506
|
+
return this.updateUV01(u2, v2);
|
|
260467
260507
|
}
|
|
260468
260508
|
if (p < 0) {
|
|
260469
|
-
//
|
|
260470
|
-
//
|
|
260471
|
-
const
|
|
260472
|
-
const uCross = this.u1 +
|
|
260509
|
+
// Current edge crosses the u-axis at edge parameter 0 < lambda < 1 by the Intermediate Value Theorem.
|
|
260510
|
+
// Solve for lambda in 0 = v1 + lambda (v2 - v1), then use it to compute the u-value of the crossing.
|
|
260511
|
+
const lambda = -this.v1 / (v2 - this.v1);
|
|
260512
|
+
const uCross = this.u1 + lambda * (u2 - this.u1);
|
|
260473
260513
|
if (uCross === 0.0) {
|
|
260474
|
-
this.numHit++;
|
|
260514
|
+
this.numHit++; // Current edge crosses at the origin.
|
|
260475
260515
|
return false;
|
|
260476
260516
|
}
|
|
260477
260517
|
if (uCross > 0)
|
|
260478
260518
|
this.numRightCrossing++;
|
|
260479
260519
|
else
|
|
260480
260520
|
this.numLeftCrossing++;
|
|
260481
|
-
this.
|
|
260482
|
-
this.v0 = this.v1;
|
|
260483
|
-
this.u1 = u;
|
|
260484
|
-
this.v1 = v;
|
|
260485
|
-
return true;
|
|
260521
|
+
return this.updateUV01(u2, v2);
|
|
260486
260522
|
}
|
|
260487
|
-
//
|
|
260488
|
-
if (
|
|
260523
|
+
// At this point, at least one endpoint of the current edge lies on the u-axis.
|
|
260524
|
+
if (v2 === 0.0) {
|
|
260489
260525
|
if (this.v1 === 0.0) {
|
|
260490
|
-
|
|
260491
|
-
|
|
260492
|
-
this.numHit++;
|
|
260526
|
+
if (u2 * this.u1 <= 0.0) {
|
|
260527
|
+
this.numHit++; // Current edge lies on u-axis and contains the origin.
|
|
260493
260528
|
return false;
|
|
260494
260529
|
}
|
|
260495
|
-
//
|
|
260496
|
-
//
|
|
260497
|
-
this.u1 =
|
|
260498
|
-
this.v1 =
|
|
260530
|
+
// Current edge lies on the u-axis to one side of the origin.
|
|
260531
|
+
// This edge doesn't contribute to parity computations, so advance past it.
|
|
260532
|
+
this.u1 = u2;
|
|
260533
|
+
this.v1 = v2;
|
|
260499
260534
|
return true;
|
|
260500
260535
|
}
|
|
260501
|
-
|
|
260502
|
-
|
|
260503
|
-
|
|
260504
|
-
|
|
260505
|
-
|
|
260506
|
-
return
|
|
260536
|
+
if (u2 === 0.0) {
|
|
260537
|
+
this.numHit++; // Current edge ends at the origin.
|
|
260538
|
+
return false;
|
|
260539
|
+
}
|
|
260540
|
+
// Current edge ends on the u-axis away from the origin.
|
|
260541
|
+
return this.updateUV01(u2, v2);
|
|
260507
260542
|
}
|
|
260508
|
-
//
|
|
260509
|
-
|
|
260510
|
-
|
|
260511
|
-
|
|
260512
|
-
if (this.u1 > 0) {
|
|
260513
|
-
if (q < 0)
|
|
260514
|
-
this.numRightCrossing++;
|
|
260543
|
+
// At this point, the current edge starts at the u-axis.
|
|
260544
|
+
if (this.u1 === 0.0) {
|
|
260545
|
+
this.numHit++; // Current edge starts at the origin.
|
|
260546
|
+
return false;
|
|
260515
260547
|
}
|
|
260516
|
-
|
|
260517
|
-
|
|
260548
|
+
// At this point, the current edge starts on the u-axis away from the origin.
|
|
260549
|
+
const q = this.v0 * v2;
|
|
260550
|
+
if (q < 0) {
|
|
260551
|
+
// The current edge and the previous edge lie on opposite sides of the u-axis, so we have a parity change.
|
|
260552
|
+
if (this.u1 > 0)
|
|
260553
|
+
this.numRightCrossing++;
|
|
260554
|
+
else
|
|
260518
260555
|
this.numLeftCrossing++;
|
|
260519
260556
|
}
|
|
260520
|
-
|
|
260521
|
-
this.
|
|
260522
|
-
this.u1 = u;
|
|
260523
|
-
this.v1 = v;
|
|
260524
|
-
return true;
|
|
260557
|
+
// The current edge and the previous edge lie on the same sides of the u-axis, so no parity change.
|
|
260558
|
+
return this.updateUV01(u2, v2);
|
|
260525
260559
|
}
|
|
260526
260560
|
/**
|
|
260527
260561
|
* Return classification as ON, IN, or OUT according to hit and crossing counts.
|
|
260528
|
-
* * Any nonzero hit count is ON
|
|
260562
|
+
* * Any nonzero hit count is ON.
|
|
260529
260563
|
* * Otherwise IN if left crossing count is odd.
|
|
260530
|
-
* @return 0 if ON, 1 if IN, -1 if OUT
|
|
260564
|
+
* @return 0 if ON, 1 if IN, -1 if OUT.
|
|
260531
260565
|
*/
|
|
260532
260566
|
classifyCounts() {
|
|
260533
260567
|
if (this.numHit > 0)
|
|
@@ -290240,7 +290274,7 @@ module.exports = JSON.parse('{"name":"axios","version":"0.21.4","description":"P
|
|
|
290240
290274
|
/***/ ((module) => {
|
|
290241
290275
|
|
|
290242
290276
|
"use strict";
|
|
290243
|
-
module.exports = JSON.parse('{"name":"@itwin/core-frontend","version":"4.4.0-dev.
|
|
290277
|
+
module.exports = JSON.parse('{"name":"@itwin/core-frontend","version":"4.4.0-dev.17","description":"iTwin.js frontend components","main":"lib/cjs/core-frontend.js","module":"lib/esm/core-frontend.js","typings":"lib/cjs/core-frontend","license":"MIT","scripts":{"build":"npm run -s copy:public && npm run -s build:cjs && npm run -s build:esm && npm run -s webpackWorkers && npm run -s copy:workers","build:cjs":"npm run -s copy:js:cjs && tsc 1>&2 --outDir lib/cjs","build:esm":"npm run -s copy:js:esm && tsc 1>&2 --module ES2020 --outDir lib/esm","clean":"rimraf lib .rush/temp/package-deps*.json","copy:public":"cpx \\"./src/public/**/*\\" ./lib/public","copy:js:cjs":"cpx \\"./src/**/*.js\\" ./lib/cjs","copy:js:esm":"cpx \\"./src/**/*.js\\" ./lib/esm","copy:workers":"cpx \\"./lib/workers/webpack/parse-imdl-worker.js\\" ./lib/public/scripts","docs":"betools docs --includes=../../generated-docs/extract --json=../../generated-docs/core/core-frontend/file.json --tsIndexFile=./core-frontend.ts --onlyJson --excludes=webgl/**/*,**/map/*.d.ts,**/tile/*.d.ts,**/*-css.ts","extract-api":"betools extract-api --entry=core-frontend && npm run extract-extension-api","extract-extension-api":"eslint -c extraction.eslint.config.js \\"./src/**/*.ts\\" 1>&2","lint":"eslint -f visualstudio \\"./src/**/*.ts\\" 1>&2","pseudolocalize":"betools pseudolocalize --englishDir ./src/public/locales/en --out ./public/locales/en-PSEUDO","test":"npm run -s webpackTests && certa -r chrome","cover":"npm -s test","test:debug":"certa -r chrome --debug","webpackTests":"webpack --config ./src/test/utils/webpack.config.js 1>&2 && npm run -s webpackTestWorker","webpackTestWorker":"webpack --config ./src/test/worker/webpack.config.js 1>&2 && cpx \\"./lib/test/test-worker.js\\" ./lib/test","webpackWorkers":"webpack --config ./src/workers/ImdlParser/webpack.config.js 1>&2"},"repository":{"type":"git","url":"https://github.com/iTwin/itwinjs-core.git","directory":"core/frontend"},"keywords":["Bentley","BIM","iModel","digital-twin","iTwin"],"author":{"name":"Bentley Systems, Inc.","url":"http://www.bentley.com"},"peerDependencies":{"@itwin/appui-abstract":"workspace:^4.4.0-dev.17","@itwin/core-bentley":"workspace:^4.4.0-dev.17","@itwin/core-common":"workspace:^4.4.0-dev.17","@itwin/core-geometry":"workspace:^4.4.0-dev.17","@itwin/core-orbitgt":"workspace:^4.4.0-dev.17","@itwin/core-quantity":"workspace:^4.4.0-dev.17"},"//devDependencies":["NOTE: All peerDependencies should also be listed as devDependencies since peerDependencies are not considered by npm install","NOTE: All tools used by scripts in this package must be listed as devDependencies"],"devDependencies":{"@itwin/appui-abstract":"workspace:*","@itwin/build-tools":"workspace:*","@itwin/core-bentley":"workspace:*","@itwin/core-common":"workspace:*","@itwin/core-geometry":"workspace:*","@itwin/core-orbitgt":"workspace:*","@itwin/core-quantity":"workspace:*","@itwin/certa":"workspace:*","@itwin/eslint-plugin":"4.0.0-dev.44","@types/chai":"4.3.1","@types/chai-as-promised":"^7","@types/mocha":"^10.0.6","@types/sinon":"^17.0.2","babel-loader":"~8.2.5","babel-plugin-istanbul":"~6.1.1","chai":"^4.3.10","chai-as-promised":"^7.1.1","cpx2":"^3.0.0","eslint":"^8.44.0","glob":"^7.1.2","mocha":"^10.2.0","nyc":"^15.1.0","rimraf":"^3.0.2","sinon":"^17.0.1","source-map-loader":"^4.0.0","typescript":"~5.0.2","typemoq":"^2.1.0","webpack":"^5.76.0"},"//dependencies":["NOTE: these dependencies should be only for things that DO NOT APPEAR IN THE API","NOTE: core-frontend should remain UI technology agnostic, so no react/angular dependencies are allowed"],"dependencies":{"@itwin/cloud-agnostic-core":"^2.1.0","@itwin/object-storage-core":"^2.2.2","@itwin/core-i18n":"workspace:*","@itwin/core-telemetry":"workspace:*","@itwin/webgl-compatibility":"workspace:*","@loaders.gl/core":"^3.1.6","@loaders.gl/draco":"^3.1.6","fuse.js":"^3.3.0","wms-capabilities":"0.4.0"},"nyc":{"extends":"./node_modules/@itwin/build-tools/.nycrc"}}');
|
|
290244
290278
|
|
|
290245
290279
|
/***/ })
|
|
290246
290280
|
|