refactor: corner radius
This commit is contained in:
+84
-56
@@ -1,73 +1,101 @@
|
||||
import {normalize} from "./normalize";
|
||||
import { normalize } from "./normalize";
|
||||
|
||||
export function pts2plotter(pts: [number, number][][], width: number, height: number, px2mm = 0.1){
|
||||
let str = init(width * px2mm, height * px2mm);
|
||||
/**
|
||||
* 生成 HPGL 代码,支持指定起点和终点
|
||||
* @param pts 路径点数组
|
||||
* @param width 页面宽度(mm)
|
||||
* @param height 页面高度(mm)
|
||||
* @param px2mm 像素到毫米的转换系数
|
||||
* @param startPoint 起点坐标(mm),默认为左上角 [0, height]
|
||||
* @param endPoint 终点坐标(mm),默认为左上角 [0, height]
|
||||
*/
|
||||
export function pts2plotter(
|
||||
pts: [number, number][][],
|
||||
width: number,
|
||||
height: number,
|
||||
px2mm = 0.1,
|
||||
startPoint?: [number, number],
|
||||
endPoint?: [number, number]
|
||||
) {
|
||||
const start = startPoint ?? [0, height];
|
||||
const end = endPoint ?? [0, height];
|
||||
|
||||
let str = init(width * px2mm, height * px2mm);
|
||||
|
||||
// sort paths by x(long) then by y(short)
|
||||
const sorted = pts.slice();
|
||||
sorted.sort(function (a, b) {
|
||||
const [ax,ay] = topleft(a);
|
||||
const [bx,by] = topleft(b);
|
||||
// 按 X 轴然后 Y 轴排序路径
|
||||
const sorted = pts.slice();
|
||||
sorted.sort(function (a, b) {
|
||||
const [ax, ay] = topleft(a);
|
||||
const [bx, by] = topleft(b);
|
||||
|
||||
if (ax !== bx) return ax - bx;
|
||||
return ay - by;
|
||||
});
|
||||
if (ax !== bx) return ax - bx;
|
||||
return ay - by;
|
||||
});
|
||||
|
||||
let lead = true;
|
||||
for(const path of sorted){
|
||||
for (const cmd of poly(normalize(path), height, px2mm, lead)) {
|
||||
str += cmd;
|
||||
}
|
||||
lead = false;
|
||||
// 从起点到第一个路径
|
||||
if (sorted.length > 0) {
|
||||
const firstPath = sorted[0];
|
||||
str += ` U${plu(start[0] * px2mm)},${plu((height - start[1]) * px2mm)}`;
|
||||
str += ` D${plu(firstPath[0][0] * px2mm)},${plu((height - firstPath[0][1]) * px2mm)}`;
|
||||
|
||||
// 切割第一个路径
|
||||
for (let i = 1; i < firstPath.length; i++) {
|
||||
const pt = firstPath[i];
|
||||
str += ` D${plu(pt[0] * px2mm)},${plu((height - pt[1]) * px2mm)}`;
|
||||
}
|
||||
|
||||
// 路径之间移动
|
||||
for (let i = 1; i < sorted.length; i++) {
|
||||
const prevPath = sorted[i - 1];
|
||||
const currPath = sorted[i];
|
||||
|
||||
// 抬刀移动到下一个路径起点
|
||||
str += ` U${plu(currPath[0][0] * px2mm)},${plu((height - currPath[0][1]) * px2mm)}`;
|
||||
// 下刀切割
|
||||
str += ` D${plu(currPath[0][0] * px2mm)},${plu((height - currPath[0][1]) * px2mm)}`;
|
||||
|
||||
for (let j = 1; j < currPath.length; j++) {
|
||||
const pt = currPath[j];
|
||||
str += ` D${plu(pt[0] * px2mm)},${plu((height - pt[1]) * px2mm)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str += end();
|
||||
// 返回终点
|
||||
str += ` U${plu(end[0] * px2mm)},${plu((height - end[1]) * px2mm)}`;
|
||||
str += endCommand();
|
||||
|
||||
return str;
|
||||
return str;
|
||||
}
|
||||
|
||||
function topleft(pts: [number, number][]){
|
||||
let minx = NaN;
|
||||
let miny = NaN;
|
||||
for(const pt of pts){
|
||||
if (isNaN(minx) || minx > pt[0]) minx = pt[0];
|
||||
if (isNaN(miny) || miny > pt[1]) miny = pt[1];
|
||||
}
|
||||
return [minx, miny] as [number, number];
|
||||
// 兼容旧版本(不使用新参数)
|
||||
export function pts2plotterLegacy(
|
||||
pts: [number, number][][],
|
||||
width: number,
|
||||
height: number,
|
||||
px2mm = 0.1
|
||||
) {
|
||||
return pts2plotter(pts, width, height, px2mm);
|
||||
}
|
||||
|
||||
function topleft(pts: [number, number][]) {
|
||||
let minx = NaN;
|
||||
let miny = NaN;
|
||||
for (const pt of pts) {
|
||||
if (isNaN(minx) || minx > pt[0]) minx = pt[0];
|
||||
if (isNaN(miny) || miny > pt[1]) miny = pt[1];
|
||||
}
|
||||
return [minx, miny] as [number, number];
|
||||
}
|
||||
|
||||
function init(w: number, h: number) {
|
||||
return ` IN TB26,${plu(w)},${plu(h)} CT1 U0,0 D0,0 D40,0`;
|
||||
return ` IN TB26,${plu(w)},${plu(h)} CT1`;
|
||||
}
|
||||
|
||||
function end() {
|
||||
return ' U0,0 @ @';
|
||||
}
|
||||
|
||||
function* poly(pts: [number, number][], height: number, px2mm: number, lead = false){
|
||||
function cutpt(down: boolean, pt: [number, number]) {
|
||||
return ` ${down ? 'D' : 'U'}${plu(pt[0] * px2mm)},${plu((height - pt[1]) * px2mm)}`;
|
||||
}
|
||||
|
||||
if (lead) {
|
||||
yield cutpt(false, [0, 0]);
|
||||
yield cutpt(true, [0, 1]);
|
||||
}
|
||||
|
||||
yield cutpt(false, pts[0]);
|
||||
for(const pt of pts){
|
||||
yield cutpt(true, pt);
|
||||
}
|
||||
}
|
||||
|
||||
function sqrlen(x: number, y: number) {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
function lerp(s: [number, number], e: [number, number], i: number) {
|
||||
return [s[0] + (e[0] - s[0]) * i, s[1] + (e[1] - s[1]) * i] as typeof s;
|
||||
function endCommand() {
|
||||
return ' @ @';
|
||||
}
|
||||
|
||||
function plu(n: number) {
|
||||
return Math.round(n / 0.025);
|
||||
}
|
||||
return Math.round(n / 0.025);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user