@2112-lab/central-plant 0.1.39 → 0.1.41
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/dist/bundle/index.js +7991 -7054
- package/dist/cjs/src/core/centralPlant.js +48 -3
- package/dist/cjs/src/core/centralPlantInternals.js +75 -566
- package/dist/cjs/src/core/sceneViewer.js +38 -13
- package/dist/cjs/src/index.js +6 -4
- package/dist/cjs/src/managers/components/pathfindingManager.js +75 -60
- package/dist/cjs/src/managers/components/transformOperationsManager.js +929 -0
- package/dist/cjs/src/managers/controls/keyboardControlsManager.js +57 -1
- package/dist/cjs/src/managers/controls/transformControls.js +11 -3
- package/dist/cjs/src/managers/controls/transformControlsManager.js +563 -263
- package/dist/cjs/src/managers/pathfinding/ConnectorManager.js +385 -0
- package/dist/cjs/src/managers/pathfinding/PathIntersectionDetector.js +387 -0
- package/dist/cjs/src/managers/pathfinding/PathRenderingManager.js +401 -0
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +378 -0
- package/dist/cjs/src/managers/pathfinding/sceneDataManager.js +256 -0
- package/dist/cjs/src/managers/scene/animationManager.js +145 -0
- package/dist/cjs/src/managers/scene/sceneExportManager.js +14 -13
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +516 -21
- package/dist/cjs/src/managers/scene/sceneTooltipsManager.js +1 -8
- package/dist/cjs/src/managers/system/operationHistoryManager.js +414 -0
- package/dist/cjs/src/managers/system/settingsManager.js +2 -1
- package/dist/cjs/src/utils/objectTypes.js +5 -7
- package/dist/esm/src/core/centralPlant.js +48 -3
- package/dist/esm/src/core/centralPlantInternals.js +76 -567
- package/dist/esm/src/core/sceneViewer.js +38 -13
- package/dist/esm/src/index.js +4 -3
- package/dist/esm/src/managers/components/pathfindingManager.js +75 -60
- package/dist/esm/src/managers/components/transformOperationsManager.js +904 -0
- package/dist/esm/src/managers/controls/keyboardControlsManager.js +57 -1
- package/dist/esm/src/managers/controls/transformControls.js +11 -3
- package/dist/esm/src/managers/controls/transformControlsManager.js +564 -264
- package/dist/esm/src/managers/pathfinding/ConnectorManager.js +361 -0
- package/dist/esm/src/managers/pathfinding/PathIntersectionDetector.js +363 -0
- package/dist/esm/src/managers/pathfinding/PathRenderingManager.js +377 -0
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +374 -0
- package/dist/esm/src/managers/pathfinding/sceneDataManager.js +232 -0
- package/dist/esm/src/managers/scene/animationManager.js +141 -0
- package/dist/esm/src/managers/scene/sceneExportManager.js +14 -13
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +516 -21
- package/dist/esm/src/managers/scene/sceneTooltipsManager.js +1 -8
- package/dist/esm/src/managers/system/operationHistoryManager.js +409 -0
- package/dist/esm/src/managers/system/settingsManager.js +2 -1
- package/dist/esm/src/utils/objectTypes.js +5 -7
- package/dist/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { createClass as _createClass, toConsumableArray as _toConsumableArray, classCallCheck as _classCallCheck } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PathIntersectionDetector - Detects intersections between pipe paths
|
|
6
|
+
*
|
|
7
|
+
* This class handles all intersection detection logic for both computed paths
|
|
8
|
+
* (from pathfinding) and manual segments (user-positioned pipes).
|
|
9
|
+
*
|
|
10
|
+
* @class PathIntersectionDetector
|
|
11
|
+
*/
|
|
12
|
+
var PathIntersectionDetector = /*#__PURE__*/function () {
|
|
13
|
+
/**
|
|
14
|
+
* Create a new PathIntersectionDetector
|
|
15
|
+
* @param {Object} sceneViewer - Reference to the scene viewer
|
|
16
|
+
*/
|
|
17
|
+
function PathIntersectionDetector(sceneViewer) {
|
|
18
|
+
_classCallCheck(this, PathIntersectionDetector);
|
|
19
|
+
this.sceneViewer = sceneViewer;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Check for intersections between paths
|
|
24
|
+
* @param {Array} paths - Array of path objects from pathfinder
|
|
25
|
+
* @param {number} tolerance - Distance tolerance for considering pipes as intersecting (default: 0.2)
|
|
26
|
+
* @param {boolean} includeManualSegments - Whether to include manual segments in the check (default: true)
|
|
27
|
+
* @returns {Object} Intersection results
|
|
28
|
+
* @property {boolean} hasIntersections - Whether any intersections were found
|
|
29
|
+
* @property {Array<Object>} intersections - Array of intersection details
|
|
30
|
+
* @property {number} count - Total number of intersections found
|
|
31
|
+
*/
|
|
32
|
+
return _createClass(PathIntersectionDetector, [{
|
|
33
|
+
key: "checkPathIntersections",
|
|
34
|
+
value: function checkPathIntersections(paths) {
|
|
35
|
+
var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.2;
|
|
36
|
+
var includeManualSegments = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
37
|
+
var intersections = [];
|
|
38
|
+
|
|
39
|
+
// Convert all paths to line segments for comparison
|
|
40
|
+
var pathSegments = paths.map(function (pathData, pathIndex) {
|
|
41
|
+
if (!pathData.path || pathData.path.length < 2) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
var segments = [];
|
|
45
|
+
var pathPoints = pathData.path.map(function (point) {
|
|
46
|
+
if (point instanceof THREE.Vector3) {
|
|
47
|
+
return point.clone();
|
|
48
|
+
} else if (Array.isArray(point)) {
|
|
49
|
+
return new THREE.Vector3().fromArray(point);
|
|
50
|
+
} else if (point.x !== undefined && point.y !== undefined && point.z !== undefined) {
|
|
51
|
+
return new THREE.Vector3(point.x, point.y, point.z);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}).filter(function (p) {
|
|
55
|
+
return p !== null;
|
|
56
|
+
});
|
|
57
|
+
for (var i = 0; i < pathPoints.length - 1; i++) {
|
|
58
|
+
segments.push({
|
|
59
|
+
start: pathPoints[i],
|
|
60
|
+
end: pathPoints[i + 1],
|
|
61
|
+
pathIndex: pathIndex,
|
|
62
|
+
segmentIndex: i,
|
|
63
|
+
pathFrom: pathData.from,
|
|
64
|
+
pathTo: pathData.to,
|
|
65
|
+
isFirstSegment: i === 0,
|
|
66
|
+
isLastSegment: i === pathPoints.length - 2,
|
|
67
|
+
isManual: false // Computed path segment
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return segments;
|
|
71
|
+
}).filter(function (s) {
|
|
72
|
+
return s !== null;
|
|
73
|
+
}).flat();
|
|
74
|
+
|
|
75
|
+
// Add manual segments if requested
|
|
76
|
+
if (includeManualSegments) {
|
|
77
|
+
var manualSegments = this._collectManualSegments(pathSegments.length);
|
|
78
|
+
pathSegments.push.apply(pathSegments, _toConsumableArray(manualSegments));
|
|
79
|
+
console.log("\uD83D\uDCE6 Added ".concat(manualSegments.length, " manual segment(s) to intersection check"));
|
|
80
|
+
}
|
|
81
|
+
console.log("\uD83D\uDD0D Checking ".concat(pathSegments.length, " segments for intersections..."));
|
|
82
|
+
|
|
83
|
+
// Check each pair of segments
|
|
84
|
+
for (var i = 0; i < pathSegments.length; i++) {
|
|
85
|
+
for (var j = i + 1; j < pathSegments.length; j++) {
|
|
86
|
+
var seg1 = pathSegments[i];
|
|
87
|
+
var seg2 = pathSegments[j];
|
|
88
|
+
|
|
89
|
+
// Skip if segments are from the same path
|
|
90
|
+
if (seg1.pathIndex === seg2.pathIndex) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check if segments intersect
|
|
95
|
+
var intersection = this._checkLineSegmentIntersection(seg1.start, seg1.end, seg2.start, seg2.end, tolerance);
|
|
96
|
+
if (intersection) {
|
|
97
|
+
// Check if this is a shared endpoint (connector/gateway)
|
|
98
|
+
// Paths naturally touch at shared connectors - this is not an intersection
|
|
99
|
+
var endpointTolerance = 0.01; // Very small tolerance for endpoint matching
|
|
100
|
+
var touchingAtEndpoint = this._areSegmentsTouchingAtSharedEndpoint(seg1, seg2, endpointTolerance);
|
|
101
|
+
if (touchingAtEndpoint) {
|
|
102
|
+
console.log("\u2139\uFE0F Segments share endpoint (not an intersection): ".concat(seg1.pathFrom, " \u2194 ").concat(seg2.pathFrom));
|
|
103
|
+
continue; // Skip this - it's a valid shared connection point
|
|
104
|
+
}
|
|
105
|
+
intersections.push({
|
|
106
|
+
path1: {
|
|
107
|
+
from: seg1.pathFrom,
|
|
108
|
+
to: seg1.pathTo,
|
|
109
|
+
segmentIndex: seg1.segmentIndex,
|
|
110
|
+
isManual: seg1.isManual
|
|
111
|
+
},
|
|
112
|
+
path2: {
|
|
113
|
+
from: seg2.pathFrom,
|
|
114
|
+
to: seg2.pathTo,
|
|
115
|
+
segmentIndex: seg2.segmentIndex,
|
|
116
|
+
isManual: seg2.isManual
|
|
117
|
+
},
|
|
118
|
+
point: intersection.point,
|
|
119
|
+
distance: intersection.distance,
|
|
120
|
+
type: intersection.type
|
|
121
|
+
});
|
|
122
|
+
var seg1Type = seg1.isManual ? 'manual' : 'computed';
|
|
123
|
+
var seg2Type = seg2.isManual ? 'manual' : 'computed';
|
|
124
|
+
console.log("\u26A0\uFE0F Intersection found between paths:\n Path 1 (".concat(seg1Type, "): ").concat(seg1.pathFrom, " \u2192 ").concat(seg1.pathTo, " (segment ").concat(seg1.segmentIndex, ")\n Path 2 (").concat(seg2Type, "): ").concat(seg2.pathFrom, " \u2192 ").concat(seg2.pathTo, " (segment ").concat(seg2.segmentIndex, ")\n Distance: ").concat(intersection.distance.toFixed(4), "\n Type: ").concat(intersection.type));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
var result = {
|
|
129
|
+
hasIntersections: intersections.length > 0,
|
|
130
|
+
intersections: intersections,
|
|
131
|
+
count: intersections.length
|
|
132
|
+
};
|
|
133
|
+
if (result.hasIntersections) {
|
|
134
|
+
console.log("\uD83D\uDEA8 Found ".concat(result.count, " intersection(s) between paths"));
|
|
135
|
+
} else {
|
|
136
|
+
console.log("\u2705 No path intersections detected");
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Collect manual segments from the scene and convert them to path segments format
|
|
143
|
+
* @private
|
|
144
|
+
* @param {number} startingPathIndex - The starting index for manual segment paths
|
|
145
|
+
* @returns {Array} Array of segment objects in the same format as computed paths
|
|
146
|
+
*/
|
|
147
|
+
}, {
|
|
148
|
+
key: "_collectManualSegments",
|
|
149
|
+
value: function _collectManualSegments(startingPathIndex) {
|
|
150
|
+
var _this = this;
|
|
151
|
+
var manualSegments = [];
|
|
152
|
+
var sceneViewer = this.sceneViewer;
|
|
153
|
+
var pathIndex = startingPathIndex;
|
|
154
|
+
|
|
155
|
+
// Traverse the scene to find manual segments (lowercase "Segment-")
|
|
156
|
+
sceneViewer.scene.traverse(function (obj) {
|
|
157
|
+
var _obj$userData, _obj$userData2;
|
|
158
|
+
if (obj.uuid && obj.uuid.startsWith('Segment-') && ((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'segment' && ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.isDeclared) === true) {
|
|
159
|
+
// Calculate segment endpoints from the cylinder geometry
|
|
160
|
+
var endpoints = _this._calculateSegmentEndpoints(obj);
|
|
161
|
+
|
|
162
|
+
// Create segment object in the same format as computed paths
|
|
163
|
+
manualSegments.push({
|
|
164
|
+
start: endpoints.start,
|
|
165
|
+
end: endpoints.end,
|
|
166
|
+
pathIndex: pathIndex,
|
|
167
|
+
segmentIndex: 0,
|
|
168
|
+
// Manual segments are single-segment paths
|
|
169
|
+
pathFrom: obj.userData.pathFrom || obj.uuid,
|
|
170
|
+
pathTo: obj.userData.pathTo || obj.uuid,
|
|
171
|
+
isFirstSegment: true,
|
|
172
|
+
isLastSegment: true,
|
|
173
|
+
isManual: true,
|
|
174
|
+
// Flag to identify manual segments
|
|
175
|
+
segmentUuid: obj.uuid
|
|
176
|
+
});
|
|
177
|
+
pathIndex++;
|
|
178
|
+
console.log("\uD83D\uDCE6 Collected manual segment: ".concat(obj.uuid));
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return manualSegments;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Calculate the start and end points of a pipe segment in world coordinates
|
|
186
|
+
* @private
|
|
187
|
+
* @param {THREE.Object3D} segment - The pipe segment
|
|
188
|
+
* @returns {Object} Object with start and end points
|
|
189
|
+
*/
|
|
190
|
+
}, {
|
|
191
|
+
key: "_calculateSegmentEndpoints",
|
|
192
|
+
value: function _calculateSegmentEndpoints(segment) {
|
|
193
|
+
// Get the segment's geometry to determine its length and orientation
|
|
194
|
+
var geometry = segment.geometry;
|
|
195
|
+
var length = geometry.parameters.height || 1;
|
|
196
|
+
|
|
197
|
+
// Calculate start and end points based on segment position and orientation
|
|
198
|
+
var startPoint = new THREE.Vector3();
|
|
199
|
+
var endPoint = new THREE.Vector3();
|
|
200
|
+
|
|
201
|
+
// Get the segment's direction vector
|
|
202
|
+
var direction = new THREE.Vector3(0, 1, 0);
|
|
203
|
+
direction.applyQuaternion(segment.quaternion);
|
|
204
|
+
|
|
205
|
+
// Calculate start point (half length back from center)
|
|
206
|
+
startPoint.copy(segment.position).sub(direction.clone().multiplyScalar(length / 2));
|
|
207
|
+
|
|
208
|
+
// Calculate end point (half length forward from center)
|
|
209
|
+
endPoint.copy(segment.position).add(direction.clone().multiplyScalar(length / 2));
|
|
210
|
+
return {
|
|
211
|
+
start: startPoint,
|
|
212
|
+
end: endPoint
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Check if two segments are touching at a shared endpoint (connector/gateway)
|
|
218
|
+
* @private
|
|
219
|
+
* @param {Object} seg1 - First segment
|
|
220
|
+
* @param {Object} seg2 - Second segment
|
|
221
|
+
* @param {number} tolerance - Distance tolerance for considering points as the same
|
|
222
|
+
* @returns {boolean} True if segments share an endpoint
|
|
223
|
+
*/
|
|
224
|
+
}, {
|
|
225
|
+
key: "_areSegmentsTouchingAtSharedEndpoint",
|
|
226
|
+
value: function _areSegmentsTouchingAtSharedEndpoint(seg1, seg2, tolerance) {
|
|
227
|
+
// Check all possible endpoint combinations
|
|
228
|
+
var endpoints = [
|
|
229
|
+
// seg1.start with seg2 endpoints
|
|
230
|
+
{
|
|
231
|
+
p1: seg1.start,
|
|
232
|
+
p2: seg2.start,
|
|
233
|
+
isSeg1Start: true,
|
|
234
|
+
isSeg2Start: true
|
|
235
|
+
}, {
|
|
236
|
+
p1: seg1.start,
|
|
237
|
+
p2: seg2.end,
|
|
238
|
+
isSeg1Start: true,
|
|
239
|
+
isSeg2Start: false
|
|
240
|
+
},
|
|
241
|
+
// seg1.end with seg2 endpoints
|
|
242
|
+
{
|
|
243
|
+
p1: seg1.end,
|
|
244
|
+
p2: seg2.start,
|
|
245
|
+
isSeg1Start: false,
|
|
246
|
+
isSeg2Start: true
|
|
247
|
+
}, {
|
|
248
|
+
p1: seg1.end,
|
|
249
|
+
p2: seg2.end,
|
|
250
|
+
isSeg1Start: false,
|
|
251
|
+
isSeg2Start: false
|
|
252
|
+
}];
|
|
253
|
+
for (var _i = 0, _endpoints = endpoints; _i < _endpoints.length; _i++) {
|
|
254
|
+
var _endpoints$_i = _endpoints[_i],
|
|
255
|
+
p1 = _endpoints$_i.p1,
|
|
256
|
+
p2 = _endpoints$_i.p2,
|
|
257
|
+
isSeg1Start = _endpoints$_i.isSeg1Start,
|
|
258
|
+
isSeg2Start = _endpoints$_i.isSeg2Start;
|
|
259
|
+
var distance = p1.distanceTo(p2);
|
|
260
|
+
if (distance <= tolerance) {
|
|
261
|
+
// Verify this is actually an endpoint of the path (not just any segment point)
|
|
262
|
+
var isSeg1Endpoint = isSeg1Start && seg1.isFirstSegment || !isSeg1Start && seg1.isLastSegment;
|
|
263
|
+
var isSeg2Endpoint = isSeg2Start && seg2.isFirstSegment || !isSeg2Start && seg2.isLastSegment;
|
|
264
|
+
|
|
265
|
+
// Only count as shared endpoint if at least one is a path endpoint
|
|
266
|
+
// (This handles both connector-to-connector and connector-to-gateway cases)
|
|
267
|
+
if (isSeg1Endpoint || isSeg2Endpoint) {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Check if two line segments intersect or come within tolerance distance
|
|
277
|
+
* @private
|
|
278
|
+
* @param {THREE.Vector3} p1 - Start of first segment
|
|
279
|
+
* @param {THREE.Vector3} p2 - End of first segment
|
|
280
|
+
* @param {THREE.Vector3} p3 - Start of second segment
|
|
281
|
+
* @param {THREE.Vector3} p4 - End of second segment
|
|
282
|
+
* @param {number} tolerance - Distance tolerance
|
|
283
|
+
* @returns {Object|null} Intersection details or null
|
|
284
|
+
*/
|
|
285
|
+
}, {
|
|
286
|
+
key: "_checkLineSegmentIntersection",
|
|
287
|
+
value: function _checkLineSegmentIntersection(p1, p2, p3, p4, tolerance) {
|
|
288
|
+
// Calculate closest points on two line segments
|
|
289
|
+
var d1 = new THREE.Vector3().subVectors(p2, p1); // Direction of segment 1
|
|
290
|
+
var d2 = new THREE.Vector3().subVectors(p4, p3); // Direction of segment 2
|
|
291
|
+
var r = new THREE.Vector3().subVectors(p1, p3);
|
|
292
|
+
var a = d1.dot(d1);
|
|
293
|
+
var b = d1.dot(d2);
|
|
294
|
+
var c = d2.dot(d2);
|
|
295
|
+
var d = d1.dot(r);
|
|
296
|
+
var e = d2.dot(r);
|
|
297
|
+
var denom = a * c - b * b;
|
|
298
|
+
|
|
299
|
+
// Check if lines are parallel
|
|
300
|
+
if (Math.abs(denom) < 1e-10) {
|
|
301
|
+
// Lines are parallel, check if they're close enough
|
|
302
|
+
var distToLine = this._distancePointToLineSegment(p3, p1, p2);
|
|
303
|
+
if (distToLine <= tolerance) {
|
|
304
|
+
return {
|
|
305
|
+
point: p3.clone(),
|
|
306
|
+
distance: distToLine,
|
|
307
|
+
type: 'parallel'
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Calculate parameters for closest points
|
|
314
|
+
var s = (b * e - c * d) / denom;
|
|
315
|
+
var t = (a * e - b * d) / denom;
|
|
316
|
+
|
|
317
|
+
// Clamp to segment bounds
|
|
318
|
+
s = Math.max(0, Math.min(1, s));
|
|
319
|
+
t = Math.max(0, Math.min(1, t));
|
|
320
|
+
|
|
321
|
+
// Calculate closest points
|
|
322
|
+
var closestPoint1 = new THREE.Vector3().addVectors(p1, d1.clone().multiplyScalar(s));
|
|
323
|
+
var closestPoint2 = new THREE.Vector3().addVectors(p3, d2.clone().multiplyScalar(t));
|
|
324
|
+
|
|
325
|
+
// Calculate distance between closest points
|
|
326
|
+
var distance = closestPoint1.distanceTo(closestPoint2);
|
|
327
|
+
|
|
328
|
+
// Check if within tolerance
|
|
329
|
+
if (distance <= tolerance) {
|
|
330
|
+
var midPoint = new THREE.Vector3().addVectors(closestPoint1, closestPoint2).multiplyScalar(0.5);
|
|
331
|
+
return {
|
|
332
|
+
point: midPoint,
|
|
333
|
+
distance: distance,
|
|
334
|
+
type: distance < 0.01 ? 'crossing' : 'near'
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Calculate distance from a point to a line segment
|
|
342
|
+
* @private
|
|
343
|
+
* @param {THREE.Vector3} point - The point
|
|
344
|
+
* @param {THREE.Vector3} lineStart - Start of line segment
|
|
345
|
+
* @param {THREE.Vector3} lineEnd - End of line segment
|
|
346
|
+
* @returns {number} Distance to line segment
|
|
347
|
+
*/
|
|
348
|
+
}, {
|
|
349
|
+
key: "_distancePointToLineSegment",
|
|
350
|
+
value: function _distancePointToLineSegment(point, lineStart, lineEnd) {
|
|
351
|
+
var line = new THREE.Vector3().subVectors(lineEnd, lineStart);
|
|
352
|
+
var lineLength = line.length();
|
|
353
|
+
if (lineLength < 1e-10) {
|
|
354
|
+
return point.distanceTo(lineStart);
|
|
355
|
+
}
|
|
356
|
+
var t = Math.max(0, Math.min(1, new THREE.Vector3().subVectors(point, lineStart).dot(line) / (lineLength * lineLength)));
|
|
357
|
+
var projection = new THREE.Vector3().addVectors(lineStart, line.multiplyScalar(t));
|
|
358
|
+
return point.distanceTo(projection);
|
|
359
|
+
}
|
|
360
|
+
}]);
|
|
361
|
+
}();
|
|
362
|
+
|
|
363
|
+
export { PathIntersectionDetector };
|