!1853 新增:模拟走刀增加孔位标注

pull/2677/MERGE
林三 6 months ago committed by ChenX
parent eab3fc6d82
commit 108dd05ef5

@ -1,7 +1,8 @@
import { Matrix4, Vector3 } from "three";
import { Box3, Matrix4, Vector3 } from "three";
import { app } from "../ApplicationServices/Application";
import { Draw } from "../Common/Draw";
import { Intent } from "../Common/Toaster";
import { DimStyleKeyCode } from "../DatabaseServices/DimStyle/DimstyleKeyCodeEnum";
import { Board } from "../DatabaseServices/Entity/Board";
import { Circle } from "../DatabaseServices/Entity/Circle";
import { Line } from "../DatabaseServices/Entity/Line";
@ -10,9 +11,11 @@ import { Command } from "../Editor/CommandMachine";
import { PromptStatus } from "../Editor/PromptResult";
import { userConfig } from "../Editor/UserConfig";
import { MoveMatrix, ZAxis, rotatePoint } from "../Geometry/GeUtils";
import { IContourData } from "../Production/Convert2PtsBul";
import { IBoardHoleInfo, IModelingData, ISpliteOrderData, Production } from "../Production/Product";
import { AppToaster } from "../UI/Components/Toaster";
import { FaceDirection } from "./DrawDrilling/DrillType";
import { DrawHoleDim } from "./DrawHoleDimUtil";
let redundancyKnif = 0;
@ -21,31 +24,45 @@ export class FeedingCommand implements Command
{
async exec()
{
let drawHoleDim = false;
let keyWordList = [{ msg: "矩形槽刀路冗余", key: "S" }];
let drawHoleKeyWordList = [{ msg: `孔洞标注`, key: "D" }];
let brRes = await app.Editor.GetSelection({
Msg: `选择板件,矩形槽刀冗余${redundancyKnif}:`,
KeyWordList: [{ msg: "矩形槽刀路冗余", key: "S" }],
UseSelect: true,
KeyWordList: [...keyWordList, ...drawHoleKeyWordList],
UseSelect: false,
Filter: { filterTypes: [Board] },
KeyWordCallback: async (key, prompt) =>
{
let distRes = await app.Editor.GetDistance({ Msg: "请点击或输入矩形槽走刀冗余值:", Default: redundancyKnif });
if (distRes.Status === PromptStatus.OK)
if (key === "S")
{
if (distRes.Distance > 2 || distRes.Distance < 0)
{
AppToaster.show({
message: "矩形槽刀路冗余值要在0-2之间",
timeout: 5000,
intent: Intent.DANGER,
});
}
else
let distRes = await app.Editor.GetDistance({ Msg: "请点击或输入矩形槽走刀冗余值:", Default: redundancyKnif });
if (distRes.Status === PromptStatus.OK)
{
redundancyKnif = distRes.Distance;
prompt.Msg = `选择板件,矩形槽刀冗余${redundancyKnif}:`;
if (distRes.Distance > 2 || distRes.Distance < 0)
{
AppToaster.show({
message: "矩形槽刀路冗余值要在0-2之间",
timeout: 5000,
intent: Intent.DANGER,
});
}
else
{
redundancyKnif = distRes.Distance;
prompt.Msg = `选择板件,矩形槽刀冗余${redundancyKnif}:`;
}
}
}
else if (key === "D")
{
drawHoleDim = !drawHoleDim;
drawHoleKeyWordList = [{ key: "D", msg: drawHoleDim ? `孔洞不标注` : `孔洞标注` }];
}
prompt.KeyWordList = [...keyWordList, ...drawHoleKeyWordList];
return true;
}
});
@ -53,16 +70,17 @@ export class FeedingCommand implements Command
if (brRes.Status === PromptStatus.Cancel)
return;
let boards = brRes.SelectSet.SelectEntityList as Board[];
AppToaster.show({
message: "正面孔位红色,反面孔为黄色. 绿色外框为封边后的外框,灰色为开料外框(扣封边)",
timeout: 5000,
intent: Intent.WARNING,
});
}, "testm");
let ens = brRes.SelectSet.SelectEntityList as Board[];
let brs: Board[] = [];
for (let e of ens)
brs.push(...e.SplitBoards);
for (let br of boards)
brs.push(...br.SplitBoards);
if (brs.length > 0)
{
let infos: ISpliteOrderData[] = [];
@ -84,7 +102,10 @@ export class FeedingCommand implements Command
{
let info = infos[i];
if (i > 0)
pos.add(new Vector3(width + userConfig.testModeSpacing));//间隔
{
if (!drawHoleDim)
pos.add(new Vector3(width + userConfig.testModeSpacing));
}
else
pos = ptRes.Point;
@ -96,44 +117,65 @@ export class FeedingCommand implements Command
let tMtx = MoveMatrix(pos);
let contouLines = this.ParseContourData(info.originOutlin);//线段形式返回封边轮廓拆成多个线段主要运用在3个点形成的平面
this.DrawHole(info.holes, tMtx, info.offsetTanslation);
let originContour = Production.Data2Polyline(info.originOutlin);
originContour.Position = originContour.Position.sub(info.offsetTanslation);
const DimStyle: Map<DimStyleKeyCode, any> = new Map();
DimStyle.set(DimStyleKeyCode.DIMASZ, 2); //箭头尺寸
DimStyle.set(DimStyleKeyCode.DIMTXT, 20); //文字尺寸
DimStyle.set(DimStyleKeyCode.DIMEXE, 4); //头部延长线
DimStyle.set(DimStyleKeyCode.DIMFXL, 10); //延长线
DimStyle.set(DimStyleKeyCode.DIMEXO, 10); //脚线偏移
DimStyle.set(DimStyleKeyCode.DIMGAP, 5); //文字在尺寸线上距离
//占位空间box
let box = new Box3();
let originContour = Production.Data2Polyline(info.originOutlin);
let sealingContour = Production.Data2Polyline(info.outline);
if (drawHoleDim)
await DrawHoleDim(info, tMtx, contouLines, DimStyle, box, originContour.BoundingBox);
originContour.Position = originContour.Position.sub(info.offsetTanslation);
originContour.ApplyMatrix(tMtx);//原始轮廓 绿色
originContour.ColorIndex = 3;
sealingContour.ApplyMatrix(tMtx);//扣除封边的轮廓 灰色
sealingContour.ColorIndex = 9;
app.Database.ModelSpace.Append(originContour);
app.Database.ModelSpace.Append(sealingContour);
if (!drawHoleDim)
app.Database.ModelSpace.Append(sealingContour);
//写出封边文字
for (let i = 0; i < info.sealing.length; i++)
{
let der = originContour.GetFirstDeriv(i + 0.5);
rotatePoint(der, Math.PI / 2).normalize().multiplyScalar(-35);
let pos = originContour.GetPointAtParam(i + 0.5).add(der);
let text = new Text(pos, info.sealing[i].size.toString());
text.TextAligen = TextAligen.Mid;
if (!drawHoleDim)
for (let i = 0; i < info.sealing.length; i++)
{
let der = originContour.GetFirstDeriv(i + 0.5);
rotatePoint(der, Math.PI / 2).normalize().multiplyScalar(-35);
let pos = originContour.GetPointAtParam(i + 0.5).add(der);
let text = new Text(pos, info.sealing[i].size.toString());
text.TextAligen = TextAligen.Mid;
Draw(text);
}
Draw(text);
}
this.DrawOriginModeling(brs[i], tMtx, info);
this.TestModeling(info.modeling, tMtx);
this.TestModeling(info.sideModeling, tMtx);
let size = originContour.BoundingBox.getSize(new Vector3);
this.DateText(info, tMtx, size.x);
this.DateText(info, tMtx, size.x, box, pos.y);
if (drawHoleDim)
pos.add(new Vector3(box.getSize(new Vector3).x * 1.3));
}
}
}
}
private DrawHole(holeInfo: IBoardHoleInfo, tMtx: Matrix4, offset: Vector3)
private async DrawHole(holeInfo: IBoardHoleInfo, tMtx: Matrix4, offset: Vector3)
{
const { frontBackHoles, sideHoles } = holeInfo;
@ -180,11 +222,11 @@ export class FeedingCommand implements Command
}
}
private DrawOriginModeling(br: Board, tMtx: Matrix4, info: ISpliteOrderData)
{
const { offsetTanslation: offset, curveBoardModeling } = info;
const modeling = [...br.BoardModeling, ...curveBoardModeling];
for (let m of modeling)
{
let c = m.shape.Outline.Curve.Clone();
@ -193,6 +235,7 @@ export class FeedingCommand implements Command
c.ApplyMatrix(tMtx);
app.Database.ModelSpace.Append(c);
c.Position = c.Position.sub(offset);
for (let h of m.shape.Holes)
{
let c = h.Curve.Clone();
@ -205,13 +248,82 @@ export class FeedingCommand implements Command
}
}
//写板名
private DateText(info: ISpliteOrderData, tMtx: Matrix4, width: number)
private DateText(info: ISpliteOrderData, tMtx: Matrix4, width: number, box: Box3, y: number)
{
//文本上下间隔 i
let i = -250;
if (box.min.y < y - 250)
i = box.min.y - y - 100;
//房间名 - 柜名
let str1 = info.info.roomName;
if (str1) str1 += `${info.info.cabinetName ? ` - ${info.info.cabinetName}` : ""}`;
else str1 += info.info.cabinetName;
if (str1)
{
let text = new Text(new Vector3(), `${str1}`);
text.Height = 50;
text.TextAligen = TextAligen.Mid;
text.ApplyMatrix(tMtx);
text.Position = text.Position.add(new Vector3(width * 0.5, i));
app.Database.ModelSpace.Append(text);
i -= 100;
box.union(text.BoundingBox);
}
//板名 - 板ID
let str2 = info.info.name;
if (str2) str2 += `${info.info.id ? ` - ${info.info.id}` : ""}`;
else str2 += info.info.id;
if (str2)
{
let text = new Text(new Vector3(), `${str2}`);
text.Height = 50;
text.TextAligen = TextAligen.Mid;
text.ApplyMatrix(tMtx);
text.Position = text.Position.add(new Vector3(width * 0.5, i));
app.Database.ModelSpace.Append(text);
i -= 100;
box.union(text.BoundingBox);
}
//材料
let str3 = info.info.material;
if (str3) str3 += `${info.info.color ? ` - ${info.info.color}` : ""}`;
if (str3) str3 += `${info.info.thickness ? ` - ${info.info.thickness}mm` : ""}`;
if (str3)
{
let text = new Text(new Vector3(), `${str3}`);
text.Height = 40;
text.TextAligen = TextAligen.Mid;
text.ApplyMatrix(tMtx);
text.Position = text.Position.add(new Vector3(width * 0.5, i));
app.Database.ModelSpace.Append(text);
box.union(text.BoundingBox);
}
}
//解析轮廓获取直线
private ParseContourData(data: IContourData)
{
let text = new Text(new Vector3(), info.info.name);
text.TextAligen = TextAligen.Mid;
text.ApplyMatrix(tMtx);
text.Position = text.Position.add(new Vector3(width * 0.5, -200));
app.Database.ModelSpace.Append(text);
let contouLines: Line[] = [];
for (let i = 0; i < data.pts.length; i++)
{
if (data.buls[i] === 0)
{
let line = new Line(
new Vector3(data.pts[i].x, data.pts[i].y), //StartPoint
(i === data.pts.length - 1) ? new Vector3(data.pts[0].x, data.pts[0].y) : new Vector3(data.pts[i + 1].x, data.pts[i + 1].y) //EndPoint
);
contouLines.push(line);
}
}
return contouLines;
}
}

@ -0,0 +1,518 @@
import { Intent } from "@blueprintjs/core";
import { Box3, Matrix4, Vector3 } from "three";
import { app } from "../ApplicationServices/Application";
import { arrayRemoveIf } from "../Common/ArrayExt";
import { Sleep } from "../Common/Sleep";
import { FixedNotZero } from "../Common/Utils";
import { DimStyleKeyCode } from "../DatabaseServices/DimStyle/DimstyleKeyCodeEnum";
import { AlignedDimension } from "../DatabaseServices/Dimension/AlignedDimension";
import { Line } from "../DatabaseServices/Entity/Line";
import { angle, equalv3, isParallelTo } from "../Geometry/GeUtils";
import { IntersectOption } from "../GraphicsSystem/IntersectWith";
import { IDrillingOption, ISpliteOrderData } from "../Production/Product";
import { AppToaster } from "../UI/Components/Toaster";
const AddLeadYNum = 30;
export async function DrawHoleDim(info: ISpliteOrderData, tMtx: Matrix4, contouLines: Line[], dimStyle: Map<DimStyleKeyCode, any>, box: Box3, originContourBox: Box3)
{
if (!contouLines.length)
{
AppToaster.show({
message: "未找到合适的标注点位",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
const Offset = info.offsetTanslation;
const PlCenter = originContourBox.getCenter(new Vector3);
const PlBoxSize = originContourBox.getSize(new Vector3);
//侧边孔信息
const SideHoleOptions = info.holes.sideHoles;
//正反面孔信息
const FrontBackHoleOptions = [...info.holes.frontBackHoles];
//侧边孔在某条边路径上
const SideHoleLineMap: Map<Line, IDrillingOption[]> = new Map();
//正反面孔 在这条线段的侧孔的endPt上
const OnSideEndPtOptions: Map<Line, IDrillingOption[]> = new Map();
//分析侧孔所在的轮廓线
for (let line of contouLines)
{
let holeOptions = SideHoleOptions.filter((hole) => line.PtOnCurve(new Vector3(hole.position.x, hole.position.y)));
if (holeOptions.length)
{
SideHoleLineMap.set(line, holeOptions);
//分析正反面孔 在这条线段的侧孔的endPt上
let options = [];
arrayRemoveIf(FrontBackHoleOptions, (option) =>
{
let pt = option.position.clone().setZ(0).add(Offset);
if (holeOptions.find((op) => equalv3(op.endPt.clone().setZ(0), pt)))
{
options.push(option);
return true;
}
});
if (options.length)
OnSideEndPtOptions.set(line, options);
}
}
const NeedDrawCrossLineOptionMap: Map<Line, IDrillingOption[]> = new Map();
//优先分析长的直线`
contouLines.sort((l1, l2) => l2.Length - l1.Length);
const FrontBackHolePts: Map<Line, Vector3[]> = new Map();
for (let line of contouLines)
{
if (SideHoleLineMap.get(line)) continue;
let pts: Vector3[] = [];
let offsetLine = line.Clone().ApplyMatrix(new Matrix4().setPosition(Offset.clone().negate()));
let { closestPt, param } = line.GetClosestAtPoint(PlCenter, true);
let dir = PlCenter.clone().sub(closestPt).normalize();
let noHasRelevanceLineOption: IDrillingOption[] = [];
arrayRemoveIf(FrontBackHoleOptions, (opt) =>
{
let pt = opt.position.clone().setZ(0);
let { closestPt, param } = offsetLine.GetClosestAtPoint(pt, true);
if (pt.distanceTo(closestPt) < 25)
{
if (!pts.find(pt => equalv3(pt, closestPt)))
pts.push(closestPt);
noHasRelevanceLineOption.push(opt);
return true;
}
});
if (noHasRelevanceLineOption.length)
NeedDrawCrossLineOptionMap.set(line, noHasRelevanceLineOption);
if (!pts.length) continue;
pts.push(offsetLine.StartPoint);
pts.push(offsetLine.EndPoint);
if (isParallelTo(dir, new Vector3(0, 1)))
pts.sort((pt1, pt2) => pt1.x - pt2.x);
else
pts.sort((pt1, pt2) => pt1.y - pt2.y);
//先缓存 不绘制
FrontBackHolePts.set(line, pts);
let dims: AlignedDimension[] = [];
let an = angle(dir);
for (let i = 0; i < pts.length - 1; i++)
{
let pt1 = pts[i];
let pt2 = pts[i + 1];
if (equalv3(pt1, pt2)) continue;
let dim = CreatAlignedDim(pt1, pt2, dir, dimStyle, tMtx);
if (an < Math.PI / 2) dim.LeadInLeft = true;
await Sleep(0);
for (let d of dims) //判断身位重叠
{
if (d.BoundingBox.intersectsBox(dim.Text.BoundingBox))
dim.LeadY += AddLeadYNum;
}
box.union(dim.BoundingBox);
dims.push(dim);
}
}
//过滤出不同X
let onlyXHolesMap: Map<number, IDrillingOption[]> = FrontBackHoleOptions.reduce((someXMap, current) =>
{
let someX: IDrillingOption[] = someXMap.get(current.position.x) ?? [];
if (!someX.find(opt => equalv3(opt.position.clone().setZ(0), current.position.clone().setZ(0))))
{
someX.push(current);
someXMap.set(current.position.x, someX);
}
return someXMap;
}, new Map());
// 按照 key 从小到大排序
const SortXHolesMap = Array.from(onlyXHolesMap.entries()).sort((a, b) => a[0] - b[0]);
// 创建一个新的 Map 来存储排序后的键值对
onlyXHolesMap = new Map(SortXHolesMap);
//过滤出不同Y
let onlyYHolesMap: Map<number, IDrillingOption[]> = FrontBackHoleOptions.reduce((someYMap, current) =>
{
let someY: IDrillingOption[] = someYMap.get(current.position.y) ?? [];
if (!someY.find(opt => equalv3(opt.position.clone().setZ(0), current.position.clone().setZ(0))))
{
someY.push(current);
someYMap.set(current.position.y, someY);
}
return someYMap;
}, new Map());
// 按照 key 从小到大排序
const SortYHolesMap = Array.from(onlyYHolesMap.entries()).sort((a, b) => a[0] - b[0]);
// 创建一个新的 Map 来存储排序后的键值对
onlyYHolesMap = new Map(SortYHolesMap);
//线周围没有孔
const NoDimLine = contouLines.filter((line) => !NeedDrawCrossLineOptionMap.get(line) && !SideHoleLineMap.get(line));
//内部正反面孔编组标注
if (onlyYHolesMap.size < onlyXHolesMap.size || PlBoxSize.x <= PlBoxSize.y)
{
//用于判断避让
let parallelToXLineDims: AlignedDimension[] = [];
for (let [n, opts] of onlyYHolesMap)
{
let isParallelToXLine: Line;
let distToXLine: number = Infinity;
let intersectYLinesMap: Map<Line, Vector3> = new Map();
opts.sort((opt1, opt2) => opt1.position.x - opt2.position.x);
let centerPt = opts[0].position.clone().setZ(0);
let yLine = new Line(new Vector3(0, n), opts[0].position.clone().setZ(0));
for (let cLine of contouLines)
{
let offsetLine = cLine.Clone().ApplyMatrix(new Matrix4().setPosition(Offset.clone().negate()));
let pts = yLine.IntersectWith(offsetLine, IntersectOption.ExtendThis);
if (pts.length)
intersectYLinesMap.set(cLine, pts[0]);
if (isParallelTo(offsetLine.GetFirstDeriv(0), new Vector3(1)))
{
let { closestPt } = offsetLine.GetClosestAtPoint(centerPt, true);
let dist = closestPt.distanceTo(centerPt);
if (distToXLine > dist)
{
isParallelToXLine = offsetLine;
distToXLine = dist;
}
}
}
let dirY: Vector3 = new Vector3(0, -1);
if (isParallelToXLine)
{
let { closestPt } = isParallelToXLine.GetClosestAtPoint(centerPt, true);
if (isParallelToXLine.PtOnCurve(closestPt))
{
if (closestPt.y > centerPt.y)
dirY = new Vector3(0, 1);
let fastPt = opts[0].position;
let dirX = new Vector3(fastPt.x - PlCenter.x).normalize().multiplyScalar(3);
let dim = CreatAlignedDim(centerPt, closestPt, dirX, dimStyle, tMtx);
await Sleep(0);
for (let d of parallelToXLineDims) //判断身位重叠
{
if (d.BoundingBox.intersectsBox(dim.BoundingBox))
{
dim.ArmP1 = dim.ArmP1.sub(dirX.clone().normalize().multiplyScalar(40));
dim.ArmP2 = dim.ArmP2.sub(dirX.clone().normalize().multiplyScalar(40));
}
}
parallelToXLineDims.push(dim);
box.union(dim.BoundingBox);
}
}
//正常情况下有两条相交线
if (intersectYLinesMap.size === 2)
{
let pts = Array.from(intersectYLinesMap.values());
if (opts.length === 1)
{
let pt1 = pts[0];
let pt2 = pts[1];
let pt = opts[0].position.clone().setZ(0);
if (pt1.distanceTo(pt) > pt2.distanceTo(pt))
pts[0] = pts[1];
pts.length = 1;
}
for (let op of opts)
pts.push(op.position.clone().setZ(0));
pts.sort((pt1, pt2) => pt1.x - pt2.x);
//用于判断避让
let dims: AlignedDimension[] = [];
let an = angle(dirY);
for (let i = 0; i < pts.length - 1; i++)
{
let pt1 = pts[i];
let pt2 = pts[i + 1];
let dim = CreatAlignedDim(pt1, pt2, dirY, dimStyle, tMtx);
if (dim.LeadVisible && an < Math.PI) dim.LeadInLeft = true;
for (let d of dims) //判断身位重叠
{
if (d.BoundingBox.intersectsBox(dim.Text.BoundingBox))
dim.LeadY += AddLeadYNum;
}
dims.push(dim);
box.union(dim.BoundingBox);
}
}
else
{
//todo
}
}
}
else if (PlBoxSize.y <= PlBoxSize.x)
{
//用于判断避让
let parallelToYLine: AlignedDimension[] = [];
for (let [n, opts] of onlyXHolesMap)
{
let isParallelToYLine: Line;
let distToYLine: number = Infinity;
let intersectXLinesMap: Map<Line, Vector3> = new Map();
opts.sort((opt1, opt2) => opt1.position.y - opt2.position.y);
let centerPtIndex = Math.max(Math.floor(opts.length / 2) - 1, 0);
let centerPt = opts[centerPtIndex].position.clone().setZ(0);
let xLine = new Line(new Vector3(n, 0), opts[0].position.clone().setZ(0));
for (let cLine of contouLines)
{
let offsetLine = cLine.Clone().ApplyMatrix(new Matrix4().setPosition(Offset.clone().negate()));
let pts = xLine.IntersectWith(offsetLine, IntersectOption.ExtendThis);
if (pts.length)
intersectXLinesMap.set(cLine, pts[0]);
if (isParallelTo(offsetLine.GetFirstDeriv(0), new Vector3(0, 1)))
{
let { closestPt } = offsetLine.GetClosestAtPoint(centerPt, true);
let dist = closestPt.distanceTo(centerPt);
if (distToYLine > dist)
{
isParallelToYLine = offsetLine;
distToYLine = dist;
}
}
}
let dirX: Vector3 = new Vector3(-1);
if (isParallelToYLine)
{
let { closestPt } = isParallelToYLine.GetClosestAtPoint(centerPt, true);
if (isParallelToYLine.PtOnCurve(closestPt))
{
if (closestPt.x > centerPt.x)
dirX = new Vector3(1);
let firstPt = opts[0].position;
let dirY = new Vector3(0, 1);
if (firstPt.y - centerPt.y > 35)
dirY = new Vector3(0, -1);
let dim = CreatAlignedDim(centerPt, closestPt, dirY, dimStyle, tMtx);
await Sleep(0);
for (let d of parallelToYLine) //判断身位重叠
{
if (d.BoundingBox.intersectsBox(dim.BoundingBox))
{
dim.ArmP1 = dim.ArmP1.sub(dirY.clone().multiplyScalar(40));
dim.ArmP2 = dim.ArmP2.sub(dirY.clone().multiplyScalar(40));
}
}
parallelToYLine.push(dim);
box.union(dim.BoundingBox);
}
}
//正常情况下有两条相交线
if (intersectXLinesMap.size === 2)
{
let an = angle(dirX);
let pts = Array.from(intersectXLinesMap.values());
for (let op of opts)
pts.push(op.position.clone().setZ(0));
pts.sort((pt1, pt2) => pt1.y - pt2.y);
//用于判断避让
let dims: AlignedDimension[] = [];
for (let i = 0; i < pts.length - 1; i++)
{
let pt1 = pts[i];
let pt2 = pts[i + 1];
let dim = CreatAlignedDim(pt1, pt2, dirX, dimStyle, tMtx);
await Sleep(0);
if (dim.LeadVisible && an < Math.PI) dim.LeadInLeft = true;
for (let d of dims) //判断身位重叠
{
if (d.BoundingBox.intersectsBox(dim.Text.BoundingBox))
dim.LeadY += AddLeadYNum;
}
dims.push(dim);
box.union(dim.BoundingBox);
}
}
}
}
//正反面的边孔宽度标注
for (let [line, options] of NeedDrawCrossLineOptionMap)
{
let { closestPt, param } = line.GetClosestAtPoint(PlCenter, true);
let dir = PlCenter.clone().sub(closestPt).normalize();
//将线段和点转化为X轴方向
let an = angle(dir);
let ocs = new Matrix4().makeRotationZ(Math.PI / 2 - an);
let parallelToXLine = line.Clone().ApplyMatrix(new Matrix4().setPosition(Offset.clone().negate())).ApplyMatrix(ocs);
let mat = new Matrix4().setPosition(parallelToXLine.BoundingBox.min.negate());
parallelToXLine.ApplyMatrix(mat);
ocs = mat.multiply(ocs);
const OCSInv = new Matrix4().getInverse(ocs);
options.sort((opt1, opt2) => opt1.position.clone().applyMatrix4(ocs).x - opt2.position.clone().applyMatrix4(ocs).x);
let distSet: Set<string> = new Set();
for (let opt of options)
{
let pt = opt.position.clone().applyMatrix4(ocs).setZ(0);
let { closestPt, param } = parallelToXLine.GetClosestAtPoint(opt.position.clone().applyMatrix4(ocs).setZ(0), true);
if (closestPt)
{
let dist = FixedNotZero(closestPt.distanceTo(pt), 2);
if (!distSet.has(dist))
{
let dir = line.GetFirstDeriv(0).normalize().multiplyScalar(param < 0.5 ? - 40 : 40);
let pt1 = pt.applyMatrix4(OCSInv);
let pt2 = closestPt.applyMatrix4(OCSInv);
if (equalv3(pt1, pt2)) continue;
let dim = new AlignedDimension(
pt1, pt2,
pt1.clone().sub(dir),
pt2.clone().sub(dir),
);
dim.LeadY = 25;
dim.SetDimStyleOverrideValues(dimStyle);
if (param < 0.5) dim.LeadInLeft = true;
dim.ApplyMatrix(tMtx);
app.Database.ModelSpace.Append(dim);
box.union(dim.BoundingBox);
distSet.add(dist);
}
}
}
}
//侧孔标注
for (let [line, options] of SideHoleLineMap)
{
let pts: Vector3[] = [line.StartPoint.clone().sub(Offset), line.EndPoint.clone().sub(Offset)];
for (let op of options)
pts.push(op.position.clone().sub(Offset).setZ(0));
let dir = options[0].endPt.clone().sub(options[0].position).normalize();
let an = angle(dir);
if (isParallelTo(dir, new Vector3(1)))
pts.sort((pt1, pt2) => pt1.y - pt2.y);
else
pts.sort((pt1, pt2) => pt1.x - pt2.x);
let dims: AlignedDimension[] = [];
for (let i = 0; i < pts.length - 1; i++)
{
let pt1 = pts[i];
let pt2 = pts[i + 1];
let dim = CreatAlignedDim(pt1, pt2, dir, dimStyle, tMtx);
if (dim.LeadVisible && an < Math.PI) dim.LeadInLeft = true;
await Sleep(0);
for (let d of dims) //判断身位重叠
{
if (d.BoundingBox.intersectsBox(dim.Text.BoundingBox))
{
dim.LeadY += AddLeadYNum;
}
}
box.union(dim.BoundingBox);
dims.push(dim);
}
}
for (let [line, options] of OnSideEndPtOptions)
{
let centerPt = options[0].position.clone().setZ(0);
let offsetLine = line.Clone().ApplyMatrix(new Matrix4().setPosition(Offset.clone().negate()));
let { closestPt, param } = offsetLine.GetClosestAtPoint(centerPt, true);
let dir = line.GetFirstDeriv(0).normalize().multiplyScalar(param < 0.5 ? - 2 : 2);
CreatAlignedDim(centerPt, closestPt, dir, dimStyle, tMtx);
}
//总轮廓标注
{
let contourBoxMin = box.clone().applyMatrix4(new Matrix4().getInverse(tMtx)).union(originContourBox).min;
let dirX = new Vector3(0, contourBoxMin.y / -30 + 1);
let dirY = new Vector3(contourBoxMin.x / -30 + 1);
const dimX = CreatAlignedDim(new Vector3().sub(info.offsetTanslation), new Vector3(originContourBox.max.x).sub(info.offsetTanslation), dirX, dimStyle, tMtx);
const dimY = CreatAlignedDim(new Vector3().sub(info.offsetTanslation), new Vector3(0, originContourBox.max.y).sub(info.offsetTanslation), dirY, dimStyle, tMtx);
box.union(dimY.BoundingBox);
box.union(dimX.BoundingBox);
}
}
function CreatAlignedDim(footP1: Vector3, footP2: Vector3, dir: Vector3, dimStyle: Map<DimStyleKeyCode, any>, tMtx: Matrix4)
{
let dim = new AlignedDimension(
footP1, footP2,
footP1.clone().sub(dir.clone().multiplyScalar(30)),
footP2.clone().sub(dir.clone().multiplyScalar(30))
);
dim.LeadY = 25;
dim.SetDimStyleOverrideValues(dimStyle);
dim.ApplyMatrix(tMtx);
app.Database.ModelSpace.Append(dim);
return dim;
}

@ -32,13 +32,24 @@ export abstract class Dimension extends Entity
this.WriteAllObjectRecord();
let oldV = this.GetDimStyleValue(key);
this._DimStyleOverride.set(key, value);
if (oldV !== value)
this.Update();
}
//设置多个覆盖的标注样式
SetDimStyleOverrideValues(valueMap: Map<DimStyleKeyCode, any>)
{
this.WriteAllObjectRecord();
for (let [key, value] of valueMap)
{
this._DimStyleOverride.set(key, value);
}
this.Update();
}
DeleteDimStyleOverrideValue(key: DimStyleKeyCode)
{
if (!this._DimStyleOverride.has(key)) return;

@ -0,0 +1,158 @@
import { BufferGeometry, Line, Object3D, Vector3 } from "three";
import { HostApplicationServices } from "../../ApplicationServices/HostApplicationServices";
import { AddEntityDrawObject } from "../../Common/AddEntityDrawObject";
import { BufferGeometryUtils } from "../../Geometry/BufferGeometryUtils";
import { MoveMatrix } from "../../Geometry/GeUtils";
import { RenderType } from "../../GraphicsSystem/RenderType";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { Text, TextAligen } from "../Text/Text";
import { Dimension } from "./Dimension";
import { GetDimLineMaterial } from "./GetDimLineMaterial";
//箭头引线标签标注 (箭头暂未实现)
@Factory
export class MLeaderDimension extends Dimension
{
protected _Text = new Text();
constructor(
protected _TextString: string = "", // 文本
protected _StartPoint: Vector3 = new Vector3(), // 引线起点
protected _EndPoint: Vector3 = new Vector3(100), // 引线终点
)
{
super();
}
get Text()
{
if (!this._Text.TextString)
this.ParseText();
return this._Text;
}
set StartPoint(p: Vector3)
{
this.WriteAllObjectRecord();
this._StartPoint.copy(p).applyMatrix4(this.OCSInv);
this.Update();
}
get StartPoint(): Vector3
{
return this._StartPoint.clone().applyMatrix4(this.OCSNoClone);
}
get EndPoint(): Vector3
{
return this._EndPoint.clone().applyMatrix4(this.OCSNoClone);
}
set EndPoint(p: Vector3)
{
this.WriteAllObjectRecord();
this._EndPoint.copy(p).applyMatrix4(this.OCSInv);
this.Update();
}
protected GetPrimitiveString(): string
{
return this._TextString;
}
//#region 拉伸相关
GetGripPoints(): Vector3[]
{
return [this.StartPoint, new Vector3().addVectors(this.EndPoint, this.StartPoint).multiplyScalar(0.5), this.EndPoint];
}
MoveGripPoints(indexList: number[], vec: Vector3)
{
for (let index of indexList)
{
if (index === 0)
this.StartPoint = this.StartPoint.add(vec);
else if (index === 2)
this.EndPoint = this.EndPoint.add(vec);
else
{
let m = MoveMatrix(vec);
this.ApplyMatrix(m);
}
}
}
//#endregion
//#region Draw
InitDrawObject(renderType: RenderType = RenderType.Wireframe)
{
let colorMaterial = GetDimLineMaterial(this, renderType);
let obj = new Object3D();
let line = new Line(new BufferGeometry, colorMaterial);
obj.add(line);
this.UpdateDrawObject(renderType, obj);
return obj;
}
UpdateDrawObject(renderType: RenderType, obj: Object3D)
{
obj.remove(...obj.children.slice(1));
let line = obj.children[0] as Line;
let colorMaterial = GetDimLineMaterial(this, renderType);
line.material = colorMaterial;
this.ParseText();
this._Text.DeferUpdate();
let geo = line.geometry as BufferGeometry;
if (!BufferGeometryUtils.UpdatePts(geo, [this._StartPoint, this._EndPoint]))
{
line.geometry.dispose();
line.geometry = BufferGeometryUtils.CreateFromPts([this._StartPoint, this._EndPoint]);
}
AddEntityDrawObject(obj, this._Text, renderType);
}
ParseText()
{
this._Text.AutoUpdate = false;
this._Text.ColorIndex = this.ColorIndex;
this._Text.TextString = this.TextString;
this._Text.Height = this.TextSize;
this._Text.TextAligen = TextAligen.LeftMid;
this._Text.OCS = this.OCS.setPosition(this._EndPoint);
this._Text.AutoUpdate = true;
}
//#endregion
//#region -------------------------File-------------------------
//对象从文件中读取数据,初始化自身
protected _ReadFile(file: CADFiler)
{
let ver = file.Read();
super._ReadFile(file);
this._TextString = file.Read();
this._StartPoint = new Vector3(file.Read(), file.Read(), file.Read());
this._EndPoint = new Vector3(file.Read(), file.Read(), file.Read());
this.ReadDimStyle(file);
this._DimStyle = file.ReadHardObjectId() ?? HostApplicationServices.CurrentDimStyle;
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(1);
super.WriteFile(file);
file.Write(this._TextString);
file.WriteVec3(this._StartPoint);
file.WriteVec3(this._EndPoint);
this.WriteDimStyle(file);
file.WriteHardObjectId(this._DimStyle);
}
//#endregion
}

@ -1,4 +1,4 @@
import { BufferGeometry, Line as TLine, Material, Matrix3, Matrix4, Mesh, Object3D, Vector3 } from "three";
import { BufferGeometry, Material, Matrix3, Matrix4, Mesh, Object3D, Line as TLine, Vector3 } from "three";
import { Line2 } from "three/examples/jsm/lines/Line2";
import { HostApplicationServices } from "../../ApplicationServices/HostApplicationServices";
import { AddEntityDrawObject } from "../../Common/AddEntityDrawObject";
@ -8,10 +8,11 @@ import { reviseMirrorMatrix } from "../../Common/Matrix4Utils";
import { FixedNotZero } from "../../Common/Utils";
import { ObjectSnapMode } from "../../Editor/ObjectSnapMode";
import { BufferGeometryUtils } from "../../Geometry/BufferGeometryUtils";
import { angle, angleAndX, MoveMatrix } from "../../Geometry/GeUtils";
import { MoveMatrix, angle, angleAndX } from "../../Geometry/GeUtils";
import { RenderType } from "../../GraphicsSystem/RenderType";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { DimStyleKeyCode } from "../DimStyle/DimstyleKeyCodeEnum";
import { Circle } from "../Entity/Circle";
import { Line } from "../Entity/Line";
import { Dimension } from "./Dimension";
@ -133,7 +134,7 @@ export class RadiusDimension extends Dimension
{
let [line, arrow, textObj] = obj.children;
let arrowSize = 10;
let arrowSize = this.GetDimStyleValue(DimStyleKeyCode.DIMASZ) ?? 10;
if (renderType === RenderType.WireframePrint)
{

@ -34,7 +34,6 @@ import { Entity } from './../DatabaseServices/Entity/Entity';
import { ICompHardwareOption } from './../UI/Components/RightPanel/RightPanelInterface';
import { ConverArcToPtsBul, ConverToPtsBul, IContourData } from "./Convert2PtsBul";
export interface I3DContourData
{
pts: Vector3[];
@ -81,6 +80,7 @@ interface IBoardProdInfo
[EBoardKeyList.Color]: string;
[EBoardKeyList.Lines]: number;
[EBoardKeyList.DrillType]: string;
[EBoardKeyList.Thick]: number;
spliteHeight: string;
spliteThickness: string;
spliteWidth: string;
@ -317,6 +317,7 @@ export namespace Production
[EBoardKeyList.Color]: data[EBoardKeyList.Color],
[EBoardKeyList.Lines]: data[EBoardKeyList.Lines],
[EBoardKeyList.DrillType]: data[EBoardKeyList.DrillType],
[EBoardKeyList.Thick]: br.Thickness,
spliteHeight: spliteSize ? spliteSize.spliteHeight.toString() : "",
spliteThickness: spliteSize ? spliteSize.spliteThickness.toString() : "",
spliteWidth: spliteSize ? spliteSize.spliteWidth.toString() : "",
@ -1192,6 +1193,7 @@ export namespace Production
}
return sizeData;
}
export function Data2Polyline(data: IContourData, isClose = true)
{
let pl = new Polyline(data.pts.map((p, i) => ({ pt: new Vector2(p.x, p.y), bul: data.buls[i] })));

Loading…
Cancel
Save