import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; import { ApplicationContext } from "cad/context"; import { EntityKind } from "cad/model/entities"; import { OperationDescriptor } from "cad/craft/operationBundle"; import { SetLocation } from "cad/craft/e0/interact"; import { MDatum } from "cad/model/mdatum"; import icon from "./HOLE.svg"; import { MFace } from 'cad/model/mface'; import { Matrix3x4 } from "math/matrix"; import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition"; import { applyRotation } from 'cad/craft/datum/rotate/rotateDatumOperation'; import CSysObject3D from 'cad/craft/datum/csysObject'; import { Circle } from 'cad/sketch/sketchModel'; import { ExpectedOrderProductionAnalyzer } from "cad/craft/production/productionAnalyzer"; interface HoleParams { sketch: MDatum | MFace; diameter: number; depth: number; counterBoreDiameter: number; counterBoreDepth: number; countersinkDiameter: number; countersinkAngle: number; holeType: string; boolean: BooleanDefinition; invertDirection: boolean; } export const HoleOperation: OperationDescriptor = { id: 'HOLE_TOOL', label: 'hole', icon, info: 'creates hole features', path: __dirname, paramsInfo: ({ diameter, depth, counterBoreDiameter, counterBoreDepth, countersinkDiameter, countersinkAngle, holeType, }) => `(${r(depth)} ${r(counterBoreDiameter)}) ${r(counterBoreDepth)})`, run: (params: HoleParams, ctx: ApplicationContext) => { const occ = ctx.occService; const oci = occ.commandInterface; //make base hole cylinder and fancy modifer geometry for countersink/counterbore oci.pcylinder("result", params.diameter / 2, params.depth); if (params.holeType === "counterbore") { oci.pcylinder("holeModifier", params.counterBoreDiameter / 2, params.counterBoreDepth); } if (params.holeType === "countersink") { const heightFromDiameterAndAngle = (params.countersinkDiameter - params.diameter) / (Math.tan((params.countersinkAngle / 180 * Math.PI) / 2)); oci.pcone("holeModifier", params.countersinkDiameter / 2, 0, heightFromDiameterAndAngle); } //union the base hole and the hole modifier together if (params.holeType !== "normal") { oci.bop("result", "holeModifier"); oci.bopfuse("result"); } //load sketch information from face const sketch = ctx.sketchStorageService.readSketch(params.sketch.id); const csys =params.sketch.csys; const holeSolids = []; //Look for circles and make hole solids using center points sketch.loops.forEach((holeSourceElement) => { if (holeSourceElement instanceof Circle) { holeSolids.push(makeHoleSolid( { id: "holeC" + holeSourceElement.id, x: holeSourceElement.c.x, y: holeSourceElement.c.y, z: holeSourceElement.c.z, csys, invert: params.invertDirection }, ctx)); } }) //check for point objects and make hole solids on locations sketch.points.forEach((holeSourceElement) => { holeSolids.push(makeHoleSolid( { id: "holeP" + holeSourceElement.id, x: holeSourceElement.pt.x, y: holeSourceElement.pt.y, z: holeSourceElement.pt.z, csys, invert: params.invertDirection }, ctx)); }) return occ.utils.applyBooleanModifier(holeSolids, params.boolean); }, form: [ { type: 'selection', name: 'sketch', capture: [EntityKind.FACE], label: 'Sketch', multi: false, defaultValue: { usePreselection: true, preselectionIndex: 0 }, }, { type: 'choice', label: 'Hole Type', name: "holeType", style: "dropdown", defaultValue: "counterbore", values: ['counterbore', 'countersink', 'normal',], }, { type: 'number', name: "diameter", defaultValue: 10, label: 'Hole ⌀' }, { type: 'number', name: "depth", defaultValue: 100, label: 'Hole ↧' }, { type: 'number', name: "counterBoreDiameter", defaultValue: 20, label: '⌴ ⌀' }, { type: 'number', name: "counterBoreDepth", defaultValue: 10, label: '⌴ ↧' }, { type: 'number', name: "countersinkDiameter", defaultValue: 20, label: '⌵ ⌀' }, { type: 'number', name: "countersinkAngle", defaultValue: 90, label: '⌵ Angle' }, { name: "invertDirection", label: 'Invert Direction', type: "checkbox", defaultValue: false }, { type: 'boolean', name: 'boolean', label: 'Boolean', optional: true, simplify: true, defaultValue: "SUBTRACT", } ], } function makeHoleSolid(holePoint, ctx) { const occ = ctx.occService; const oci = occ.commandInterface; const NewHoleName = holePoint.id; oci.copy("result", NewHoleName); const flipped = new Matrix3x4(); if (holePoint.invert === false) flipped.myy = -1; const tr = new Matrix3x4().setTranslation(holePoint.x, holePoint.y, holePoint.z); const location = holePoint.csys.outTransformation.combine(tr.combine(flipped)); SetLocation(NewHoleName, location.toFlatArray()); return occ.io.getShell(NewHoleName); } //Face ID templates function productionAnalyser() { return new ExpectedOrderProductionAnalyzer( [ { id: 'F:SIDE', productionInfo: { role: 'sweep' } }, { id: 'F:BASE', productionInfo: { role: 'base' } }, { id: 'F:LID', productionInfo: { role: 'lid' } }, ], [], [] ); }