214 lines
6.7 KiB
JavaScript
214 lines
6.7 KiB
JavaScript
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
|
|
|
"use strict";
|
|
|
|
// dep: kiri-mode.cam.driver
|
|
gapp.register("kiri-mode.cam.tools", [], (root, exports) => {
|
|
|
|
const { kiri } = root;
|
|
const { driver } = kiri;
|
|
const { CAM } = driver;
|
|
|
|
const HPI = Math.PI/2;
|
|
const RAD2DEG = 180/Math.PI;
|
|
|
|
class Tool {
|
|
constructor(settings, id, number) {
|
|
if (number >= 0) {
|
|
this.tool = settings.tools.filter(tool => tool.number == number)[0];
|
|
} else {
|
|
this.tool = settings.tools.filter(tool => tool.id == id)[0];
|
|
}
|
|
if (!this.tool) {
|
|
this.tool = Object.assign({}, settings.tools[0]);
|
|
this.tool.number = number >= 0 ? number : this.tool.number;
|
|
this.tool.id = id >= 0 ? id : this.tool.id;
|
|
}
|
|
}
|
|
|
|
getID() {
|
|
return this.tool.id;
|
|
}
|
|
|
|
getName() {
|
|
return this.tool.name;
|
|
}
|
|
|
|
getType() {
|
|
return this.tool.type;
|
|
}
|
|
|
|
getNumber() {
|
|
return this.tool.number;
|
|
}
|
|
|
|
isMetric() {
|
|
return this.tool.metric;
|
|
}
|
|
|
|
unitScale() {
|
|
return this.isMetric() ? 1 : 25.4;
|
|
}
|
|
|
|
fluteLength() {
|
|
return this.unitScale() * this.tool.flute_len;
|
|
}
|
|
|
|
fluteDiameter() {
|
|
return this.unitScale() * this.tool.flute_diam;
|
|
}
|
|
|
|
tipDiameter() {
|
|
return this.unitScale() * this.tool.taper_tip;
|
|
}
|
|
|
|
maxDiameter() {
|
|
return Math.max(this.fluteDiameter(), this.tipDiameter(), this.shaftDiameter());
|
|
}
|
|
|
|
traceOffset() {
|
|
return (this.hasTaper() ? this.tipDiameter() : this.fluteDiameter()) / 2;
|
|
}
|
|
|
|
contourOffset(step) {
|
|
const diam = Math.min(this.hasTaper() ? this.tipDiameter() : this.fluteDiameter());
|
|
return diam ? diam * step : step;
|
|
}
|
|
|
|
setTaperLengthFromAngle(angle) {
|
|
const rad = (this.flute_diam - this.taper_tip) / 2;
|
|
return this.flute_len = CAM.calcTaperLength(rad, angle);
|
|
}
|
|
|
|
getTaperAngle() {
|
|
return CAM.calcTaperAngle((this.flute_diam - this.taper_tip) / 2, this.flute_len);
|
|
}
|
|
|
|
shaftLength() {
|
|
return this.unitScale() * this.tool.shaft_len;
|
|
}
|
|
|
|
/**
|
|
* returns the length of the drill tip as a function of the flute diameter,
|
|
* given a 118 deg point angle. the result is in workspace units.
|
|
*
|
|
* @return {number} length of the drill tip.
|
|
*/
|
|
drillTipLength() {
|
|
const drillAngleRad = 140 * Math.PI / 180;
|
|
return 0.5 * this.fluteDiameter() * Math.sin(drillAngleRad);
|
|
}
|
|
|
|
shaftDiameter() {
|
|
return this.unitScale() * this.tool.shaft_diam;
|
|
}
|
|
|
|
isBallMill() {
|
|
return this.tool.type === "ballmill";
|
|
}
|
|
|
|
isTaperMill() {
|
|
return this.tool.type === "tapermill";
|
|
}
|
|
|
|
isDrill(){
|
|
return this.tool.type === "drill";
|
|
}
|
|
|
|
hasTaper() {
|
|
return this.isTaperMill();
|
|
}
|
|
|
|
/**
|
|
* generate tool profile with resolution number of pixels. the result is a
|
|
* Float32Array stored in `this.profile` and `this.profileDim` containing
|
|
* dimensions of the profile in pixels and shared array buffer size.
|
|
*
|
|
* @param {number} resolution - number of pixels for the tool profile
|
|
*
|
|
* @return {Tool} this
|
|
*/
|
|
generateProfile(resolution) {
|
|
// generate tool profile
|
|
let ball = this.isBallMill(),
|
|
taper = this.hasTaper(),
|
|
drill = this.isDrill(),
|
|
tip_diameter = this.tipDiameter(),
|
|
drill_tip_length = this.drillTipLength(),
|
|
shaft_offset = this.fluteLength(),
|
|
flute_diameter = this.fluteDiameter(),
|
|
shaft_diameter = Math.max(flute_diameter, this.shaftDiameter()),
|
|
max_diameter = Math.max(flute_diameter, shaft_diameter),
|
|
shaft_pix_float = max_diameter / resolution,
|
|
shaft_pix_int = Math.round(shaft_pix_float),
|
|
shaft_radius_pix_float = shaft_pix_float / 2,
|
|
flute_radius = flute_diameter / 2,
|
|
flute_pix_float = flute_diameter / resolution,
|
|
flute_radius_pix_float = flute_pix_float / 2,
|
|
tip_pix_float = tip_diameter / resolution,
|
|
tip_radius_pix_float = tip_pix_float / 2,
|
|
tip_max_radius_offset = flute_radius_pix_float - tip_radius_pix_float,
|
|
profile_pix_iter = shaft_pix_int + (1 - shaft_pix_int % 2),
|
|
toolCenter = (shaft_pix_int - (shaft_pix_int % 2)) / 2,
|
|
toolOffset = [],
|
|
larger_shaft = shaft_diameter - flute_diameter > 0.001,
|
|
rpixsq = flute_radius_pix_float * flute_radius_pix_float,
|
|
maxo = -Infinity;
|
|
|
|
// for each point in tool profile, check inside radius
|
|
for (let x = 0; x < profile_pix_iter; x++) {
|
|
for (let y = 0; y < profile_pix_iter; y++) {
|
|
let dx = x - toolCenter,
|
|
dy = y - toolCenter,
|
|
dist_from_center = Math.sqrt(dx * dx + dy * dy);
|
|
if (dist_from_center <= flute_radius_pix_float) { // if xy point inside flute radius
|
|
maxo = Math.max(maxo, dx, dy);
|
|
// flute offset points
|
|
let z_offset = 0;
|
|
if (ball) {
|
|
let rd = dist_from_center * dist_from_center;
|
|
z_offset = Math.sqrt(rpixsq - rd) * resolution - flute_radius;
|
|
// z_offset = (1 - Math.cos((dist_from_center / flute_radius_pix_float) * HPI)) * -flute_radius;
|
|
} else if (taper && dist_from_center >= tip_radius_pix_float) {// if tapered and not in the flat tip radius
|
|
z_offset = ((dist_from_center - tip_radius_pix_float) / tip_max_radius_offset) * -shaft_offset;
|
|
}else if(drill){
|
|
z_offset = -dist_from_center /45;
|
|
}
|
|
toolOffset.push(dx, dy, z_offset);
|
|
} else if (shaft_offset && larger_shaft && dist_from_center <= shaft_radius_pix_float) {
|
|
// shaft offset points
|
|
toolOffset.push(dx, dy, -shaft_offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
// convert to shared array for use with minions
|
|
const profile = new Float32Array(new SharedArrayBuffer(toolOffset.length * 4));
|
|
profile.set(toolOffset);
|
|
|
|
this.profile = profile;
|
|
this.profileDim = {
|
|
size: shaft_diameter,
|
|
pix: profile_pix_iter + 2,
|
|
maxo
|
|
};
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
CAM.Tool = Tool;
|
|
|
|
CAM.calcTaperAngle = function(rad, len) {
|
|
return (Math.atan(rad / len) * RAD2DEG);
|
|
};
|
|
|
|
CAM.calcTaperLength = function(rad, angle) {
|
|
return (rad / Math.tan(angle));
|
|
};
|
|
|
|
CAM.getToolDiameter = function(settings, id) {
|
|
return new CAM.Tool(settings, id).fluteDiameter();
|
|
};
|
|
|
|
});
|