@@ -952,74 +952,24 @@ function _edgeLength(edge) {
952952}
953953
954954function _edgeCurveType ( edge ) {
955- // Sample 3 points along the edge to determine curve type geometrically
956- // (GetType() is unavailable — GeomAbs_CurveType enum is unbound)
957955 let curve = new self . oc . BRepAdaptor_Curve_2 ( edge ) ;
958- let u0 = curve . FirstParameter ( ) , u1 = curve . LastParameter ( ) ;
959- let p0 = new self . oc . gp_Pnt_1 ( ) , p1 = new self . oc . gp_Pnt_1 ( ) , p2 = new self . oc . gp_Pnt_1 ( ) ;
960- curve . D0 ( u0 , p0 ) ; curve . D0 ( ( u0 + u1 ) / 2 , p1 ) ; curve . D0 ( u1 , p2 ) ;
961- let a = [ p0 . X ( ) , p0 . Y ( ) , p0 . Z ( ) ] ;
962- let b = [ p1 . X ( ) , p1 . Y ( ) , p1 . Z ( ) ] ;
963- let c = [ p2 . X ( ) , p2 . Y ( ) , p2 . Z ( ) ] ;
964-
965- // Check collinearity: if cross product of (b-a) and (c-a) is ~zero → Line
966- let ab = [ b [ 0 ] - a [ 0 ] , b [ 1 ] - a [ 1 ] , b [ 2 ] - a [ 2 ] ] ;
967- let ac = [ c [ 0 ] - a [ 0 ] , c [ 1 ] - a [ 1 ] , c [ 2 ] - a [ 2 ] ] ;
968- let cross = [
969- ab [ 1 ] * ac [ 2 ] - ab [ 2 ] * ac [ 1 ] ,
970- ab [ 2 ] * ac [ 0 ] - ab [ 0 ] * ac [ 2 ] ,
971- ab [ 0 ] * ac [ 1 ] - ab [ 1 ] * ac [ 0 ]
972- ] ;
973- let crossMag = Math . sqrt ( cross [ 0 ] * cross [ 0 ] + cross [ 1 ] * cross [ 1 ] + cross [ 2 ] * cross [ 2 ] ) ;
974- let abMag = Math . sqrt ( ab [ 0 ] * ab [ 0 ] + ab [ 1 ] * ab [ 1 ] + ab [ 2 ] * ab [ 2 ] ) ;
975- if ( abMag < 1e-10 || crossMag / abMag < 1e-6 ) { return "Line" ; }
976-
977- // Check if it's a circle: sample more points and check equal distance from center
978- let nSamples = 8 ;
979- let pts = [ ] ;
980- for ( let i = 0 ; i <= nSamples ; i ++ ) {
981- let u = u0 + ( u1 - u0 ) * i / nSamples ;
982- let p = new self . oc . gp_Pnt_1 ( ) ;
983- curve . D0 ( u , p ) ;
984- pts . push ( [ p . X ( ) , p . Y ( ) , p . Z ( ) ] ) ;
985- }
986- // Approximate center as average of all points
987- let cx = 0 , cy = 0 , cz = 0 ;
988- for ( let p of pts ) { cx += p [ 0 ] ; cy += p [ 1 ] ; cz += p [ 2 ] ; }
989- cx /= pts . length ; cy /= pts . length ; cz /= pts . length ;
990- // Check if all distances from center are approximately equal
991- let dists = pts . map ( p => Math . sqrt ( ( p [ 0 ] - cx ) ** 2 + ( p [ 1 ] - cy ) ** 2 + ( p [ 2 ] - cz ) ** 2 ) ) ;
992- let avgDist = dists . reduce ( ( s , d ) => s + d , 0 ) / dists . length ;
993- let maxDeviation = Math . max ( ...dists . map ( d => Math . abs ( d - avgDist ) ) ) ;
994- if ( avgDist > 1e-10 && maxDeviation / avgDist < 0.01 ) { return "Circle" ; }
995-
956+ let type = curve . GetType ( ) ;
957+ let CT = self . oc . GeomAbs_CurveType ;
958+ if ( type === CT . GeomAbs_Line ) return "Line" ;
959+ if ( type === CT . GeomAbs_Circle ) return "Circle" ;
960+ if ( type === CT . GeomAbs_Ellipse ) return "Ellipse" ;
961+ if ( type === CT . GeomAbs_Hyperbola ) return "Hyperbola" ;
962+ if ( type === CT . GeomAbs_Parabola ) return "Parabola" ;
963+ if ( type === CT . GeomAbs_BezierCurve ) return "BezierCurve" ;
964+ if ( type === CT . GeomAbs_BSplineCurve ) return "BSplineCurve" ;
996965 return "Other" ;
997966}
998967
999968function _edgeDirection ( edge ) {
1000- // Compute direction from start and end points (no GetType() needed)
1001969 let curve = new self . oc . BRepAdaptor_Curve_2 ( edge ) ;
1002- let u0 = curve . FirstParameter ( ) , u1 = curve . LastParameter ( ) ;
1003- let p0 = new self . oc . gp_Pnt_1 ( ) , p1 = new self . oc . gp_Pnt_1 ( ) , p2 = new self . oc . gp_Pnt_1 ( ) ;
1004- curve . D0 ( u0 , p0 ) ; curve . D0 ( ( u0 + u1 ) / 2 , p1 ) ; curve . D0 ( u1 , p2 ) ;
1005-
1006- // Check if the edge is a line (collinear points)
1007- let a = [ p0 . X ( ) , p0 . Y ( ) , p0 . Z ( ) ] ;
1008- let b = [ p1 . X ( ) , p1 . Y ( ) , p1 . Z ( ) ] ;
1009- let c = [ p2 . X ( ) , p2 . Y ( ) , p2 . Z ( ) ] ;
1010- let ab = [ b [ 0 ] - a [ 0 ] , b [ 1 ] - a [ 1 ] , b [ 2 ] - a [ 2 ] ] ;
1011- let ac = [ c [ 0 ] - a [ 0 ] , c [ 1 ] - a [ 1 ] , c [ 2 ] - a [ 2 ] ] ;
1012- let cross = [
1013- ab [ 1 ] * ac [ 2 ] - ab [ 2 ] * ac [ 1 ] ,
1014- ab [ 2 ] * ac [ 0 ] - ab [ 0 ] * ac [ 2 ] ,
1015- ab [ 0 ] * ac [ 1 ] - ab [ 1 ] * ac [ 0 ]
1016- ] ;
1017- let crossMag = Math . sqrt ( cross [ 0 ] * cross [ 0 ] + cross [ 1 ] * cross [ 1 ] + cross [ 2 ] * cross [ 2 ] ) ;
1018- let abMag = Math . sqrt ( ab [ 0 ] * ab [ 0 ] + ab [ 1 ] * ab [ 1 ] + ab [ 2 ] * ab [ 2 ] ) ;
1019- if ( abMag < 1e-10 ) { return null ; }
1020- if ( crossMag / abMag > 1e-6 ) { return null ; } // Not a line
1021-
1022- return _normalize ( ac ) ;
970+ if ( curve . GetType ( ) !== self . oc . GeomAbs_CurveType . GeomAbs_Line ) return null ;
971+ let dir = curve . Line ( ) . Direction ( ) ;
972+ return [ dir . X ( ) , dir . Y ( ) , dir . Z ( ) ] ;
1023973}
1024974
1025975function _faceCentroid ( face ) {
@@ -1036,81 +986,17 @@ function _faceArea(face) {
1036986}
1037987
1038988function _faceNormal ( face ) {
1039- // Compute face normal from edge geometry (BRepAdaptor_Surface not available)
1040- // Sample 3 non-collinear points from the face's edges to determine normal
1041- try {
1042- let points = [ ] ;
1043- let explorer = new self . oc . TopExp_Explorer_2 (
1044- face , self . oc . TopAbs_ShapeEnum . TopAbs_EDGE , self . oc . TopAbs_ShapeEnum . TopAbs_SHAPE
1045- ) ;
1046- while ( explorer . More ( ) && points . length < 10 ) {
1047- let edge = self . oc . TopoDS . Edge_1 ( explorer . Current ( ) ) ;
1048- let curve = new self . oc . BRepAdaptor_Curve_2 ( edge ) ;
1049- let u0 = curve . FirstParameter ( ) , u1 = curve . LastParameter ( ) ;
1050- for ( let t of [ 0 , 0.5 , 1 ] ) {
1051- let p = new self . oc . gp_Pnt_1 ( ) ;
1052- curve . D0 ( u0 + ( u1 - u0 ) * t , p ) ;
1053- points . push ( [ p . X ( ) , p . Y ( ) , p . Z ( ) ] ) ;
1054- }
1055- explorer . Next ( ) ;
1056- }
1057- // Find 3 non-collinear points
1058- if ( points . length < 3 ) { return [ 0 , 0 , 1 ] ; }
1059- let a = points [ 0 ] ;
1060- for ( let i = 1 ; i < points . length ; i ++ ) {
1061- let ab = [ points [ i ] [ 0 ] - a [ 0 ] , points [ i ] [ 1 ] - a [ 1 ] , points [ i ] [ 2 ] - a [ 2 ] ] ;
1062- let abLen = _vecLength ( ab ) ;
1063- if ( abLen < 1e-10 ) continue ;
1064- for ( let j = i + 1 ; j < points . length ; j ++ ) {
1065- let ac = [ points [ j ] [ 0 ] - a [ 0 ] , points [ j ] [ 1 ] - a [ 1 ] , points [ j ] [ 2 ] - a [ 2 ] ] ;
1066- let cross = [
1067- ab [ 1 ] * ac [ 2 ] - ab [ 2 ] * ac [ 1 ] ,
1068- ab [ 2 ] * ac [ 0 ] - ab [ 0 ] * ac [ 2 ] ,
1069- ab [ 0 ] * ac [ 1 ] - ab [ 1 ] * ac [ 0 ]
1070- ] ;
1071- let crossMag = _vecLength ( cross ) ;
1072- if ( crossMag > 1e-8 ) {
1073- return _normalize ( cross ) ;
1074- }
1075- }
1076- }
1077- return [ 0 , 0 , 1 ] ; // Fallback (degenerate face)
1078- } catch ( e ) {
1079- return [ 0 , 0 , 1 ] ; // Fallback
1080- }
1081- }
1082-
1083- function _isFacePlanar ( face ) {
1084- // Check if all sampled points on the face lie on a plane
1085- try {
1086- let points = [ ] ;
1087- let explorer = new self . oc . TopExp_Explorer_2 (
1088- face , self . oc . TopAbs_ShapeEnum . TopAbs_EDGE , self . oc . TopAbs_ShapeEnum . TopAbs_SHAPE
1089- ) ;
1090- while ( explorer . More ( ) ) {
1091- let edge = self . oc . TopoDS . Edge_1 ( explorer . Current ( ) ) ;
1092- let curve = new self . oc . BRepAdaptor_Curve_2 ( edge ) ;
1093- let u0 = curve . FirstParameter ( ) , u1 = curve . LastParameter ( ) ;
1094- for ( let t = 0 ; t <= 1 ; t += 0.25 ) {
1095- let p = new self . oc . gp_Pnt_1 ( ) ;
1096- curve . D0 ( u0 + ( u1 - u0 ) * t , p ) ;
1097- points . push ( [ p . X ( ) , p . Y ( ) , p . Z ( ) ] ) ;
1098- }
1099- explorer . Next ( ) ;
1100- }
1101- if ( points . length < 3 ) { return true ; }
1102- // Get the normal from first 3 non-collinear points
1103- let normal = _faceNormal ( face ) ;
1104- if ( _vecLength ( normal ) < 1e-10 ) { return true ; }
1105- // Check all points lie on the plane defined by points[0] and normal
1106- let d = _dot ( points [ 0 ] , normal ) ;
1107- for ( let p of points ) {
1108- if ( Math . abs ( _dot ( p , normal ) - d ) > 1e-4 ) { return false ; }
1109- }
1110- return true ;
1111- } catch ( e ) {
1112- return false ;
1113- }
989+ let surf = new self . oc . BRepAdaptor_Surface_2 ( face , true ) ;
990+ let uMid = ( surf . FirstUParameter ( ) + surf . LastUParameter ( ) ) / 2 ;
991+ let vMid = ( surf . FirstVParameter ( ) + surf . LastVParameter ( ) ) / 2 ;
992+ let pnt = new self . oc . gp_Pnt_1 ( ) ;
993+ let du = new self . oc . gp_Vec_1 ( ) ;
994+ let dv = new self . oc . gp_Vec_1 ( ) ;
995+ surf . D1 ( uMid , vMid , pnt , du , dv ) ;
996+ let normal = du . Crossed ( dv ) ;
997+ let mag = normal . Magnitude ( ) ;
998+ if ( mag < 1e-10 ) return [ 0 , 0 , 1 ] ;
999+ return [ normal . X ( ) / mag , normal . Y ( ) / mag , normal . Z ( ) / mag ] ;
11141000}
11151001
11161002function _dot ( a , b ) {
@@ -1123,7 +1009,7 @@ function _vecLength(v) {
11231009
11241010function _normalize ( v ) {
11251011 let len = _vecLength ( v ) ;
1126- if ( len < 1e-10 ) { return [ 0 , 0 , 0 ] ; }
1012+ if ( len < 1e-10 ) { throw new Error ( "Cannot normalize a zero-length vector; check your axis parameter" ) ; }
11271013 return [ v [ 0 ] / len , v [ 1 ] / len , v [ 2 ] / len ] ;
11281014}
11291015
@@ -1324,16 +1210,21 @@ class FaceSelector {
13241210 // --- Filtering ---
13251211
13261212 ofType ( type ) {
1327- // BRepAdaptor_Surface not available in bindings — use geometry heuristics
1213+ let ST = self . oc . GeomAbs_SurfaceType ;
1214+ let typeMap = {
1215+ "Plane" : ST . GeomAbs_Plane ,
1216+ "Cylinder" : ST . GeomAbs_Cylinder ,
1217+ "Cone" : ST . GeomAbs_Cone ,
1218+ "Sphere" : ST . GeomAbs_Sphere ,
1219+ "Torus" : ST . GeomAbs_Torus ,
1220+ "BSplineSurface" : ST . GeomAbs_BSplineSurface ,
1221+ "BezierSurface" : ST . GeomAbs_BezierSurface ,
1222+ } ;
1223+ let target = typeMap [ type ] ;
13281224 let sel = this . _clone ( ) ;
13291225 sel . _entries = sel . _entries . filter ( e => {
1330- let normal = _faceNormal ( e . face ) ;
1331- if ( type === "Plane" ) {
1332- // A planar face has consistent normals at all edge points
1333- return _isFacePlanar ( e . face ) ;
1334- }
1335- // Other types not reliably detectable without BRepAdaptor_Surface
1336- return false ;
1226+ let surf = new self . oc . BRepAdaptor_Surface_2 ( e . face , true ) ;
1227+ return surf . GetType ( ) === target ;
13371228 } ) ;
13381229 return sel ;
13391230 }
@@ -1505,59 +1396,14 @@ function Wedge(dx, dy, dz, ltx) {
15051396function Section ( shape , planeOrigin , planeNormal ) {
15061397 if ( ! planeNormal ) { planeNormal = [ 0 , 0 , 1 ] ; }
15071398 if ( ! planeOrigin ) { planeOrigin = [ 0 , 0 , 0 ] ; }
1399+ if ( _vecLength ( planeNormal ) < 1e-10 ) { throw new Error ( "Section: planeNormal must be a non-zero vector" ) ; }
15081400 let curSection = self . CacheOp ( arguments , "Section" , ( ) => {
1509- // Create a very thin slab at the cutting plane and intersect with shape.
1510- // (gp_Pln and BRepAlgoAPI_Section are not available in the bindings.)
1511- let n = _normalize ( planeNormal ) ;
1512- let thickness = 1e-3 ;
1513- // Create a large box centered at origin
1514- let slab = new self . oc . BRepPrimAPI_MakeBox_4 (
1515- new self . oc . gp_Pnt_3 ( - 1e4 , - 1e4 , - thickness / 2 ) ,
1516- new self . oc . gp_Pnt_3 ( 1e4 , 1e4 , thickness / 2 )
1517- ) . Shape ( ) ;
1518- // Rotate slab to align Z-axis with planeNormal
1519- if ( Math . abs ( n [ 2 ] - 1.0 ) > 1e-8 ) {
1520- // Need to rotate: find rotation axis (cross product of Z and normal)
1521- let zAxis = [ 0 , 0 , 1 ] ;
1522- let rotAxis = [
1523- zAxis [ 1 ] * n [ 2 ] - zAxis [ 2 ] * n [ 1 ] ,
1524- zAxis [ 2 ] * n [ 0 ] - zAxis [ 0 ] * n [ 2 ] ,
1525- zAxis [ 0 ] * n [ 1 ] - zAxis [ 1 ] * n [ 0 ]
1526- ] ;
1527- let rotAxisLen = _vecLength ( rotAxis ) ;
1528- if ( rotAxisLen > 1e-10 ) {
1529- let angle = Math . acos ( Math . max ( - 1 , Math . min ( 1 , _dot ( zAxis , n ) ) ) ) ;
1530- rotAxis = _normalize ( rotAxis ) ;
1531- let ax1 = new self . oc . gp_Ax1_2 (
1532- new self . oc . gp_Pnt_3 ( 0 , 0 , 0 ) ,
1533- new self . oc . gp_Dir_4 ( rotAxis [ 0 ] , rotAxis [ 1 ] , rotAxis [ 2 ] )
1534- ) ;
1535- let trsf = new self . oc . gp_Trsf_1 ( ) ;
1536- trsf . SetRotation_1 ( ax1 , angle ) ;
1537- let brep = new self . oc . BRepBuilderAPI_Transform_2 ( slab , trsf , true ) ;
1538- slab = brep . Shape ( ) ;
1539- } else if ( n [ 2 ] < 0 ) {
1540- // Normal is [0,0,-1], rotate 180 degrees around X
1541- let ax1 = new self . oc . gp_Ax1_2 (
1542- new self . oc . gp_Pnt_3 ( 0 , 0 , 0 ) ,
1543- new self . oc . gp_Dir_4 ( 1 , 0 , 0 )
1544- ) ;
1545- let trsf = new self . oc . gp_Trsf_1 ( ) ;
1546- trsf . SetRotation_1 ( ax1 , Math . PI ) ;
1547- let brep = new self . oc . BRepBuilderAPI_Transform_2 ( slab , trsf , true ) ;
1548- slab = brep . Shape ( ) ;
1549- }
1550- }
1551- // Translate slab to planeOrigin
1552- if ( planeOrigin [ 0 ] !== 0 || planeOrigin [ 1 ] !== 0 || planeOrigin [ 2 ] !== 0 ) {
1553- let trsf = new self . oc . gp_Trsf_1 ( ) ;
1554- trsf . SetTranslation_1 ( new self . oc . gp_Vec_4 ( planeOrigin [ 0 ] , planeOrigin [ 1 ] , planeOrigin [ 2 ] ) ) ;
1555- let brep = new self . oc . BRepBuilderAPI_Transform_2 ( slab , trsf , true ) ;
1556- slab = brep . Shape ( ) ;
1557- }
1558- // Intersect
1559- let common = new self . oc . BRepAlgoAPI_Common_3 ( shape , slab , new self . oc . Message_ProgressRange_1 ( ) ) ;
1560- return common . Shape ( ) ;
1401+ let origin = new self . oc . gp_Pnt_3 ( planeOrigin [ 0 ] , planeOrigin [ 1 ] , planeOrigin [ 2 ] ) ;
1402+ let normal = new self . oc . gp_Dir_4 ( planeNormal [ 0 ] , planeNormal [ 1 ] , planeNormal [ 2 ] ) ;
1403+ let plane = new self . oc . gp_Pln_3 ( origin , normal ) ;
1404+ let section = new self . oc . BRepAlgoAPI_Section_5 ( shape , plane , false ) ;
1405+ section . Build ( new self . oc . Message_ProgressRange_1 ( ) ) ;
1406+ return section . Shape ( ) ;
15611407 } ) ;
15621408 self . sceneShapes . push ( curSection ) ;
15631409 return curSection ;
0 commit comments