@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
JavaScript
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;
}
}