@@ -126,6 +126,45 @@ export class Point {
126126 return this . geometryHelper . transformControlPoints ( rotationTransforms , inputs . points ) ;
127127 }
128128
129+ /**
130+ * Gets a bounding box of the points
131+ * @param inputs Points
132+ * @returns Bounding box of points
133+ * @group extract
134+ * @shortname bounding box pts
135+ * @drawable true
136+ */
137+ boundingBoxOfPoints ( inputs : Inputs . Point . PointsDto ) : Inputs . Base . BoundingBox {
138+ const xVals = [ ] ;
139+ const yVals = [ ] ;
140+ const zVals = [ ] ;
141+
142+ inputs . points . forEach ( pt => {
143+ xVals . push ( pt [ 0 ] ) ;
144+ yVals . push ( pt [ 1 ] ) ;
145+ zVals . push ( pt [ 2 ] ) ;
146+ } ) ;
147+
148+ const min = [ Math . min ( ...xVals ) , Math . min ( ...yVals ) , Math . min ( ...zVals ) ] as Inputs . Base . Point3 ;
149+ const max = [ Math . max ( ...xVals ) , Math . max ( ...yVals ) , Math . max ( ...zVals ) ] as Inputs . Base . Point3 ;
150+ const center = [
151+ ( min [ 0 ] + max [ 0 ] ) / 2 ,
152+ ( min [ 1 ] + max [ 1 ] ) / 2 ,
153+ ( min [ 2 ] + max [ 2 ] ) / 2 ,
154+ ] as Inputs . Base . Point3 ;
155+ const width = max [ 0 ] - min [ 0 ] ;
156+ const height = max [ 1 ] - min [ 1 ] ;
157+ const length = max [ 2 ] - min [ 2 ] ;
158+ return {
159+ min,
160+ max,
161+ center,
162+ width,
163+ height,
164+ length,
165+ } ;
166+ }
167+
129168 /**
130169 * Measures the closest distance between a point and a collection of points
131170 * @param inputs Point from which to measure and points to measure the distance against
@@ -365,6 +404,55 @@ export class Point {
365404 return this . geometryHelper . removeConsecutivePointDuplicates ( inputs . points , inputs . checkFirstAndLast , inputs . tolerance ) ;
366405 }
367406
407+ /**
408+ * Creates a normal vector from 3 points
409+ * @param inputs Three points and the reverse normal flag
410+ * @returns Normal vector
411+ * @group create
412+ * @shortname normal from 3 points
413+ * @drawable true
414+ */
415+ normalFromThreePoints ( inputs : Inputs . Point . ThreePointsNormalDto ) : Inputs . Base . Vector3 {
416+ const p1 = inputs . point1 ;
417+ const p2 = inputs . point2 ;
418+ const p3 = inputs . point3 ;
419+
420+ if ( ! p1 || ! p2 || ! p3 || p1 . length !== 3 || p2 . length !== 3 || p3 . length !== 3 ) {
421+ throw new Error ( "All points must be arrays of 3 numbers [x, y, z]" ) ;
422+ }
423+
424+ // Calculate vector A = p2 - p1
425+ const ax = p2 [ 0 ] - p1 [ 0 ] ;
426+ const ay = p2 [ 1 ] - p1 [ 1 ] ;
427+ const az = p2 [ 2 ] - p1 [ 2 ] ;
428+
429+ // Calculate vector B = p3 - p1
430+ const bx = p3 [ 0 ] - p1 [ 0 ] ;
431+ const by = p3 [ 1 ] - p1 [ 1 ] ;
432+ const bz = p3 [ 2 ] - p1 [ 2 ] ;
433+
434+ // Calculate the cross product N = A x B
435+ let nx = ( ay * bz ) - ( az * by ) ;
436+ let ny = ( az * bx ) - ( ax * bz ) ;
437+ let nz = ( ax * by ) - ( ay * bx ) ;
438+
439+ // Check for collinear points (resulting in a zero vector)
440+ // A zero vector indicates the points don't form a unique plane.
441+ // You might want to handle this case depending on your application.
442+ if ( nx === 0 && ny === 0 && nz === 0 ) {
443+ console . warn ( "Points are collinear or coincident; cannot calculate a unique normal." ) ;
444+ return undefined ; // Or return [0, 0, 0] if that's acceptable
445+ }
446+
447+ if ( inputs . reverseNormal ) {
448+ nx = - nx ;
449+ ny = - ny ;
450+ nz = - nz ;
451+ }
452+
453+ return [ nx , ny , nz ] ;
454+ }
455+
368456 private closestPointFromPointData ( inputs : Inputs . Point . ClosestPointFromPointsDto ) : {
369457 index : number , point : Inputs . Base . Point3 , distance : number
370458 } {
0 commit comments