UNPKG

@bitbybit-dev/occt

Version:

Bit By Bit Developers CAD algorithms using OpenCascade Technology kernel. Run in Node and in Browser.

1,003 lines (1,002 loc) 46.2 kB
import * as Inputs from "../../api/inputs"; import { TextWiresDataDto, ObjectDefinition } from "../../api/models/bucket"; export class WiresService { constructor(occ, occRefReturns, base, shapesHelperService, shapeGettersService, transformsService, enumService, entitiesService, converterService, geomService, edgesService, vecHelper, filletsService, operationsService) { this.occ = occ; this.occRefReturns = occRefReturns; this.base = base; this.shapesHelperService = shapesHelperService; this.shapeGettersService = shapeGettersService; this.transformsService = transformsService; this.enumService = enumService; this.entitiesService = entitiesService; this.converterService = converterService; this.geomService = geomService; this.edgesService = edgesService; this.vecHelper = vecHelper; this.filletsService = filletsService; this.operationsService = operationsService; } getWireLength(inputs) { const curve = new this.occ.BRepAdaptor_CompCurve(inputs.shape, false); const length = this.geomService.curveLengthCompCurve({ shape: curve }); curve.delete(); return length; } getWiresLengths(inputs) { if (inputs.shapes === undefined) { throw (Error(("Shapes are not defined"))); } return inputs.shapes.map(wire => this.getWireLength({ shape: wire })); } createRectangleWire(inputs) { const cw = inputs.width / 2; const cl = inputs.length / 2; const pt1 = [cw, 0, cl]; const pt2 = [-cw, 0, cl]; const pt3 = [-cw, 0, -cl]; const pt4 = [cw, 0, -cl]; const points = [pt1, pt2, pt3, pt4].reverse(); const wire = this.createPolygonWire({ points }); const alignedWire = this.transformsService.alignAndTranslate({ shape: wire, direction: inputs.direction, center: inputs.center }); wire.delete(); return alignedWire; } createSquareWire(inputs) { return this.createRectangleWire({ width: inputs.size, length: inputs.size, center: inputs.center, direction: inputs.direction }); } reversedWire(inputs) { const wire = inputs.shape; const reversed = wire.Reversed(); const result = this.converterService.getActualTypeOfShape(reversed); reversed.delete(); return result; } reversedWireFromReversedEdges(inputs) { const wire = inputs.shape; const edges = this.edgesService.getEdgesAlongWire({ shape: wire }); const reversedEdges = edges.map(e => { return this.converterService.getActualTypeOfShape(e.Reversed()); }); const reversed = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: reversedEdges.reverse() }); const result = this.converterService.getActualTypeOfShape(reversed); reversed.delete(); reversedEdges.forEach(e => e.delete()); return result; } createChristmasTreeWire(inputs) { const frameInner = this.createLineWire({ start: [inputs.innerDist, 0, 0], end: [0, inputs.height, 0], }); const frameOuter = this.createLineWire({ start: [inputs.outerDist, 0, 0], end: [0, inputs.height, 0], }); const pointsOnInner = this.divideWireByEqualDistanceToPoints({ shape: frameInner, nrOfDivisions: inputs.nrSkirts, removeEndPoint: false, removeStartPoint: false, }); const pointsOnOuter = this.divideWireByEqualDistanceToPoints({ shape: frameOuter, nrOfDivisions: inputs.nrSkirts, removeEndPoint: false, removeStartPoint: false, }); const halfShapeTreePts = []; if (inputs.trunkWidth > 0 && inputs.trunkHeight > 0) { halfShapeTreePts.push([0, -inputs.trunkHeight, 0]); halfShapeTreePts.push([inputs.trunkWidth / 2, -inputs.trunkHeight, 0]); halfShapeTreePts.push([inputs.trunkWidth / 2, 0, 0]); } else { halfShapeTreePts.push([0, 0, 0]); } pointsOnInner.forEach((pt, index) => { const ptOnOuter = pointsOnOuter[index]; if (index === 0) { halfShapeTreePts.push(ptOnOuter); } else if (index !== 0 && index < pointsOnOuter.length - 1) { halfShapeTreePts.push([pt[0], ptOnOuter[1] + ((inputs.height / inputs.nrSkirts) * 0.1), pt[2]]); halfShapeTreePts.push(ptOnOuter); } else { halfShapeTreePts.push(pt); } }); if (!inputs.half) { const secondHalf = halfShapeTreePts.map(pt => [-pt[0], pt[1], pt[2]]); secondHalf.pop(); halfShapeTreePts.push(...secondHalf.reverse()); } let result; if (inputs.trunkHeight > 0 && inputs.trunkWidth > 0) { const offsetToTrunkHeight = halfShapeTreePts.map(pt => [pt[0], pt[1] + inputs.trunkHeight, pt[2]]); result = this.createPolylineWire({ points: offsetToTrunkHeight }); } else { result = this.createPolylineWire({ points: halfShapeTreePts }); } const rotated = this.transformsService.rotate({ shape: result, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.origin }); return aligned; } createStarWire(inputs) { const lines = this.shapesHelperService.starLines(inputs.innerRadius, inputs.outerRadius, inputs.numRays, inputs.half, inputs.offsetOuterEdges); const edges = []; lines.forEach(line => { edges.push(this.edgesService.lineEdge(line)); }); const wire = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: edges }); const alignedWire = this.transformsService.alignAndTranslate({ shape: wire, direction: inputs.direction, center: inputs.center }); wire.delete(); return alignedWire; } createParallelogramWire(inputs) { const lines = this.shapesHelperService.parallelogram(inputs.width, inputs.height, inputs.angle, inputs.aroundCenter); const edges = []; lines.forEach(line => { edges.push(this.edgesService.lineEdge(line)); }); const wire = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: edges }); const aligned = this.transformsService.alignAndTranslate({ shape: wire, direction: inputs.direction, center: inputs.center }); wire.delete(); return aligned; } createHeartWire(inputs) { const sizeOfBox = inputs.sizeApprox; const halfSize = sizeOfBox / 2; const points1 = [ [0, 0, halfSize * 0.7], [halfSize / 6, 0, halfSize * 0.9], [halfSize / 2, 0, halfSize], [halfSize * 0.75, 0, halfSize * 0.9], [halfSize, 0, halfSize / 4], [halfSize / 2, 0, -halfSize / 2], [0, 0, -halfSize], ]; const points2 = points1.map(p => [-p[0], p[1], p[2]]); const tolerance = 0.00001; const wireFirstHalf = this.interpolatePoints({ points: points1, periodic: false, tolerance }); const wireSecondHalf = this.interpolatePoints({ points: points2.reverse(), periodic: false, tolerance }); const wire = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: [wireFirstHalf, wireSecondHalf] }); const rotated = this.transformsService.rotate({ shape: wire, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.center }); wire.delete(); rotated.delete(); wireFirstHalf.delete(); wireSecondHalf.delete(); return aligned; } createNGonWire(inputs) { const lines = this.shapesHelperService.ngon(inputs.nrCorners, inputs.radius, [0, 0]); const edges = []; lines.forEach(line => { edges.push(this.edgesService.lineEdge(line)); }); const wire = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: edges }); const aligned = this.transformsService.alignAndTranslate({ shape: wire, direction: inputs.direction, center: inputs.center }); wire.delete(); return aligned; } createLPolygonWire(inputs) { let points; switch (inputs.align) { case Inputs.OCCT.directionEnum.outside: points = this.shapesHelperService.polygonL(inputs.widthFirst, inputs.lengthFirst, inputs.widthSecond, inputs.lengthSecond); break; case Inputs.OCCT.directionEnum.inside: points = this.shapesHelperService.polygonLInverted(inputs.widthFirst, inputs.lengthFirst, inputs.widthSecond, inputs.lengthSecond); break; case Inputs.OCCT.directionEnum.middle: points = this.shapesHelperService.polygonLMiddle(inputs.widthFirst, inputs.lengthFirst, inputs.widthSecond, inputs.lengthSecond); break; default: points = this.shapesHelperService.polygonL(inputs.widthFirst, inputs.lengthFirst, inputs.widthSecond, inputs.lengthSecond); } const wire = this.createPolygonWire({ points }); const rotated = this.transformsService.rotate({ shape: wire, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.center }); wire.delete(); rotated.delete(); return aligned; } createIBeamProfileWire(inputs) { const points = this.shapesHelperService.beamIProfile(inputs.width, inputs.height, inputs.webThickness, inputs.flangeThickness, inputs.alignment); const wire = this.createPolygonWire({ points }); const rotated = this.transformsService.rotate({ shape: wire, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.center }); wire.delete(); rotated.delete(); return aligned; } createHBeamProfileWire(inputs) { const points = this.shapesHelperService.beamHProfile(inputs.width, inputs.height, inputs.webThickness, inputs.flangeThickness, inputs.alignment); const wire = this.createPolygonWire({ points }); const rotated = this.transformsService.rotate({ shape: wire, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.center }); wire.delete(); rotated.delete(); return aligned; } createTBeamProfileWire(inputs) { const points = this.shapesHelperService.beamTProfile(inputs.width, inputs.height, inputs.webThickness, inputs.flangeThickness, inputs.alignment); const wire = this.createPolygonWire({ points }); const rotated = this.transformsService.rotate({ shape: wire, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.center }); wire.delete(); rotated.delete(); return aligned; } createUBeamProfileWire(inputs) { const points = this.shapesHelperService.beamUProfile(inputs.width, inputs.height, inputs.webThickness, inputs.flangeThickness, inputs.flangeWidth, inputs.alignment); const wire = this.createPolygonWire({ points }); const rotated = this.transformsService.rotate({ shape: wire, angle: inputs.rotation, axis: [0, 1, 0] }); const aligned = this.transformsService.alignAndTranslate({ shape: rotated, direction: inputs.direction, center: inputs.center }); wire.delete(); rotated.delete(); return aligned; } createPolygonWire(inputs) { const gpPoints = []; for (let ind = 0; ind < inputs.points.length; ind++) { gpPoints.push(this.entitiesService.gpPnt(inputs.points[ind])); } const wireMaker = new this.occ.BRepBuilderAPI_MakeWire(); for (let ind = 0; ind < inputs.points.length - 1; ind++) { const pt1 = gpPoints[ind]; const pt2 = gpPoints[ind + 1]; const innerWire = this.makeWireBetweenTwoPoints(pt1, pt2); wireMaker.AddWire(innerWire); } const pt1 = gpPoints[inputs.points.length - 1]; const pt2 = gpPoints[0]; const innerWire2 = this.makeWireBetweenTwoPoints(pt1, pt2); wireMaker.AddWire(innerWire2); const wire = wireMaker.Wire(); wireMaker.delete(); return wire; } createPolylineWire(inputs) { const gpPoints = []; for (let ind = 0; ind < inputs.points.length; ind++) { gpPoints.push(this.entitiesService.gpPnt(inputs.points[ind])); } const wireMaker = new this.occ.BRepBuilderAPI_MakeWire(); for (let ind = 0; ind < inputs.points.length - 1; ind++) { const pt1 = gpPoints[ind]; const pt2 = gpPoints[ind + 1]; const innerWire = this.makeWireBetweenTwoPoints(pt1, pt2); wireMaker.AddWire(innerWire); } const wire = wireMaker.Wire(); wireMaker.delete(); return wire; } createLineWire(inputs) { const gpPoints = []; gpPoints.push(this.entitiesService.gpPnt(inputs.start)); gpPoints.push(this.entitiesService.gpPnt(inputs.end)); const wireMaker = new this.occ.BRepBuilderAPI_MakeWire(); for (let ind = 0; ind < gpPoints.length - 1; ind++) { const pt1 = gpPoints[ind]; const pt2 = gpPoints[ind + 1]; const innerWire = this.makeWireBetweenTwoPoints(pt1, pt2); wireMaker.AddWire(innerWire); } const wire = wireMaker.Wire(); wireMaker.delete(); return wire; } createLineWireWithExtensions(inputs) { const direction = this.base.vector.normalized({ vector: this.base.vector.sub({ first: inputs.end, second: inputs.start }) }); const scaledVecStart = this.base.vector.mul({ vector: direction, scalar: -inputs.extensionStart }); const scaledVecEnd = this.base.vector.mul({ vector: direction, scalar: inputs.extensionEnd }); const start = this.base.vector.add({ first: inputs.start, second: scaledVecStart }); const end = this.base.vector.add({ first: inputs.end, second: scaledVecEnd }); return this.createLineWire({ start, end }); } makeWireBetweenTwoPoints(pt1, pt2) { const edge = this.occ.MakeLineEdgeBetweenPoints(pt1, pt2); const wireMaker = new this.occ.BRepBuilderAPI_MakeWire(edge); const innerWire = wireMaker.Wire(); edge.delete(); wireMaker.delete(); return innerWire; } divideWireByParamsToPoints(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const points = this.geomService.divideCurveToNrSegments(Object.assign(Object.assign({}, inputs), { shape: curve }), curve.FirstParameter(), curve.LastParameter()); curve.delete(); return points; } divideWireByEqualDistanceToPoints(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const points = this.geomService.divideCompCurveByEqualLengthDistance(Object.assign(Object.assign({}, inputs), { shape: curve })); curve.delete(); return points; } pointOnWireAtParam(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const pt = this.geomService.pointOnCurveAtParam(Object.assign(Object.assign({}, inputs), { shape: curve })); curve.delete(); return pt; } tangentOnWireAtParam(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const tangent = this.geomService.tangentOnCurveAtParam(Object.assign(Object.assign({}, inputs), { shape: curve })); curve.delete(); return tangent; } pointOnWireAtLength(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const res = this.geomService.pointOnCompCurveAtLength(Object.assign(Object.assign({}, inputs), { shape: curve })); curve.delete(); return res; } pointsOnWireAtLengths(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const res = this.geomService.pointsOnCompCurveAtLengths(Object.assign(Object.assign({}, inputs), { shape: curve })); curve.delete(); return res; } pointsOnWireAtEqualLength(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const wireLength = this.getWireLength({ shape: wire }); const nrOfLengths = wireLength / inputs.length; const lengths = []; let total = 0; for (let i = 0; i < nrOfLengths; i++) { lengths.push(inputs.length * i); total += inputs.length; } if (!inputs.includeFirst) { lengths.shift(); } if (inputs.tryNext) { lengths.push(total + inputs.length); } const res = this.geomService.pointsOnCompCurveAtLengths({ lengths, shape: curve }); if (inputs.includeLast) { res.push(this.endPointOnWire({ shape: wire })); } curve.delete(); return res; } pointsOnWireAtPatternOfLengths(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const wireLength = this.getWireLength({ shape: wire }); const lengths = []; let total = 0; let lastIndex = 0; let reachedGoal = false; while (!reachedGoal) { for (let i = 0; i < inputs.lengths.length; i++) { const length = inputs.lengths[i]; if (total + length <= wireLength) { lengths.push(total + length); total += length; lastIndex = i; } else { reachedGoal = true; break; } } } if (inputs.includeFirst) { lengths.unshift(0); } if (inputs.tryNext) { if (lastIndex + 1 < inputs.lengths.length) { lengths.push(total + inputs.lengths[lastIndex + 1]); } else { lengths.push(total + inputs.lengths[0]); } } const res = this.geomService.pointsOnCompCurveAtLengths({ lengths, shape: curve }); if (inputs.includeLast) { res.push(this.endPointOnWire({ shape: wire })); } curve.delete(); return res; } tangentOnWireAtLength(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const res = this.geomService.tangentOnCurveAtLengthCompCurve(Object.assign(Object.assign({}, inputs), { shape: curve })); curve.delete(); return res; } interpolatePoints(inputs) { // Create flat array of coordinates for the new API const coords = new this.occ.VectorDouble(); for (const pt of inputs.points) { coords.push_back(pt[0]); coords.push_back(pt[1]); coords.push_back(pt[2]); } let wire; if (inputs.periodic) { wire = this.occ.MakePeriodicBSplineWire(coords); } else { const edge = this.occ.MakeBSplineEdge(coords); const wireMaker = new this.occ.BRepBuilderAPI_MakeWire(edge); wire = wireMaker.Wire(); edge.delete(); wireMaker.delete(); } coords.delete(); if (wire && !wire.IsNull()) { return wire; } else { return undefined; } } /** * Interpolate points with symmetric periodic (closed) curve * Uses chord-based tangent constraints to ensure the curve is symmetrical * (e.g., 4 points of a square will produce a perfectly symmetric curve like Rhino) * @param inputs Points to interpolate and tolerance * @returns Symmetric periodic BSpline wire */ interpolatePointsSymmetric(inputs) { // Create flat array of coordinates for the new API const coords = new this.occ.VectorDouble(); for (const pt of inputs.points) { coords.push_back(pt[0]); coords.push_back(pt[1]); coords.push_back(pt[2]); } const wire = this.occ.MakeSymmetricPeriodicBSplineWire(coords); coords.delete(); if (wire && !wire.IsNull()) { return wire; } else { return undefined; } } isWireClosed(inputs) { const tolerance = 1.0e-7; const startPointOnWire = this.startPointOnWire({ shape: inputs.shape }); const endPointOnWire = this.endPointOnWire({ shape: inputs.shape }); // This is needed to make follow up algorithm to work properly on open wires const wireIsClosed = this.base.vector.vectorsTheSame({ vec1: endPointOnWire, vec2: startPointOnWire, tolerance }); return wireIsClosed; } splitOnPoints(inputs) { const wire = inputs.shape; // Remove duplicate points to avoid incorrect behavior const splitPoints = this.vecHelper.removeAllDuplicateVectors(inputs.points, 1e-7); // 1. Get the list of edges from the wire in correct order along the wire const edges = this.edgesService.getEdgesAlongWire({ shape: wire }); if (edges.length === 0) return []; // 2. Collect split locations as {edgeIndex, parameter} const splitLocations = []; // Add the wire's start point const firstEdge = edges[0]; let first = { current: 0 }; let last = { current: 0 }; this.occRefReturns.BRep_Tool_Range_1(firstEdge, first, last); splitLocations.push({ edgeIndex: 0, parameter: first.current }); // Project each split point onto the wire splitPoints.forEach((pt) => { let minDist = Infinity; let bestEdgeIndex = -1; let bestParam = 0; edges.forEach((edge, index) => { const first = { current: 0 }; const last = { current: 0 }; this.occRefReturns.BRep_Tool_Range_1(edge, first, last); const firstVal = first.current; const lastVal = last.current; const gpPnt = this.entitiesService.gpPnt(pt); try { const result = this.occ.ProjectPointOnCurve(gpPnt, edge); const param = result.param; // Clamp the parameter to the edge's range const clampedParam = Math.max(firstVal, Math.min(lastVal, param)); const projectedPt = result.Point; const dx = projectedPt.X() - gpPnt.X(); const dy = projectedPt.Y() - gpPnt.Y(); const dz = projectedPt.Z() - gpPnt.Z(); const dist = Math.sqrt(dx * dx + dy * dy + dz * dz); if (dist < minDist) { minDist = dist; bestEdgeIndex = index; bestParam = clampedParam; } projectedPt.delete(); } catch (_a) { // Projection failed, skip this edge } gpPnt.delete(); }); if (bestEdgeIndex >= 0) { splitLocations.push({ edgeIndex: bestEdgeIndex, parameter: bestParam }); } }); // Add the wire's end point const lastEdge = edges[edges.length - 1]; first = { current: 0 }; last = { current: 0 }; this.occRefReturns.BRep_Tool_Range_1(lastEdge, first, last); splitLocations.push({ edgeIndex: edges.length - 1, parameter: last.current }); // 3. Remove duplicates and sort split locations by edgeIndex, then parameter const uniqueLocations = splitLocations.filter((loc, index, self) => index === self.findIndex((t) => t.edgeIndex === loc.edgeIndex && t.parameter === loc.parameter)); uniqueLocations.sort((a, b) => { if (a.edgeIndex !== b.edgeIndex) return a.edgeIndex - b.edgeIndex; return a.parameter - b.parameter; }); // 4. Create new wires between consecutive split locations const newWires = []; for (let i = 0; i < uniqueLocations.length - 1; i++) { const startLoc = uniqueLocations[i]; const endLoc = uniqueLocations[i + 1]; const wireBuilder = new this.occ.BRepBuilderAPI_MakeWire(); if (startLoc.edgeIndex === endLoc.edgeIndex) { // Same edge: create a single trimmed edge const edge = edges[startLoc.edgeIndex]; // Avoid zero-length segments if (startLoc.parameter === endLoc.parameter) continue; const newEdge = this.occ.TrimEdgeToParams(edge, startLoc.parameter, endLoc.parameter); if (!newEdge.IsNull()) { wireBuilder.AddEdge(newEdge); } } else { // Spans multiple edges // Trim the start edge const startEdge = edges[startLoc.edgeIndex]; const startFirst = { current: 0 }; const startLast = { current: 0 }; this.occRefReturns.BRep_Tool_Range_1(startEdge, startFirst, startLast); const startLastVal = startLast.current; if (startLoc.parameter < startLastVal) { const newStartEdge = this.occ.TrimEdgeToParams(startEdge, startLoc.parameter, startLastVal); if (!newStartEdge.IsNull()) { wireBuilder.AddEdge(newStartEdge); } } // Add full edges in between for (let j = startLoc.edgeIndex + 1; j < endLoc.edgeIndex; j++) { wireBuilder.AddEdge(edges[j]); } // Trim the end edge const endEdge = edges[endLoc.edgeIndex]; const endFirst = { current: 0 }; const endLast = { current: 0 }; this.occRefReturns.BRep_Tool_Range_1(endEdge, endFirst, endLast); const endFirstVal = endFirst.current; if (endLoc.parameter > endFirstVal) { const newEndEdge = this.occ.TrimEdgeToParams(endEdge, endFirstVal, endLoc.parameter); if (!newEndEdge.IsNull()) { wireBuilder.AddEdge(newEndEdge); } } } if (wireBuilder.IsDone()) { const newWire = wireBuilder.Wire(); newWires.push(newWire); } } return newWires; } createLines(inputs) { const wires = inputs.lines.map(p => this.createLineWire(p)).filter(s => s !== undefined); return this.converterService.makeCompoundIfNeeded(wires, inputs.returnCompound); } createWireFromTwoCirclesTan(inputs) { const circleEdge1 = this.shapeGettersService.getEdges({ shape: inputs.circle1 }); const circleEdge2 = this.shapeGettersService.getEdges({ shape: inputs.circle2 }); if (circleEdge1.length === 1 && circleEdge2.length === 1) { const circularEdge1 = circleEdge1[0]; const circularEdge2 = circleEdge2[0]; const result = this.edgesService.constraintTanLinesOnTwoCircles({ circle1: circularEdge1, circle2: circularEdge2, positionResult: inputs.keepLines === Inputs.OCCT.twoSidesStrictEnum.outside ? Inputs.OCCT.positionResultEnum.keepSide2 : Inputs.OCCT.positionResultEnum.keepSide1, circleRemainders: this.enumService.convertFourSidesStrictEnumToTwoCircleInclusionEnum(inputs.circleRemainders), tolerance: inputs.tolerance, }); const wire = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: result }); result.forEach(e => e.delete()); circularEdge1.delete(); circularEdge2.delete(); return wire; } else { throw new Error("Could not find the edges of the provided circle wires."); } } createZigZagBetweenTwoWires(inputs) { const wire1 = inputs.wire1; const wire2 = inputs.wire2; let points1 = []; let points2 = []; if (inputs.zigZagsPerEdge) { const edges1 = this.edgesService.getEdgesAlongWire({ shape: wire1 }); const edges2 = this.edgesService.getEdgesAlongWire({ shape: wire2 }); if (inputs.divideByEqualDistance) { points1 = edges1.map(e => this.edgesService.divideEdgeByEqualDistanceToPoints({ shape: e, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })); points2 = edges2.map(e => this.edgesService.divideEdgeByEqualDistanceToPoints({ shape: e, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })); } else { points1 = edges1.map(e => this.edgesService.divideEdgeByParamsToPoints({ shape: e, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })); points2 = edges2.map(e => this.edgesService.divideEdgeByParamsToPoints({ shape: e, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })); } } else { if (inputs.divideByEqualDistance) { points1 = [this.divideWireByEqualDistanceToPoints({ shape: wire1, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })]; points2 = [this.divideWireByEqualDistanceToPoints({ shape: wire2, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })]; } else { points1 = [this.divideWireByParamsToPoints({ shape: wire1, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })]; points2 = [this.divideWireByParamsToPoints({ shape: wire2, nrOfDivisions: inputs.nrZigZags * 2, removeEndPoint: false, removeStartPoint: false })]; } } const wires = points1.map((pts1, index) => { const pts2 = points2[index]; const ptsInZigZagOrder = []; for (let i = 0; i < pts1.length; i++) { if (i % 2 === 0) { if (inputs.inverse) { ptsInZigZagOrder.push(pts2[i]); } else { ptsInZigZagOrder.push(pts1[i]); } } else { if (inputs.inverse) { ptsInZigZagOrder.push(pts1[i]); } else { ptsInZigZagOrder.push(pts2[i]); } } } return this.createPolylineWire({ points: ptsInZigZagOrder }); }); return this.converterService.combineEdgesAndWiresIntoAWire({ shapes: wires }); } getWireCenterOfMass(inputs) { return this.geomService.getLinearCenterOfMass(inputs); } hexagonsInGrid(inputs) { const hex = this.base.point.hexGridScaledToFit(Object.assign(Object.assign({}, inputs), { centerGrid: true, pointsOnGround: true })); const wires = hex.hexagons.map(hex => { return this.createPolygonWire({ points: hex }); }); let currentScalePatternWidthIndex = 0; let currentScalePatternHeightIndex = 0; let currentInclusionPatternIndex = 0; let currentFilletPatternIndex = 0; const res = []; for (let i = 0; i < inputs.nrHexagonsInHeight; i++) { for (let j = 0; j < inputs.nrHexagonsInWidth; j++) { let scaleFromPatternWidth = 1; if (inputs.scalePatternWidth && inputs.scalePatternWidth.length > 0) { scaleFromPatternWidth = inputs.scalePatternWidth[currentScalePatternWidthIndex]; currentScalePatternWidthIndex++; if (currentScalePatternWidthIndex >= inputs.scalePatternWidth.length) { currentScalePatternWidthIndex = 0; } } let scaleFromPatternHeight = 1; if (inputs.scalePatternHeight && inputs.scalePatternHeight.length > 0) { scaleFromPatternHeight = inputs.scalePatternHeight[currentScalePatternHeightIndex]; currentScalePatternHeightIndex++; if (currentScalePatternHeightIndex >= inputs.scalePatternHeight.length) { currentScalePatternHeightIndex = 0; } } let include = true; if (inputs.inclusionPattern && inputs.inclusionPattern.length > 0) { include = inputs.inclusionPattern[currentInclusionPatternIndex]; currentInclusionPatternIndex++; if (currentInclusionPatternIndex >= inputs.inclusionPattern.length) { currentInclusionPatternIndex = 0; } } let fillet = 0; if (inputs.filletPattern && inputs.filletPattern.length > 0) { fillet = inputs.filletPattern[currentFilletPatternIndex]; currentFilletPatternIndex++; if (currentFilletPatternIndex >= inputs.filletPattern.length) { currentFilletPatternIndex = 0; } } if (include) { fillet = hex.maxFilletRadius * fillet; const hexagon = wires[i * inputs.nrHexagonsInWidth + j]; const hexagonCenter = hex.centers[i * inputs.nrHexagonsInWidth + j]; if (fillet > 0) { const filletRectangle = this.filletsService.fillet2d({ shape: hexagon, radius: fillet, }); const scaleVec2 = [scaleFromPatternWidth, 1, scaleFromPatternHeight]; let hexScaled = filletRectangle; if (scaleFromPatternWidth !== 1 || scaleFromPatternHeight !== 1) { hexScaled = this.transformsService.scale3d({ shape: filletRectangle, center: hexagonCenter, scale: scaleVec2, }); } res.push(hexScaled); } else { const scaleVec2 = [scaleFromPatternWidth, 1, scaleFromPatternHeight]; let hexScaled = hexagon; if (scaleFromPatternWidth !== 1 || scaleFromPatternHeight !== 1) { hexScaled = this.transformsService.scale3d({ shape: hexagon, center: hexagonCenter, scale: scaleVec2, }); } res.push(hexScaled); } } } } return res; } createWireFromEdge(inputs) { const makeWire = new this.occ.BRepBuilderAPI_MakeWire(inputs.shape); const wire = makeWire.Wire(); makeWire.delete(); return wire; } createBSpline(inputs) { // Create flat array of coordinates for the new API const coords = new this.occ.VectorDouble(); for (const pt of inputs.points) { coords.push_back(pt[0]); coords.push_back(pt[1]); coords.push_back(pt[2]); } // If closed, add first point again if (inputs.closed) { coords.push_back(inputs.points[0][0]); coords.push_back(inputs.points[0][1]); coords.push_back(inputs.points[0][2]); } // Use MakeApproxBSplineEdge which uses GeomAPI_PointsToBSpline const edge = this.occ.MakeApproxBSplineEdge(coords, 3, 8, 1.0e-3); const wireMaker = new this.occ.BRepBuilderAPI_MakeWire(edge); const wire = wireMaker.Wire(); coords.delete(); edge.delete(); wireMaker.delete(); return wire; } createBezier(inputs) { // Create flat array of coordinates for the new API const coords = new this.occ.VectorDouble(); for (const pt of inputs.points) { coords.push_back(pt[0]); coords.push_back(pt[1]); coords.push_back(pt[2]); } // If closed, add first point again if (inputs.closed) { coords.push_back(inputs.points[0][0]); coords.push_back(inputs.points[0][1]); coords.push_back(inputs.points[0][2]); } const wire = this.occ.MakeBezierWire(coords); coords.delete(); return wire; } createBezierWeights(inputs) { if (!inputs.closed && inputs.points.length !== inputs.weights.length) { throw new Error("Number of points and weights must be the same when bezier is not closed."); } else if (inputs.closed && inputs.points.length !== inputs.weights.length - 1) { throw new Error("Number of points must be one less than number of weights when bezier is closed."); } // Create flat array of coordinates for the new API const coords = new this.occ.VectorDouble(); for (const pt of inputs.points) { coords.push_back(pt[0]); coords.push_back(pt[1]); coords.push_back(pt[2]); } // If closed, add first point again if (inputs.closed) { coords.push_back(inputs.points[0][0]); coords.push_back(inputs.points[0][1]); coords.push_back(inputs.points[0][2]); } // Create weights array const weights = new this.occ.VectorDouble(); for (const w of inputs.weights) { weights.push_back(w); } const wire = this.occ.MakeWeightedBezierWire(coords, weights); coords.delete(); weights.delete(); return wire; } addEdgesAndWiresToWire(inputs) { const makeWire = new this.occ.BRepBuilderAPI_MakeWire(); makeWire.AddWire(inputs.shape); inputs.shapes.forEach((shape) => { if (shape.ShapeType() === this.occ.TopAbs_ShapeEnum.EDGE) { makeWire.AddEdge(shape); } else if (shape.ShapeType() === this.occ.TopAbs_ShapeEnum.WIRE) { makeWire.AddWire(shape); } }); let result; if (makeWire.IsDone()) { result = makeWire.Wire(); } else { throw new Error("Wire could not be constructed. Check if edges and wires do not have disconnected elements."); } makeWire.delete(); return result; } startPointOnWire(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const res = this.geomService.startPointOnCurve({ shape: curve }); return res; } midPointOnWire(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const res = this.geomService.pointOnCurveAtParam({ shape: curve, param: 0.5 }); return res; } endPointOnWire(inputs) { const wire = inputs.shape; const curve = new this.occ.BRepAdaptor_CompCurve(wire, false); const res = this.geomService.endPointOnCurve({ shape: curve }); return res; } textWires(inputs) { const lines = this.base.textService.vectorText(inputs); const wires = []; lines.forEach((line) => { line.chars.forEach((char) => { char.paths.forEach(polyline => { const wire = this.createPolylineWire({ points: polyline }); if (wire) { wires.push(wire); } }); }); }); return wires; } textWiresWithData(inputs) { const lines = this.base.textService.vectorText(inputs); const wires = []; const characterCompounds = []; lines.forEach((line) => { line.chars.forEach((char, index) => { const characterWires = []; char.paths.forEach(polyline => { const wire = this.createPolylineWire({ points: polyline }); if (wire) { wires.push(wire); characterWires.push(wire); } }); const characterCompound = this.converterService.makeCompound({ shapes: characterWires }); characterCompounds.push({ id: `char-${index}`, shape: characterCompound }); }); }); const compound = this.converterService.makeCompound({ shapes: wires }); const dataRes = new TextWiresDataDto(); const box = this.operationsService.boundingBoxOfShape({ shape: compound }); const width = box.max[0] - box.min[0]; const height = box.max[1] - box.min[1]; dataRes.width = width; dataRes.height = height; dataRes.compound = "text-compound"; const res = new ObjectDefinition(); res.data = dataRes; res.compound = compound; res.shapes = [{ id: "text-compound", shape: compound }, ...characterCompounds]; return res; } placeWire(wire, surface) { const edges = this.shapeGettersService.getEdges({ shape: wire }); const newEdges = []; edges.forEach(e => { const umin = { current: 0 }; const umax = { current: 0 }; this.occRefReturns.BRep_Tool_Range_1(e, umin, umax); // Use the new API: GetEdgeCurve returns Handle_Geom_Curve wrapper const crv = this.occ.GetEdgeCurve(e); if (crv && !crv.IsNull()) { const plane = this.entitiesService.gpPln([0, 0, 0], [0, 1, 0]); const c2 = this.occ.GeomAPI_To2d(crv, plane); const newEdgeOnSrf = this.edgesService.makeEdgeFromGeom2dCurveAndSurfaceBounded({ curve: c2, surface }, umin.current, umax.current); if (newEdgeOnSrf) { newEdges.push(newEdgeOnSrf); } plane.delete(); c2.delete(); crv.delete(); } }); edges.forEach(e => e.delete()); const res = this.converterService.combineEdgesAndWiresIntoAWire({ shapes: newEdges }); newEdges.forEach(e => e.delete()); return res; } wiresToPoints(inputs) { const wires = this.shapeGettersService.getWires({ shape: inputs.shape }); const allWirePoints = []; wires.forEach(w => { const edgePoints = this.edgesService.edgesToPoints(Object.assign(Object.assign({}, inputs), { shape: w })); const flatPoints = edgePoints.flat(); const dupsRemoved = this.vecHelper.removeConsecutiveDuplicates(flatPoints, false); allWirePoints.push(dupsRemoved); }); return allWirePoints; } createHelixWire(inputs) { const ax = this.entitiesService.gpAx3_4(inputs.center, inputs.direction); const wire = this.occ.MakeHelixWire(ax, inputs.radius, inputs.pitch, inputs.height, inputs.clockwise, inputs.tolerance); ax.delete(); return wire; } createHelixWireByTurns(inputs) { const ax = this.entitiesService.gpAx3_4(inputs.center, inputs.direction); const wire = this.occ.MakeHelixWireByTurns(ax, inputs.radius, inputs.pitch, inputs.numTurns, inputs.clockwise, inputs.tolerance); ax.delete(); return wire; } createTaperedHelixWire(inputs) { const ax = this.entitiesService.gpAx3_4(inputs.center, inputs.direction); const wire = this.occ.MakeTaperedHelixWire(ax, inputs.startRadius, inputs.endRadius, inputs.pitch, inputs.height, inputs.clockwise, inputs.tolerance); ax.delete(); return wire; } createFlatSpiralWire(inputs) { const ax = this.entitiesService.gpAx3_4(inputs.center, inputs.direction); const wire = this.occ.MakeFlatSpiralWire(ax, inputs.startRadius, inputs.endRadius, inputs.numTurns, inputs.clockwise, inputs.tolerance); ax.delete(); return wire; } }