Example in TypeScript

Example in TypeScript script details
Type
Typescript logo image
typescript
App Version
0.13.0
Visibility
public
Date Created
Mar 19, 2021, 1:29:25 PM
Last Edit Date
Dec 5, 2023, 6:02:15 PM

Script Details

The Code
type TopoDSShapePointer = Bit.Inputs.OCCT.TopoDSShapePointer; start(); async function start() { const hexRadius = 20; const innerSideLength = 1.5; const nrHexagonsX = 6; const nrHexagonsY = 7; const cornerFilletRadiusForBase = 0.6; createLightsAndAdjustCamera(); const trianglePoints = createTrianglePoints(hexRadius); const baseFlatTriangle = await baseSetupForHexagonTriangleShape(trianglePoints); const hexGrid = makeHexGrid(nrHexagonsX, nrHexagonsY, hexRadius); const linesForIntersection = verticalLinesForIntersection(hexGrid); const nurbsSurface = createNurbsSurfaceForHexGridProjections(hexGrid, nrHexagonsY); const pointsOnSurface = findIntersectionsOnSurface(linesForIntersection, nurbsSurface); const pointsAboveSurface = bitbybit.point.transformPoints({ points: pointsOnSurface, transformation: bitbybit.babylon.transforms.translationXYZ({ translation: [0, 15, 0] }) }); const columns = bitbybit.line.linesBetweenStartAndEndPoints({ startPoints: hexGrid, endPoints: pointsAboveSurface }); const bulbBox = await bitbybit.occt.shapes.solid.createBox({ width: 1, length: 1, height: 4, center: [0, 0, 0] }); const loftSolid = await createLoftSolid(trianglePoints[1], trianglePoints[2]); const innerVoidSolid = await createSolidForDifference(-innerSideLength, baseFlatTriangle); const baseTriangleSolid = await findDifferenceAndFilletResult(loftSolid, innerVoidSolid, cornerFilletRadiusForBase); const chamferedGlassSolid = await createChamferGlassSolid(baseTriangleSolid); const hexagonsBase = await rotateTriangles(baseTriangleSolid, 0, 300, 60); const hexagonsGlass = await rotateTriangles(chamferedGlassSolid, 0, 300, 60); const ground = await bitbybit.occt.transforms.translate({ shape: await bitbybit.occt.shapes.solid.createBox({ width: 500, length: 500, height: 1, center: [0, 0, 0] }), translation: [125, 0, 125] }) drawEverything(hexagonsBase, hexagonsGlass, bulbBox, ground, pointsOnSurface, pointsAboveSurface, columns); } function createLightsAndAdjustCamera() { bitbybit.babylon.scene.adjustActiveArcRotateCamera({ position: [250, 170, 250], lookAt: [0, 0, 0], maxZ: 1000, wheelPrecision: 3, panningSensibility: 100 }); const lightOpts = { diffuse: '#ff99ff', specular: '#ffffff', radius: 0.5, intensity: 60000 }; bitbybit.babylon.scene.drawPointLight({ position: [200, 130, 200], ...lightOpts }); bitbybit.babylon.scene.drawPointLight({ position: [0, 160, 0], ...lightOpts }); bitbybit.babylon.scene.drawPointLight({ position: [200, 130, 200], ...lightOpts }); } async function baseSetupForHexagonTriangleShape(trianglePoints: Bit.Inputs.Base.Point3[]): Promise<TopoDSShapePointer> { return await bitbybit.occt.shapes.wire.createPolygonWire({ points: trianglePoints }); } function createTrianglePoints(length: number): Bit.Inputs.Base.Point3[] { const lineOrient = bitbybit.line.create({ start: [0, 0, 0], end: [0, 0, length] }); const point1 = [0, 0, 0] as Bit.Inputs.Base.Point3; const point2 = bitbybit.line.getEndPoint({ line: bitbybit.line.transformLine({ line: lineOrient, transformation: bitbybit.babylon.transforms.rotationCenterY({ center: [0, 0, 0], angle: 59.99 }) }) }); const point3 = bitbybit.line.getEndPoint({ line: bitbybit.line.transformLine({ line: lineOrient, transformation: bitbybit.babylon.transforms.rotationCenterY({ center: [0, 0, 0], angle: 0.01 }) }) }); return [point1, point2, point3]; } function makeHexGrid(nrHexagonsX: number, nrHexagonsY: number, radiusHexagon: number) { return bitbybit.point.transformPoints({ points: bitbybit.point.hexGrid({ nrHexagonsX, nrHexagonsY, radiusHexagon }), transformation: bitbybit.babylon.transforms.rotationCenterX({ angle: 90, center: [0, 0, 0] }) }); } function verticalLinesForIntersection(hexGrid: Bit.Inputs.Base.Point3[]) { return bitbybit.line.linesBetweenStartAndEndPoints({ startPoints: hexGrid, endPoints: bitbybit.point.transformPoints({ points: hexGrid, transformation: bitbybit.babylon.transforms.translationXYZ({ translation: [0, 200, 0] }) }) }); } function createNurbsSurfaceForHexGridProjections(hexGridPoints: Bit.Inputs.Base.Point3[], nrHexagonsY: number) { const surface = bitbybit.verb.surface.createSurfaceByCorners({ point1: bitbybit.point.transformPoint({ point: hexGridPoints[0], transformation: bitbybit.babylon.transforms.translationXYZ({ translation: [0, 100, 0] }), }), point2: bitbybit.point.transformPoint({ point: hexGridPoints[nrHexagonsY - 1], transformation: bitbybit.babylon.transforms.translationXYZ({ translation: [0, 50, 0] }), }), point3: bitbybit.point.transformPoint({ point: hexGridPoints[hexGridPoints.length - 1], transformation: bitbybit.babylon.transforms.translationXYZ({ translation: [0, 90, 0] }), }), point4: bitbybit.point.transformPoint({ point: hexGridPoints[hexGridPoints.length - nrHexagonsY], transformation: bitbybit.babylon.transforms.translationXYZ({ translation: [0, 40, 0] }), }), }); return bitbybit.verb.surface.transformSurface({ surface, transformation: [ bitbybit.babylon.transforms.scaleXYZ({ scaleXyz: [1.5, 1, 1.5] }), bitbybit.babylon.transforms.translationXYZ({ translation: [-20, 0, -20] }) ] }) } function findIntersectionsOnSurface(linesForIntersection: Bit.Inputs.Line.LinePointsDto[], surface: number): Bit.Inputs.Base.Point3[] { return linesForIntersection.map(line => { const curve = bitbybit.line.convertToNurbsCurve({ line }); const intersection = bitbybit.verb.intersect.curveAndSurface({ curve, surface }); let result; if (intersection.length > 0) { result = intersection[0].curvePoint; } else { result = line.start; } return result; }) } async function createLoftSolid(point2: number[], point3: number[]): Promise<TopoDSShapePointer> { const heightOfHexagon = 14; const tiltedBottomTriangleWire = await bitbybit.occt.shapes.wire.createPolygonWire({ points: [ [0, 5, 0], [point2[0], 0, point2[2]], [point3[0], 0, point3[2]], ] }); const tiltedTopTriangleWire = await bitbybit.occt.shapes.wire.createPolygonWire({ points: [ [0, 10, 0], [point2[0], heightOfHexagon, point2[2]], [point3[0], heightOfHexagon, point3[2]], ] }); return await bitbybit.occt.operations.loft({ shapes: [tiltedBottomTriangleWire, tiltedTopTriangleWire], makeSolid: true }); } async function createSolidForDifference(offset: number, baseTriangle: TopoDSShapePointer): Promise<TopoDSShapePointer> { const offTriangleWire = await bitbybit.occt.operations.offset({ shape: baseTriangle, distance: offset, tolerance: 0.00001 }); const offTraingleFace = await bitbybit.occt.shapes.face.createFaceFromWire({ shape: offTriangleWire, planar: true }); return await bitbybit.occt.operations.extrude({ shape: offTraingleFace, direction: [0, 50, 0] }); } async function findDifferenceAndFilletResult(outerSolid, innerSolid, radius): Promise<TopoDSShapePointer> { const hollowSolid = await bitbybit.occt.booleans.difference({ shape: outerSolid, shapes: [innerSolid], keepEdges: true }); return await bitbybit.occt.fillets.filletEdges({ shape: hollowSolid, radius, indexes: undefined }); } async function createChamferGlassSolid(baseTriangleSolid: TopoDSShapePointer): Promise<TopoDSShapePointer> { const edgeIndexesToChamfer = [15, 12, 3]; const faceIndexForWire = 14; const chamferDist = 0.5; const wireOfFilletShape = await bitbybit.occt.shapes.wire.getWire({ shape: baseTriangleSolid, index: faceIndexForWire }); const faceOfTheWire = await bitbybit.occt.shapes.face.createFaceFromWire({ shape: wireOfFilletShape, planar: true }); const extruded = await bitbybit.occt.operations.extrude({ shape: faceOfTheWire, direction: [0, 1, 0] }); return await bitbybit.occt.fillets.chamferEdges({ shape: extruded, distance: chamferDist, indexes: edgeIndexesToChamfer }); } async function rotateTriangles(shape: TopoDSShapePointer, angleFrom: number, angleTo: number, angleStep: number): Promise<TopoDSShapePointer[]> { let result = []; for (let angle = angleFrom; angle <= angleTo; angle += angleStep) { const rotated = await bitbybit.occt.transforms.rotate({ shape, axis: [0, 1, 0], angle }); result.push(rotated); } return result; } async function drawEverything( hexagonsBase: Bit.Inputs.OCCT.TopoDSShapePointer[], hexagonsGlass: Bit.Inputs.OCCT.TopoDSShapePointer[], bulbBox: Bit.Inputs.OCCT.TopoDSShapePointer, ground: Bit.Inputs.OCCT.TopoDSShapePointer, pointsOnHexagonSurface: Bit.Inputs.Base.Point3[], pointsAboveSurface: Bit.Inputs.Base.Point3[], columns, ): Promise<void> { const whiteColour = '#ffffff'; const violetColour = '#993399'; const goldColour = '#ffcc33'; const blueColour = '#3366ff'; const blackColour = '#000000'; const lineDrawOptions = new Bit.Inputs.Line.DrawLinesDto(columns); lineDrawOptions.size = 50; lineDrawOptions.opacity = 0.5; lineDrawOptions.colours = whiteColour; bitbybit.line.drawLines(lineDrawOptions); const hexagonsBaseInPosition = await Promise.all(hexagonsBase.map(hexagonBase => { return bitbybit.occt.transforms.translate({ shape: hexagonBase, translation: pointsOnHexagonSurface[0], }) })); const hexagonsGlassInPosition = await Promise.all(hexagonsGlass.map(hexagonGlass => { return bitbybit.occt.transforms.translate({ shape: hexagonGlass, translation: pointsOnHexagonSurface[0], }) })); const drawingOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions(); drawingOptions.precision = 1; drawingOptions.faceColour = violetColour; drawingOptions.edgeColour = whiteColour; drawingOptions.edgeWidth = 5; await bitbybit.draw.drawAny({ entity: hexagonsBaseInPosition[0], options: drawingOptions }); drawingOptions.faceColour = goldColour; drawingOptions.faceOpacity = 0.3; drawingOptions.drawEdgeIndexes = true; drawingOptions.edgeIndexHeight = 0.15; drawingOptions.edgeWidth = 3; drawingOptions.edgeIndexColour = whiteColour; await bitbybit.draw.drawAnyAsync({ entity: hexagonsGlassInPosition[0], options: drawingOptions }); const fiveTriangleBasesOnFirsHexagon = await bitbybit.occt.shapes.compound.makeCompound({ shapes: hexagonsBaseInPosition.filter((_, index) => index !== 0) }); drawingOptions.faceColour = violetColour; drawingOptions.faceOpacity = 0.2; drawingOptions.drawEdgeIndexes = false; drawingOptions.edgeWidth = 3; drawingOptions.edgeOpacity = 0.6; await bitbybit.draw.drawAnyAsync({ entity: fiveTriangleBasesOnFirsHexagon, options: drawingOptions }); const compoundRemainderBases = await bitbybit.occt.shapes.compound.makeCompound({ shapes: hexagonsBase }); const compoundRemainderGlasses = await bitbybit.occt.shapes.compound.makeCompound({ shapes: hexagonsGlass }); drawingOptions.precision = 40; drawingOptions.drawEdges = false; drawingOptions.faceColour = blueColour; drawingOptions.faceOpacity = 1; const meshBase = await bitbybit.draw.drawAnyAsync({ entity: compoundRemainderBases, options: drawingOptions }); drawingOptions.faceColour = goldColour; drawingOptions.faceOpacity = 0.3; const meshGlass = await bitbybit.draw.drawAnyAsync({ entity: compoundRemainderGlasses, options: drawingOptions }); const pointsOnWhichToDrawRemainder = pointsOnHexagonSurface.filter((_, index) => index !== 0); pointsOnWhichToDrawRemainder.forEach(point => { bitbybit.babylon.mesh.createMeshInstanceAndTransform({ mesh: meshBase, position: point, rotation: [0, 0, 0], scaling: [1, 1, 1], }); bitbybit.babylon.mesh.createMeshInstanceAndTransform({ mesh: meshGlass, position: point, rotation: [0, 0, 0], scaling: [1, 1, 1], }); }); const boxDrawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions(); boxDrawOptions.drawEdges = false; boxDrawOptions.faceColour = whiteColour; const meshBulbBox = await bitbybit.draw.drawAnyAsync({ entity: bulbBox, options: boxDrawOptions }); pointsAboveSurface.forEach(point => { bitbybit.babylon.mesh.createMeshInstanceAndTransform({ mesh: meshBulbBox, position: point, rotation: [0, 0, 0], scaling: [1, 1, 1], }) }); const groundDrawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions(); groundDrawOptions.drawEdges = false; groundDrawOptions.faceOpacity = 0.99; groundDrawOptions.faceColour = blackColour; await bitbybit.draw.drawAnyAsync({ entity: ground, options: groundDrawOptions }); }