diff --git a/api.cjs.js b/api.cjs.js
index aae6b05..36ffb1f 100644
--- a/api.cjs.js
+++ b/api.cjs.js
@@ -384,7 +384,7 @@ class ObjectId {
let HostApplicationServices = { ShowHistoryLog: true };
/**
- * 销毁Object对象的Geometry,并不会销毁材质.
+ * 销毁Object对象的Geometry,并不会销毁材质(新版本销毁材质,好像问题不大?)
*/
function DisposeThreeObj(obj) {
for (let o of obj.children) {
@@ -392,11 +392,15 @@ function DisposeThreeObj(obj) {
//文字的geometry缓存保留下来
if (oany.geometry && oany.geometry.name !== "Text")
oany.geometry.dispose();
+ if (oany.material)
+ oany.material.dispose();
DisposeThreeObj(o);
- o.parent = null;
- o.dispatchEvent({ type: "removed" });
+ // 下面这个代码可能导致Object3d无法复用,删除它应该问题不大
+ // o.parent = null;
+ // o.dispatchEvent({ type: "removed" });
}
- obj.children.length = 0;
+ // 下面这个代码可能导致Object3d无法复用,删除它应该问题不大
+ // obj.children.length = 0;
return obj;
}
function Object3DRemoveAll(obj) {
@@ -459,6 +463,49 @@ class CoordinateSystem {
}
}
+let OPERATORS = new Set(["+", "-", "*", "/"]);
+/**
+ * eval2("+10", { L: 100 }, "L")
+ * @param expr
+ * @param [params]
+ * @param [defaultParam] 当输入 +10 这样的表达式时,设置默认的操作变量
+ * @returns 计算结果
+ */
+function eval2(expr, params, defaultParam) {
+ let code = "";
+ if (params)
+ for (let name in params)
+ code += `let ${name} = ${params[name]};`;
+ if (defaultParam) {
+ expr = expr.trimLeft();
+ if (expr[0] && OPERATORS.has(expr[0]))
+ expr = defaultParam + expr;
+ }
+ code += expr;
+ let result = eval(code);
+ if (typeof result === "function")
+ return result();
+ return Number(result); //防止bigint乱入
+}
+function safeEval(expr, params, defaultParam) {
+ try {
+ return eval2(expr, params);
+ }
+ catch (error) {
+ return NaN;
+ }
+}
+const Reg_Expr = /\{[^\}]+\}/g;
+/**解析大括号内的 */
+function ParseExpr(expr, params) {
+ let strs = expr.match(Reg_Expr);
+ if (!strs)
+ return expr;
+ for (let str of strs)
+ expr = expr.replace(str, FixedNotZero(safeEval(str.slice(1, -1), params), 2));
+ return expr;
+}
+
var StoreageKeys;
(function (StoreageKeys) {
StoreageKeys["IsLogin"] = "isLogin";
@@ -479,6 +526,8 @@ var StoreageKeys;
StoreageKeys["kjlConfig"] = "kjl";
})(StoreageKeys || (StoreageKeys = {}));
+/**扣除封边是否相连和连接共用精度 */
+const LINK_FUZZ = 1e-3;
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
@@ -491,6 +540,44 @@ function FixIndex(index, arr) {
else
return index;
}
+//使用定点表示法来格式化一个数,小数点后面不尾随0. 如 FixedNotZero(1.1 , 3) => 1.1
+function FixedNotZero(v, fractionDigits = 0) {
+ if (typeof v === "string")
+ v = parseFloat(v);
+ if (isNaN(v))
+ return "";
+ if (equaln(v, 0))
+ return "0";
+ let str = v.toFixed(fractionDigits);
+ let commonIndex = str.indexOf(".");
+ if (commonIndex !== -1) {
+ let zeroCount = 0;
+ let strCount = str.length;
+ for (let l = strCount; l--;) {
+ if (str[l] === "0")
+ zeroCount++;
+ else
+ break;
+ }
+ if (zeroCount > 0) {
+ if (zeroCount === (strCount - commonIndex - 1))
+ zeroCount++;
+ return str.slice(0, strCount - zeroCount);
+ }
+ }
+ return str;
+}
+/**
+ * To fixed
+ * @param v
+ * @param [fractionDigits]
+ * @returns
+ */
+function ToFixed(v, fractionDigits = 5) {
+ if (equaln(v, 0, Math.pow(0.1, fractionDigits)))
+ return "0";
+ return v.toFixed(fractionDigits);
+}
const IdentityMtx4 = new three.Matrix4();
const ZeroVec = new three.Vector3();
@@ -505,6 +592,12 @@ function AsVector2(p) {
function AsVector3(p) {
return new three.Vector3(p.x, p.y, p.z);
}
+/**
+ * 判断一维线段a和b是否存在交集
+ */
+function isIntersect(amin, amax, bmin, bmax, eps = 0) {
+ return Math.max(amin, bmin) < Math.min(amax, bmax) + eps;
+}
/**
* 旋转一个点,旋转中心在原点
* @param {Vector3} p 点
@@ -606,6 +699,12 @@ function getLoocAtUpVec(dir) {
function isParallelTo(v1, v2, fuzz = 1e-8) {
return v1.clone().cross(v2).lengthSq() < fuzz;
}
+/**
+ * 垂直向量
+ */
+function isPerpendicularityTo(v1, v2, fuzz = 1e-8) {
+ return equaln(v1.dot(v2), 0, fuzz);
+}
function midPoint(v1, v2) {
return v1.clone().add(v2).multiplyScalar(0.5);
}
@@ -738,6 +837,16 @@ function reviseMirrorMatrix(mtx) {
mtx.copy(cs.getMatrix4());
return mtx;
}
+let cacheVec;
+function Vector2ApplyMatrix4(mtx, vec) {
+ if (!cacheVec)
+ cacheVec = new three.Vector3();
+ cacheVec.x = vec.x;
+ cacheVec.y = vec.y;
+ cacheVec.applyMatrix4(mtx);
+ vec.x = cacheVec.x;
+ vec.y = cacheVec.y;
+}
/**
* 把变换矩阵展平成2d矩阵,避免出现三维坐标.
*/
@@ -781,9 +890,6 @@ var DuplicateRecordCloning;
/**
* 场景的渲染类型.
- *
- * @export
- * @enum {number}
*/
var RenderType;
(function (RenderType) {
@@ -803,6 +909,23 @@ var RenderType;
RenderType[RenderType["Print"] = 5] = "Print";
/**物理带线框 */
RenderType[RenderType["Physical2"] = 6] = "Physical2";
+ /******************************************** 在视口时的渲染模式 */
+ /**
+ * 线框模式
+ */
+ RenderType[RenderType["WireframePrint"] = 101] = "WireframePrint";
+ /**
+ * 概念
+ */
+ RenderType[RenderType["ConceptualPrint"] = 102] = "ConceptualPrint";
+ /**
+ * 物理着色PBR
+ */
+ RenderType[RenderType["PhysicalPrint"] = 103] = "PhysicalPrint";
+ RenderType[RenderType["JigPrint"] = 104] = "JigPrint";
+ RenderType[RenderType["PrintPrint"] = 105] = "PrintPrint";
+ /**物理带线框 */
+ RenderType[RenderType["Physical2Print"] = 106] = "Physical2Print";
})(RenderType || (RenderType = {}));
var AAType;
@@ -868,6 +991,7 @@ class UserConfig {
radius: 2.5,
modeling2HoleRad: 20,
isCheckInterfere: false,
+ noModeingData: "",
};
this.autoLines = false;
this.dimTextHeight = 60;
@@ -915,6 +1039,7 @@ class UserConfig {
useDefaultRad: false,
radius: 2.5,
modeling2HoleRad: 20,
+ noModeingData: "",
});
this.dimTextHeight = 60;
}
@@ -1190,10 +1315,12 @@ let Entity = Entity_1 = class Entity extends CADObject {
return new three.Vector3().setFromMatrixPosition(this._Matrix);
}
set Position(pt) {
- this.WriteAllObjectRecord();
let moveX = pt.x - this._Matrix.elements[12];
let moveY = pt.y - this._Matrix.elements[13];
let moveZ = pt.z - this._Matrix.elements[14];
+ if (moveX === 0 && moveY === 0 && moveZ === 0)
+ return;
+ this.WriteAllObjectRecord();
this._Matrix.setPosition(pt);
this._SpaceOCS.elements[12] += moveX;
this._SpaceOCS.elements[13] += moveY;
@@ -1202,6 +1329,8 @@ let Entity = Entity_1 = class Entity extends CADObject {
}
//Z轴归0
Z0() {
+ if (this._Matrix.elements[14] === 0)
+ return this;
this.WriteAllObjectRecord();
this._Matrix.elements[14] = 0;
this.Update(UpdateDraw.Matrix);
@@ -1254,16 +1383,18 @@ let Entity = Entity_1 = class Entity extends CADObject {
if (jig)
this._CacheDrawObject.set(RenderType.Jig, jig);
}
+ get IsOnlyRender() {
+ return this.OnlyRenderType;
+ }
get DrawObject() {
- var _a;
if (this._drawObject)
return this._drawObject;
this._drawObject = new three.Object3D();
if (!this.IsEmbedEntity)
this._drawObject.userData.Entity = this;
if (this.IsVisible) {
- this._CurRenderType = (_a = this.__CacheRenderType__) !== null && _a !== void 0 ? _a : userConfig.RenderType;
- let obj = this.GetDrawObjectFromRenderType(this._CurRenderType);
+ this._CurRenderType = userConfig.RenderType;
+ let obj = this.GetDrawObjectFromRenderType(userConfig.RenderType);
if (obj)
this._drawObject.add(obj);
}
@@ -1298,19 +1429,24 @@ let Entity = Entity_1 = class Entity extends CADObject {
}
}
GetDrawObjectFromRenderType(renderType = RenderType.Wireframe) {
- var _a;
if (this.OnlyRenderType) {
if (renderType === RenderType.Jig)
return;
- renderType = (_a = this.__CacheRenderType__) !== null && _a !== void 0 ? _a : userConfig.RenderType;
+ if (renderType < 100)
+ renderType = RenderType.Wireframe;
+ else
+ renderType = RenderType.WireframePrint;
}
if (this._CacheDrawObject.has(renderType)) {
return this._CacheDrawObject.get(renderType);
}
else {
let drawObj = this.InitDrawObject(renderType);
- if (drawObj === undefined)
+ if (drawObj === undefined) {
+ if (renderType > 100) //如果实体没有实现打印类型,那么就使用原先的实体的渲染类型
+ return this.GetDrawObjectFromRenderType(renderType - 100);
return;
+ }
//矩阵直接使用指针,因为已经关闭自动更新,所以矩阵不会被Object3D修改.
drawObj.matrixAutoUpdate = false;
drawObj.matrix = this._Matrix;
@@ -1370,8 +1506,8 @@ let Entity = Entity_1 = class Entity extends CADObject {
this.UpdateDrawObjectMaterial(type, obj);
if (mode & UpdateDraw.Matrix || mode & UpdateDraw.Geometry) {
obj.updateMatrixWorld(true);
- if (this.Id) //如果这个是Jig实体,那么我们更新这个盒子球似乎也没有意义
- obj.traverse(UpdateBoundingSphere);
+ // if (this.Id)//如果这个是Jig实体,那么我们更新这个盒子球似乎也没有意义 (虽然这在某些情况能改进性能,但是在绘制圆弧的时候,因为没有更新圆弧的盒子,导致绘制出来的圆弧无法被选中)
+ obj.traverse(UpdateBoundingSphere);
}
}
this.NeedUpdateFlag = UpdateDraw.None;
@@ -1414,11 +1550,10 @@ let Entity = Entity_1 = class Entity extends CADObject {
return !this._isErase && this._Visible;
}
UpdateVisible() {
- var _a;
if (this._drawObject) {
this._drawObject.visible = this.IsVisible;
if (this.IsVisible)
- this.UpdateRenderType((_a = this.__CacheRenderType__) !== null && _a !== void 0 ? _a : userConfig.RenderType);
+ this.UpdateRenderType(userConfig.RenderType);
}
}
//#endregion
@@ -1738,7 +1873,7 @@ function GetGoodShaderSimple(color = new three.Vector3) {
}
const ColorPalette = [
- [255, 0, 0, 255],
+ [0, 0, 0, 0],
//[255, 255, 255, 255],//----- 0 - ByBlock - White
[255, 0, 0, 255],
// [255, 0, 0, 255], //----- 1 - Red
@@ -2095,8 +2230,9 @@ ColorMaterial.SnapAxisMaterial = new three.LineDashedMaterial({
});
ColorMaterial.PrintLineMatrial = new LineMaterial.LineMaterial({
color: 0x000000,
- linewidth: LINE_WIDTH / 1000,
- dashed: false
+ linewidth: LINE_WIDTH,
+ dashed: false,
+ resolution: new three.Vector2(1000, 1000)
});
ColorMaterial.GrayTransparentMeshMaterial = new three.MeshBasicMaterial({
color: 0xcccccc,
@@ -2189,6 +2325,15 @@ function equalArray(a, b, checkF = checkEqual) {
return false;
return true;
}
+function arrayClone(arr) {
+ return arr.slice();
+}
+function arraySum(arr) {
+ let sum = 0;
+ for (let n of arr)
+ sum += n;
+ return sum;
+}
/**
* OSMODE
@@ -3134,8 +3279,11 @@ let Curve = class Curve extends Entity {
* 重载:更新实体材质
*/
UpdateDrawObjectMaterial(type, obj, material) {
- let m = obj;
- m.material = material || ColorMaterial.GetLineMaterial(this._Color);
+ if (type === RenderType.WireframePrint) ;
+ else {
+ let m = obj;
+ m.material = material || ColorMaterial.GetLineMaterial(this._Color);
+ }
}
UpdateJigMaterial(color = 8) {
for (let [type, obj] of this._CacheDrawObject) {
@@ -4077,10 +4225,10 @@ Ellipse = Ellipse_1 = __decorate([
var Line_1;
exports.Line = Line_1 = class Line extends Curve {
- constructor(sp, ep) {
+ constructor(_StartPoint = new three.Vector3, _EndPoint = new three.Vector3) {
super();
- this._StartPoint = sp || new three.Vector3(0, 0, 0);
- this._EndPoint = ep || new three.Vector3(0, 0, 0);
+ this._StartPoint = _StartPoint;
+ this._EndPoint = _EndPoint;
}
get Is2D() {
return super.Is2D && equaln(this._StartPoint.z, 0) && equaln(this._EndPoint.z, 0);
@@ -4111,7 +4259,7 @@ exports.Line = Line_1 = class Line extends Curve {
}
InitDrawObject(renderType = RenderType.Wireframe) {
let geo = BufferGeometryUtils.CreateFromPts([this._StartPoint, this._EndPoint]);
- if (renderType === RenderType.Print) {
+ if (renderType === RenderType.WireframePrint) {
var geometry = new LineGeometry.LineGeometry();
geometry.setPositions(geo.attributes.position.array);
return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
@@ -6121,7 +6269,7 @@ exports.Polyline = Polyline_1 = class Polyline extends Curve {
InitDrawObject(renderType = RenderType.Wireframe) {
let shape = this.Shape;
let geo = BufferGeometryUtils.CreateFromPts(shape.getPoints(50).map(AsVector3));
- if (renderType === RenderType.Print) {
+ if (renderType === RenderType.WireframePrint) {
var geometry = new LineGeometry.LineGeometry().setPositions(geo.attributes.position.array);
return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
}
@@ -7015,14 +7163,16 @@ exports.Circle = Circle_1 = class Circle extends Curve {
return new three.Box3().setFromPoints(this.GetGripPoints());
}
InitDrawObject(renderType = RenderType.Wireframe) {
+ let obj = new three.Object3D();
let cirGeo = GetCircleGeometry();
- if (renderType === RenderType.Print) {
- var geometry = new LineGeometry.LineGeometry().setPositions(cirGeo.attributes.position.array);
- geometry.scale(this._Radius, this._Radius, this._Radius);
- return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
+ if (renderType === RenderType.WireframePrint) {
+ let geometry = new LineGeometry.LineGeometry().setPositions(cirGeo.attributes.position.array);
+ obj.add(new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial));
+ }
+ else {
+ let line = new three.Line(cirGeo, ColorMaterial.GetLineMaterial(this._Color));
+ obj.add(line);
}
- let line = new three.Line(cirGeo, ColorMaterial.GetLineMaterial(this._Color));
- let obj = new three.Object3D().add(line);
this.UpdateDrawObject(renderType, obj);
return obj;
}
@@ -7031,8 +7181,12 @@ exports.Circle = Circle_1 = class Circle extends Curve {
obj.children[0].updateMatrix();
}
UpdateDrawObjectMaterial(type, obj, material) {
- let m = obj.children[0];
- m.material = material ? material : ColorMaterial.GetLineMaterial(this._Color);
+ if (type === RenderType.WireframePrint) ;
+ else {
+ let m = obj.children[0];
+ m.material = material ? material : ColorMaterial.GetLineMaterial(this._Color);
+ return obj;
+ }
}
GetDragPointCount(drag) {
if (drag === DragPointType.Grip)
@@ -7406,6 +7560,31 @@ function equalCurve(cu1, cu2, tolerance = 1e-4) {
}
return false;
}
+/**
+* 计算点在曲线前进方向的方位,左边或者右边
+*
+* @param {Curve} cu
+* @param {Vector3} pt
+* @returns {boolean} 左边为-1,右边为1
+*/
+function GetPointAtCurveDir(cu, pt) {
+ if (cu instanceof exports.Circle)
+ return cu.PtInCurve(pt) ? -1 : 1;
+ else if (cu instanceof exports.Polyline) {
+ let u = new OffsetPolyline(cu, 1);
+ u.InitSubCurves();
+ return u.GetPointAtCurveDir(pt.clone().applyMatrix4(cu.OCSInv).setZ(0));
+ }
+ //最近点
+ let cp = cu.GetClosestPointTo(pt, false);
+ if (equalv3(cp, pt, 1e-6))
+ return 0;
+ //最近点参数
+ let cparam = cu.GetParamAtPoint(cp);
+ let dri = cu.GetFistDeriv(cparam);
+ let cross = dri.cross(pt.clone().sub(cp)).applyMatrix4(cu.OCSInv);
+ return -Math.sign(cross.z);
+}
function ConverCircleToPolyline(cir) {
//该写法不支持三维坐标系
// let pl = new Polyline();
@@ -7469,6 +7648,60 @@ function getArcOrCirNearPts(cu, pickPoint, viewXform) {
function getTanPtsOnEllipse(cu, lastPoint) {
return [];
}
+function IsRect(cu) {
+ if (cu instanceof exports.Polyline) {
+ if (!cu.IsClose)
+ return { isRect: false };
+ let pts = cu.GetStretchPoints();
+ if (pts.length < 4)
+ return { isRect: false };
+ let xVec;
+ let p1 = pts[0];
+ for (let i = 1; i < pts.length; i++) {
+ xVec = pts[i].clone().sub(p1).normalize();
+ if (!equalv3(xVec, ZeroVec))
+ break;
+ }
+ if (!xVec)
+ return { isRect: false };
+ let zVec = cu.Normal;
+ let yVec = zVec.clone().cross(xVec).normalize();
+ let rectOCS = new three.Matrix4().makeBasis(xVec, yVec, zVec);
+ let rectOCSInv = new three.Matrix4().getInverse(rectOCS);
+ for (let p of pts)
+ p.applyMatrix4(rectOCSInv);
+ let box = new three.Box3().setFromPoints(pts);
+ let size = box.getSize(new three.Vector3);
+ if (equaln(size.x * size.y, cu.Area, 0.1)) {
+ return {
+ isRect: true,
+ size,
+ box,
+ OCS: rectOCS,
+ };
+ }
+ }
+ return { isRect: false };
+}
+function MergeCurvelist(cus) {
+ for (let i = 0; i < cus.length; i++) {
+ let c1 = cus[i];
+ let nextI = FixIndex(i + 1, cus);
+ let c2 = cus[nextI];
+ let status = equaln(c2.Length, 0, LINK_FUZZ) ? Status.True : c1.Join(c2, false, LINK_FUZZ);
+ if (status === Status.True) {
+ cus.splice(nextI, 1);
+ i--;
+ }
+ else if (status === Status.ConverToCircle) {
+ cus.length = 0;
+ let a = c1;
+ cus.push(new exports.Circle(a.Center, a.Radius));
+ break;
+ }
+ }
+ return cus;
+}
function SwapParam(res) {
for (let r of res)
[r.thisParam, r.argParam] = [r.argParam, r.thisParam];
@@ -7544,6 +7777,64 @@ function Pts2Polyline(pts, isClose) {
}
return pl;
}
+const PolylineSpliteRectFuzz = 1e-3;
+/**封闭多段线 分割成矩形 */
+function PolylineSpliteRect(outline) {
+ if (!outline.IsClose || IsRect(outline).isRect)
+ return [outline];
+ let firstDerv = outline.GetFistDeriv(0).normalize();
+ if (!isParallelTo(firstDerv, XAxis, PolylineSpliteRectFuzz) && !isParallelTo(firstDerv, YAxis, PolylineSpliteRectFuzz))
+ return [outline];
+ let cus = outline.Explode();
+ let yCus = [];
+ for (let c of cus) {
+ if (c instanceof exports.Arc)
+ return [outline];
+ let derv = c.GetFistDeriv(0).normalize();
+ if (isParallelTo(derv, YAxis, PolylineSpliteRectFuzz))
+ yCus.push(c);
+ else if (!isParallelTo(derv, XAxis, PolylineSpliteRectFuzz)) {
+ return [outline];
+ }
+ }
+ yCus.sort((c1, c2) => c1.StartPoint.x - c2.StartPoint.x);
+ let rects = [];
+ for (let i = 0; i < yCus.length - 1; i++) {
+ let c1 = yCus[i];
+ let c2 = yCus[i + 1];
+ let x1 = c1.StartPoint.x;
+ let x2 = c2.StartPoint.x;
+ if (equaln(x1, x2))
+ continue;
+ let y1;
+ let y2;
+ let res = c1.IntersectWith2(outline, IntersectOption.ExtendThis);
+ let res2 = c2.IntersectWith2(outline, IntersectOption.ExtendThis);
+ let pars = [...res.map(r => Math.floor(r.argParam)), ...res2.map(r => Math.floor(r.argParam))];
+ pars = [...new Set(pars)];
+ pars.sort((a, b) => a - b);
+ let ys = [];
+ for (let par of pars) {
+ let c = outline.GetCurveAtParam(par);
+ let derv = c.GetFistDeriv(0).normalize();
+ if (isParallelTo(derv, XAxis, PolylineSpliteRectFuzz)) {
+ let x3 = c.StartPoint.x;
+ let x4 = c.EndPoint.x;
+ if (x3 > x4)
+ [x3, x4] = [x4, x3];
+ if (isIntersect(x1, x2, x3, x4, -PolylineSpliteRectFuzz))
+ ys.push(c.StartPoint.y);
+ }
+ }
+ if (ys.length < 2)
+ return [outline];
+ ys.sort((a, b) => a - b);
+ y1 = ys[0];
+ y2 = arrayLast(ys);
+ rects.push(new exports.Polyline().RectangleFrom2Pt(new three.Vector3(x1, y1), new three.Vector3(x2, y2)));
+ }
+ return rects;
+}
var Arc_1;
/**
@@ -7919,7 +8210,7 @@ exports.Arc = Arc_1 = class Arc extends Curve {
//顺时针
if (this._Clockwise) {
if (this._StartAngle > endAngle)
- return this._StartAngle - endAngle;
+ return this.StartAngle - endAngle;
else //越过0点绘制圆弧
return (Math.PI * 2) - (endAngle - this._StartAngle);
}
@@ -7994,7 +8285,7 @@ exports.Arc = Arc_1 = class Arc extends Curve {
*/
InitDrawObject(renderType = RenderType.Wireframe) {
let geo = BufferGeometryUtils.CreateFromPts(this.Shape.getPoints(60).map(AsVector3));
- if (renderType === RenderType.Print) {
+ if (renderType === RenderType.WireframePrint) {
var geometry = new LineGeometry.LineGeometry();
geometry.setPositions(geo.attributes.position.array);
return new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
@@ -8140,8 +8431,10487 @@ exports.Arc = Arc_1 = __decorate([
Factory
], exports.Arc);
+const _LogInjectFunctions = [];
+function Log(message, ...optionalParams) {
+ for (let f of _LogInjectFunctions)
+ f(message, ...optionalParams);
+}
+
+let instanceMap = new Map();
+/**
+ * 构造单例类的静态类.
+ * # Example:
+ * class A extends Singleton(){};
+ * //获得单例
+ * let a = A.GetInstance();
+ */
+class Singleton {
+ constructor() { }
+ //FIXME: https://github.com/Microsoft/TypeScript/issues/5863
+ static GetInstance() {
+ if (instanceMap.has(this))
+ return instanceMap.get(this);
+ //@ts-ignore
+ let __instance__ = new this.prototype.constructor();
+ instanceMap.set(this, __instance__);
+ return __instance__;
+ }
+}
+
+function ScaleUV(geo, scale = 1e-3) {
+ for (let uvsg of geo.faceVertexUvs) {
+ for (let uvs of uvsg) {
+ for (let uv of uvs) {
+ uv.multiplyScalar(scale);
+ }
+ }
+ }
+}
+function ScaleUV2(geo, ocs, xScale = 1e-3, yScale = 1e-3, isInvert = false) {
+ for (let uvsg of geo.faceVertexUvs) {
+ for (let uvs of uvsg) {
+ for (let uv of uvs) {
+ let p = new three.Vector3(uv.x, uv.y).applyMatrix4(ocs);
+ uv.x = p.x;
+ uv.y = p.y;
+ if (isInvert) {
+ uv.x /= yScale;
+ uv.y /= xScale;
+ }
+ else {
+ uv.x /= xScale;
+ uv.y /= yScale;
+ }
+ }
+ }
+ }
+}
+
+class Shape {
+ constructor(out, hols) {
+ this._Holes = [];
+ this._Shape = new three.Shape();
+ this._Outline = out || new Contour();
+ hols && this._Holes.push(...hols);
+ }
+ get Outline() {
+ return this._Outline;
+ }
+ get Holes() {
+ return this._Holes;
+ }
+ get Area() {
+ let outlineArea = this._Outline.Area;
+ let holeArea = this._Holes.map(l => l.Area).reduce((a1, a2) => a1 + a2, 0);
+ return outlineArea - holeArea;
+ }
+ get BoundingBox() {
+ return this._Outline.BoundingBox;
+ }
+ set Outline(cus) {
+ this._Outline = cus;
+ this.UpdateShape();
+ }
+ set Holes(cus) {
+ this._Holes = cus;
+ this.UpdateShape();
+ }
+ get Shape() {
+ this.UpdateShape();
+ return this._Shape;
+ }
+ get Position() {
+ return this._Outline.Curve.Position;
+ }
+ set Position(p) {
+ let vec = p.clone().sub(this._Outline.Curve.Position);
+ this._Outline.Curve.Position = p;
+ for (let h of this._Holes)
+ h.Curve.Position = h.Curve.Position.add(vec);
+ }
+ Z0() {
+ this._Outline.Curve.Z0();
+ for (let h of this._Holes)
+ h.Curve.Z0();
+ return this;
+ }
+ MatrixPlanarizere() {
+ this._Outline.Curve.MatrixPlanarizere();
+ for (let h of this._Holes)
+ h.Curve.MatrixPlanarizere();
+ }
+ ApplyMatrix(m) {
+ this._Outline.Curve.ApplyMatrix(m);
+ this._Holes.forEach(h => h.Curve.ApplyMatrix(m));
+ return this;
+ }
+ ApplyScaleMatrix(m) {
+ let cu = this.Outline.Curve;
+ let cus = this._Holes.map(h => h.Curve);
+ cus.unshift(cu);
+ for (let c of cus) {
+ c.ApplyMatrix(c.OCS);
+ c.ApplyMatrix(m);
+ c.ApplyMatrix(c.OCSInv);
+ }
+ return this;
+ }
+ Explode() {
+ let cus = [];
+ let contours = [this._Outline, ...this._Holes];
+ for (let con of contours) {
+ if (con.Curve instanceof exports.Polyline)
+ cus.push(...con.Curve.Explode());
+ else
+ cus.push(con.Curve.Clone());
+ }
+ return cus;
+ }
+ Clone() {
+ let shape = new Shape();
+ shape.Outline = this._Outline.Clone();
+ shape.Holes = this.Holes.map(h => h.Clone());
+ return shape;
+ }
+ SetColor(color) {
+ this._Outline.Curve.ColorIndex = color;
+ this._Holes.forEach(h => h.Curve.ColorIndex = color);
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ switch (snapMode) {
+ case ObjectSnapMode.End:
+ return this.GetStretchPoints();
+ case ObjectSnapMode.Mid:
+ case ObjectSnapMode.Cen:
+ case ObjectSnapMode.Nea:
+ case ObjectSnapMode.Ext:
+ case ObjectSnapMode.Per:
+ case ObjectSnapMode.Tan:
+ {
+ let cus = [this._Outline.Curve];
+ for (let h of this._Holes) {
+ cus.push(h.Curve);
+ }
+ let pts = [];
+ for (let c of cus) {
+ pts.push(...c.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ }
+ return pts;
+ }
+ }
+ return [];
+ }
+ GetGripPoints() {
+ let pts = this.Outline.Curve.GetGripPoints();
+ for (let h of this._Holes) {
+ pts.push(...h.Curve.GetGripPoints());
+ }
+ return pts;
+ }
+ MoveGripPoints(indexList, vec) {
+ let i = indexList[0];
+ let outlineIndex = this._Outline.Curve.GetGripPoints().length;
+ let cu = this._Outline.Curve;
+ if (i >= outlineIndex) {
+ for (let h of this._Holes) {
+ let len = h.Curve.GetGripPoints().length;
+ if (indexList[0] < outlineIndex + len) {
+ indexList = [indexList[0] - outlineIndex];
+ cu = h.Curve;
+ break;
+ }
+ outlineIndex += len;
+ }
+ }
+ cu.MoveGripPoints(indexList, vec);
+ }
+ GetStretchPoints() {
+ let pts = this.Outline.Curve.GetStretchPoints();
+ for (let h of this._Holes) {
+ pts.push(...h.Curve.GetStretchPoints());
+ }
+ return pts;
+ }
+ MoveStretchPoints(indexList, vec) {
+ let outlen = 0;
+ for (let cu of [this._Outline.Curve, ...this._Holes.map(h => h.Curve)]) {
+ let count = cu.GetStretchPoints().length;
+ let refIndex = outlen + count;
+ let curIndexs = [];
+ while (indexList.length) {
+ if (indexList[0] < refIndex)
+ curIndexs.push(indexList.shift() - outlen);
+ else
+ break;
+ }
+ cu.MoveStretchPoints(curIndexs, vec);
+ if (indexList.length === 0)
+ break;
+ outlen += count;
+ }
+ }
+ //交集 如果成功返回一个面域 失败返回0个
+ IntersectionBoolOperation(targetShape) {
+ let resOutlines = this._Outline.IntersectionBoolOperation(targetShape._Outline);
+ let cus = this.targetOutlineSubHoleOutline(resOutlines, Shape.mergeContours([...this._Holes, ...targetShape._Holes]));
+ return Shape.pairHoleAndOutline(cus);
+ }
+ //并集,如果成功返回1个形状,不成功返回2个形状
+ UnionBoolOperation(targetShape) {
+ let { contours, holes } = this._Outline.UnionBoolOperation(targetShape._Outline);
+ let shapes = [];
+ //提取出所有的孔洞, 目标线段孔洞和原线段差,如果孔洞和目标相减后有被包围轮廓,应把这个单独提取出来作为形状
+ let unionHoles = [];
+ //合并运算时提取出运算后的孔洞和形状
+ const pickUpHoleOrShape = (srcHoles, tarHoles, outline) => {
+ srcHoles.forEach(cu => {
+ let tmpContours = cu.SubstactBoolOperation(outline).sort((a, b) => b.Area - a.Area);
+ let isAllContainered = tmpContours.length > 1 && tmpContours.slice(1).every((cu, index) => tmpContours[0].CuInOutline(cu.Curve));
+ //洞是否被最大的洞包含,是,则把被包含的洞都提取出来加入形状数组
+ if (isAllContainered) {
+ shapes.push(...this.targetOutlinesSubHoles(tmpContours.slice(1).map(c => new Shape(c)), tarHoles.map(c => new Shape(c))));
+ }
+ else
+ unionHoles.push(...tmpContours);
+ });
+ };
+ pickUpHoleOrShape(targetShape._Holes, this._Holes, this._Outline);
+ pickUpHoleOrShape(this._Holes, targetShape._Holes, targetShape._Outline);
+ targetShape._Holes.forEach(cu => {
+ this._Holes.forEach(c => {
+ unionHoles.push(...c.IntersectionBoolOperation(cu));
+ });
+ });
+ shapes.push(...this.targetOutlinesSubHoles(contours.map(c => new Shape(c, holes)), unionHoles.map(c => new Shape(c))));
+ return shapes;
+ }
+ /**
+ * 如果完全被减掉,就返回0个.其他的返回1个或者n个
+ * @param targetShapes 已经是合并后的形状数组
+ */
+ SubstactBoolOperation(targetShapes) {
+ let originOutline = this.Outline;
+ let targetOutlines = targetShapes.map(s => s.Outline);
+ const { holes, outlines } = originOutline.GetSubtractListByMoreTargets(targetOutlines);
+ holes.push(...this.Holes);
+ let newShapes = [];
+ if (outlines.length === 1 && equaln(outlines[0].Area, originOutline.Area)) {
+ newShapes = [new Shape(outlines[0], Shape.mergeContours(holes))];
+ }
+ else if (holes.length === 0) {
+ newShapes = outlines.map(o => new Shape(o));
+ }
+ else {
+ for (let outline of outlines)
+ newShapes.push(...new Shape(outline).SubstactBoolOperation(holes.map(h => new Shape(h))));
+ }
+ let holeShape = this.Holes.map(h => new Shape(h));
+ for (let target of targetShapes) {
+ let tmpInterList = [];
+ if (target.Holes.length === 0)
+ continue;
+ for (let hole of target.Holes) {
+ let list = hole.IntersectionBoolOperation(originOutline);
+ tmpInterList.push(...list);
+ }
+ for (let ot of tmpInterList) {
+ let subShapes = [];
+ subShapes.push(...holeShape);
+ for (let t of targetShapes) {
+ if (t !== target)
+ subShapes.push(new Shape(t.Outline));
+ }
+ newShapes.push(...new Shape(ot).SubstactBoolOperation(subShapes));
+ }
+ }
+ return newShapes;
+ }
+ Equal(targetShape) {
+ if (this._Outline.Equal(targetShape._Outline)) {
+ return this._Holes.length === targetShape._Holes.length
+ && this._Holes.every(h1 => targetShape._Holes.some(h2 => h1.Equal(h2)));
+ }
+ return false;
+ }
+ targetOutlinesSubHoles(targetShapes, holeShapes) {
+ let resultShapes = [];
+ for (let ts of targetShapes) {
+ let res = ts.SubstactBoolOperation(holeShapes);
+ resultShapes.push(...res);
+ }
+ return resultShapes;
+ }
+ /**
+ * 目标轮廓减去洞
+ *
+ * @private
+ * @param {Contour[]} tarContours 轮廓列表
+ * @param {Contour[]} holes 洞列表
+ * @returns {Contour[]} 新的轮廓列表
+ * @memberof Shape
+ */
+ targetOutlineSubHoleOutline(tarContours, holes) {
+ if (!holes.length)
+ return tarContours;
+ let resultContours = [];
+ for (let minuendContour of tarContours) {
+ //需要被差集的形状列表
+ let tmpContour = [minuendContour];
+ for (let hole of holes) {
+ //缓存差集生成的轮廓
+ let tmps = [];
+ tmpContour.forEach(r => {
+ let cus = r.SubstactBoolOperation(hole);
+ tmps.push(...cus);
+ });
+ tmpContour = tmps; //使用新生成的进行下一轮计算
+ }
+ resultContours.push(...tmpContour);
+ }
+ return resultContours;
+ }
+ //整理轮廓数组,匹配洞和外轮廓
+ static pairHoleAndOutline(contours) {
+ let shapes = [];
+ contours.sort((a, b) => b.Area - a.Area);
+ while (contours.length) {
+ //洞列表
+ let tmpHoles = [];
+ let outline = contours.shift();
+ //取出包含的洞
+ arrayRemoveIf(contours, (con) => {
+ let bisIn = outline.CuInOutline(con.Curve);
+ if (bisIn)
+ tmpHoles.push(con);
+ return bisIn;
+ });
+ let holes = Shape.removeBeContaineredHoles(tmpHoles);
+ shapes.push(new Shape(outline, holes));
+ }
+ return shapes;
+ }
+ /**
+ * 合并洞,本质是使用(并集算法)将可以并集的洞合并在一起,减少洞的数量.
+ * canSidewipe 用于走刀,擦边的是否合并
+ */
+ static mergeContours(holes, canSidewipe = true) {
+ if (holes.length <= 1)
+ return holes;
+ let rets = []; //返回的合并轮廓
+ let cache = new Map();
+ while (holes.length > 0) {
+ let c = holes.shift(); //取第一个
+ let b1 = cache.get(c);
+ if (!b1) {
+ b1 = c.BoundingBox;
+ cache.set(c, b1);
+ }
+ while (true) {
+ //剩余的 不相交的形状表 remaining
+ let remHoles = holes.filter(ic => {
+ let b2 = cache.get(ic);
+ if (!b2) {
+ b2 = ic.BoundingBox;
+ cache.set(ic, b2);
+ }
+ if (!IntersectBox2(b1, b2))
+ return true;
+ let unions = c.UnionBoolOperation(ic);
+ if (unions.holes.length > 0)
+ console.warn("未知情况");
+ if (unions.contours.length === 1) //并集成功
+ {
+ if (!canSidewipe) {
+ if (equaln(c.Area + ic.Area, unions.contours[0].Area, 0.1))
+ return true;
+ }
+ c = unions.contours[0]; //更新c
+ b1 = c.BoundingBox;
+ cache.set(c, b1);
+ }
+ return unions.contours.length !== 1; //过滤出并集失败的形状
+ });
+ //如果c和剩余的轮廓都不相交,那么退出
+ if (remHoles.length === holes.length) {
+ rets.push(c); //c已经是一个独立的轮廓,不和任意轮廓相交(不能合并了)
+ break; //退出循环.下一个
+ }
+ else
+ holes = remHoles; //更新为剩下的轮廓列表
+ }
+ }
+ return rets;
+ }
+ /**
+ * 移除被包含的洞.(移除无效的洞,已经被更大的洞包含)
+ *
+ * @private
+ * @param {Contour[]} tmpHoles 洞列表
+ * @returns {Contour[]} 返回的洞列表都不会互相包含.
+ * @memberof Shape
+ */
+ static removeBeContaineredHoles(tmpHoles) {
+ let holes = [];
+ if (tmpHoles.length <= 1)
+ return tmpHoles;
+ tmpHoles.sort((a, b) => b.Area - a.Area);
+ while (tmpHoles.length) {
+ let srcHole = tmpHoles.shift();
+ holes.push(srcHole);
+ //移除包含的洞
+ arrayRemoveIf(tmpHoles, h => srcHole.CuInOutline(h.Curve));
+ }
+ return holes;
+ }
+ UpdateShape() {
+ this._Shape = this.Outline.Shape;
+ for (let h of this._Holes) {
+ if (h.Curve instanceof exports.Polyline)
+ h.Curve.UpdateMatrixTo(this.Outline.Curve.OCS);
+ if (h.Curve instanceof exports.Circle) {
+ let sp = new three.Path();
+ let cen = h.Curve.Center.applyMatrix4(this.Outline.Curve.OCSInv);
+ sp.ellipse(cen.x, cen.y, h.Curve.Radius, h.Curve.Radius, 0, 2 * Math.PI, false, 0);
+ this._Shape.holes.push(sp);
+ }
+ else
+ this._Shape.holes.push(h.Shape);
+ }
+ }
+ //读写文件
+ ReadFile(file) {
+ let ver = file.Read(); //1
+ this._Outline = Contour.CreateContour([file.ReadObject()]);
+ let count = file.Read();
+ for (let i = 0; i < count; i++) {
+ this._Holes.push(Contour.CreateContour([file.ReadObject()]));
+ }
+ }
+ //对象将自身数据写入到文件.
+ WriteFile(file) {
+ file.Write(1); //ver
+ file.WriteObject(this._Outline.Curve);
+ file.Write(this._Holes.length);
+ this._Holes.forEach(h => file.WriteObject(h.Curve));
+ }
+}
+
+class ShapeManager {
+ constructor() {
+ this._ShapeList = [];
+ }
+ get ShapeList() {
+ return this._ShapeList.slice();
+ }
+ get ShapeCount() {
+ return this._ShapeList.length;
+ }
+ get ShapeArea() {
+ return this._ShapeList.map(s => s.Area).reduce((a1, a2) => a1 + a2, 0);
+ }
+ AppendShapeList(shapes) {
+ Array.isArray(shapes) ? this._ShapeList.push(...shapes) : this._ShapeList.push(shapes);
+ return this;
+ }
+ Clear() {
+ this._ShapeList.length = 0;
+ }
+ BoolOper(otherMg, booltype) {
+ switch (booltype) {
+ case exports.BoolOpeartionType.Intersection:
+ return this.IntersectionBoolOperation(otherMg);
+ case exports.BoolOpeartionType.Union:
+ return this.UnionBoolOperation(otherMg);
+ case exports.BoolOpeartionType.Subtract:
+ return this.SubstactBoolOperation(otherMg);
+ }
+ }
+ //交集 如果成功返回一个面域 失败返回0个
+ IntersectionBoolOperation(target) {
+ let shapes = [];
+ for (let srcShape of this._ShapeList) {
+ for (let tarShape of target._ShapeList) {
+ let tmpShapes = srcShape.IntersectionBoolOperation(tarShape);
+ shapes.push(...tmpShapes);
+ }
+ }
+ this.Clear();
+ this._ShapeList = shapes;
+ return this._ShapeList.length > 0;
+ }
+ //并集,如果有一个形状并集成功,就成功
+ UnionBoolOperation(targetMg) {
+ let isSuccess = false;
+ let srcShapes = this._ShapeList;
+ let tarShapes = targetMg._ShapeList;
+ let alones = []; //孤立的形状
+ const boxCache = new WeakMap();
+ for (let src of srcShapes) {
+ let notUnions = []; //未被合并的形状列表 来自tarShapes
+ let srcBox = src.BoundingBox;
+ for (let tar of tarShapes) {
+ let tarBox = boxCache.get(tar);
+ if (!tarBox) {
+ tarBox = tar.BoundingBox;
+ boxCache.set(tar, tarBox);
+ }
+ if (!IntersectBox2(srcBox, tarBox)) {
+ notUnions.push(tar);
+ continue;
+ }
+ let unions = src.UnionBoolOperation(tar);
+ if (unions.length === 1) //并集成功
+ {
+ isSuccess = true;
+ src = unions[0]; //src设置为 合并完的形状
+ }
+ else //并集失败
+ notUnions.push(tar); //设置为未计算
+ }
+ //如果发现src和任意一个形状并集成功,那么
+ if (notUnions.length != tarShapes.length) {
+ notUnions.push(src); //加入src 进行下一轮
+ tarShapes = notUnions;
+ }
+ else
+ alones.push(src); //它是孤独的一个形状
+ }
+ this._ShapeList = alones.concat(tarShapes);
+ return isSuccess;
+ }
+ SubstactBoolOperation(target) {
+ let newShapes = [];
+ for (let s of this._ShapeList) {
+ let ss = s.SubstactBoolOperation(target.ShapeList);
+ newShapes.push(...ss);
+ }
+ this._ShapeList = newShapes;
+ return true;
+ }
+ /**
+ * 与region.ApplyMatrix不同的是,这个是直接操作内部对象.
+ * 通常用来计算布尔运算时需要真实的移动这个位置.
+ * 并且将不会刷新显示
+ *
+ * @param {Matrix4} mat4
+ * @memberof ShapeManager
+ */
+ ApplyMatrix(mat4) {
+ for (let s of this._ShapeList) {
+ s.Outline.Curve.ApplyMatrix(mat4);
+ s.Holes.forEach(o => o.Curve.ApplyMatrix(mat4));
+ }
+ }
+ ReadFile(file) {
+ let ver = file.Read(); //1
+ let cout = file.Read();
+ for (let i = 0; i < cout; i++) {
+ let obj = new Shape();
+ obj.ReadFile(file);
+ this._ShapeList.push(obj);
+ }
+ }
+ WriteFile(file) {
+ file.Write(1); //ver
+ file.Write(this.ShapeList.length);
+ for (let s of this.ShapeList) {
+ s.WriteFile(file);
+ }
+ }
+}
+
+var Region_1;
+let Region = Region_1 = class Region extends Entity {
+ constructor(_ShapeManager = new ShapeManager()) {
+ super();
+ this._ShapeManager = _ShapeManager;
+ }
+ static CreateFromCurves(cus) {
+ let shapes = Contour.GetAllContour(cus).map(out => new Shape(out));
+ if (shapes.length > 0) {
+ let reg = new Region_1();
+ //MarkX:曲线同面域一起移动
+ reg.ApplyMatrix(shapes[0].Outline.Curve.OCS);
+ reg.ShapeManager.AppendShapeList(shapes);
+ return reg;
+ }
+ }
+ //如果需要修改获取到的属性,需要Clone后进行操作,否则会对原实体进行破坏
+ get ShapeManager() {
+ return this._ShapeManager;
+ }
+ get Area() {
+ return this.ShapeManager.ShapeArea;
+ }
+ get BoundingBox() {
+ let box = new three.Box3();
+ for (let s of this._ShapeManager.ShapeList)
+ box.union(s.BoundingBox);
+ return box;
+ }
+ Explode() {
+ let shapeList = this._ShapeManager.ShapeList;
+ if (shapeList.length <= 1) {
+ return shapeList[0].Explode();
+ }
+ else {
+ let regs = [];
+ shapeList.forEach(s => {
+ let reg = new Region_1().ApplyMatrix(this.OCS);
+ reg.ShapeManager.AppendShapeList(s);
+ regs.push(reg);
+ });
+ return regs;
+ }
+ }
+ /**
+ * 对于布尔操作,这个将会变换内部轮廓到对方坐标系.
+ * 并且这个变换不会更新图形绘制.
+ * @param {Matrix4} m
+ * @memberof Region
+ */
+ ShapeApplyMatrix(m) {
+ this.WriteAllObjectRecord();
+ this._ShapeManager.ApplyMatrix(m);
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ switch (snapMode) {
+ case ObjectSnapMode.End:
+ return this.GetGripPoints();
+ case ObjectSnapMode.Mid:
+ case ObjectSnapMode.Cen:
+ case ObjectSnapMode.Nea:
+ case ObjectSnapMode.Ext:
+ case ObjectSnapMode.Per:
+ case ObjectSnapMode.Tan:
+ {
+ let pts = [];
+ for (let s of this._ShapeManager.ShapeList) {
+ pts.push(...s.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ }
+ return pts;
+ }
+ }
+ return [];
+ }
+ GetGripPoints() {
+ let pts = [];
+ for (let s of this._ShapeManager.ShapeList)
+ pts.push(...s.GetStretchPoints());
+ return pts;
+ }
+ MoveGripPoints(indexList, moveVec) {
+ this.WriteAllObjectRecord();
+ let moveVLoc = moveVec.clone().applyMatrix4(new three.Matrix4().extractRotation(this.OCSInv));
+ this.ApplyMatrix(MoveMatrix(moveVLoc));
+ }
+ ApplyMatrix(m) {
+ this.WriteAllObjectRecord();
+ //面域移动,组成面域的曲线也要移动 MarkX:曲线同面域一起移动
+ this._ShapeManager.ShapeList.forEach(s => s.ApplyMatrix(m));
+ return super.ApplyMatrix(m);
+ }
+ get Position() {
+ return super.Position;
+ }
+ set Position(pt) {
+ this.WriteAllObjectRecord();
+ let moveX = pt.x - this._Matrix.elements[12];
+ let moveY = pt.y - this._Matrix.elements[13];
+ let moveZ = pt.z - this._Matrix.elements[14];
+ this._Matrix.setPosition(pt);
+ this._SpaceOCS.elements[12] += moveX;
+ this._SpaceOCS.elements[13] += moveY;
+ this._SpaceOCS.elements[14] += moveZ;
+ let m = new three.Matrix4().setPosition(moveX, moveY, moveZ);
+ for (let s of this.ShapeManager.ShapeList)
+ s.ApplyMatrix(m);
+ this.Update(UpdateDraw.Matrix);
+ }
+ ApplyScaleMatrix(m) {
+ this.WriteAllObjectRecord();
+ for (let s of this._ShapeManager.ShapeList)
+ s.ApplyScaleMatrix(m);
+ this.Update(UpdateDraw.Geometry);
+ return this;
+ }
+ //Z轴归0
+ Z0() {
+ super.Z0();
+ for (let s of this._ShapeManager.ShapeList)
+ s.Z0();
+ return this;
+ }
+ MatrixPlanarizere() {
+ super.MatrixPlanarizere();
+ for (let s of this._ShapeManager.ShapeList)
+ s.MatrixPlanarizere();
+ return this;
+ }
+ ApplyMirrorMatrix(m) {
+ return this;
+ }
+ /**
+ * 请注意:该计算会操作otherRegion的矩阵
+ * @param {Region} otherRegion
+ * @param {BoolOpeartionType} boolType
+ */
+ BooleanOper(otherRegion, boolType) {
+ if (this.IsCoplaneTo(otherRegion)) {
+ this.WriteAllObjectRecord();
+ let oldOcs = this.OCS;
+ //把形状曲线转移到二维屏幕计算后还原回来
+ this.ShapeApplyMatrix(this.OCSInv);
+ otherRegion.ShapeApplyMatrix(this.OCSInv);
+ let isSuccess = this._ShapeManager.BoolOper(otherRegion._ShapeManager, boolType);
+ this.ShapeApplyMatrix(oldOcs);
+ this.Update();
+ return isSuccess;
+ }
+ return false;
+ }
+ get MeshGeometry() {
+ if (this._MeshGeometry)
+ return this._MeshGeometry;
+ this.UpdateGeometry();
+ return this._MeshGeometry;
+ }
+ get EdgeGeometry() {
+ if (this._EdgeGeometry)
+ return this._EdgeGeometry;
+ this.UpdateGeometry();
+ return this._EdgeGeometry;
+ }
+ UpdateGeometry() {
+ let shapeList = this._ShapeManager.ShapeList;
+ let edgePts = [];
+ let meshGeoms = [];
+ const AddEdgePts = (pts, diffMat) => {
+ for (let i = 0; i < pts.length; i++) {
+ let p = AsVector3(pts[i]);
+ p.applyMatrix4(diffMat);
+ edgePts.push(p);
+ if (i !== 0 && i !== pts.length - 1)
+ edgePts.push(p);
+ }
+ };
+ for (let i = 0; i < shapeList.length; i++) {
+ let shape = shapeList[i];
+ let geometry = new three.ShapeGeometry(shape.Shape, 60); //60 可以优化.
+ let diffMat = this.OCSInv.clone().multiply(shape.Outline.Curve.OCSNoClone);
+ geometry.applyMatrix4(diffMat);
+ ScaleUV(geometry);
+ meshGeoms.push(new three.BufferGeometry().fromGeometry(geometry));
+ let shapeInfo = shape.Shape.extractPoints(60);
+ let pts = shapeInfo.shape;
+ AddEdgePts(pts, diffMat);
+ let holePtss = shapeInfo.holes;
+ for (let holePts of holePtss)
+ AddEdgePts(holePts, diffMat);
+ }
+ this._EdgeGeometry = BufferGeometryUtils.CreateFromPts(edgePts);
+ this._MeshGeometry = BufferGeometryUtils.MergeBufferGeometries(meshGeoms);
+ this._MeshGeometry["IsMesh"] = true;
+ this._MeshGeometry.computeVertexNormals();
+ }
+ UpdateDrawGeometry() {
+ this._EdgeGeometry = undefined;
+ this._MeshGeometry = undefined;
+ }
+ InitDrawObject(renderType = RenderType.Wireframe) {
+ if (renderType === RenderType.Wireframe) {
+ return new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex));
+ }
+ else if (renderType === RenderType.Conceptual) {
+ return new three.Object3D().add(new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex)), new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)));
+ }
+ else if (renderType === RenderType.Physical) {
+ let mesh = new three.Mesh(this.MeshGeometry, this.MeshMaterial);
+ mesh.castShadow = true;
+ mesh.receiveShadow = true;
+ return mesh;
+ }
+ }
+ UpdateDrawObject(renderType, obj) {
+ DisposeThreeObj(obj);
+ Object3DRemoveAll(obj);
+ if (renderType === RenderType.Wireframe) {
+ let l = obj;
+ l.geometry = this.EdgeGeometry;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (renderType === RenderType.Conceptual) {
+ return obj.add(new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex)), new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)));
+ }
+ else if (renderType === RenderType.Physical) {
+ let mesh = obj;
+ mesh.geometry = this.MeshGeometry;
+ mesh.material = this.MeshMaterial;
+ }
+ }
+ /**
+ * 当实体需要被更新时,更新实体材质
+ */
+ UpdateDrawObjectMaterial(type, obj, material) {
+ if (type === RenderType.Wireframe) {
+ for (let l of obj.children) {
+ let line = l;
+ line.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ }
+ else if (type === RenderType.Conceptual) {
+ for (let i = 0; i < obj.children.length; i++) {
+ if (i % 2 === 0) {
+ let l = obj.children[i];
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else {
+ let mesh = obj.children[i];
+ mesh.material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
+ }
+ }
+ }
+ else {
+ for (let m of obj.children) {
+ let mesh = m;
+ mesh.material = this.MeshMaterial;
+ }
+ }
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read(); //1
+ this._ShapeManager.Clear();
+ this._ShapeManager.ReadFile(file);
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(1); //ver
+ this._ShapeManager.WriteFile(file);
+ }
+};
+Region = Region_1 = __decorate([
+ Factory
+], Region);
+
+/**
+ * 把板件炸开成面域,0,1为正反面,其余的为边面(没有圆弧面)
+ */
+function Board2Regions(br) {
+ let ocs = br.OCS;
+ let cu = br.ContourCurve.Clone();
+ if (cu instanceof exports.Circle)
+ cu = ConverCircleToPolyline(cu);
+ let frontReg = Region.CreateFromCurves([cu.Clone()]);
+ let regFrontOcs = ocs.clone();
+ regFrontOcs.setPosition(br.Position.add(br.Normal.multiplyScalar(br.Thickness)));
+ frontReg.ApplyMatrix(regFrontOcs);
+ let backReg = Region.CreateFromCurves([cu.Flip()]);
+ backReg.ApplyMatrix(ocs);
+ let resultRegs = [frontReg, backReg];
+ //edges
+ let lines = cu.Explode().filter(c => c instanceof exports.Line);
+ for (let l of lines) {
+ let rectPl = new exports.Polyline().Rectangle(l.Length, br.Thickness);
+ let reg = Region.CreateFromCurves([rectPl]);
+ if (!reg)
+ continue;
+ let p = l.StartPoint.applyMatrix4(ocs);
+ let x = l.GetFistDeriv(0).transformDirection(ocs);
+ let y = br.Normal;
+ let z = new three.Vector3().crossVectors(x, y);
+ let mtx = new three.Matrix4().makeBasis(x, y, z).setPosition(p);
+ reg.ApplyMatrix(mtx);
+ resultRegs.push(reg);
+ }
+ return resultRegs;
+}
+
+/**统一板件属性key的命名,修改值会导致无法 .xxx该属性 */
+var EBoardKeyList;
+(function (EBoardKeyList) {
+ EBoardKeyList["Height"] = "height";
+ EBoardKeyList["Width"] = "width";
+ EBoardKeyList["Thick"] = "thickness";
+ EBoardKeyList["RoomName"] = "roomName";
+ EBoardKeyList["CabinetName"] = "cabinetName";
+ EBoardKeyList["BrMat"] = "boardName";
+ EBoardKeyList["Mat"] = "material";
+ EBoardKeyList["Color"] = "color";
+ EBoardKeyList["Lines"] = "lines";
+ EBoardKeyList["ProcessGroup"] = "ProcessGroup";
+ EBoardKeyList["BigHole"] = "bigHoleDir";
+ /**
+ * 排钻类型,当没有定义每个边的排钻数据时,使用统一的排钻类型
+ */
+ EBoardKeyList["DrillType"] = "drillType";
+ EBoardKeyList["ComposingFace"] = "composingFace";
+ /**
+ * 封边数组,定义每个边的封边信息
+ */
+ EBoardKeyList["HighSealed"] = "highSealed";
+ EBoardKeyList["UpSealed"] = "sealedUp";
+ EBoardKeyList["DownSealed"] = "sealedDown";
+ EBoardKeyList["LeftSealed"] = "sealedLeft";
+ EBoardKeyList["RightSealed"] = "sealedRight";
+ EBoardKeyList["KnifeRad"] = "knifeRadius";
+})(EBoardKeyList || (EBoardKeyList = {}));
+
+/**序列化板件数据 */
+function serializeBoardData(file, processData) {
+ file.Write(processData[EBoardKeyList.RoomName]);
+ file.Write(processData[EBoardKeyList.CabinetName]);
+ file.Write(processData[EBoardKeyList.BrMat]);
+ file.Write(processData[EBoardKeyList.Mat]);
+ file.Write(processData[EBoardKeyList.Color]);
+ file.Write(processData[EBoardKeyList.Lines]);
+ file.Write(processData[EBoardKeyList.BigHole]);
+ file.Write(processData[EBoardKeyList.DrillType]);
+ file.Write(processData[EBoardKeyList.ComposingFace]);
+ file.Write(processData[EBoardKeyList.HighSealed].length);
+ for (let n of processData[EBoardKeyList.HighSealed]) {
+ file.Write(n.size);
+ }
+ file.Write(processData[EBoardKeyList.UpSealed]);
+ file.Write(processData[EBoardKeyList.DownSealed]);
+ file.Write(processData[EBoardKeyList.LeftSealed]);
+ file.Write(processData[EBoardKeyList.RightSealed]);
+ file.Write(processData.spliteHeight);
+ file.Write(processData.spliteWidth);
+ file.Write(processData.spliteThickness);
+ file.Write(processData.highDrill.length);
+ for (let n of processData.highDrill)
+ file.Write(n);
+ file.Write(processData.frontDrill);
+ file.Write(processData.backDrill);
+ file.Write(processData.remarks.length);
+ for (let d of processData.remarks) {
+ file.Write(d[0]);
+ file.Write(d[1]);
+ }
+}
+//反序列化板件数据
+function deserializationBoardData(file, processData, ver) {
+ processData[EBoardKeyList.RoomName] = file.Read();
+ processData[EBoardKeyList.CabinetName] = file.Read();
+ processData[EBoardKeyList.BrMat] = file.Read();
+ processData[EBoardKeyList.Mat] = file.Read();
+ processData[EBoardKeyList.Color] = file.Read();
+ processData[EBoardKeyList.Lines] = file.Read();
+ processData[EBoardKeyList.BigHole] = file.Read();
+ processData[EBoardKeyList.DrillType] = file.Read();
+ processData[EBoardKeyList.ComposingFace] = file.Read();
+ let count = file.Read();
+ processData[EBoardKeyList.HighSealed].length = 0;
+ for (let i = 0; i < count; i++) {
+ let size = file.Read();
+ if (ver < 4) {
+ file.Read();
+ }
+ processData[EBoardKeyList.HighSealed].push({ size });
+ }
+ processData[EBoardKeyList.UpSealed] = file.Read();
+ processData[EBoardKeyList.DownSealed] = file.Read();
+ processData[EBoardKeyList.LeftSealed] = file.Read();
+ processData[EBoardKeyList.RightSealed] = file.Read();
+ processData.spliteHeight = file.Read();
+ processData.spliteWidth = file.Read();
+ processData.spliteThickness = file.Read();
+ count = file.Read();
+ processData.highDrill = file.ReadArray(count);
+ processData.frontDrill = file.Read();
+ processData.backDrill = file.Read();
+ if (ver >= 7) {
+ let count = file.Read();
+ processData.remarks.length = 0;
+ for (let i = 0; i < count; i++) {
+ let d = ["", ""];
+ d[0] = file.Read();
+ d[1] = file.Read();
+ processData.remarks.push(d);
+ }
+ }
+}
+
+class BoardUVGenerator {
+ generateTopUV(geometry, vertices, indexA, indexB, indexC) {
+ var a_x = vertices[indexA * 3];
+ var a_y = vertices[indexA * 3 + 1];
+ var b_x = vertices[indexB * 3];
+ var b_y = vertices[indexB * 3 + 1];
+ var c_x = vertices[indexC * 3];
+ var c_y = vertices[indexC * 3 + 1];
+ return [
+ new three.Vector2(a_x, a_y),
+ new three.Vector2(b_x, b_y),
+ new three.Vector2(c_x, c_y)
+ ];
+ }
+ generateSideWallUV(geometry, vertices, indexA, indexB, indexC, indexD) {
+ var a_x = vertices[indexA * 3];
+ var a_y = vertices[indexA * 3 + 1];
+ var a_z = vertices[indexA * 3 + 2];
+ var b_x = vertices[indexB * 3];
+ var b_y = vertices[indexB * 3 + 1];
+ var b_z = vertices[indexB * 3 + 2];
+ var c_x = vertices[indexC * 3];
+ var c_y = vertices[indexC * 3 + 1];
+ var c_z = vertices[indexC * 3 + 2];
+ var d_x = vertices[indexD * 3];
+ var d_y = vertices[indexD * 3 + 1];
+ var d_z = vertices[indexD * 3 + 2];
+ let pts;
+ if (Math.abs(a_y - b_y) < 0.01) {
+ pts = [
+ new three.Vector2(a_z - 1, a_x),
+ new three.Vector2(b_z - 1, b_x),
+ new three.Vector2(c_z - 1, c_x),
+ new three.Vector2(d_z - 1, d_x)
+ ];
+ }
+ else {
+ pts = [
+ new three.Vector2(a_z - 1, a_y),
+ new three.Vector2(b_z - 1, b_y),
+ new three.Vector2(c_z - 1, c_y),
+ new three.Vector2(d_z - 1, d_y)
+ ];
+ }
+ return pts;
+ }
+}
+class BoardUVGenerator2 extends BoardUVGenerator {
+ generateTopUV(geometry, vertices, indexA, indexB, indexC) {
+ var a_x = vertices[indexA * 3];
+ var a_y = vertices[indexA * 3 + 1];
+ var b_x = vertices[indexB * 3];
+ var b_y = vertices[indexB * 3 + 1];
+ var c_x = vertices[indexC * 3];
+ var c_y = vertices[indexC * 3 + 1];
+ return [
+ new three.Vector2(a_y, a_x),
+ new three.Vector2(b_y, b_x),
+ new three.Vector2(c_y, c_x)
+ ];
+ }
+}
+let boardUVGenerator = new BoardUVGenerator();
+let boardUVGenerator2 = new BoardUVGenerator2();
+
+var BoardType;
+(function (BoardType) {
+ BoardType[BoardType["Layer"] = 0] = "Layer";
+ BoardType[BoardType["Vertical"] = 1] = "Vertical";
+ BoardType[BoardType["Behind"] = 2] = "Behind"; //背板
+})(BoardType || (BoardType = {}));
+//排钻类型
+var DrillType;
+(function (DrillType) {
+ DrillType["Yes"] = "\u6392";
+ DrillType["None"] = "\u4E0D\u6392";
+ DrillType["More"] = "**\u591A\u79CD**";
+ DrillType["Invail"] = "\u65E0\u6548\u914D\u7F6E";
+})(DrillType || (DrillType = {}));
+//偏心轮类型
+var FaceDirection;
+(function (FaceDirection) {
+ FaceDirection[FaceDirection["Front"] = 0] = "Front";
+ FaceDirection[FaceDirection["Back"] = 1] = "Back";
+})(FaceDirection || (FaceDirection = {}));
+//纹路类型
+var LinesType;
+(function (LinesType) {
+ /** 正纹 */
+ LinesType[LinesType["Positive"] = 0] = "Positive";
+ /** 反纹 */
+ LinesType[LinesType["Reverse"] = 1] = "Reverse";
+ /** 可翻转 */
+ LinesType[LinesType["CanReversal"] = 2] = "CanReversal";
+})(LinesType || (LinesType = {}));
+// 排版面
+var ComposingType;
+(function (ComposingType) {
+ ComposingType[ComposingType["Positive"] = 0] = "Positive";
+ ComposingType[ComposingType["Reverse"] = 1] = "Reverse";
+ ComposingType[ComposingType["Arbitrary"] = 2] = "Arbitrary";
+})(ComposingType || (ComposingType = {}));
+/**
+ *背板靠上还是靠下
+ *
+ * @export
+ * @enum {number}
+ */
+var BehindHeightPositon;
+(function (BehindHeightPositon) {
+ BehindHeightPositon["ForTop"] = "top";
+ BehindHeightPositon["ForBottom"] = "bottom";
+ BehindHeightPositon["AllHeight"] = "all"; //总高
+})(BehindHeightPositon || (BehindHeightPositon = {}));
+/**
+ *板件相对位置
+ *
+ * @export
+ * @enum {number}
+ */
+var BrRelativePos;
+(function (BrRelativePos) {
+ BrRelativePos["Front"] = "front";
+ BrRelativePos["Back"] = "back";
+ BrRelativePos["Top"] = "top";
+ BrRelativePos["Bottom"] = "bottom";
+ BrRelativePos["Left"] = "left";
+ BrRelativePos["Right"] = "right";
+ BrRelativePos["Div"] = "div";
+})(BrRelativePos || (BrRelativePos = {}));
+var StripType;
+(function (StripType) {
+ StripType["H"] = "h";
+ StripType["V"] = "v";
+})(StripType || (StripType = {}));
+var CurtailType;
+(function (CurtailType) {
+ CurtailType["PerBr"] = "0";
+ CurtailType["Total"] = "1";
+})(CurtailType || (CurtailType = {}));
+var BoardOpenDir;
+(function (BoardOpenDir) {
+ BoardOpenDir[BoardOpenDir["Left"] = 1] = "Left";
+ BoardOpenDir[BoardOpenDir["Right"] = 2] = "Right";
+ BoardOpenDir[BoardOpenDir["Up"] = 3] = "Up";
+ BoardOpenDir[BoardOpenDir["Down"] = 4] = "Down";
+ BoardOpenDir[BoardOpenDir["None"] = 0] = "None";
+})(BoardOpenDir || (BoardOpenDir = {}));
+
+//将嵌入的实体绘制对象添加到当前的绘制对象(由于内嵌的实体可能被重复引用)
+function AddEntityDrawObject(obj, embedEntity, renderType = RenderType.Wireframe) {
+ let embedObject = embedEntity.GetDrawObjectFromRenderType(renderType);
+ if (embedObject.parent)
+ obj.children.push(embedObject); //为了避免这个内嵌实体加入到不同的Object中(因为我们有PrintObject),这个写法能行,是因为我们会在其他地方更新它的矩阵
+ else
+ obj.add(embedObject);
+}
+
+let x = new three.Vector3();
+let y = new three.Vector3();
+let z = new three.Vector3();
+function IsMirror(mtx) {
+ mtx.extractBasis(x, y, z);
+ // for a true orthogonal, non-mirrored base, u.cross(v) == w
+ // If they have an opposite direction then we are mirroring
+ const mirrorvalue = x.cross(y).dot(z);
+ const ismirror = (mirrorvalue < 0);
+ return ismirror;
+}
+
+/** Epsilon used during determination of near zero distances.
+ * @default
+ */
+const EPS = 1e-5;
+// Tag factory: we can request a unique tag through CSG.getTag()
+let staticTag = 1;
+const getTag = () => staticTag++;
+
+/** Class Vector3D
+ * Represents a 3D vector with X, Y, Z coordinates.
+ */
+class Vector3D extends three.Vector3 {
+ clone() {
+ return new Vector3D(this.x, this.y, this.z);
+ }
+ // find a vector that is somewhat perpendicular to this one
+ randomNonParallelVector() {
+ let x = Math.abs(this.x);
+ let y = Math.abs(this.y);
+ let z = Math.abs(this.z);
+ if (x <= y && x <= z)
+ return new Vector3D(1, 0, 0);
+ else if (y <= x && y <= z)
+ return new Vector3D(0, 1, 0);
+ else
+ return new Vector3D(0, 0, 1);
+ }
+ toString() {
+ return ("(" +
+ this.x.toFixed(5) +
+ ", " +
+ this.y.toFixed(5) +
+ ", " +
+ this.z.toFixed(5) +
+ ")");
+ }
+}
+
+class Vector2D extends three.Vector2 {
+ // extend to a 3D vector by adding a z coordinate:
+ toVector3D(z) {
+ return new Vector3D(this.x, this.y, z);
+ }
+ clone() {
+ return new Vector2D(this.x, this.y);
+ }
+ // returns the vector rotated by 90 degrees clockwise
+ normal() {
+ return new Vector2D(this.y, -this.x);
+ }
+ cross(a) {
+ return this.x * a.y - this.y * a.x;
+ }
+}
+
+// # class Vertex
+// Represents a vertex of a polygon. Use your own vertex class instead of this
+// one to provide additional features like texture coordinates and vertex
+// colors. Custom vertex classes need to provide a `pos` property
+// `flipped()`, and `interpolate()` methods that behave analogous to the ones
+// FIXME: And a lot MORE (see plane.fromVector3Ds for ex) ! This is fragile code
+// defined by `Vertex`.
+class Vertex3D {
+ constructor(pos, uv = new Vector2D()) {
+ this.pos = pos;
+ this.uv = uv;
+ }
+ clone() {
+ return new Vertex3D(this.pos.clone(), this.uv.clone());
+ }
+ // Return a vertex with all orientation-specific data (e.g. vertex normal) flipped. Called when the
+ // orientation of a polygon is flipped.
+ flipped() {
+ return this;
+ }
+ getTag() {
+ let result = this.tag;
+ if (!result) {
+ result = getTag();
+ this.tag = result;
+ }
+ return result;
+ }
+ // Create a new vertex between this vertex and `other` by linearly
+ // interpolating all properties using a parameter of `t`. Subclasses should
+ // override this to interpolate additional properties.
+ interpolate(other, t) {
+ let pos = this.pos.clone().lerp(other.pos, t);
+ let uv = this.uv.clone().lerp(other.uv, t);
+ return new Vertex3D(pos, uv);
+ }
+ // Affine transformation of vertex. Returns a new Vertex
+ transform(matrix4x4) {
+ const newpos = this.pos.clone().applyMatrix4(matrix4x4);
+ return new Vertex3D(newpos, this.uv);
+ }
+}
+
+// # class Plane
+// Represents a plane in 3D space.
+class Plane {
+ constructor(normal, w) {
+ this.normal = normal;
+ this.w = w;
+ }
+ flipped() {
+ return new Plane(this.normal.clone().negate(), -this.w);
+ }
+ getTag() {
+ if (!this.tag)
+ this.tag = getTag();
+ return this.tag;
+ }
+ coplanarTo(plane) {
+ return equalv3(this.normal, plane.normal, 1e-4) && equaln(this.w, plane.w, 1e-4);
+ }
+ transform(matrix4x4) {
+ // get two vectors in the plane:
+ let r = this.normal.randomNonParallelVector();
+ let u = this.normal.clone().cross(r);
+ let v = this.normal.clone().cross(u);
+ // get 3 points in the plane:
+ let point1 = this.normal.clone().multiplyScalar(this.w);
+ let point2 = u.add(point1);
+ let point3 = v.add(point1);
+ // transform the points:
+ point1.applyMatrix4(matrix4x4);
+ point2.applyMatrix4(matrix4x4);
+ point3.applyMatrix4(matrix4x4);
+ // and create a new plane from the transformed points:
+ let newplane = Plane.fromVector3Ds(point1, point2, point3);
+ if (IsMirror(matrix4x4)) {
+ // the transform is mirroring
+ // We should mirror the plane:
+ newplane = newplane.flipped();
+ }
+ return newplane;
+ }
+ splitLineBetweenPoints(p1, p2) {
+ let direction = p2.pos.clone().sub(p1.pos);
+ let labda = (this.w - this.normal.dot(p1.pos)) / this.normal.dot(direction);
+ if (isNaN(labda))
+ labda = 0;
+ if (labda > 1)
+ labda = 1;
+ if (labda < 0)
+ labda = 0;
+ let pos = p1.pos.clone().add(direction.multiplyScalar(labda));
+ let uv = p1.uv.clone().lerp(p2.uv, labda);
+ return new Vertex3D(pos, uv);
+ }
+ static fromVector3Ds(a, b, c) {
+ let n = b.clone()
+ .sub(a)
+ .cross(c.clone().sub(a))
+ .normalize();
+ return new Plane(n, n.dot(a));
+ }
+}
+
+var Type;
+(function (Type) {
+ Type[Type["CoplanarFront"] = 0] = "CoplanarFront";
+ Type[Type["CoplanarBack"] = 1] = "CoplanarBack";
+ Type[Type["Front"] = 2] = "Front";
+ Type[Type["Back"] = 3] = "Back";
+ Type[Type["Spanning"] = 4] = "Spanning";
+})(Type || (Type = {}));
+/** Class Polygon
+ * Represents a convex polygon. The vertices used to initialize a polygon must
+ * be coplanar and form a convex loop. They do not have to be `Vertex`
+ * instances but they must behave similarly (duck typing can be used for
+ * customization).
+ *
+ * Each convex polygon has a `shared` property, which is shared between all
+ * polygons that are clones of each other or were split from the same polygon.
+ * This can be used to define per-polygon properties (such as surface color).
+ *
+ * The plane of the polygon is calculated from the vertex coordinates if not provided.
+ * The plane can alternatively be passed as the third argument to avoid calculations.
+ *
+ *表示凸多边形。 用于初始化多边形的顶点必须共面并形成凸环。
+ *多边形是彼此克隆或从同一多边形分割的多边形。
+ *这可用于定义每个多边形属性(例如表面颜色)。
+ */
+class Polygon {
+ constructor(vertices, plane) {
+ this.vertices = vertices;
+ this.plane = plane;
+ if (!plane)
+ this.plane = Plane.fromVector3Ds(vertices[0].pos, vertices[1].pos, vertices[2].pos);
+ }
+ /** Check whether the polygon is convex. (it should be, otherwise we will get unexpected results)*/
+ checkIfConvex() {
+ return Polygon.verticesConvex(this.vertices, this.plane.normal);
+ }
+ // returns an array with a Vector3D (center point) and a radius
+ boundingSphere() {
+ if (!this.cachedBoundingSphere) {
+ let box = this.boundingBox();
+ let middle = box[0].clone().add(box[1]).multiplyScalar(0.5);
+ let radius3 = box[1].clone().sub(middle);
+ let radius = radius3.length();
+ this.cachedBoundingSphere = [middle, radius];
+ }
+ return this.cachedBoundingSphere;
+ }
+ // returns an array of two Vector3Ds (minimum coordinates and maximum coordinates)
+ boundingBox() {
+ if (!this.cachedBoundingBox) {
+ let minpoint;
+ let maxpoint;
+ let vertices = this.vertices;
+ let numvertices = vertices.length;
+ if (numvertices === 0)
+ minpoint = new Vector3D(0, 0, 0);
+ else
+ minpoint = vertices[0].pos.clone();
+ maxpoint = minpoint.clone();
+ for (let i = 1; i < numvertices; i++) {
+ let point = vertices[i].pos;
+ minpoint.min(point);
+ maxpoint.max(point);
+ }
+ this.cachedBoundingBox = [minpoint, maxpoint];
+ }
+ return this.cachedBoundingBox;
+ }
+ flipped() {
+ let newvertices = this.vertices.map(v => v.flipped());
+ newvertices.reverse();
+ let newplane = this.plane.flipped();
+ return new Polygon(newvertices, newplane);
+ }
+ // Affine transformation of polygon. Returns a new Polygon
+ transform(matrix4x4) {
+ let newvertices = this.vertices.map(v => v.transform(matrix4x4));
+ let newplane = this.plane.transform(matrix4x4);
+ if (IsMirror(matrix4x4)) {
+ // need to reverse the vertex order
+ // in order to preserve the inside/outside orientation:
+ newvertices.reverse();
+ }
+ return new Polygon(newvertices, newplane);
+ }
+ splitByPlane(plane) {
+ let result = { type: null, front: null, back: null };
+ // cache in local lets (speedup):
+ let planeNormal = plane.normal;
+ let vertices = this.vertices;
+ let numVertices = vertices.length;
+ if (this.plane.coplanarTo(plane)) {
+ result.type = Type.CoplanarFront;
+ }
+ else {
+ let thisW = plane.w;
+ let hasFront = false;
+ let hasBack = false;
+ let vertexIsBack = [];
+ let MINEPS = -EPS;
+ for (let i = 0; i < numVertices; i++) {
+ let t = planeNormal.dot(vertices[i].pos) - thisW;
+ let isBack = t < 0;
+ vertexIsBack.push(isBack);
+ if (t > EPS)
+ hasFront = true;
+ if (t < MINEPS)
+ hasBack = true;
+ }
+ if (!hasFront && !hasBack) {
+ // all points coplanar
+ let t = planeNormal.dot(this.plane.normal);
+ result.type = t >= 0 ? Type.CoplanarFront : Type.CoplanarBack;
+ }
+ else if (!hasBack)
+ result.type = Type.Front;
+ else if (!hasFront)
+ result.type = Type.Back;
+ else {
+ result.type = Type.Spanning;
+ let frontVertices = [];
+ let backVertices = [];
+ let isBack = vertexIsBack[0];
+ for (let vertexIndex = 0; vertexIndex < numVertices; vertexIndex++) {
+ let vertex = vertices[vertexIndex];
+ let nextVertexindex = vertexIndex + 1;
+ if (nextVertexindex >= numVertices)
+ nextVertexindex = 0;
+ let nextIsBack = vertexIsBack[nextVertexindex];
+ if (isBack === nextIsBack) {
+ // line segment is on one side of the plane:
+ if (isBack)
+ backVertices.push(vertex);
+ else
+ frontVertices.push(vertex);
+ }
+ else {
+ let intersectionVertex = plane.splitLineBetweenPoints(vertex, vertices[nextVertexindex]);
+ if (isBack) {
+ backVertices.push(vertex);
+ backVertices.push(intersectionVertex);
+ frontVertices.push(intersectionVertex);
+ }
+ else {
+ frontVertices.push(vertex);
+ frontVertices.push(intersectionVertex);
+ backVertices.push(intersectionVertex);
+ }
+ }
+ isBack = nextIsBack;
+ } // for vertexindex
+ // remove duplicate vertices:
+ let EPS_SQUARED = EPS * EPS;
+ arrayRemoveDuplicateBySort(backVertices, (v1, v2) => {
+ return v1.pos.distanceToSquared(v2.pos) < EPS_SQUARED;
+ });
+ arrayRemoveDuplicateBySort(frontVertices, (v1, v2) => {
+ return v1.pos.distanceToSquared(v2.pos) < EPS_SQUARED;
+ });
+ if (frontVertices.length >= 3)
+ result.front = new Polygon(frontVertices, this.plane);
+ if (backVertices.length >= 3)
+ result.back = new Polygon(backVertices, this.plane);
+ }
+ }
+ return result;
+ }
+ static verticesConvex(vertices, planenormal) {
+ let count = vertices.length;
+ if (count < 3)
+ return false;
+ let prevPrevPos = vertices[count - 2].pos;
+ let prevPos = vertices[count - 1].pos;
+ for (let i = 0; i < count; i++) {
+ let pos = vertices[i].pos;
+ if (!Polygon.isConvexPoint(prevPrevPos, prevPos, pos, planenormal))
+ return false;
+ prevPrevPos = prevPos;
+ prevPos = pos;
+ }
+ return true;
+ }
+ // 计算3点是否凸角
+ static isConvexPoint(prevpoint, point, nextpoint, normal) {
+ let crossproduct = point.clone().sub(prevpoint).cross(nextpoint.clone().sub(point));
+ let crossdotnormal = crossproduct.dot(normal);
+ return crossdotnormal >= 0;
+ }
+}
+
+// # class PolygonTreeNode
+// This class manages hierarchical splits of polygons
+// At the top is a root node which doesn hold a polygon, only child PolygonTreeNodes
+// Below that are zero or more 'top' nodes; each holds a polygon. The polygons can be in different planes
+// splitByPlane() splits a node by a plane. If the plane intersects the polygon, two new child nodes
+// are created holding the splitted polygon.
+// getPolygons() retrieves the polygon from the tree. If for PolygonTreeNode the polygon is split but
+// the two split parts (child nodes) are still intact, then the unsplit polygon is returned.
+// This ensures that we can safely split a polygon into many fragments. If the fragments are untouched,
+// getPolygons() will return the original unsplit polygon instead of the fragments.
+// remove() removes a polygon from the tree. Once a polygon is removed, the parent polygons are invalidated
+// since they are no longer intact.
+// constructor creates the root node:
+//此类管理多边形的层次分割
+//顶部是一个根节点,它不包含多边形,只有子PolygonTreeNodes
+//下面是零个或多个“顶部”节点; 每个都有一个多边形。 多边形可以位于不同的平面中
+// splitByPlane()按平面拆分节点。 如果平面与多边形相交,则会有两个新的子节点
+//创建持有分割多边形。
+// getPolygons()从树中检索多边形。 如果对于PolygonTreeNode,则多边形被拆分但是
+//两个分割部分(子节点)仍然完好无损,然后返回未分割的多边形。
+//这确保我们可以安全地将多边形拆分为多个片段。 如果碎片未受影响,
+// getPolygons()将返回原始的未分割多边形而不是片段。
+// remove()从树中删除多边形。 删除多边形后,父多边形将失效
+//因为它们不再完好无损
+//构造函数创建根节点:
+class PolygonTreeNode {
+ constructor(polygon) {
+ this.children = [];
+ this.removed = false;
+ this.polygon = polygon;
+ }
+ // fill the tree with polygons. Should be called on the root node only; child nodes must
+ // always be a derivate (split) of the parent node.
+ addPolygons(polygons) {
+ // new polygons can only be added to root node; children can only be splitted polygons
+ if (!this.isRootNode())
+ throw new Error("Assertion failed");
+ for (let polygon of polygons)
+ this.addChild(polygon);
+ }
+ // remove a node
+ // - the siblings become toplevel nodes
+ // - the parent is removed recursively
+ remove() {
+ if (this.removed)
+ return;
+ this.removed = true;
+ // remove ourselves from the parent's children list:
+ let parentschildren = this.parent.children;
+ let i = parentschildren.indexOf(this);
+ if (i < 0)
+ throw new Error("Assertion failed");
+ parentschildren.splice(i, 1);
+ // invalidate the parent's polygon, and of all parents above it:
+ this.parent.recursivelyInvalidatePolygon();
+ }
+ isRemoved() {
+ return this.removed;
+ }
+ isRootNode() {
+ return !this.parent;
+ }
+ // invert all polygons in the tree. Call on the root node
+ invert() {
+ if (!this.isRootNode())
+ throw new Error("Assertion failed"); // can only call this on the root node
+ this.invertSub();
+ }
+ getPolygon() {
+ if (!this.polygon)
+ throw new Error("Assertion failed"); // doesn't have a polygon, which means that it has been broken down
+ return this.polygon;
+ }
+ getPolygons(outPolygons = []) {
+ let children = [this];
+ let queue = [children];
+ for (let i = 0; i < queue.length; ++i) {
+ // queue size can change in loop, don't cache length
+ children = queue[i];
+ for (let node of children) {
+ if (node.polygon)
+ // the polygon hasn't been broken yet. We can ignore the children and return our polygon:
+ outPolygons.push(node.polygon);
+ else
+ // our polygon has been split up and broken, so gather all subpolygons from the children
+ queue.push(node.children);
+ }
+ }
+ return outPolygons;
+ }
+ // split the node by a plane; add the resulting nodes to the frontnodes and backnodes array
+ // If the plane doesn't intersect the polygon, the 'this' object is added to one of the arrays
+ // If the plane does intersect the polygon, two new child nodes are created for the front and back fragments,
+ // and added to both arrays.
+ splitByPlane(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes) {
+ if (this.children.length) {
+ let queue = [this.children];
+ for (let i = 0; i < queue.length; i++) {
+ // queue.length can increase, do not cache
+ let nodes = queue[i];
+ for (let j = 0, l = nodes.length; j < l; j++) {
+ // ok to cache length
+ let node = nodes[j];
+ if (node.children.length)
+ queue.push(node.children);
+ else {
+ // no children. Split the polygon:
+ node.splitByPlaneNotChildren(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes);
+ }
+ }
+ }
+ }
+ else {
+ this.splitByPlaneNotChildren(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes);
+ }
+ }
+ // only to be called for nodes with no children
+ // 仅用于没有子节点的节点
+ splitByPlaneNotChildren(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes) {
+ if (!this.polygon)
+ return;
+ let polygon = this.polygon;
+ let bound = polygon.boundingSphere();
+ let sphereradius = bound[1] + EPS; // FIXME Why add imprecision?
+ let planenormal = plane.normal;
+ let spherecenter = bound[0];
+ let d = planenormal.dot(spherecenter) - plane.w;
+ if (d > sphereradius)
+ frontNodes.push(this);
+ else if (d < -sphereradius)
+ backNodes.push(this);
+ else {
+ let splitresult = polygon.splitByPlane(plane);
+ switch (splitresult.type) {
+ case Type.CoplanarFront:
+ coplanarFrontNodes.push(this);
+ break;
+ case Type.CoplanarBack:
+ coplanarBackNodes.push(this);
+ break;
+ case Type.Front:
+ frontNodes.push(this);
+ break;
+ case Type.Back:
+ backNodes.push(this);
+ break;
+ case Type.Spanning:
+ if (splitresult.front) {
+ let frontNode = this.addChild(splitresult.front);
+ frontNodes.push(frontNode);
+ }
+ if (splitresult.back) {
+ let backNode = this.addChild(splitresult.back);
+ backNodes.push(backNode);
+ }
+ break;
+ }
+ }
+ }
+ // add child to a node
+ // this should be called whenever the polygon is split
+ // a child should be created for every fragment of the split polygon
+ // returns the newly created child
+ addChild(polygon) {
+ let newchild = new PolygonTreeNode(polygon);
+ newchild.parent = this;
+ this.children.push(newchild);
+ return newchild;
+ }
+ invertSub() {
+ let queue = [[this]];
+ for (let i = 0; i < queue.length; i++) {
+ let children = queue[i];
+ for (let j = 0, l = children.length; j < l; j++) {
+ let node = children[j];
+ if (node.polygon)
+ node.polygon = node.polygon.flipped();
+ queue.push(node.children);
+ }
+ }
+ }
+ recursivelyInvalidatePolygon() {
+ let node = this;
+ while (node.polygon) {
+ node.polygon = null;
+ if (node.parent)
+ node = node.parent;
+ }
+ }
+}
+// # class Tree
+// This is the root of a BSP tree
+// We are using this separate class for the root of the tree, to hold the PolygonTreeNode root
+// The actual tree is kept in this.rootnode
+class Tree {
+ constructor(polygons) {
+ this.polygonTree = new PolygonTreeNode();
+ this.rootNode = new Node(null);
+ this.addPolygons(polygons);
+ }
+ invert() {
+ this.polygonTree.invert();
+ this.rootNode.invert();
+ }
+ // Remove all polygons in this BSP tree that are inside the other BSP tree
+ /**
+ * this 减去 tree 删除此BSP树中位于其他BSP树内的所有多边形
+ * @param tree 不会被修改
+ * @param [alsoRemovecoplanarFront=false] 同时删除共面
+ */
+ clipTo(tree, alsoRemovecoplanarFront = false) {
+ this.rootNode.clipTo(tree, alsoRemovecoplanarFront);
+ }
+ allPolygons() {
+ return this.polygonTree.getPolygons();
+ }
+ addPolygons(polygons) {
+ if (polygons.length > 1e4)
+ return;
+ let polygonTreeNodes = polygons.map((p) => this.polygonTree.addChild(p));
+ this.rootNode.addPolygonTreeNodes(polygonTreeNodes);
+ }
+}
+// # class Node
+// Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
+// by picking a polygon to split along.
+// Polygons are not stored directly in the tree, but in PolygonTreeNodes, stored in
+// this.polygontreenodes. Those PolygonTreeNodes are children of the owning
+// Tree.polygonTree
+// This is not a leafy BSP tree since there is
+// no distinction between internal and leaf nodes.
+class Node {
+ constructor(parent) {
+ this.polygonTreeNodes = [];
+ this.parent = parent;
+ }
+ // Convert solid space to empty space and empty space to solid space.
+ invert() {
+ let queue = [this];
+ for (let i = 0; i < queue.length; i++) {
+ let node = queue[i];
+ if (node.plane)
+ node.plane = node.plane.flipped();
+ if (node.front)
+ queue.push(node.front);
+ if (node.back)
+ queue.push(node.back);
+ let temp = node.front;
+ node.front = node.back;
+ node.back = temp;
+ }
+ }
+ // clip polygontreenodes to our plane
+ // calls remove() for all clipped PolygonTreeNodes
+ //将polygontreenodes剪辑到我们的飞机上
+ //为所有剪切的PolygonTreeNodes调用remove()
+ clipPolygons(polygonTreeNodes, alsoRemoveCoplanarFront) {
+ let args = { node: this, polygonTreeNodes };
+ let stack = [];
+ do {
+ let node = args.node;
+ let polygonTreeNodes1 = args.polygonTreeNodes;
+ // begin "function"
+ if (node.plane) {
+ let backnodes = [];
+ let frontnodes = [];
+ let coplanarfrontnodes = alsoRemoveCoplanarFront ? backnodes : frontnodes;
+ let plane = node.plane;
+ for (let node1 of polygonTreeNodes1) {
+ if (!node1.isRemoved())
+ node1.splitByPlane(plane, coplanarfrontnodes, backnodes, frontnodes, backnodes);
+ }
+ if (node.front && frontnodes.length > 0)
+ stack.push({ node: node.front, polygonTreeNodes: frontnodes });
+ let numbacknodes = backnodes.length;
+ if (node.back && numbacknodes > 0)
+ stack.push({ node: node.back, polygonTreeNodes: backnodes });
+ else {
+ // there's nothing behind this plane. Delete the nodes behind this plane:
+ // 这架飞机背后什么也没有。 删除此平面后面的节点:
+ for (let i = 0; i < numbacknodes; i++)
+ backnodes[i].remove();
+ }
+ }
+ args = stack.pop();
+ } while (args);
+ }
+ // Remove all polygons in this BSP tree that are inside the other BSP tree
+ // `tree`.
+ clipTo(tree, alsoRemovecoplanarFront) {
+ let node = this;
+ let stack = [];
+ do {
+ if (node.polygonTreeNodes.length > 0) {
+ tree.rootNode.clipPolygons(node.polygonTreeNodes, alsoRemovecoplanarFront);
+ }
+ if (node.front)
+ stack.push(node.front);
+ if (node.back)
+ stack.push(node.back);
+ node = stack.pop();
+ } while (node);
+ }
+ addPolygonTreeNodes(polygonTreeNodes) {
+ let args = { node: this, polygontreenodes: polygonTreeNodes };
+ let stack = [];
+ do {
+ let node = args.node;
+ polygonTreeNodes = args.polygontreenodes;
+ if (polygonTreeNodes.length === 0) {
+ args = stack.pop();
+ continue;
+ }
+ if (!node.plane) {
+ let bestplane = polygonTreeNodes[Math.floor(polygonTreeNodes.length / 2)].getPolygon().plane;
+ node.plane = bestplane;
+ }
+ let frontNodes = [];
+ let backNodes = [];
+ for (let i = 0, n = polygonTreeNodes.length; i < n; ++i) {
+ polygonTreeNodes[i].splitByPlane(node.plane, node.polygonTreeNodes, backNodes, frontNodes, backNodes);
+ }
+ if (frontNodes.length > 0) {
+ if (!node.front)
+ node.front = new Node(node);
+ stack.push({ node: node.front, polygontreenodes: frontNodes });
+ }
+ if (backNodes.length > 0) {
+ if (!node.back)
+ node.back = new Node(node);
+ stack.push({ node: node.back, polygontreenodes: backNodes });
+ }
+ args = stack.pop();
+ } while (args);
+ }
+ getParentPlaneNormals(normals, maxdepth) {
+ if (maxdepth > 0) {
+ if (this.parent) {
+ normals.push(this.parent.plane.normal);
+ this.parent.getParentPlaneNormals(normals, maxdepth - 1);
+ }
+ }
+ }
+}
+
+// //////////////////////////////
+// ## class fuzzyFactory
+// This class acts as a factory for objects. We can search for an object with approximately
+// the desired properties (say a rectangle with width 2 and height 1)
+// The lookupOrCreate() method looks for an existing object (for example it may find an existing rectangle
+// with width 2.0001 and height 0.999. If no object is found, the user supplied callback is
+// called, which should generate a new object. The new object is inserted into the database
+// so it can be found by future lookupOrCreate() calls.
+// Constructor:
+// numdimensions: the number of parameters for each object
+// for example for a 2D rectangle this would be 2
+// tolerance: The maximum difference for each parameter allowed to be considered a match
+class FuzzyFactory {
+ constructor(numdimensions, tolerance) {
+ this.lookuptable = {};
+ this.multiplier = 1.0 / tolerance;
+ }
+ // let obj = f.lookupOrCreate([el1, el2, el3], function(elements) {/* create the new object */});
+ // Performs a fuzzy lookup of the object with the specified elements.
+ // If found, returns the existing object
+ // If not found, calls the supplied callback function which should create a new object with
+ // the specified properties. This object is inserted in the lookup database.
+ lookupOrCreate(els, object) {
+ let hash = "";
+ let multiplier = this.multiplier;
+ for (let el of els) {
+ let valueQuantized = Math.round(el * multiplier);
+ hash += valueQuantized + "/";
+ }
+ if (hash in this.lookuptable)
+ return this.lookuptable[hash];
+ else {
+ let hashparts = els.map(el => {
+ let q0 = Math.floor(el * multiplier);
+ let q1 = q0 + 1;
+ return ["" + q0 + "/", "" + q1 + "/"];
+ });
+ let numelements = els.length;
+ let numhashes = 1 << numelements;
+ for (let hashmask = 0; hashmask < numhashes; ++hashmask) {
+ let hashmaskShifted = hashmask;
+ hash = "";
+ hashparts.forEach(hashpart => {
+ hash += hashpart[hashmaskShifted & 1];
+ hashmaskShifted >>= 1;
+ });
+ this.lookuptable[hash] = object;
+ }
+ return object;
+ }
+ }
+}
+
+class FuzzyCSGFactory {
+ constructor() {
+ this.vertexfactory = new FuzzyFactory(3, EPS);
+ this.planefactory = new FuzzyFactory(4, EPS);
+ }
+ getVertex(sourcevertex) {
+ let elements = [sourcevertex.pos.x, sourcevertex.pos.y, sourcevertex.pos.z];
+ let result = this.vertexfactory.lookupOrCreate(elements, sourcevertex);
+ return result;
+ }
+ getPlane(sourceplane) {
+ let elements = [sourceplane.normal.x, sourceplane.normal.y, sourceplane.normal.z, sourceplane.w];
+ let result = this.planefactory.lookupOrCreate(elements, sourceplane);
+ return result;
+ }
+ getPolygon(sourcePolygon, outputPolygon = sourcePolygon) {
+ let newPlane = this.getPlane(sourcePolygon.plane);
+ let newVertices = sourcePolygon.vertices.map(vertex => this.getVertex(vertex));
+ // two vertices that were originally very close may now have become
+ // truly identical (referring to the same Vertex object).
+ // Remove duplicate vertices:
+ let newVerticesDedup = []; //新的顶点列表(已过滤重复)
+ if (newVertices.length > 0) {
+ let prevVertexTag = newVertices[newVertices.length - 1].getTag();
+ for (let vertex of newVertices) {
+ let vertextag = vertex.getTag();
+ if (vertextag !== prevVertexTag)
+ newVerticesDedup.push(vertex);
+ prevVertexTag = vertextag;
+ }
+ }
+ // If it's degenerate, remove all vertices:
+ if (newVerticesDedup.length < 3)
+ newVerticesDedup = [];
+ outputPolygon.vertices = newVertices;
+ outputPolygon.plane = newPlane;
+ return outputPolygon;
+ }
+}
+
+/**
+ * Returns a cannoicalized version of the input csg : ie every very close
+ * points get deduplicated
+ *
+ * 返回删除重复点的csg,重复点将被合并
+ */
+function canonicalizeCSG(csg) {
+ const factory = new FuzzyCSGFactory();
+ let result = CSGFromCSGFuzzyFactory(factory, csg);
+ result.isCanonicalized = true;
+ result.isRetesselated = csg.isRetesselated;
+ return result;
+}
+function CSGFromCSGFuzzyFactory(factory, sourcecsg) {
+ let newpolygons = sourcecsg.polygons.filter(poly => {
+ return factory.getPolygon(poly).vertices.length >= 3;
+ });
+ return new CSG(newpolygons);
+}
+
+/**
+ * Returns an array of Vector3D, providing minimum coordinates and maximum coordinates
+ * of this solid.
+ * @example
+ * let bounds = A.getBounds()
+ * let minX = bounds[0].x
+ */
+function bounds(csg) {
+ if (!csg.cachedBoundingBox) {
+ let minpoint;
+ let maxpoint;
+ let polygons = csg.polygons;
+ let numpolygons = polygons.length;
+ for (let i = 0; i < numpolygons; i++) {
+ let polygon = polygons[i];
+ let bounds = polygon.boundingBox();
+ if (i === 0) {
+ minpoint = bounds[0].clone();
+ maxpoint = bounds[1].clone();
+ }
+ else {
+ minpoint.min(bounds[0]);
+ maxpoint.max(bounds[1]);
+ }
+ }
+ // FIXME: not ideal, we are mutating the input, we need to move some of it out
+ csg.cachedBoundingBox = [minpoint, maxpoint];
+ }
+ return csg.cachedBoundingBox;
+}
+
+function fnNumberSort(a, b) {
+ return a - b;
+}
+function insertSorted(array, element, comparefunc) {
+ let leftbound = 0;
+ let rightbound = array.length;
+ while (rightbound > leftbound) {
+ let testindex = Math.floor((leftbound + rightbound) / 2);
+ let testelement = array[testindex];
+ let compareresult = comparefunc(element, testelement);
+ if (compareresult > 0)
+ // element > testelement
+ leftbound = testindex + 1;
+ else
+ rightbound = testindex;
+ }
+ array.splice(leftbound, 0, element);
+}
+// Get the x coordinate of a point with a certain y coordinate, interpolated between two
+// points (CSG.Vector2D).
+// Interpolation is robust even if the points have the same y coordinate
+function interpolateBetween2DPointsForY(point1, point2, y) {
+ let f1 = y - point1.y;
+ let f2 = point2.y - point1.y;
+ if (f2 < 0) {
+ f1 = -f1;
+ f2 = -f2;
+ }
+ let t;
+ if (f1 <= 0)
+ t = 0.0;
+ else if (f1 >= f2)
+ t = 1.0;
+ else if (f2 < 1e-10)
+ // FIXME Should this be CSG.EPS?
+ t = 0.5;
+ else
+ t = f1 / f2;
+ let result = point1.x + t * (point2.x - point1.x);
+ return result;
+}
+
+/** class Line2D
+ * Represents a directional line in 2D space
+ * A line is parametrized by its normal vector (perpendicular to the line, rotated 90 degrees counter clockwise)
+ * and w. The line passes through the point .times(w).
+ * Equation: p is on line if normal.dot(p)==w
+ */
+class Line2D {
+ constructor(normal, w) {
+ this.normal = normal.clone();
+ let l = this.normal.length();
+ w *= l;
+ this.normal.normalize();
+ this.w = w;
+ }
+ direction() {
+ return this.normal;
+ }
+ static fromPoints(p1, p2) {
+ let direction = p2.clone().sub(p1);
+ let normal = direction
+ .normal()
+ .negate()
+ .normalize();
+ let w = p1.dot(normal);
+ return new Line2D(normal, w);
+ }
+}
+
+/** class OrthoNormalBasis
+ * Reprojects points on a 3D plane onto a 2D plane
+ * or from a 2D plane back onto the 3D plane
+ */
+class OrthoNormalBasis {
+ constructor(plane, rightVector = plane.normal.randomNonParallelVector()) {
+ this.plane = plane;
+ this.v = plane.normal.clone().cross(rightVector).normalize();
+ this.u = this.v.clone().cross(plane.normal);
+ this.plane = plane;
+ this.planeorigin = plane.normal.clone().multiplyScalar(plane.w);
+ }
+ to2D(vec3) {
+ return new Vector2D(vec3.dot(this.u), vec3.dot(this.v));
+ }
+ to3D(vec2) {
+ return this.planeorigin.clone()
+ .add(this.u.clone().multiplyScalar(vec2.x))
+ .add(this.v.clone().multiplyScalar(vec2.y));
+ }
+}
+
+//一组共面多边形的Retesselation函数。 请参阅此文件顶部的介绍。
+function reTesselateCoplanarPolygons(sourcePolygons, destpolygons = []) {
+ let numPolygons = sourcePolygons.length;
+ if (numPolygons < 2) {
+ destpolygons.push(...sourcePolygons);
+ return;
+ }
+ let plane = sourcePolygons[0].plane;
+ let orthobasis = new OrthoNormalBasis(plane);
+ // let xcoordinatebins = {}
+ let yCoordinateBins = {}; //整数map
+ let yCoordinateBinningFactor = (1.0 / EPS) * 10;
+ let polygonVertices2d = []; // (Vector2[])[];
+ let polygonTopVertexIndexes = []; // 每个多边形最顶层顶点的索引数组 minIndex
+ let topY2PolygonIndexes = {}; // Map
+ let yCoordinateToPolygonIndexes = {}; // Map > Y坐标映射所有的多边形
+ //将多边形转换为2d点表 polygonVertices2d
+ //建立y对应的多边形Map yCoordinateToPolygonIndexes
+ for (let polygonIndex = 0; polygonIndex < numPolygons; polygonIndex++) {
+ let poly3d = sourcePolygons[polygonIndex];
+ let numVertices = poly3d.vertices.length;
+ if (numVertices === 0)
+ continue;
+ let vertices2d = []; //Vector2d[];
+ let minIndex = -1;
+ let miny, maxy;
+ for (let i = 0; i < numVertices; i++) {
+ let pos2d = orthobasis.to2D(poly3d.vertices[i].pos);
+ // perform binning of y coordinates: If we have multiple vertices very
+ // close to each other, give them the same y coordinate:
+ let yCoordinatebin = Math.floor(pos2d.y * yCoordinateBinningFactor);
+ let newy;
+ if (yCoordinatebin in yCoordinateBins)
+ newy = yCoordinateBins[yCoordinatebin];
+ else if (yCoordinatebin + 1 in yCoordinateBins)
+ newy = yCoordinateBins[yCoordinatebin + 1];
+ else if (yCoordinatebin - 1 in yCoordinateBins)
+ newy = yCoordinateBins[yCoordinatebin - 1];
+ else {
+ newy = pos2d.y;
+ yCoordinateBins[yCoordinatebin] = pos2d.y;
+ }
+ pos2d = new Vector2D(pos2d.x, newy);
+ vertices2d.push(pos2d);
+ if (i === 0 || newy < miny) {
+ miny = newy;
+ minIndex = i;
+ }
+ if (i === 0 || newy > maxy)
+ maxy = newy;
+ if (!(newy in yCoordinateToPolygonIndexes))
+ yCoordinateToPolygonIndexes[newy] = {};
+ yCoordinateToPolygonIndexes[newy][polygonIndex] = true;
+ }
+ //退化多边形,所有顶点都具有相同的y坐标。 从现在开始忽略它:
+ if (miny >= maxy)
+ continue;
+ if (!(miny in topY2PolygonIndexes))
+ topY2PolygonIndexes[miny] = [];
+ topY2PolygonIndexes[miny].push(polygonIndex);
+ // reverse the vertex order:
+ vertices2d.reverse();
+ minIndex = numVertices - minIndex - 1;
+ polygonVertices2d.push(vertices2d);
+ polygonTopVertexIndexes.push(minIndex);
+ }
+ //所有的y坐标,从小到大排序
+ let yCoordinates = [];
+ for (let ycoordinate in yCoordinateToPolygonIndexes)
+ yCoordinates.push(ycoordinate);
+ yCoordinates.sort(fnNumberSort);
+ //迭代y坐标 从低到高
+ // activepolygons :'active'的源多边形,即与y坐标相交
+ // 多边形是从左往右排序的
+ // activepolygons 中的每个元素都具有以下属性:
+ // polygonindex 源多边形的索引(即sourcepolygons的索引 和polygonvertices2d数组)
+ // leftvertexindex 左边 在当前y坐标处或刚好在当前y坐标之上
+ // rightvertexindex 右边
+ // topleft bottomleft 与当前y坐标交叉的多边形左侧的坐标
+ // topright bottomright 与当前y坐标交叉的多边形右侧的坐标
+ let activePolygons = [];
+ let prevOutPolygonRow = []; //上一个输出多边形行?
+ for (let yindex = 0; yindex < yCoordinates.length; yindex++) {
+ let yCoordinateStr = yCoordinates[yindex];
+ let yCoordinate = Number(yCoordinateStr);
+ // 用当前的y 更新 activePolygons
+ // - 删除以y坐标结尾的所有多边形 删除polygon maxy = y 的多边形
+ // - 更新 leftvertexindex 和 rightvertexindex (指向当前顶点索引)
+ // 在多边形的左侧和右侧
+ // 迭代在Y坐标处有一个角的所有多边形
+ let polygonIndexeSwithCorner = yCoordinateToPolygonIndexes[yCoordinateStr];
+ for (let activePolygonIndex = 0; activePolygonIndex < activePolygons.length; activePolygonIndex++) {
+ let activepolygon = activePolygons[activePolygonIndex];
+ let polygonindex = activepolygon.polygonindex;
+ if (!polygonIndexeSwithCorner[polygonindex]) //如果不在角内
+ continue;
+ //多边形在此y坐标处有一个角
+ let vertices2d = polygonVertices2d[polygonindex];
+ let numvertices = vertices2d.length;
+ let newleftvertexindex = activepolygon.leftvertexindex;
+ let newrightvertexindex = activepolygon.rightvertexindex;
+ //看看我们是否需要增加 leftvertexindex 或减少 rightvertexindex :
+ while (true) {
+ let nextleftvertexindex = newleftvertexindex + 1;
+ if (nextleftvertexindex >= numvertices)
+ nextleftvertexindex = 0;
+ if (vertices2d[nextleftvertexindex].y !== yCoordinate)
+ break;
+ newleftvertexindex = nextleftvertexindex;
+ }
+ //减少 rightvertexindex
+ let nextrightvertexindex = newrightvertexindex - 1;
+ if (nextrightvertexindex < 0)
+ nextrightvertexindex = numvertices - 1;
+ if (vertices2d[nextrightvertexindex].y === yCoordinate)
+ newrightvertexindex = nextrightvertexindex;
+ if (newleftvertexindex !== activepolygon.leftvertexindex //有向上更新
+ && newleftvertexindex === newrightvertexindex //指向同一个点
+ ) {
+ // We have increased leftvertexindex or decreased rightvertexindex, and now they point to the same vertex
+ // This means that this is the bottom point of the polygon. We'll remove it:
+ //我们增加了leftvertexindex或减少了rightvertexindex,现在它们指向同一个顶点
+ //这意味着这是多边形的底点。 我们将删除它:
+ activePolygons.splice(activePolygonIndex, 1);
+ --activePolygonIndex;
+ }
+ else {
+ activepolygon.leftvertexindex = newleftvertexindex;
+ activepolygon.rightvertexindex = newrightvertexindex;
+ activepolygon.topleft = vertices2d[newleftvertexindex];
+ activepolygon.topright = vertices2d[newrightvertexindex];
+ let nextleftvertexindex = newleftvertexindex + 1;
+ if (nextleftvertexindex >= numvertices)
+ nextleftvertexindex = 0;
+ activepolygon.bottomleft = vertices2d[nextleftvertexindex];
+ let nextrightvertexindex = newrightvertexindex - 1;
+ if (nextrightvertexindex < 0)
+ nextrightvertexindex = numvertices - 1;
+ activepolygon.bottomright = vertices2d[nextrightvertexindex];
+ }
+ }
+ let nextYCoordinate; // number y
+ if (yindex >= yCoordinates.length - 1) {
+ // last row, all polygons must be finished here:
+ // 最后一行,所有多边形必须在这里完成:
+ activePolygons = [];
+ }
+ else // yindex < ycoordinates.length-1
+ {
+ nextYCoordinate = Number(yCoordinates[yindex + 1]);
+ let middleYCoordinate = 0.5 * (yCoordinate + nextYCoordinate);
+ // update activepolygons by adding any polygons that start here:
+ // 添加从这里开始的多边形 到 activePolygons
+ let startingPolygonIndexes = topY2PolygonIndexes[yCoordinateStr];
+ for (let polygonindex_key in startingPolygonIndexes) {
+ let polygonindex = startingPolygonIndexes[polygonindex_key];
+ let vertices2d = polygonVertices2d[polygonindex];
+ let numvertices = vertices2d.length;
+ let topVertexIndex = polygonTopVertexIndexes[polygonindex];
+ // the top of the polygon may be a horizontal line. In that case topvertexindex can point to any point on this line.
+ // Find the left and right topmost vertices which have the current y coordinate:
+ // 顶部可以是一条直线,寻找最左边的点和最右边的点
+ let topleftvertexindex = topVertexIndex;
+ while (true) {
+ let i = topleftvertexindex + 1;
+ if (i >= numvertices)
+ i = 0;
+ if (vertices2d[i].y !== yCoordinate)
+ break;
+ if (i === topVertexIndex)
+ break; // should not happen, but just to prevent endless loops
+ topleftvertexindex = i;
+ }
+ let toprightvertexindex = topVertexIndex;
+ while (true) {
+ let i = toprightvertexindex - 1;
+ if (i < 0)
+ i = numvertices - 1;
+ if (vertices2d[i].y !== yCoordinate)
+ break;
+ if (i === topleftvertexindex)
+ break; // should not happen, but just to prevent endless loops
+ toprightvertexindex = i;
+ }
+ let nextleftvertexindex = topleftvertexindex + 1;
+ if (nextleftvertexindex >= numvertices)
+ nextleftvertexindex = 0;
+ let nextrightvertexindex = toprightvertexindex - 1;
+ if (nextrightvertexindex < 0)
+ nextrightvertexindex = numvertices - 1;
+ let newactivepolygon = {
+ polygonindex: polygonindex,
+ leftvertexindex: topleftvertexindex,
+ rightvertexindex: toprightvertexindex,
+ topleft: vertices2d[topleftvertexindex],
+ topright: vertices2d[toprightvertexindex],
+ bottomleft: vertices2d[nextleftvertexindex],
+ bottomright: vertices2d[nextrightvertexindex]
+ };
+ //二分插入
+ insertSorted(activePolygons, newactivepolygon, function (el1, el2) {
+ let x1 = interpolateBetween2DPointsForY(el1.topleft, el1.bottomleft, middleYCoordinate);
+ let x2 = interpolateBetween2DPointsForY(el2.topleft, el2.bottomleft, middleYCoordinate);
+ if (x1 > x2)
+ return 1;
+ if (x1 < x2)
+ return -1;
+ return 0;
+ });
+ }
+ }
+ //#region
+ // if( (yindex === ycoordinates.length-1) || (nextycoordinate - ycoordinate > EPS) )
+ // if(true)
+ // {
+ let newOutPolygonRow = []; //输出多边形
+ // Build the output polygons for the next row in newOutPolygonRow:
+ //现在 activepolygons 是最新的
+ //为 newOutPolygonRow 中的下一行构建输出多边形:
+ for (let activepolygonKey in activePolygons) {
+ let activepolygon = activePolygons[activepolygonKey];
+ let x = interpolateBetween2DPointsForY(activepolygon.topleft, activepolygon.bottomleft, yCoordinate);
+ let topleft = new Vector2D(x, yCoordinate);
+ x = interpolateBetween2DPointsForY(activepolygon.topright, activepolygon.bottomright, yCoordinate);
+ let topright = new Vector2D(x, yCoordinate);
+ x = interpolateBetween2DPointsForY(activepolygon.topleft, activepolygon.bottomleft, nextYCoordinate);
+ let bottomleft = new Vector2D(x, nextYCoordinate);
+ x = interpolateBetween2DPointsForY(activepolygon.topright, activepolygon.bottomright, nextYCoordinate);
+ let bottomright = new Vector2D(x, nextYCoordinate);
+ let outPolygon = {
+ topleft: topleft,
+ topright: topright,
+ bottomleft: bottomleft,
+ bottomright: bottomright,
+ leftline: Line2D.fromPoints(topleft, bottomleft),
+ rightline: Line2D.fromPoints(bottomright, topright)
+ };
+ if (newOutPolygonRow.length > 0) {
+ let prevoutpolygon = newOutPolygonRow[newOutPolygonRow.length - 1];
+ let d1 = outPolygon.topleft.distanceTo(prevoutpolygon.topright);
+ let d2 = outPolygon.bottomleft.distanceTo(prevoutpolygon.bottomright);
+ if (d1 < EPS && d2 < EPS) {
+ // we can join this polygon with the one to the left:
+ outPolygon.topleft = prevoutpolygon.topleft;
+ outPolygon.leftline = prevoutpolygon.leftline;
+ outPolygon.bottomleft = prevoutpolygon.bottomleft;
+ newOutPolygonRow.splice(newOutPolygonRow.length - 1, 1);
+ }
+ }
+ newOutPolygonRow.push(outPolygon);
+ }
+ if (yindex > 0) {
+ // try to match the new polygons against the previous row:
+ //尝试将新多边形与上一行匹配:
+ let prevContinuedIndexes = {};
+ let matchedIndexes = {};
+ for (let i = 0; i < newOutPolygonRow.length; i++) {
+ let thispolygon = newOutPolygonRow[i];
+ for (let ii = 0; ii < prevOutPolygonRow.length; ii++) {
+ if (!matchedIndexes[ii]) {
+ // not already processed?
+ // We have a match if the sidelines are equal or if the top coordinates
+ // are on the sidelines of the previous polygon
+ let prevpolygon = prevOutPolygonRow[ii];
+ if (prevpolygon.bottomleft.distanceTo(thispolygon.topleft) < EPS) {
+ if (prevpolygon.bottomright.distanceTo(thispolygon.topright) < EPS) {
+ // Yes, the top of this polygon matches the bottom of the previous:
+ matchedIndexes[ii] = true;
+ // Now check if the joined polygon would remain convex:
+ let d1 = thispolygon.leftline.direction().x - prevpolygon.leftline.direction().x;
+ let d2 = thispolygon.rightline.direction().x - prevpolygon.rightline.direction().x;
+ let leftlinecontinues = Math.abs(d1) < EPS;
+ let rightlinecontinues = Math.abs(d2) < EPS;
+ let leftlineisconvex = leftlinecontinues || d1 >= 0;
+ let rightlineisconvex = rightlinecontinues || d2 >= 0;
+ if (leftlineisconvex && rightlineisconvex) {
+ // yes, both sides have convex corners:
+ // This polygon will continue the previous polygon
+ thispolygon.outpolygon = prevpolygon.outpolygon;
+ thispolygon.leftlinecontinues = leftlinecontinues;
+ thispolygon.rightlinecontinues = rightlinecontinues;
+ prevContinuedIndexes[ii] = true;
+ }
+ break;
+ }
+ }
+ } // if(!prevcontinuedindexes[ii])
+ } // for ii
+ } // for i
+ for (let ii = 0; ii < prevOutPolygonRow.length; ii++) {
+ if (!prevContinuedIndexes[ii]) {
+ // polygon ends here
+ // Finish the polygon with the last point(s):
+ let prevpolygon = prevOutPolygonRow[ii];
+ prevpolygon.outpolygon.rightpoints.push(prevpolygon.bottomright);
+ if (prevpolygon.bottomright.distanceTo(prevpolygon.bottomleft) > EPS) {
+ // polygon ends with a horizontal line:
+ prevpolygon.outpolygon.leftpoints.push(prevpolygon.bottomleft);
+ }
+ // reverse the left half so we get a counterclockwise circle:
+ prevpolygon.outpolygon.leftpoints.reverse();
+ let points2d = prevpolygon.outpolygon.rightpoints.concat(prevpolygon.outpolygon.leftpoints);
+ let vertices = points2d.map(v => new Vertex3D(orthobasis.to3D(v)));
+ let polygon = new Polygon(vertices, plane);
+ destpolygons.push(polygon);
+ }
+ }
+ }
+ for (let i = 0; i < newOutPolygonRow.length; i++) {
+ let thispolygon = newOutPolygonRow[i];
+ if (!thispolygon.outpolygon) {
+ // polygon starts here:
+ thispolygon.outpolygon = {
+ leftpoints: [],
+ rightpoints: []
+ };
+ thispolygon.outpolygon.leftpoints.push(thispolygon.topleft);
+ if (thispolygon.topleft.distanceTo(thispolygon.topright) > EPS) {
+ // we have a horizontal line at the top:
+ thispolygon.outpolygon.rightpoints.push(thispolygon.topright);
+ }
+ }
+ else {
+ // continuation of a previous row
+ if (!thispolygon.leftlinecontinues) {
+ thispolygon.outpolygon.leftpoints.push(thispolygon.topleft);
+ }
+ if (!thispolygon.rightlinecontinues) {
+ thispolygon.outpolygon.rightpoints.push(thispolygon.topright);
+ }
+ }
+ }
+ prevOutPolygonRow = newOutPolygonRow;
+ // }
+ //#endregion
+ } // for yindex
+}
+
+function reTesselate(csg) {
+ if (csg.isRetesselated)
+ return csg;
+ let polygonsPerPlane = {};
+ let isCanonicalized = csg.isCanonicalized;
+ let fuzzyfactory = new FuzzyCSGFactory();
+ for (let polygon of csg.polygons) {
+ let plane = polygon.plane;
+ if (!isCanonicalized) {
+ // in order to identify polygons having the same plane, we need to canonicalize the planes
+ // We don't have to do a full canonizalization (including vertices), to save time only do the planes and the shared data:
+ plane = fuzzyfactory.getPlane(plane);
+ }
+ let tag = plane.getTag();
+ if (!(tag in polygonsPerPlane))
+ polygonsPerPlane[tag] = [polygon];
+ else
+ polygonsPerPlane[tag].push(polygon);
+ }
+ let destpolygons = [];
+ for (let planetag in polygonsPerPlane) {
+ let sourcepolygons = polygonsPerPlane[planetag];
+ reTesselateCoplanarPolygons(sourcepolygons, destpolygons);
+ }
+ let resultCSG = new CSG(destpolygons);
+ resultCSG.isRetesselated = true;
+ return resultCSG;
+}
+
+/** Class CSG
+ * Holds a binary space partition tree representing a 3D solid. Two solids can
+ * be combined using the `union()`, `subtract()`, and `intersect()` methods.
+ * @constructor
+ */
+class CSG {
+ constructor(polygons = []) {
+ this.polygons = polygons;
+ /** # 是否已精简重复点 */
+ this.isCanonicalized = false;
+ /** # 是否已合并轮廓 */
+ this.isRetesselated = false;
+ }
+ /**
+ * Return a new CSG solid representing the space in either this solid or
+ * in the given solids. Neither this solid nor the given solids are modified.
+ * @param {CSG[]} csg - list of CSG objects
+ * @returns {CSG} new CSG object
+ * @example
+ * let C = A.union(B)
+ * @example
+ * +-------+ +-------+
+ * | | | |
+ * | A | | |
+ * | +--+----+ = | +----+
+ * +----+--+ | +----+ |
+ * | B | | |
+ * | | | |
+ * +-------+ +-------+
+ */
+ union(csg) {
+ let csgs;
+ if (csg instanceof Array) {
+ csgs = csg.slice(0);
+ csgs.push(this);
+ }
+ else
+ csgs = [this, csg];
+ let i;
+ // combine csg pairs in a way that forms a balanced binary tree pattern
+ for (i = 1; i < csgs.length; i += 2) {
+ csgs.push(csgs[i - 1].unionSub(csgs[i]));
+ }
+ return csgs[i - 1].reTesselated().canonicalized();
+ }
+ unionSub(csg, retesselate = false, canonicalize = false) {
+ if (!this.mayOverlap(csg))
+ return this.unionForNonIntersecting(csg);
+ let a = new Tree(this.polygons);
+ let b = new Tree(csg.polygons);
+ a.clipTo(b);
+ // b.clipTo(a, true); // ERROR: this doesn't work
+ b.clipTo(a);
+ b.invert();
+ b.clipTo(a);
+ b.invert();
+ let newpolygons = [...a.allPolygons(), ...b.allPolygons()];
+ let resultCSG = new CSG(newpolygons);
+ if (retesselate)
+ resultCSG = resultCSG.reTesselated();
+ if (canonicalize)
+ resultCSG = resultCSG.canonicalized();
+ return resultCSG;
+ }
+ // Like union, but when we know that the two solids are not intersecting
+ // Do not use if you are not completely sure that the solids do not intersect!
+ unionForNonIntersecting(csg) {
+ let newpolygons = [...this.polygons, ...csg.polygons];
+ let result = new CSG(newpolygons);
+ result.isCanonicalized = this.isCanonicalized && csg.isCanonicalized;
+ result.isRetesselated = this.isRetesselated && csg.isRetesselated;
+ return result;
+ }
+ /**
+ * Return a new CSG solid representing space in this solid but
+ * not in the given solids. Neither this solid nor the given solids are modified.
+ * @returns new CSG object
+ * @example
+ * let C = A.subtract(B)
+ * @example
+ * +-------+ +-------+
+ * | | | |
+ * | A | | |
+ * | +--+----+ = | +--+
+ * +----+--+ | +----+
+ * | B |
+ * | |
+ * +-------+
+ */
+ subtract(csg) {
+ let csgs;
+ if (csg instanceof Array)
+ csgs = csg;
+ else
+ csgs = [csg];
+ let result = this;
+ for (let i = 0; i < csgs.length; i++) {
+ let islast = i === csgs.length - 1;
+ result = result.subtractSub(csgs[i], islast, islast);
+ }
+ return result;
+ }
+ subtractSub(csg, retesselate = false, canonicalize = false) {
+ let a = new Tree(this.polygons);
+ let b = new Tree(csg.polygons);
+ a.invert();
+ a.clipTo(b);
+ b.clipTo(a, true);
+ a.addPolygons(b.allPolygons());
+ a.invert();
+ let result = new CSG(a.allPolygons());
+ // if (retesselate) result = result.reTesselated();
+ // if (canonicalize) result = result.canonicalized();
+ return result;
+ }
+ /**
+ * Return a new CSG solid representing space in both this solid and
+ * in the given solids. Neither this solid nor the given solids are modified.
+ * let C = A.intersect(B)
+ * @returns new CSG object
+ * @example
+ * +-------+
+ * | |
+ * | A |
+ * | +--+----+ = +--+
+ * +----+--+ | +--+
+ * | B |
+ * | |
+ * +-------+
+ */
+ intersect(csg) {
+ let csgs;
+ if (csg instanceof Array)
+ csgs = csg;
+ else
+ csgs = [csg];
+ let result = this;
+ for (let i = 0; i < csgs.length; i++) {
+ let islast = i === csgs.length - 1;
+ result = result.intersectSub(csgs[i], islast, islast);
+ }
+ return result;
+ }
+ intersectSub(csg, retesselate = false, canonicalize = false) {
+ let a = new Tree(this.polygons);
+ let b = new Tree(csg.polygons);
+ a.invert();
+ b.clipTo(a);
+ b.invert();
+ a.clipTo(b);
+ b.clipTo(a);
+ a.addPolygons(b.allPolygons());
+ a.invert();
+ let result = new CSG(a.allPolygons());
+ // if (retesselate) result = result.reTesselated();
+ // if (canonicalize) result = result.canonicalized();
+ return result;
+ }
+ /**
+ * Return a new CSG solid with solid and empty space switched.
+ * This solid is not modified.
+ */
+ invert() {
+ let flippedpolygons = this.polygons.map(p => p.flipped());
+ return new CSG(flippedpolygons);
+ }
+ // Affine transformation of CSG object. Returns a new CSG object
+ transform1(matrix4x4) {
+ let newpolygons = this.polygons.map(p => {
+ return p.transform(matrix4x4);
+ });
+ let result = new CSG(newpolygons);
+ result.isCanonicalized = this.isCanonicalized;
+ result.isRetesselated = this.isRetesselated;
+ return result;
+ }
+ /**
+ * Return a new CSG solid that is transformed using the given Matrix.
+ * Several matrix transformations can be combined before transforming this solid.
+ * @param {CSG.Matrix4x4} matrix4x4 - matrix to be applied
+ * @returns {CSG} new CSG object
+ * @example
+ * var m = new CSG.Matrix4x4()
+ * m = m.multiply(CSG.Matrix4x4.rotationX(40))
+ * m = m.multiply(CSG.Matrix4x4.translation([-.5, 0, 0]))
+ * let B = A.transform(m)
+ */
+ transform(matrix4x4) {
+ let ismirror = IsMirror(matrix4x4);
+ let transformedvertices = {};
+ let transformedplanes = {};
+ let newpolygons = this.polygons.map(p => {
+ let newplane;
+ let plane = p.plane;
+ let planetag = plane.getTag();
+ if (planetag in transformedplanes) {
+ newplane = transformedplanes[planetag];
+ }
+ else {
+ newplane = plane.transform(matrix4x4);
+ transformedplanes[planetag] = newplane;
+ }
+ let newvertices = p.vertices.map(v => {
+ let newvertex;
+ let vertextag = v.getTag();
+ if (vertextag in transformedvertices) {
+ newvertex = transformedvertices[vertextag];
+ }
+ else {
+ newvertex = v.transform(matrix4x4);
+ transformedvertices[vertextag] = newvertex;
+ }
+ return newvertex;
+ });
+ if (ismirror)
+ newvertices.reverse();
+ return new Polygon(newvertices, newplane);
+ });
+ let result = new CSG(newpolygons);
+ result.isRetesselated = this.isRetesselated;
+ result.isCanonicalized = this.isCanonicalized;
+ return result;
+ }
+ canonicalized() {
+ if (this.isCanonicalized)
+ return this;
+ return canonicalizeCSG(this);
+ }
+ reTesselated() {
+ if (this.isRetesselated)
+ return this;
+ return reTesselate(this);
+ }
+ //如果两个实体有可能重叠,返回true
+ mayOverlap(csg) {
+ if (this.polygons.length === 0 || csg.polygons.length === 0)
+ return false;
+ let mybounds = bounds(this);
+ let otherbounds = bounds(csg);
+ if (mybounds[1].x < otherbounds[0].x)
+ return false;
+ if (mybounds[0].x > otherbounds[1].x)
+ return false;
+ if (mybounds[1].y < otherbounds[0].y)
+ return false;
+ if (mybounds[0].y > otherbounds[1].y)
+ return false;
+ if (mybounds[1].z < otherbounds[0].z)
+ return false;
+ if (mybounds[0].z > otherbounds[1].z)
+ return false;
+ return true;
+ }
+ toTriangles() {
+ let polygons = [];
+ for (let poly of this.polygons) {
+ let firstVertex = poly.vertices[0];
+ for (let i = poly.vertices.length - 3; i >= 0; i--) {
+ polygons.push(new Polygon([
+ firstVertex,
+ poly.vertices[i + 1],
+ poly.vertices[i + 2]
+ ], poly.plane));
+ }
+ }
+ return polygons;
+ }
+}
+
+function Geometry2CSG(geometry) {
+ if (geometry instanceof three.BufferGeometry)
+ geometry = new three.Geometry().fromBufferGeometry(geometry);
+ let polygons = [];
+ for (let i = 0; i < geometry.faces.length; i++) {
+ let face = geometry.faces[i];
+ let faceVertexUvs = geometry.faceVertexUvs[0][i];
+ let vertices = [];
+ if (face instanceof three.Face3) {
+ let uv = faceVertexUvs ? faceVertexUvs[0].clone() : null;
+ let vertex1 = new Vertex3D(Vector3ToVector3D(geometry.vertices[face.a]), new Vector2D(uv.x, uv.y));
+ vertices.push(vertex1);
+ uv = faceVertexUvs ? faceVertexUvs[1].clone() : null;
+ let vertex2 = new Vertex3D(Vector3ToVector3D(geometry.vertices[face.b]), new Vector2D(uv.x, uv.y));
+ vertices.push(vertex2);
+ uv = faceVertexUvs ? faceVertexUvs[2].clone() : null;
+ let vertex3 = new Vertex3D(Vector3ToVector3D(geometry.vertices[face.c]), new Vector2D(uv.x, uv.y));
+ vertices.push(vertex3);
+ }
+ let polygon = new Polygon(vertices);
+ let normal = Vector3DToVector3(polygon.plane.normal);
+ if (!isNaN(polygon.plane.w) && !equalv3(normal, new three.Vector3()))
+ polygons.push(polygon);
+ }
+ return new CSG(polygons);
+}
+function Vector3ToVector3D(v) {
+ return new Vector3D(v.x, v.y, v.z);
+}
+function Vector3DToVector3(v) {
+ return new three.Vector3(v.x, v.y, v.z);
+}
+
+/**
+ * 解决 THREEBSP(CSG) 产生的结果没有办法得到分裂的个数.
+ * 本类分析了THREEBSP的组合情况.
+ *
+ * Example:
+ *
+ * let topology = new BSPGroupParse(csg);
+ * topology.parse();
+ */
+class BSPGroupParse {
+ constructor(bsp, fractionDigits = 1) {
+ this.fractionDigits = fractionDigits;
+ this.map = new Map();
+ this.vecMap = new Map();
+ if (bsp)
+ for (let poly of bsp.polygons)
+ this.Add(poly);
+ }
+ Add(poly) {
+ let strs = poly.vertices.map(p => this.GenerateP(p.pos));
+ let str0 = strs[0];
+ let s0 = this.Get(str0);
+ for (let i = 1; i < strs.length; i++) {
+ let stri = strs[i];
+ s0.add(stri);
+ this.Get(stri).add(str0);
+ }
+ }
+ /**
+ * 返回组合点
+ */
+ Parse() {
+ let set = new Set([...this.map.keys()]);
+ let res = [];
+ while (set.size > 0) {
+ let fp = set[Symbol.iterator]().next().value;
+ set.delete(fp);
+ let cset = new Set();
+ cset.add(fp);
+ this.GetPts(fp, cset, set);
+ let pts = [...cset].map(str => {
+ let v3 = this.vecMap.get(str);
+ return new three.Vector3(v3.x, v3.y, v3.z);
+ });
+ res.push(pts);
+ }
+ return res;
+ }
+ Get(vstr) {
+ if (!this.map.has(vstr)) {
+ let s = new Set();
+ this.map.set(vstr, s);
+ return s;
+ }
+ return this.map.get(vstr);
+ }
+ GetPts(p, cset, oset) {
+ let strs = this.map.get(p);
+ for (let str of strs) {
+ if (!cset.has(str)) {
+ cset.add(str);
+ oset.delete(str);
+ this.GetPts(str, cset, oset);
+ }
+ }
+ }
+ GenerateP(v) {
+ let str = [v.x, v.y, v.z].map(n => ToFixed(n, this.fractionDigits)).join(",");
+ this.vecMap.set(str, v);
+ return str;
+ }
+}
+
+function GenerateExtrudeEdgeGeometry(contourPoints, height) {
+ let pts = [];
+ for (let cs of contourPoints)
+ pts.push(...GenerateExtrudeEdgeGeometryPoints(cs, height));
+ let geo = new three.BufferGeometry().setFromPoints(pts);
+ return geo;
+}
+function GenerateExtrudeEdgeGeometryPoints(contourPoints, height) {
+ if (contourPoints.length < 3)
+ return [];
+ if (equalv3(contourPoints[0], arrayLast(contourPoints)))
+ contourPoints.pop();
+ let pts = [];
+ let hpts = contourPoints.map(p => new three.Vector3(p.x, p.y, height));
+ let count = contourPoints.length;
+ for (let i = 0; i < count; i++) {
+ pts.push(contourPoints[i], contourPoints[FixIndex(i + 1, count)], hpts[i], hpts[FixIndex(i + 1, count)], contourPoints[i], hpts[i]);
+ }
+ return pts;
+}
+
+var DepthType;
+(function (DepthType) {
+ DepthType[DepthType["Front"] = 1] = "Front";
+ DepthType[DepthType["Back"] = 2] = "Back";
+ DepthType[DepthType["All"] = 3] = "All";
+})(DepthType || (DepthType = {}));
+/**
+ * 槽的几何数据,包括槽的墙面和槽的盖子
+ */
+class Groove {
+ constructor(contour, holes, depthType, depth, allDepth, box = contour.BoundingBox) {
+ this.depthType = depthType;
+ this.depth = depth;
+ this.allDepth = allDepth;
+ this.box = box;
+ this.holeWalls = []; //槽的网洞的墙
+ this.contourWall = new ExtudeWall(contour.Curve, depthType, depth, allDepth, DirectionType.Inner);
+ for (let h of holes)
+ this.holeWalls.push(new ExtudeWall(h.Curve, depthType, depth, allDepth, DirectionType.Outer));
+ this.lid = new CurveTapeShape(contour, holes);
+ }
+ /**
+ * @param groove this - groove
+ * @param [eachOther=true] 相互裁剪
+ */
+ ClipTo(groove, eachOther = true) {
+ //相同深度和面不用操作
+ if (groove.depthType === this.depthType && groove.depth === this.depth)
+ return;
+ if (!IntersectsBox(this.box, groove.box))
+ return;
+ this.ClipLid(groove);
+ groove.ClipLid(this);
+ //一正一反,不交集
+ if (this.depthType + groove.depthType === 3 && this.depth + groove.depth < this.allDepth)
+ return;
+ this.contourWall.ClipTo(groove, true);
+ for (let wall of this.holeWalls)
+ wall.ClipTo(groove, true);
+ if (eachOther) {
+ groove.contourWall.ClipTo(this, false);
+ for (let wall of groove.holeWalls)
+ wall.ClipTo(this, false);
+ }
+ }
+ ClipLid(groove) {
+ if (this.depthType === DepthType.All)
+ return;
+ if (groove.depthType === DepthType.All)
+ return;
+ if (this.depthType === groove.depthType) {
+ if (groove.depth > this.depth)
+ this.lid.ClipTo(groove.lid, true);
+ else
+ this.lid.SplitTo(groove.lid);
+ }
+ else {
+ if (this.depth + groove.depth >= this.allDepth)
+ this.lid.ClipTo(groove.lid, true);
+ else
+ this.lid.SplitTo(groove.lid);
+ }
+ }
+ Draw(verticesArray, uvArray, edgeBuild, rotateUv) {
+ this.contourWall.Draw(verticesArray, uvArray, edgeBuild);
+ for (let wall of this.holeWalls)
+ wall.Draw(verticesArray, uvArray, edgeBuild);
+ if (this.depthType === DepthType.All)
+ return;
+ let isFront = this.depthType === DepthType.Front;
+ this.lid.Draw(verticesArray, uvArray, isFront, isFront ? this.allDepth - this.depth : this.depth, rotateUv);
+ }
+}
+function CreateTape(faceType, startParam, endParam, depth, allDepth) {
+ if (faceType === DepthType.Front)
+ return new Tape(startParam, endParam, allDepth - depth, allDepth);
+ else
+ return new Tape(startParam, endParam, 0, depth);
+}
+//朝向类型
+var DirectionType;
+(function (DirectionType) {
+ DirectionType[DirectionType["Outer"] = 0] = "Outer";
+ DirectionType[DirectionType["Inner"] = 1] = "Inner"; //内墙
+})(DirectionType || (DirectionType = {}));
+//轮廓树节点,用于重新确认外墙和网洞的关系
+class ContourTreeNode {
+ constructor(contour, children = []) {
+ this.contour = contour;
+ this.children = children;
+ }
+ SetParent(node) {
+ this.parent = node;
+ node.children.push(this);
+ }
+ Draw(verticesArray, uvArray, front, z, rotateUv) {
+ // TestDraw(this.contour.Curve, depth);
+ let pts = this.contour.Curve.GetStretchPoints();
+ let vertices = [...pts];
+ let holes = this.children.map(h => {
+ // TestDraw(h.contour.Curve, depth + 1);
+ let pts = h.contour.Curve.GetStretchPoints();
+ vertices.push(...pts);
+ return pts;
+ });
+ let faces = three.ShapeUtils.triangulateShape(pts, holes);
+ for (let f of faces) {
+ if (front) {
+ AddVertice(vertices[f[0]]);
+ AddVertice(vertices[f[1]]);
+ AddVertice(vertices[f[2]]);
+ }
+ else {
+ AddVertice(vertices[f[0]]);
+ AddVertice(vertices[f[2]]);
+ AddVertice(vertices[f[1]]);
+ }
+ }
+ function AddVertice(v) {
+ verticesArray.push(v.x, v.y, z);
+ if (rotateUv)
+ uvArray.push(v.y * 1e-3, v.x * 1e-3);
+ else
+ uvArray.push(v.x * 1e-3, v.y * 1e-3);
+ }
+ for (let hole of this.children) {
+ for (let h of hole.children) {
+ h.Draw(verticesArray, uvArray, front, z, rotateUv); //, depth + 2
+ }
+ }
+ }
+ static ParseContourTree(contourNodes) {
+ contourNodes.sort((c1, c2) => c1.contour.Curve.Area - c2.contour.Curve.Area);
+ for (let i = 0; i < contourNodes.length; i++) {
+ const node1 = contourNodes[i];
+ let p = node1.contour.Curve.StartPoint;
+ for (let j = i + 1; j < contourNodes.length; j++) {
+ const node2 = contourNodes[j];
+ if (node2.contour.BoundingBox.intersectsBox(node1.contour.BoundingBox)
+ && node2.contour.Curve.PtInCurve(p)) {
+ node1.SetParent(node2);
+ break;
+ }
+ }
+ }
+ }
+}
+class EdgeGeometryBuild {
+ constructor(allDepth) {
+ this.allDepth = allDepth;
+ this.lineVerticesArray = [];
+ this.frontLines = [];
+ this.backLines = [];
+ }
+ AddLidLine(p1, p2, depth) {
+ if (depth === 0) {
+ p1 = p1.clone().setZ(0);
+ p2 = p2.clone().setZ(0);
+ let line = new exports.Line(p1, p2);
+ this.backLines.push(line);
+ }
+ else if (depth === this.allDepth) {
+ p1 = p1.clone().setZ(0);
+ p2 = p2.clone().setZ(0);
+ let line = new exports.Line(p1, p2);
+ this.frontLines.push(line);
+ }
+ }
+ BuildLid(verticesArray, uvArray, rotateUv) {
+ let arr = [this.backLines, this.frontLines];
+ for (let index = 0; index < 2; index++) {
+ let lines = arr[index];
+ let parse = new RegionParse(lines);
+ let contourNodes = [];
+ for (let routes of parse.RegionsOutline) {
+ let cs = [];
+ for (let r of routes)
+ cs.push(r.curve);
+ let c = Contour.CreateContour(cs, false);
+ if (c)
+ contourNodes.push(new ContourTreeNode(c));
+ else
+ console.error("未能构建盖子");
+ }
+ ContourTreeNode.ParseContourTree(contourNodes);
+ for (let j = contourNodes.length; j--;) {
+ let node = contourNodes[j];
+ if (node.parent)
+ continue;
+ node.Draw(verticesArray, uvArray, index === 1, this.allDepth * index, rotateUv);
+ }
+ }
+ }
+}
+/**
+ * 胶带
+ */
+class Tape {
+ constructor(start, end, bottom, top) {
+ this.start = start;
+ this.end = end;
+ this.bottom = bottom;
+ this.top = top;
+ }
+ //用于测试
+ get Curve() {
+ return new exports.Polyline().RectangleFrom2Pt(new three.Vector3(this.start, this.bottom), new three.Vector3(this.end, this.top));
+ }
+ Clip(t) {
+ let yr = IntersectRange(this.bottom, this.top, t.bottom, t.top, 1e5);
+ if (yr === undefined)
+ return [this];
+ let xr = IntersectRange(this.start, this.end, t.start, t.end, 1e5);
+ if (xr === undefined)
+ return [this];
+ let rem = SubtractRange(this.start, this.end, t.start, t.end, 1e5).map(r => {
+ return new Tape(r[0], r[1], this.bottom, this.top);
+ });
+ let remR = SubtractRange(this.bottom, this.top, t.bottom, t.top, 1e5);
+ for (let hr of remR) {
+ rem.push(new Tape(xr[0], xr[1], hr[0], hr[1]));
+ }
+ return rem;
+ }
+ Split(xlst) {
+ let ret = [];
+ let pre = this.start;
+ for (let x of xlst) {
+ if (x > pre) {
+ if (x >= this.end)
+ x = this.end;
+ if (equaln(pre, x))
+ continue;
+ ret.push(new Tape(pre, x, this.bottom, this.top));
+ pre = x;
+ if (x === this.end)
+ break;
+ }
+ }
+ return ret;
+ }
+}
+/**
+ * 二维形状,内部用曲线胶带表示(用来计算盖子差集算法)
+ */
+class CurveTapeShape {
+ constructor(contour, holes) {
+ this.children = [];
+ this.contour = new CurveTape(contour, DirectionType.Outer);
+ this.holes = holes.map(h => new CurveTape(h, DirectionType.Inner));
+ }
+ CloneNew() {
+ let s = new CurveTapeShape(this.contour.contour, this.holes.map(h => h.contour));
+ return s;
+ }
+ /**
+ * 删除包含,同向
+ */
+ ClipTo(s, append = false) {
+ for (let c of [this.contour, ...this.holes])
+ if (c.tapes.length > 0)
+ c.ClipTo(s);
+ if (append) {
+ let sn = s.CloneNew();
+ sn.ReverseClipTo(this);
+ this.children.push(sn);
+ }
+ }
+ //合理打断(以保证三维网格对齐(否则圆弧点将无法正确的对齐))
+ SplitTo(s) {
+ for (let c of [this.contour, ...this.holes]) {
+ for (let c2 of [s.contour, ...s.holes]) {
+ let int = GetIntersection(c.contour.Curve, c2.contour.Curve);
+ c.splitParams.push(...int.map(i => i.thisParam));
+ }
+ }
+ }
+ /**
+ * 只保留被包含部分
+ */
+ ReverseClipTo(s) {
+ for (let c of [this.contour, ...this.holes])
+ if (c.tapes.length > 0)
+ c.ReverseClipTo(s);
+ return this;
+ }
+ ChildrenClip() {
+ for (let i = 0; i < this.children.length; i++) {
+ let s1 = this.children[i];
+ for (let j = i + 1; j < this.children.length; j++) {
+ let s2 = this.children[j];
+ s1.ClipTo(s2, false);
+ s2.ClipTo(s1, false);
+ }
+ }
+ }
+ Draw(verticesArray, uvArray, front, z, rotateUv) {
+ this.ChildrenClip();
+ let polylines = this.contour.Curves;
+ for (let h of this.holes)
+ polylines.push(...h.Curves);
+ for (let s of this.children) {
+ polylines.push(...s.contour.Curves);
+ for (let h of s.holes)
+ polylines.push(...h.Curves);
+ }
+ // TestDraw(polylines, z);
+ let groups = curveLinkGroup(polylines);
+ let contourNodes = [];
+ for (let cus of groups) {
+ let c = Contour.CreateContour(cus, false);
+ if (c)
+ contourNodes.push(new ContourTreeNode(c));
+ else
+ console.error("出错");
+ }
+ ContourTreeNode.ParseContourTree(contourNodes);
+ for (let j = contourNodes.length; j--;) {
+ let node = contourNodes[j];
+ // TestDraw(s.contour.Curve.Clone(), z);
+ if (node.parent)
+ continue;
+ node.Draw(verticesArray, uvArray, front, z, rotateUv);
+ }
+ }
+}
+const SplitLength = 4;
+const MinSplitCount = 12;
+const MaxSplitCount = 360;
+function SplitCurveParams(cu) {
+ let xparams = [];
+ if (cu instanceof exports.Circle) {
+ let splitCount = cu.Radius / SplitLength;
+ splitCount = clamp(Math.floor(splitCount), MinSplitCount, MaxSplitCount);
+ for (let i = 0; i < splitCount; i++)
+ xparams.push(i / splitCount);
+ }
+ else
+ //分段1
+ for (let i = 0; i < cu.EndParam; i++) {
+ xparams.push(i);
+ if (cu.GetBuilgeAt(i) !== 0) {
+ let arc = cu.GetCurveAtIndex(i);
+ let splitCount = arc.Radius / SplitLength;
+ splitCount = clamp(Math.floor(splitCount), MinSplitCount, MaxSplitCount);
+ if (splitCount === 0)
+ continue;
+ let a = Math.PI * 2 / splitCount;
+ let params = [];
+ for (let j = 0; j < splitCount; j++) {
+ let param = arc.GetParamAtAngle(a * j);
+ if (arc.ParamOnCurve(param))
+ params.push(param);
+ }
+ arraySortByNumber(params);
+ if (params.length === 0)
+ continue;
+ for (let p of params) {
+ if (p > 1e-5 && p < 9.99999)
+ xparams.push(p + i);
+ }
+ }
+ }
+ xparams.push(cu.EndParam);
+ return xparams;
+}
+/**
+ * 曲线胶带(一维)
+ */
+class CurveTape {
+ constructor(contour, wallType) {
+ this.contour = contour;
+ this.wallType = wallType;
+ this.splitParams = [];
+ this.tapes = [[0, this.contour.Curve.EndParam]];
+ }
+ get Curves() {
+ let xparams = SplitCurveParams(this.contour.Curve);
+ if (this.splitParams.length > 0) {
+ xparams.push(...this.splitParams);
+ arraySortByNumber(xparams);
+ arrayRemoveDuplicateBySort(xparams, (p1, p2) => equaln(p1, p2));
+ }
+ let polylines = [];
+ function TD(p) {
+ return { pt: AsVector2(p), bul: 0 };
+ }
+ const addPolyline = (t) => {
+ let pts = [TD(this.contour.Curve.GetPointAtParam(t[0]))];
+ for (let x of xparams) {
+ if (x <= t[0])
+ continue;
+ if (x >= t[1])
+ break;
+ pts.push(TD(this.contour.Curve.GetPointAtParam(x)));
+ }
+ pts.push(TD(this.contour.Curve.GetPointAtParam(t[1])));
+ let pl = new exports.Polyline(pts);
+ polylines.push(pl);
+ };
+ for (let t of this.tapes) {
+ if (t[0] > t[1]) {
+ addPolyline([0, t[1]]);
+ addPolyline([t[0], this.contour.Curve.EndParam]);
+ }
+ else
+ addPolyline(t);
+ }
+ return polylines;
+ }
+ /**
+ * 分析与另一个形状的包含关系
+ */
+ Parse(s) {
+ let [res1] = ParseCurveParamRangeRelation(this.contour.Curve, s.contour.contour.Curve);
+ if (this.wallType === DirectionType.Inner)
+ [res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy];
+ if (res1.container.length > 0) {
+ for (let h of s.holes) {
+ let [res2] = ParseCurveParamRangeRelation(this.contour.Curve, h.contour.Curve);
+ if (this.wallType === DirectionType.Outer)
+ [res2.syntropy, res2.reverse] = [res2.reverse, res2.syntropy];
+ res1.syntropy.push(...res2.syntropy);
+ res1.reverse.push(...res2.reverse);
+ res1.container = SubtractRanges(res1.container, res2.container, this.contour.Curve.EndParam);
+ res1.container = SubtractRanges(res1.container, res2.syntropy, this.contour.Curve.EndParam);
+ res1.container = SubtractRanges(res1.container, res2.reverse, this.contour.Curve.EndParam);
+ }
+ }
+ return res1;
+ }
+ /**
+ * 删除包含,同向面
+ */
+ ClipTo(s) {
+ let d = this.Parse(s);
+ this.tapes = SubtractRanges(this.tapes, d.container, this.contour.Curve.EndParam);
+ this.tapes = SubtractRanges(this.tapes, d.syntropy, this.contour.Curve.EndParam);
+ return this;
+ }
+ /**
+ * 保留被包含的部分
+ */
+ ReverseClipTo(s) {
+ this.tapes = this.Parse(s).container;
+ return this;
+ }
+}
+class ExtudeWall {
+ constructor(curve, depthType, depth, allDepth, wallType) {
+ this.curve = curve;
+ this.depthType = depthType;
+ this.depth = depth;
+ this.allDepth = allDepth;
+ this.wallType = wallType;
+ //一整段
+ this.Tape = [CreateTape(depthType, 0, this.curve.EndParam, depth, allDepth)];
+ }
+ /**
+ * 减去在另一个groove内的部分
+ * @param groove this - groove
+ * @param [clipSyntropy=false] 删除同向的面
+ */
+ ClipTo(groove, clipSyntropy = false) {
+ let [res1] = ParseCurveParamRangeRelation(this.curve, groove.contourWall.curve);
+ if (this.wallType !== groove.contourWall.wallType)
+ [res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy];
+ if (res1.container.length > 0) {
+ for (let h of groove.holeWalls) {
+ let [resh1] = ParseCurveParamRangeRelation(this.curve, h.curve);
+ //翻转
+ if (this.wallType !== h.wallType)
+ [resh1.syntropy, resh1.reverse] = [resh1.reverse, resh1.syntropy];
+ //删除在网洞内的
+ let subParams;
+ if (clipSyntropy)
+ subParams = resh1.container; //删除共面,
+ else
+ subParams = [...resh1.container, ...resh1.syntropy]; //保留共面部分
+ for (let i of subParams) {
+ let rems = [];
+ for (let r of res1.container)
+ rems.push(...SubtractRange(r[0], r[1], i[0], i[1], this.curve.EndParam));
+ res1.container = rems;
+ }
+ }
+ }
+ let params = [...res1.container, ...res1.reverse];
+ if (clipSyntropy)
+ params.push(...res1.syntropy);
+ for (let c of params)
+ this.ClipFromParam(c[0], c[1], groove.depthType, groove.depth);
+ }
+ ClipReverse(wall) {
+ let [res1] = ParseCurveParamRangeRelation(this.curve, wall.curve);
+ for (let c of res1.syntropy)
+ this.ClipFromParam(c[0], c[1], wall.depthType, wall.depth);
+ }
+ /**
+ * 当起始参数大于终止参数时,裁剪的区域经过终点
+ *
+ * @param startParam 起始参数
+ * @param endParam 终止参数
+ * @param faceType 裁剪面朝向
+ * @param depth 裁剪面的深度
+ */
+ ClipFromParam(startParam, endParam, faceType, depth) {
+ if (equaln(startParam, endParam))
+ return;
+ if (startParam > endParam) {
+ this.ClipFromParam(startParam, this.curve.EndParam, faceType, depth);
+ this.ClipFromParam(0, endParam, faceType, depth);
+ return this;
+ }
+ let subTape = CreateTape(faceType, startParam, endParam, depth, this.allDepth);
+ let taps = [];
+ for (let t of this.Tape)
+ taps.push(...t.Clip(subTape));
+ this.Tape = taps;
+ return this;
+ }
+ Draw(verticesArray, uvArray, edgeBuild) {
+ let xparams = SplitCurveParams(this.curve);
+ function AddVertice(v) {
+ verticesArray.push(v.x);
+ verticesArray.push(v.y);
+ verticesArray.push(v.z);
+ }
+ let tapes = [];
+ this.Tape.sort((t1, t2) => t1.start - t2.start);
+ for (let tape of this.Tape)
+ tapes.push(...tape.Split(xparams));
+ for (let i = 0; i < tapes.length; i++) {
+ let preIndex = FixIndex(i - 1, tapes);
+ let nextIndex = FixIndex(i + 1, tapes);
+ let tape = tapes[i];
+ let preTape = tapes[preIndex];
+ let nextTape = tapes[nextIndex];
+ let p1 = this.curve.GetPointAtParam(tape.start).setZ(tape.bottom);
+ let p2 = this.curve.GetPointAtParam(tape.end).setZ(tape.bottom);
+ let vs = [p1, p2, p2.clone().setZ(tape.top), p1.clone().setZ(tape.top), p1];
+ edgeBuild.AddLidLine(p1, p2, tape.bottom);
+ edgeBuild.AddLidLine(p1, p2, tape.top);
+ //#region 构造线框
+ {
+ let leftRanges;
+ let rightRange;
+ const IsInteger = (n) => equaln(n, Math.round(n), 1e-8);
+ if (!IsInteger(tape.start) && equaln(tape.start, preTape.end))
+ leftRanges = SubtractRange(tape.bottom, tape.top, preTape.bottom, preTape.top, this.allDepth);
+ else
+ leftRanges = [[tape.bottom, tape.top]];
+ if (equaln(tape.end, nextTape.start))
+ rightRange = SubtractRange(tape.bottom, tape.top, nextTape.bottom, nextTape.top, this.allDepth);
+ else
+ rightRange = [[tape.bottom, tape.top]];
+ //上下两条线
+ edgeBuild.lineVerticesArray.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, p1.x, p1.y, tape.top, p2.x, p2.y, tape.top);
+ //左右线
+ for (let range of leftRanges) {
+ edgeBuild.lineVerticesArray.push(p1.x, p1.y, range[0], p1.x, p1.y, range[1]);
+ }
+ for (let range of rightRange) {
+ edgeBuild.lineVerticesArray.push(p2.x, p2.y, range[0], p2.x, p2.y, range[1]);
+ }
+ }
+ //#endregion
+ //和X平行平行
+ let isXPar = (vs[0].y + vs[1].y + vs[2].y) < 0.01;
+ function AddUv(p) {
+ if (isXPar)
+ uvArray.push((p.z - 1) * 1e-3, p.y * 1e-3);
+ else
+ uvArray.push((p.z - 1) * 1e-3, p.x * 1e-3);
+ }
+ if (this.wallType === DirectionType.Outer) {
+ AddVertice(vs[0]);
+ AddUv(vs[0]);
+ AddVertice(vs[1]);
+ AddUv(vs[1]);
+ AddVertice(vs[2]);
+ AddUv(vs[2]);
+ AddVertice(vs[0]);
+ AddUv(vs[0]);
+ AddVertice(vs[2]);
+ AddUv(vs[2]);
+ AddVertice(vs[3]);
+ AddUv(vs[3]);
+ }
+ else {
+ AddVertice(vs[0]);
+ AddUv(vs[0]);
+ AddVertice(vs[2]);
+ AddUv(vs[2]);
+ AddVertice(vs[1]);
+ AddUv(vs[1]);
+ AddVertice(vs[0]);
+ AddUv(vs[0]);
+ AddVertice(vs[3]);
+ AddUv(vs[3]);
+ AddVertice(vs[2]);
+ AddUv(vs[2]);
+ }
+ }
+ }
+}
+/**
+ * 分析两个曲线关系(包含,分离,同向共线,反向共线)(用参数范围表示)
+ */
+function ParseCurveParamRangeRelation(cu1, cu2, reverseParse = false) {
+ let ins = GetIntersection(cu1, cu2);
+ let c1Res = { container: [], syntropy: [], reverse: [], outer: [] };
+ let c2Res = { container: [], syntropy: [], reverse: [], outer: [] };
+ if (ins.length === 0) {
+ if (cu2.PtInCurve(cu1.StartPoint))
+ c1Res.container.push([0, cu1.EndParam]);
+ else
+ c1Res.outer.push([0, cu1.EndParam]);
+ if (cu1.PtInCurve(cu2.StartPoint))
+ c2Res.container.push([0, cu2.EndParam]);
+ else
+ c2Res.outer.push([0, cu2.EndParam]);
+ return [c1Res, c2Res];
+ }
+ //解析出线段列表
+ let c1Curves = [];
+ let c2Curves = [];
+ ins.sort((a1, a2) => a1.thisParam - a2.thisParam);
+ //点重复->下方ins会sort,导致交点对应不上,导致错误
+ arrayRemoveDuplicateBySort(ins, (i1, i2) => equalv3(i1.pt, i2.pt, 1e-4));
+ if (ins.length > 1 && equalv3(ins[0].pt, ins[ins.length - 1].pt, 1e-4))
+ ins.pop();
+ for (let i = 0; i < ins.length; i++) {
+ let n1 = ins[i];
+ let n2 = ins[FixIndex(i + 1, ins)];
+ c1Curves.push({ startParam: n1.thisParam, endParam: n2.thisParam, startPoint: n1.pt, endPoint: n2.pt });
+ }
+ ins.sort((a1, a2) => a1.argParam - a2.argParam);
+ for (let i = 0; i < ins.length; i++) {
+ let n1 = ins[i];
+ let n2 = ins[FixIndex(i + 1, ins)];
+ c2Curves.push({ startParam: n1.argParam, endParam: n2.argParam, startPoint: n1.pt, endPoint: n2.pt });
+ }
+ //分析共边关系和包含关系
+ for (let c of c1Curves) {
+ let c1MidPoint = CenterPoint(cu1, c.startParam, c.endParam);
+ for (let c2 of c2Curves) {
+ if (c2.used)
+ continue;
+ let c2MidPoint = CenterPoint(cu2, c2.startParam, c2.endParam);
+ if (!equalv3(c1MidPoint, c2MidPoint, 1e-4))
+ continue;
+ c.used = true;
+ if (c.startPoint === c2.startPoint
+ && c.endPoint === c2.endPoint) {
+ c1Res.syntropy.push([c.startParam, c.endParam]);
+ c2Res.syntropy.push([c2.startParam, c2.endParam]);
+ c2.used = true;
+ break;
+ }
+ else if (c.startPoint === c2.endPoint
+ && c.endPoint === c2.startPoint) {
+ c1Res.reverse.push([c.startParam, c.endParam]);
+ c2Res.reverse.push([c2.startParam, c2.endParam]);
+ c2.used = true;
+ break;
+ }
+ else
+ c.used = false;
+ }
+ if (!c.used) {
+ if (cu2.PtInCurve(c1MidPoint))
+ c1Res.container.push([c.startParam, c.endParam]);
+ else
+ c1Res.outer.push([c.startParam, c.endParam]);
+ }
+ }
+ //只分析包含关系
+ if (reverseParse)
+ for (let c of c2Curves) {
+ if (c.used)
+ continue;
+ let p = CenterPoint(cu2, c.startParam, c.endParam);
+ if (cu1.PtInCurve(p))
+ c2Res.container.push([c.startParam, c.endParam]);
+ else
+ c2Res.outer.push([c.startParam, c.endParam]);
+ }
+ return [c1Res, c2Res];
+}
+function CenterPoint(cu, start, end) {
+ let lenStart = cu.GetDistAtParam(start);
+ let lenEnd = cu.GetDistAtParam(end);
+ if (end > start)
+ return cu.GetPointAtDistance((lenEnd + lenStart) * 0.5);
+ let lenAll = cu.Length;
+ let lenDiv = ((lenAll - lenStart) + lenEnd) * 0.5;
+ if (lenStart + lenDiv >= lenAll)
+ return cu.GetPointAtDistance(lenStart + lenDiv - lenAll);
+ else
+ return cu.GetPointAtDistance(lenStart + lenDiv);
+}
+// //0-1
+// UnionRange(0.5, 0.3, 0.3, 0.5, 1);//?
+// //0-1
+// UnionRange(0.4, 0.3, 0.3, 0.5, 1);//?
+// //[ [ 0.8, 0.1 ], [ 0.3, 0.5 ] ]
+// UnionRange(0.8, 0.1, 0.3, 0.5, 1);//?
+// //[ 0.3, 0.10000000000000009 ] ]
+// UnionRange(0.8, 0.1, 0.3, 0.9, 1);//?
+function SubtractRange(a, b, c, d, end) {
+ if (a < 0 || b < 0)
+ return [];
+ if (a > b)
+ return [...SubtractRange(a, end, c, d, end), ...SubtractRange(0, b, c, d, end)];
+ if (c > d) {
+ let arr = SubtractRange(a, b, c, end, end);
+ let rem = [];
+ for (let s of arr)
+ rem.push(...SubtractRange(s[0], s[1], 0, d, end));
+ return rem;
+ }
+ if (c >= b || d <= a)
+ return [[a, b]];
+ if (c <= a) // c1 a1 b1
+ {
+ if (d >= b)
+ return [];
+ return [[d, b]];
+ }
+ if (d < b)
+ return [[a, c], [d, b]];
+ return [[a, c]];
+}
+function SubtractRange2(r, sr, end) {
+ return SubtractRange(r[0], r[1], sr[0], sr[1], end);
+}
+function SubtractRanges(ranges, subRanges, end) {
+ let rets = ranges;
+ for (let sr of subRanges) {
+ let temps = [];
+ for (let r of rets)
+ temps.push(...SubtractRange2(r, sr, end));
+ rets = temps;
+ }
+ return rets;
+}
+function IntersectRange(a, b, c, d, end) {
+ let b1 = b < a ? b + end : b;
+ let d1 = d < c ? d + end : d;
+ let a1 = a;
+ let c1 = c;
+ if (c < a)
+ [a1, b1, c1, d1] = [c1, d1, a1, b1];
+ if (c1 > b1)
+ return;
+ return [c1, Math.min(b1, d1)];
+}
+const alMatrix4 = new three.Matrix4;
+class ExtrudeGeometryBuilder {
+ constructor(br) {
+ this.br = br;
+ this.verticesArray = []; //用于构建三维网格
+ this.uvArray = []; //uv
+ this.edgeAndLidBuilder = new EdgeGeometryBuild(this.br.Thickness);
+ let rotateUv = (br instanceof Board && br.BoardProcessOption.lines === LinesType.Reverse);
+ //计算墙(创建轮廓取出,为了得到正确的轮廓曲线(逆时针之类的))
+ let outerWall = new ExtudeWall(Contour.CreateContour(br.ContourCurve.Clone()).Curve, DepthType.All, br.Thickness, br.Thickness, DirectionType.Outer);
+ let grooves = this.ParseGrooves();
+ for (let i = 0; i < grooves.length; i++) {
+ let s1 = grooves[i];
+ outerWall.ClipTo(s1, false);
+ s1.contourWall.ClipReverse(outerWall);
+ for (let j = i + 1; j < grooves.length; j++) {
+ let s2 = grooves[j];
+ s1.ClipTo(s2, true);
+ }
+ s1.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder, rotateUv);
+ }
+ outerWall.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder);
+ //这里构建盖子
+ this.edgeAndLidBuilder.BuildLid(this.verticesArray, this.uvArray, rotateUv);
+ intCache.clear();
+ }
+ get MeshGeometry() {
+ let geo = new three.BufferGeometry();
+ geo.setAttribute('position', new three.Float32BufferAttribute(this.verticesArray, 3));
+ geo.setAttribute('uv', new three.Float32BufferAttribute(this.uvArray, 2));
+ geo.computeVertexNormals();
+ return geo;
+ }
+ get EdgeGeometry() {
+ let geo = new three.BufferGeometry();
+ geo.setAttribute('position', new three.Float32BufferAttribute(this.edgeAndLidBuilder.lineVerticesArray, 3));
+ return geo;
+ }
+ ParseGrooves() {
+ let br = this.br;
+ const brOcsInv = br.OCSInv;
+ let grooves = [];
+ for (let groove of br.Grooves) {
+ //判断槽正反面
+ let type;
+ if (equaln(groove.Thickness, br.Thickness))
+ type = DepthType.All;
+ else {
+ if (equaln(groove.Position.applyMatrix4(brOcsInv).z, 0))
+ type = DepthType.Back;
+ else
+ type = DepthType.Front;
+ }
+ alMatrix4.multiplyMatrices(brOcsInv, groove.OCSNoClone);
+ //槽轮廓
+ let grooveContourCurve = groove.ContourCurve.Clone();
+ grooveContourCurve.ApplyMatrix(alMatrix4);
+ grooveContourCurve.Z0();
+ if (grooveContourCurve instanceof exports.Polyline)
+ grooveContourCurve.UpdateMatrixTo(IdentityMtx4); //不可能改变这个
+ let grooveContour = Contour.CreateContour(grooveContourCurve);
+ let grooveHoleContours = [];
+ //孤岛
+ for (let grooveChild of groove.Grooves) {
+ let grooveChildContourCurve = grooveChild.ContourCurve.Clone();
+ alMatrix4.multiplyMatrices(brOcsInv, grooveChild.OCSNoClone);
+ grooveChildContourCurve.ApplyMatrix(alMatrix4).Z0();
+ if (grooveChildContourCurve instanceof exports.Polyline)
+ grooveChildContourCurve.UpdateMatrixTo(IdentityMtx4);
+ let grooveChildContour = Contour.CreateContour(grooveChildContourCurve);
+ grooveHoleContours.push(grooveChildContour);
+ }
+ grooves.push(new Groove(grooveContour, grooveHoleContours, type, groove.Thickness, br.Thickness));
+ }
+ return grooves;
+ }
+}
+let intCache = new Map();
+function GetIntersection(cu1, cu2) {
+ let m = intCache.get(cu1);
+ if (m) {
+ let r = m.get(cu2);
+ if (r)
+ return r;
+ }
+ else
+ m = new Map();
+ intCache.set(cu1, m);
+ let r = cu1.IntersectWith2(cu2, IntersectOption.OnBothOperands);
+ let cu1EndParam = cu1.EndParam;
+ let cu2EndParam = cu2.EndParam;
+ for (let d of r) {
+ d.thisParam = three.MathUtils.clamp(d.thisParam, 0, cu1EndParam);
+ d.argParam = three.MathUtils.clamp(d.argParam, 0, cu2EndParam);
+ }
+ m.set(cu2, r);
+ let r2 = r.map(r => {
+ return { thisParam: r.argParam, argParam: r.thisParam, pt: r.pt };
+ });
+ let m2 = intCache.get(cu2);
+ if (!m2) {
+ m2 = new Map();
+ intCache.set(cu2, m2);
+ }
+ m2.set(cu1, r2);
+ return r;
+}
+
+// Quote from:
+// https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js
+// 即obb.js(本项目中已存在)
+// Reference material:
+//https://stackoverflow.com/questions/28499800/oriented-box-intersection-in-threejs
+//http://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html
+//https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js
+class OBB {
+ constructor(ocs, halfSizes) {
+ this.ocs = ocs;
+ this.halfSizes = halfSizes;
+ this._EPSILON = 1e-3;
+ this.center = halfSizes.clone().applyMatrix4(ocs);
+ }
+ intersectsOBB(obb, is2D, ucsInv) {
+ let newCenter;
+ let newObbCenter;
+ let cs;
+ let obbcs;
+ if (is2D) {
+ let mtx1 = new three.Matrix4().multiplyMatrices(ucsInv, this.ocs);
+ let mtx2 = new three.Matrix4().multiplyMatrices(ucsInv, obb.ocs);
+ cs = mtx1;
+ obbcs = mtx2;
+ cs.elements[14] = 0;
+ obbcs.elements[14] = 0;
+ newCenter = this.halfSizes.clone().applyMatrix4(cs);
+ newObbCenter = obb.halfSizes.clone().applyMatrix4(obbcs);
+ }
+ let xAxisA = new three.Vector3();
+ let yAxisA = new three.Vector3();
+ let zAxisA = new three.Vector3();
+ let xAxisB = new three.Vector3();
+ let yAxisB = new three.Vector3();
+ let zAxisB = new three.Vector3();
+ let translation = new three.Vector3();
+ let vector = new three.Vector3();
+ let axisA = [];
+ let axisB = [];
+ let rotationMatrix = [[], [], []];
+ let rotationMatrixAbs = [[], [], []];
+ let halfSizeA, halfSizeB;
+ let t, i;
+ // extract each axis
+ (cs !== null && cs !== void 0 ? cs : this.ocs).extractBasis(xAxisA, yAxisA, zAxisA);
+ (obbcs !== null && obbcs !== void 0 ? obbcs : obb.ocs).extractBasis(xAxisB, yAxisB, zAxisB);
+ // push basis vectors into arrays, so you can access them via indices
+ axisA.push(xAxisA, yAxisA, zAxisA);
+ axisB.push(xAxisB, yAxisB, zAxisB);
+ // get displacement vector
+ vector.subVectors(newObbCenter !== null && newObbCenter !== void 0 ? newObbCenter : obb.center, newCenter !== null && newCenter !== void 0 ? newCenter : this.center);
+ // express the translation vector in the coordinate frame of the current
+ // OBB (this)
+ for (i = 0; i < 3; i++) {
+ translation.setComponent(i, vector.dot(axisA[i]));
+ }
+ // generate a rotation matrix that transforms from world space to the
+ // OBB's coordinate space
+ for (i = 0; i < 3; i++) {
+ for (let j = 0; j < 3; j++) {
+ rotationMatrix[i][j] = axisA[i].dot(axisB[j]);
+ rotationMatrixAbs[i][j] = Math.abs(rotationMatrix[i][j]) + this._EPSILON;
+ }
+ }
+ // test the three major axes of this OBB
+ for (i = 0; i < 3; i++) {
+ vector.set(rotationMatrixAbs[i][0], rotationMatrixAbs[i][1], rotationMatrixAbs[i][2]);
+ halfSizeA = this.halfSizes.getComponent(i);
+ halfSizeB = obb.halfSizes.dot(vector);
+ if (Math.abs(translation.getComponent(i)) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ }
+ // test the three major axes of other OBB
+ for (i = 0; i < 3; i++) {
+ vector.set(rotationMatrixAbs[0][i], rotationMatrixAbs[1][i], rotationMatrixAbs[2][i]);
+ halfSizeA = this.halfSizes.dot(vector);
+ halfSizeB = obb.halfSizes.getComponent(i);
+ vector.set(rotationMatrix[0][i], rotationMatrix[1][i], rotationMatrix[2][i]);
+ t = translation.dot(vector);
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ }
+ // test the 9 different cross-axes
+ // A.x B.x
+ halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][0] + this.halfSizes.z * rotationMatrixAbs[1][0];
+ halfSizeB = obb.halfSizes.y * rotationMatrixAbs[0][2] + obb.halfSizes.z * rotationMatrixAbs[0][1];
+ t = translation.z * rotationMatrix[1][0] - translation.y * rotationMatrix[2][0];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.x < cross> B.y
+ halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][1] + this.halfSizes.z * rotationMatrixAbs[1][1];
+ halfSizeB = obb.halfSizes.x * rotationMatrixAbs[0][2] + obb.halfSizes.z * rotationMatrixAbs[0][0];
+ t = translation.z * rotationMatrix[1][1] - translation.y * rotationMatrix[2][1];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.x B.z
+ halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][2] + this.halfSizes.z * rotationMatrixAbs[1][2];
+ halfSizeB = obb.halfSizes.x * rotationMatrixAbs[0][1] + obb.halfSizes.y * rotationMatrixAbs[0][0];
+ t = translation.z * rotationMatrix[1][2] - translation.y * rotationMatrix[2][2];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.y B.x
+ halfSizeA = this.halfSizes.x * rotationMatrixAbs[2][0] + this.halfSizes.z * rotationMatrixAbs[0][0];
+ halfSizeB = obb.halfSizes.y * rotationMatrixAbs[1][2] + obb.halfSizes.z * rotationMatrixAbs[1][1];
+ t = translation.x * rotationMatrix[2][0] - translation.z * rotationMatrix[0][0];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.y B.y
+ halfSizeA = this.halfSizes.x * rotationMatrixAbs[2][1] + this.halfSizes.z * rotationMatrixAbs[0][1];
+ halfSizeB = obb.halfSizes.x * rotationMatrixAbs[1][2] + obb.halfSizes.z * rotationMatrixAbs[1][0];
+ t = translation.x * rotationMatrix[2][1] - translation.z * rotationMatrix[0][1];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.y B.z
+ halfSizeA = this.halfSizes.x * rotationMatrixAbs[2][2] + this.halfSizes.z * rotationMatrixAbs[0][2];
+ halfSizeB = obb.halfSizes.x * rotationMatrixAbs[1][1] + obb.halfSizes.y * rotationMatrixAbs[1][0];
+ t = translation.x * rotationMatrix[2][2] - translation.z * rotationMatrix[0][2];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.z B.x
+ halfSizeA = this.halfSizes.x * rotationMatrixAbs[1][0] + this.halfSizes.y * rotationMatrixAbs[0][0];
+ halfSizeB = obb.halfSizes.y * rotationMatrixAbs[2][2] + obb.halfSizes.z * rotationMatrixAbs[2][1];
+ t = translation.y * rotationMatrix[0][0] - translation.x * rotationMatrix[1][0];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.z B.y
+ halfSizeA = this.halfSizes.x * rotationMatrixAbs[1][1] + this.halfSizes.y * rotationMatrixAbs[0][1];
+ halfSizeB = obb.halfSizes.x * rotationMatrixAbs[2][2] + obb.halfSizes.z * rotationMatrixAbs[2][0];
+ t = translation.y * rotationMatrix[0][1] - translation.x * rotationMatrix[1][1];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // A.z B.z
+ halfSizeA = this.halfSizes.x * rotationMatrixAbs[1][2] + this.halfSizes.y * rotationMatrixAbs[0][2];
+ halfSizeB = obb.halfSizes.x * rotationMatrixAbs[2][1] + obb.halfSizes.y * rotationMatrixAbs[2][0];
+ t = translation.y * rotationMatrix[0][2] - translation.x * rotationMatrix[1][2];
+ if (Math.abs(t) > halfSizeA + halfSizeB) {
+ return false;
+ }
+ // no separating axis exists, so the two OBB don't intersect
+ return true;
+ }
+}
+
+let Spline = class Spline extends Curve {
+ constructor(points) {
+ super();
+ this._ClosedMark = false;
+ this._PointList = points || [];
+ }
+ get Shape() {
+ return new three.Shape();
+ }
+ get Curve3() {
+ return new three.CatmullRomCurve3(this.Points);
+ }
+ get Length() {
+ return this.Curve3.getLength();
+ }
+ get Points() {
+ return this._PointList;
+ }
+ set Points(v) {
+ this.WriteAllObjectRecord();
+ this._PointList = v.map(p => p.clone().applyMatrix4(this.OCSInv));
+ this.Update();
+ }
+ //闭合标志
+ get CloseMark() {
+ return this._ClosedMark;
+ }
+ //曲线是否闭合
+ get IsClose() {
+ return this.CloseMark || (equalv3(this.StartPoint, this.EndPoint, 1e-4)) && this.EndParam > 1;
+ }
+ set CloseMark(v) {
+ this.WriteAllObjectRecord();
+ this._ClosedMark = v;
+ this.Update();
+ }
+ get StartPoint() {
+ return this._PointList[0];
+ }
+ get EndPoint() {
+ return arrayLast(this._PointList);
+ }
+ get StartParam() {
+ return 0;
+ }
+ get EndParam() {
+ return this._PointList.length - 1;
+ }
+ GetGripPoints() {
+ return this._PointList.map(p => p.clone().applyMatrix4(this.OCS));
+ }
+ GetStretchPoints() {
+ return this.GetGripPoints();
+ }
+ MoveGripPoints(indexList, vec) {
+ this.WriteAllObjectRecord();
+ for (let index of indexList) {
+ this._PointList[index].add(vec);
+ }
+ this.Update();
+ }
+ MoveStretchPoints(indexList, vec) {
+ this.WriteAllObjectRecord();
+ for (let index of indexList) {
+ this._PointList[index].add(vec);
+ }
+ this.Update();
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ switch (snapMode) {
+ case ObjectSnapMode.End:
+ return this.GetStretchPoints();
+ case ObjectSnapMode.Mid:
+ case ObjectSnapMode.Nea:
+ case ObjectSnapMode.Ext:
+ case ObjectSnapMode.Cen:
+ case ObjectSnapMode.Per:
+ case ObjectSnapMode.Tan:
+ }
+ return [];
+ }
+ InitDrawObject(renderType = RenderType.Wireframe) {
+ let geometry = new three.BufferGeometry().setFromPoints(this.Curve3.getPoints(60));
+ return new three.Line(geometry, ColorMaterial.GetLineMaterial(this._Color));
+ }
+ UpdateDrawObject(type, en) {
+ let spl = en;
+ if (this.CloseMark && !equalv3(this._PointList[0], arrayLast(this._PointList)))
+ this._PointList.push(this._PointList[0].clone());
+ let curve = this.Curve3;
+ let pts = curve.getPoints(this.Points.length * 10);
+ if (!BufferGeometryUtils.UpdatePts(spl.geometry, pts)) {
+ spl.geometry.dispose();
+ spl.geometry = BufferGeometryUtils.CreateFromPts(pts);
+ }
+ }
+ Convert2Polyline(count = 0) {
+ let curve3 = this.Curve3;
+ //修正个数
+ if (!count)
+ count = Math.floor(curve3.getLength() / 30);
+ count = three.MathUtils.clamp(count, this._PointList.length * 5, this._PointList.length * 20);
+ if ((count & 1) === 1)
+ count++;
+ let pts = curve3.getPoints(count);
+ let isClose = this.IsClose;
+ if (isClose)
+ pts.pop();
+ let pl = Pts2Polyline(pts, isClose);
+ pl.CloseMark = isClose;
+ pl.ApplyMatrix(this.OCS);
+ return pl;
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read(); //1
+ let count = file.Read();
+ this._PointList.length = 0;
+ for (let i = 0; i < count; i++)
+ this._PointList.push(new three.Vector3().fromArray(file.Read()));
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(1); //ver
+ file.Write(this._PointList.length);
+ this._PointList.forEach(p => file.Write(p.toArray()));
+ }
+};
+Spline = __decorate([
+ Factory
+], Spline);
+
+var ExtrudeSolid_1;
+let ExtrudeSolid = ExtrudeSolid_1 = class ExtrudeSolid extends Entity {
+ constructor() {
+ super();
+ /*
+ ------------
+ | |
+ | |
+ | | height
+ | |
+ | |
+ ----width---
+ */
+ this.height = 1; //y
+ this.width = 1; //x
+ /**
+ * 拉伸实体的厚度
+ * 我们允许它是一个负数,但是这个时候这个实体已经是一个无效的拉伸实体了.
+ * 允许负数,用来校验凹槽的合理性.
+ */
+ this.thickness = 1;
+ this.isRect = true;
+ this.IsKnife = false;
+ /**
+ * 正面和反面的凹槽造型
+ */
+ this.grooves = [];
+ this.knifeRadius = 3;
+ this.groovesAddLength = 0;
+ this.groovesAddWidth = 0;
+ this.groovesAddDepth = 0;
+ this.RelevanceKnifs = this.CreateProxyArray((v) => {
+ //可以更新自己,但是不建议,建议手动更新
+ });
+ this.RelevanceMeats = this.CreateProxyArray((v) => {
+ //可以更新肉,简单是不建议,建议手动更新
+ });
+ }
+ get KnifeRadius() {
+ return this.knifeRadius;
+ }
+ set KnifeRadius(v) {
+ if (!equaln(v, this.knifeRadius)) {
+ this.WriteAllObjectRecord();
+ this.knifeRadius = v;
+ }
+ }
+ get BoundingBox() {
+ return this.BoundingBoxInOCS.applyMatrix4(this.OCS);
+ }
+ get BoundingBoxInOCS() {
+ return new Box3Ext(new three.Vector3(), new three.Vector3(this.width, this.height, this.thickness));
+ }
+ get OBB() {
+ return new OBB(this.OCS, new three.Vector3(this.width, this.height, this.thickness).multiplyScalar(0.5));
+ }
+ get GroovesAddLength() {
+ return this.groovesAddLength;
+ }
+ set GroovesAddLength(v) {
+ if (!equaln(v, this.groovesAddLength)) {
+ this.WriteAllObjectRecord();
+ this.groovesAddLength = v;
+ }
+ }
+ get GroovesAddWidth() {
+ return this.groovesAddWidth;
+ }
+ set GroovesAddWidth(v) {
+ if (!equaln(v, this.groovesAddWidth)) {
+ this.WriteAllObjectRecord();
+ this.groovesAddWidth = v;
+ }
+ }
+ get GroovesAddDepth() {
+ return this.groovesAddDepth;
+ }
+ set GroovesAddDepth(v) {
+ if (!equaln(v, this.groovesAddDepth)) {
+ this.WriteAllObjectRecord();
+ this.groovesAddDepth = v;
+ }
+ }
+ Clone() {
+ let en = super.Clone();
+ return en;
+ }
+ ApplyMatrix(m) {
+ //暂时关闭更新,避免内部实体还没有更新位置时,先更新了实体的Geometry,导致后续没有进行更新
+ let updateBak = this.AutoUpdate;
+ this.AutoUpdate = false;
+ super.ApplyMatrix(m);
+ for (let g of this.grooves)
+ g.ApplyMatrix(m);
+ //由于修改矩阵会导致矩阵错误
+ this.csg = undefined;
+ this.AutoUpdate = updateBak;
+ if (!equaln(m.getMaxScaleOnAxis(), 1))
+ this.Update(UpdateDraw.Geometry);
+ else if (this.AutoUpdate)
+ this.DeferUpdate();
+ return this;
+ }
+ ApplyScaleMatrix(m) {
+ this.WriteAllObjectRecord();
+ let cu = this.ContourCurve;
+ cu.ApplyMatrix(this.OCS);
+ cu.ApplyMatrix(m);
+ cu.ApplyMatrix(this.OCSInv);
+ this.CheckContourCurve();
+ return this;
+ }
+ get Position() {
+ return super.Position;
+ }
+ set Position(p) {
+ let v = p.clone().sub(this.Position);
+ if (equalv3(v, ZeroVec))
+ return;
+ super.Position = p;
+ let m = MoveMatrix(v);
+ for (let g of this.grooves)
+ g.ApplyMatrix(m);
+ //由于修改矩阵会导致bsp错误
+ this.csg = undefined;
+ }
+ get Width() {
+ return this.width;
+ }
+ get Height() {
+ return this.height;
+ }
+ get Thickness() {
+ return this.thickness;
+ }
+ set Thickness(thickness) {
+ if (!equaln(thickness, this.thickness, 1e-3)) {
+ this.WriteAllObjectRecord();
+ if (this.grooves.length > 0) {
+ let inv = this.OCSInv;
+ let v = this.Normal.multiplyScalar(thickness - this.thickness);
+ let m = new three.Matrix4().setPosition(v);
+ for (let g of this.grooves) {
+ let p = g.Position.applyMatrix4(inv);
+ if (equaln(g.thickness, this.thickness))
+ g.Thickness = thickness;
+ else if (!equaln(p.z, 0))
+ g.ApplyMatrix(m);
+ }
+ }
+ this.thickness = thickness;
+ this.Update(UpdateDraw.Geometry);
+ }
+ }
+ get Grooves() {
+ return this.grooves;
+ }
+ /**
+ * 返回未拷贝的轮廓曲线
+ */
+ get ContourCurve() {
+ if (!this.contourCurve)
+ this.GeneralRectContour();
+ return this.contourCurve;
+ }
+ set ContourCurve(cu) {
+ this.SetContourCurve(cu);
+ }
+ /**
+ * 生成矩形轮廓(强制)
+ */
+ GeneralRectContour() {
+ if (!this.contourCurve || !(this.contourCurve instanceof exports.Polyline))
+ this.contourCurve = new exports.Polyline();
+ this.contourCurve.Rectangle(this.width, this.height);
+ this.contourCurve.OCS = IdentityMtx4;
+ this.ContourCurve = this.contourCurve;
+ }
+ /**
+ * 转换成矩形拉伸实体
+ */
+ ConverToRectSolid(width = this.width, height = this.height, thickness = this.thickness) {
+ this.WriteAllObjectRecord();
+ this.height = height;
+ this.width = width;
+ this.thickness = thickness;
+ this.isRect = true;
+ this.GeneralRectContour();
+ return this;
+ }
+ /**
+ * 更新拉伸实体的轮廓
+ * @param curve 曲线已经存在WCS坐标系
+ */
+ SetContourCurve(curve) {
+ if (!curve.IsClose)
+ return;
+ let area = curve.Area;
+ if (!area || equaln(area, 0))
+ return;
+ if (curve instanceof Spline || curve instanceof Ellipse)
+ curve = curve.Convert2Polyline();
+ if (curve instanceof exports.Polyline) {
+ curve.CloseMark = true;
+ let pts = curve.LineData;
+ if (equalv2(pts[0].pt, arrayLast(pts).pt))
+ pts.pop();
+ //如果曲线被旋转了,那么修正它的旋转矩阵,避免纹路错误
+ let ocs = curve.OCS;
+ let isMirror = equaln(ocs.elements[10], -1, 1e-4);
+ let isRotate = !equaln(ocs.elements[0], 1);
+ if (isMirror || isRotate) // || ocs.elements[9] || ocs.elements[10]
+ {
+ for (let p of pts) {
+ Vector2ApplyMatrix4(ocs, p.pt);
+ if (isMirror)
+ p.bul *= -1;
+ }
+ curve.OCS = IdentityMtx4;
+ }
+ }
+ else {
+ curve.OCS = new three.Matrix4().setPosition(curve.Position);
+ }
+ curve.ClearDraw();
+ this.WriteAllObjectRecord();
+ this.contourCurve = curve;
+ this.CheckContourCurve();
+ this.Update();
+ }
+ /**
+ * 在不改变Normal和实体显示的情况下,修改X轴的指向
+ * @param xAxis
+ */
+ SetXAxis(xAxis) {
+ let m = this.OCSInv.setPosition(ZeroVec);
+ let x = xAxis.applyMatrix4(m).setZ(0).normalize();
+ if (equalv3(ZeroVec, x))
+ return this;
+ this.WriteAllObjectRecord();
+ let a = Math.atan2(x.y, x.x);
+ m.copy(this._Matrix).setPosition(ZeroVec);
+ x.applyMatrix4(m);
+ let z = this.Normal;
+ let y = z.cross(x);
+ this._Matrix.elements[0] = x.x;
+ this._Matrix.elements[1] = x.y;
+ this._Matrix.elements[2] = x.z;
+ this._Matrix.elements[4] = y.x;
+ this._Matrix.elements[5] = y.y;
+ this._Matrix.elements[6] = y.z;
+ m.makeRotationZ(-a);
+ this.contourCurve.ApplyMatrix(m);
+ this.CheckContourCurve();
+ if (this.contourCurve instanceof exports.Polyline)
+ this.contourCurve.UpdateMatrixTo(m.identity());
+ return this;
+ }
+ /**
+ * 检验轮廓曲线,通常当轮廓曲线被修改时,都需要检验轮廓曲线,并更新实体大小和轮廓位置.
+ * >计算轮廓大小
+ * >判断是否矩形
+ * >修正轮廓基点
+ */
+ CheckContourCurve() {
+ let box = this.ContourCurve.BoundingBox;
+ let size = box.getSize(new three.Vector3());
+ this.width = size.x;
+ this.height = size.y;
+ if (equaln(size.x, 0) || equaln(size.y, 0))
+ Log(`注意!!该板件尺寸为0!`);
+ this.isRect = equaln(this.width * this.height, this.ContourCurve.Area, 1);
+ //修正轮廓基点
+ if (!equalv3(box.min, ZeroVec)) {
+ this.contourCurve.Position =
+ this.contourCurve.Position.sub(box.min);
+ let v = box.min.applyMatrix4(this.OCS.setPosition(ZeroVec));
+ this._Matrix.setPosition(this.Position.add(v));
+ }
+ }
+ get IsRect() {
+ return this.isRect;
+ }
+ /**
+ * 这个拉伸实体的面域形状
+ */
+ get Shape() {
+ let contour = Contour.CreateContour(this.ContourCurve.Clone(), false);
+ let holes = [];
+ for (let g of this.grooves) {
+ if (equaln(g.thickness, this.thickness))
+ holes.push(Contour.CreateContour(g.ContourCurve.Clone().ApplyMatrix(this.OCSInv.multiply(g.OCS)), false));
+ }
+ return new Shape(contour, holes);
+ }
+ /**
+ * 实体合并(不会删除target)
+ */
+ Join(target) {
+ let [n, tn] = [this.Normal, target.Normal];
+ if (!isParallelTo(n, tn))
+ return Status.False;
+ let isEqualNorm = equalv3(n, tn);
+ let targetZMin = target.Position.applyMatrix4(this.OCSInv).z;
+ let targetZMax = targetZMin + target.Thickness * (isEqualNorm ? 1 : -1);
+ [targetZMin, targetZMax] = arraySortByNumber([targetZMin, targetZMax]);
+ const MergeRelevance = () => {
+ if (!this.Id || !target.Id)
+ return;
+ for (let kf of target.RelevanceKnifs) {
+ let kfBr = kf.Object;
+ if (!kfBr)
+ continue;
+ if (!kfBr.RelevanceMeats.includes(this.Id))
+ kfBr.RelevanceMeats.push(this.Id);
+ if (!this.RelevanceKnifs.includes(kf))
+ this.RelevanceKnifs.push(kf);
+ }
+ for (let meat of target.RelevanceMeats) {
+ let meatBr = meat.Object;
+ if (!meatBr)
+ continue;
+ if (!meatBr.RelevanceKnifs.includes(this.Id))
+ meatBr.RelevanceKnifs.push(this.Id);
+ if (!this.RelevanceMeats.includes(meat))
+ this.RelevanceMeats.push(meat);
+ }
+ };
+ if (equaln(this.thickness, target.thickness)
+ && equaln(0, targetZMin)) {
+ let matrixToLocal = this.OCSInv.multiply(target.OCS);
+ let thisShape = this.Shape;
+ let targetShape = target.Shape.ApplyMatrix(matrixToLocal);
+ let unionShapes = thisShape.UnionBoolOperation(targetShape);
+ if (unionShapes.length === 1) {
+ this.WriteAllObjectRecord();
+ // [ + ] 产生网洞.
+ for (let hole of unionShapes[0].Holes) {
+ let g = new ExtrudeSolid_1();
+ g.thickness = this.thickness;
+ g.ContourCurve = hole.Curve;
+ g.ApplyMatrix(this.OCS);
+ this.AppendGroove(g);
+ }
+ this.ContourCurve = unionShapes[0].Outline.Curve;
+ this.grooves.push(...target.grooves.map(g => g.Clone()));
+ MergeRelevance();
+ this.GrooveCheckMerge();
+ this.Update();
+ return Status.True;
+ }
+ }
+ else {
+ if (!isIntersect(0, this.thickness, targetZMin, targetZMax, 1e-5))
+ return Status.False;
+ let matrixToLocal = this.OCSInv.multiply(target.OCS);
+ let thisCurve = this.ContourCurve;
+ let targetCurve = target.ContourCurve.Clone().ApplyMatrix(matrixToLocal);
+ targetCurve.Position = targetCurve.Position.setZ(0);
+ if (equalCurve(thisCurve, targetCurve)) {
+ this.WriteAllObjectRecord();
+ if (targetZMin < 0)
+ this.Position = this.Position.add(n.multiplyScalar(targetZMin));
+ this.Thickness = Math.max(this.Thickness, targetZMax) - Math.min(0, targetZMin);
+ this.grooves.push(...target.grooves.map(g => g.Clone()));
+ MergeRelevance();
+ this.GrooveCheckMerge();
+ this.Update();
+ return Status.True;
+ }
+ }
+ return Status.False;
+ }
+ get Volume() {
+ let sum = this.ContourCurve.Area * this.thickness;
+ for (let g of this.grooves)
+ sum -= g.Volume;
+ return sum;
+ }
+ /**
+ * 被切割
+ * @param extrudes 切割刀
+ * @param [output=undefined] 如果实体被分裂,那么输出分裂的其他实体(如果为空,则尝试入当前实体的容器中)
+ * @param [checkIntersect=true] 检查相交,性能优化
+ * @returns 切割是否成功
+ */
+ Subtract(extrudes, output = undefined, checkIntersect = true) {
+ if (checkIntersect) {
+ let box = this.BoundingBox;
+ extrudes = extrudes.filter(e => box.intersectsBox(e.BoundingBox));
+ }
+ //清除原先的关联关系
+ if (this.Id) {
+ let ids = new Set();
+ for (let e of extrudes) {
+ if (!e.Id)
+ continue;
+ arrayRemoveOnce(e.RelevanceMeats, this.Id);
+ ids.add(e.Id.Index);
+ }
+ arrayRemoveIf(this.RelevanceKnifs, id => ids.has(id.Index));
+ }
+ let grooves = [];
+ for (let br of extrudes) {
+ let gs = this.ConverToLocalGroove(br);
+ grooves.push(...gs);
+ }
+ let area1 = this.ContourCurve.Area;
+ let sum1 = this.Volume;
+ this.AppendGrooves(grooves, output);
+ let sum2 = this.Volume;
+ let area2 = this.ContourCurve.Area;
+ if (!equaln(sum1, sum2) || !equaln(area1, area2)) {
+ if (!this.ReadFileIng && this instanceof Board) {
+ if (this.Id)
+ Log(`${this.Name}(${this.Id.Index})被切割成功!`);
+ else if (this.__OriginalId__)
+ Log(`${this.Name}(${this.__OriginalId__.Index})关联切割成功更新槽!`);
+ }
+ return true;
+ }
+ return false;
+ }
+ RelevanceSubtract(knif, check = false) {
+ if (!this.Id || !knif.Id)
+ return;
+ //判断是否已经存在
+ if (check) {
+ let index = this.RelevanceKnifs.findIndex(id => id.Index === knif.Id.Index);
+ if (index !== -1)
+ return;
+ }
+ this.RelevanceKnifs.push(knif.Id);
+ knif.RelevanceMeats.push(this.Id);
+ }
+ /**
+ * 当实体被分裂后,加入新图纸时,需要修复关联拉槽
+ */
+ RepairRelevance() {
+ if (!this.Id) {
+ console.error("不能修复未加入到图纸的板件!");
+ return;
+ }
+ for (let id of this.RelevanceKnifs) {
+ if (id && !id.IsErase) {
+ let br = id.Object;
+ br.RelevanceMeats.push(this.Id);
+ }
+ }
+ for (let id of this.RelevanceMeats) {
+ if (id && !id.IsErase) {
+ let br = id.Object;
+ br.RelevanceKnifs.push(this.Id);
+ }
+ }
+ }
+ AppendGroove(groove) {
+ this.WriteAllObjectRecord();
+ this.grooves.push(groove);
+ }
+ /** 添加槽进板件,并且自动分裂.
+ * 通常槽已经校验过准确性,所以不在校验
+ */
+ AppendGrooves(grooves, output = undefined) {
+ if (grooves.length === 0)
+ return;
+ this.WriteAllObjectRecord();
+ this.grooves.push(...grooves);
+ this.GrooveCheckAllAutoSplit(output);
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ switch (snapMode) {
+ case ObjectSnapMode.End:
+ return this.GetStretchPoints();
+ case ObjectSnapMode.Mid:
+ case ObjectSnapMode.Cen:
+ case ObjectSnapMode.Nea:
+ case ObjectSnapMode.Ext:
+ case ObjectSnapMode.Per:
+ case ObjectSnapMode.Tan:
+ {
+ let contour = this.ContourCurve.Clone();
+ contour.ApplyMatrix(this.OCS);
+ let pts = contour.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform);
+ contour.Position = contour.Position.add(this.Normal.multiplyScalar(this.thickness));
+ pts.push(...contour.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ let ps = this.contourCurve.GetStretchPoints();
+ for (let p of ps) {
+ let l = new exports.Line(p, p.clone().setZ(this.thickness));
+ l.ApplyMatrix(this.OCS);
+ pts.push(...l.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ }
+ for (let g of this.grooves)
+ pts.push(...g.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ return pts;
+ }
+ }
+ return [];
+ }
+ //#region Stretch
+ GetStrectchPointCountList(dragType) {
+ let counts = [this.ContourCurve.GetDragPointCount(dragType) * 2];
+ for (let g of this.grooves) {
+ let c = g.ContourCurve.GetDragPointCount(dragType) * 2;
+ for (let g1 of g.grooves)
+ c += g1.contourCurve.GetDragPointCount(dragType) * 2;
+ counts.push(c);
+ }
+ return counts;
+ }
+ GetGripOrStretchPoints(dragType) {
+ let isGrip = dragType === DragPointType.Grip;
+ let pts = isGrip ? this.ContourCurve.GetGripPoints() : this.ContourCurve.GetStretchPoints();
+ let v = new three.Vector3(0, 0, this.thickness);
+ pts.push(...pts.map(p => p.clone().add(v)));
+ pts.forEach(p => { p.applyMatrix4(this.OCS); });
+ for (let g of this.grooves) {
+ let gpts = g.GetGripOrStretchPoints(dragType);
+ pts.push(...gpts);
+ }
+ return pts;
+ }
+ MoveGripOrStretchPoints(indexList, vec, dragType) {
+ this.WriteAllObjectRecord();
+ let counts = this.GetStrectchPointCountList(dragType);
+ if (dragType === DragPointType.Stretch && indexList.length === arraySum(counts)) {
+ this.Position = this.Position.add(vec);
+ return;
+ }
+ arraySortByNumber(indexList);
+ let updateBak = this.AutoUpdate;
+ this.AutoUpdate = false;
+ if (this.grooves.length === 0) {
+ this.MoveGripOrStretchPointsOnly(indexList, vec, dragType);
+ }
+ else {
+ let i = 0;
+ let icount = indexList.length;
+ let offset = 0;
+ let grooveIndex = -1;
+ for (let count of counts) {
+ offset += count;
+ let ilist = [];
+ for (; i < icount; i++) {
+ if (indexList[i] < offset)
+ ilist.push(indexList[i] - offset + count);
+ else
+ break;
+ }
+ if (ilist.length > 0) {
+ if (grooveIndex === -1)
+ this.MoveGripOrStretchPointsOnly(ilist, vec, dragType);
+ else
+ this.grooves[grooveIndex].MoveGripOrStretchPoints(ilist, vec, dragType);
+ }
+ grooveIndex++;
+ }
+ }
+ if (this.objectId) {
+ this.CheckContourCurve();
+ let splitEntitys = [];
+ this.GrooveCheckAll(splitEntitys);
+ if (splitEntitys.length > 0 && this.Owner) {
+ let ms = this.Owner.Object;
+ for (let e of splitEntitys)
+ ms.Append(e);
+ }
+ }
+ this.AutoUpdate = updateBak;
+ this.Update();
+ }
+ GetGripPoints() {
+ return this.GetGripOrStretchPoints(DragPointType.Grip);
+ }
+ MoveGripPoints(indexList, vec) {
+ this.MoveGripOrStretchPoints(indexList, vec, DragPointType.Grip);
+ }
+ GetStretchPoints() {
+ return this.GetGripOrStretchPoints(DragPointType.Stretch);
+ }
+ MoveStretchPoints(indexList, vec) {
+ this.MoveGripOrStretchPoints(indexList, vec, DragPointType.Stretch);
+ }
+ /**
+ * 只对自身的轮廓和厚度进行拉伸,忽略子实体
+ */
+ MoveGripOrStretchPointsOnly(indexList, vec, dragType) {
+ let stretchCount = this.ContourCurve.GetDragPointCount(dragType);
+ if (dragType === DragPointType.Stretch) {
+ //Move
+ if (indexList.length === stretchCount * 2) {
+ this.Position = this.Position.add(vec);
+ return;
+ }
+ //判断是否拉伸厚度
+ if (this.IsStretchThickness(indexList)) {
+ let isFront = indexList[0] < stretchCount;
+ if (indexList.every(v => v < stretchCount === isFront)) {
+ //Change thickness
+ let lvec = vec.clone().applyMatrix4(this.OCSInv.setPosition(ZeroVec));
+ if (isFront) {
+ // if (lvec.z >= this.thickness) return;
+ this.thickness -= lvec.z;
+ //移动位置而不改变内部拉槽
+ let v = this.Normal.multiplyScalar(lvec.z);
+ this._Matrix.elements[12] += v.x;
+ this._Matrix.elements[13] += v.y;
+ this._Matrix.elements[14] += v.z;
+ }
+ else {
+ // if (-lvec.z > this.thickness) return;
+ this.thickness += lvec.z;
+ }
+ return;
+ }
+ }
+ indexList = arrayClone(indexList);
+ }
+ //修正点的索引
+ for (let i = 0; i < indexList.length; i++) {
+ let index = indexList[i];
+ if (index >= stretchCount) {
+ index -= stretchCount;
+ indexList[i] = index;
+ }
+ }
+ indexList = [...new Set(indexList)];
+ let localVec = vec.clone().applyMatrix4(this.OCSInv.setPosition(ZeroVec));
+ if (dragType === DragPointType.Grip) {
+ if (this.ContourCurve instanceof exports.Polyline
+ && indexList.length === 1
+ && indexList[0] % 2 === 1) {
+ let param = indexList[0] / 2;
+ if (this.ContourCurve.GetBuilgeAt(Math.floor(param)) === 0) {
+ let der = this.ContourCurve.GetFistDeriv(param).normalize();
+ [der.x, der.y] = [der.y, -der.x];
+ let d = localVec.dot(der);
+ localVec.copy(der).multiplyScalar(d);
+ }
+ }
+ this.ContourCurve.MoveGripPoints(indexList, localVec);
+ }
+ else
+ this.ContourCurve.MoveStretchPoints(indexList, localVec);
+ }
+ IsStretchThickness(indexs) {
+ let count = this.ContourCurve.GetStretchPoints().length;
+ if (indexs.length === count) {
+ let isF = indexs[0] < count;
+ return indexs.every(i => isF === (i < count));
+ }
+ return false;
+ }
+ get CSG() {
+ if (this.csg)
+ return this.csg;
+ this.csg = Geometry2CSG(this.MeshGeometry);
+ return this.csg;
+ }
+ /**
+ * (步骤1.2.)
+ * 将目标拉伸实体转换成在板件内部可用的凹槽实体
+ * @param target 该对象可能被修改(内部不拷贝该实体)
+ * @param useClone 转换后的实体是目标实体拷贝后修改的
+ */
+ ConverToLocalGroove(target) {
+ if (!this.OBB.intersectsOBB(target.OBB))
+ return [];
+ let n1 = this.Normal;
+ let n2 = target.Normal;
+ if (isParallelTo(n1, n2)) {
+ target = target.Clone().ClearDraw();
+ if (!equalv3(n1, n2, 1e-6)) {
+ let mtx = target._Matrix;
+ matrixSetVector(mtx, 2, n1);
+ let p = n1.setFromMatrixColumn(mtx, 3);
+ p.add(n2.multiplyScalar(target.thickness));
+ matrixSetVector(mtx, 3, p);
+ }
+ if (this.GrooveCheckPosition(target) !== Status.True)
+ return [];
+ return [target];
+ }
+ else {
+ let grooves = [];
+ let project = ProjectBoard(target, this);
+ if (!project) {
+ let yv = target.Normal;
+ let zv = this.Normal;
+ let xv = yv.clone().cross(zv);
+ yv.copy(zv).cross(xv);
+ let m = new three.Matrix4().makeBasis(xv, yv, zv).copyPosition(this.OCS);
+ let mi = new three.Matrix4().getInverse(m).multiply(this.OCS);
+ let interBSP = this.CSG.intersect(target.CSG.transform1(this.OCSInv.multiply(target.OCS)));
+ let topology = new BSPGroupParse(interBSP);
+ let grooves = [];
+ for (let pts of topology.Parse()) {
+ for (let p of pts)
+ p.applyMatrix4(mi);
+ let box = new Box3Ext().setFromPoints(pts);
+ if (!box.isSolid(0.1))
+ continue;
+ let size = box.getSize(new three.Vector3());
+ let ext = new ExtrudeSolid_1();
+ ext.groovesAddDepth = target.groovesAddDepth;
+ ext.groovesAddLength = target.groovesAddLength;
+ ext.groovesAddWidth = target.groovesAddWidth;
+ ext.knifeRadius = target.knifeRadius;
+ ext.ConverToRectSolid(size.x, size.y, size.z);
+ ext.OCS = m.clone().setPosition(box.min.applyMatrix4(m));
+ grooves.push(ext);
+ }
+ return grooves;
+ }
+ // project.ApplyMatrix(target.OCSInv);
+ project.Z0();
+ let c1 = Contour.CreateContour(project);
+ let c2 = Contour.CreateContour(target.ContourCurve);
+ //投影轮廓列表
+ let contours = c1.IntersectionBoolOperation(c2);
+ let outlines = [];
+ for (let c of contours) {
+ if (c.Curve instanceof exports.Polyline)
+ outlines.push(...PolylineSpliteRect(c.Curve));
+ else
+ outlines.push(c.Curve);
+ }
+ let xv = this.Normal;
+ let zv = target.Normal;
+ let yv = zv.clone().cross(xv);
+ //把<投影轮廓>对齐到肉的侧面坐标系上
+ let projection2SideMatrix4 = new three.Matrix4().makeBasis(xv, yv, zv);
+ for (let c of outlines) {
+ let g = target.Clone().ClearDraw();
+ let gs = [g];
+ g.ContourCurve = c;
+ g.GrooveCheckAll(gs);
+ for (let g1 of gs) {
+ //按g1的位置设置
+ projection2SideMatrix4.setPosition(g1.Position);
+ //投影到肉的侧面坐标系,求槽在肉里面的长度(x)和厚度(z)
+ let alm = new three.Matrix4().getInverse(projection2SideMatrix4).multiply(g1.OCS);
+ g1.ContourCurve.ApplyMatrix(alm); //破坏它
+ let box = g1.ContourCurve.BoundingBox;
+ let size = box.getSize(new three.Vector3);
+ if (equaln(size.x, 0, 1e-2) || equaln(size.y, 0, 1e-2))
+ continue;
+ //构造新槽
+ let g2 = new ExtrudeSolid_1().ConverToRectSolid(size.y, g1.Thickness, size.x);
+ g2.groovesAddDepth = target.groovesAddDepth;
+ g2.groovesAddLength = target.groovesAddLength;
+ g2.groovesAddWidth = target.groovesAddWidth;
+ g2.knifeRadius = target.knifeRadius;
+ g2.ApplyMatrix(OverturnMatrix); //翻转到和原先的投影曲线(肉侧面)一样的状态
+ g2.ApplyMatrix(MoveMatrix(box.min)); //和投影曲线重叠
+ g2.ApplyMatrix(projection2SideMatrix4); //按照矩形还原回去
+ grooves.push(g2);
+ }
+ }
+ return grooves;
+ }
+ }
+ /**
+ * (步骤2)
+ * 更新凹槽位置和厚度(校验凹槽的Z轴位置是否存在交集)
+ */
+ GrooveCheckPosition(target) {
+ if (target.Width < 1e-2 || target.Height < 1e-2 || target.Thickness < 1e-2)
+ return Status.False;
+ let tp = target.Position.applyMatrix4(this.OCSInv);
+ let minZ = tp.z;
+ let maxZ = tp.z + target.thickness;
+ if (minZ <= 1e-2) //背面
+ {
+ target.Thickness = Math.min(maxZ, this.thickness);
+ if (!(equaln(minZ, 0)))
+ target.ApplyMatrix(MoveMatrix(this.Normal.multiplyScalar(-minZ)));
+ }
+ else if (maxZ >= (this.thickness - 1e-3) && minZ > 0) //正面
+ target.Thickness = this.thickness - minZ;
+ else
+ return Status.False;
+ return target.thickness > 0 ? Status.True : Status.False;
+ }
+ /**
+ * (步骤3)
+ * 计算凹槽合并
+ */
+ GrooveCheckMerge() {
+ let gs = [];
+ while (this.grooves.length > 0) {
+ let g = this.grooves.pop();
+ while (this.grooves.length > 0) {
+ //剩余的 无法合并的板件
+ let remGs = this.grooves.filter(gn => {
+ if (equaln(g.knifeRadius, gn.knifeRadius))
+ return g.Join(gn) === Status.False;
+ else
+ return true;
+ });
+ if (remGs.length === this.grooves.length)
+ break;
+ this.grooves = remGs;
+ }
+ gs.push(g);
+ }
+ if (gs.length !== this.grooves.length) {
+ this.grooves = gs;
+ for (let g of this.grooves)
+ g.CheckContourCurve();
+ }
+ }
+ /**
+ * (步骤4.1)
+ * 计算凹槽轮廓(可能分裂)
+ * @param target 不拷贝修改
+ * @returns this[] 凹槽在本实体中正确的约束状态.(可能分裂成为多个)
+ */
+ GrooveCheckContour(target) {
+ let matrixToTarget = target.OCSInv.multiply(this.OCS);
+ matrixToTarget.elements[14] = 0; //z->0
+ let thisShape = this.Shape.ApplyMatrix(matrixToTarget);
+ let targetShape = new Shape(Contour.CreateContour([target.ContourCurve.Clone()], false));
+ let inters = thisShape.IntersectionBoolOperation(targetShape);
+ if (inters.length === 1) {
+ target.ContourCurve = inters[0].Outline.Curve;
+ let grooves = [target];
+ target.GrooveCheckAll(grooves);
+ return grooves;
+ }
+ else {
+ let grooves = [];
+ for (let contour of inters) {
+ let ext = target.Clone().ClearDraw();
+ ext.ContourCurve = contour.Outline.Curve;
+ ext.GrooveCheckAll(grooves);
+ grooves.push(ext);
+ }
+ return grooves;
+ }
+ }
+ /**
+ * (步骤4.2)
+ * 计算本实体被全身度的凹槽差集后正确的实体轮廓,和有可能的分裂实体
+ * @param splitEntitys 分裂出来的实体
+ * @returns [Status] Status : 消失不见
+ */
+ ContourCheckSubtract(splitEntitys) {
+ let shapeManager = new ShapeManager();
+ shapeManager.AppendShapeList(new Shape(Contour.CreateContour(this.ContourCurve.Clone(), false)));
+ let subtractShape = new ShapeManager();
+ let grooves = [];
+ arrayRemoveIf(this.grooves, groove => {
+ if (equaln(groove.thickness, this.thickness)) {
+ let grooveCurve = groove.ContourCurve.Clone();
+ let matrixToLocal = this.OCSInv.multiply(groove.OCS);
+ grooveCurve.ApplyMatrix(matrixToLocal);
+ subtractShape.AppendShapeList(new Shape(Contour.CreateContour([grooveCurve], false)));
+ grooves.push(groove);
+ return true;
+ }
+ return false;
+ });
+ shapeManager.SubstactBoolOperation(subtractShape);
+ let shapes = shapeManager.ShapeList;
+ //不做任何改变
+ if (shapeManager.ShapeCount === 1 && shapes[0].Holes.length === grooves.length) {
+ this.grooves.push(...grooves);
+ return true;
+ }
+ //分裂
+ for (let i = 1; i < shapeManager.ShapeCount; i++) {
+ let ext = this.Clone();
+ let shape = shapes[i];
+ for (let hole of shape.Holes) {
+ let groove = new ExtrudeSolid_1();
+ groove.OCS = this.OCS;
+ groove.ContourCurve = hole.Curve;
+ groove.thickness = this.thickness;
+ ext.grooves.push(groove);
+ }
+ ext.ContourCurve = shape.Outline.Curve;
+ ext.GrooveCheckAll(splitEntitys);
+ ext.Update();
+ splitEntitys.push(ext);
+ }
+ if (shapes.length > 0) {
+ let shape = shapes[0];
+ for (let hole of shape.Holes) {
+ let groove = new ExtrudeSolid_1();
+ groove.OCS = this.OCS;
+ groove.ContourCurve = hole.Curve;
+ groove.thickness = this.thickness;
+ this.grooves.push(groove);
+ }
+ if (!equaln(this.contourCurve.Area, shape.Outline.Area))
+ this.ContourCurve = shape.Outline.Curve;
+ return true;
+ }
+ else
+ return false;
+ }
+ /**
+ * 无法知道修改了轮廓是否为更新到内部凹槽.
+ * 无法知道修改了内部凹槽之后是否会更新到轮廓.
+ * 所以默认全部校验内部的凹槽
+ */
+ GrooveCheckAll(splitEntitys) {
+ if (this.IsLazyGrooveCheck) {
+ this.IsNeedGrooveCheck = true;
+ return;
+ }
+ this.IsNeedGrooveCheck = false;
+ this.WriteAllObjectRecord();
+ //校验Z轴位置
+ arrayRemoveIf(this.grooves, g => {
+ return this.GrooveCheckPosition(g) === Status.False;
+ });
+ //清除全深洞的子槽
+ for (let g of this.grooves) {
+ if (equaln(g.thickness, this.thickness)) {
+ /*
+ 此刻我们直接将它的子槽清空,虽然子槽可能将这个槽分裂成2个,
+ 但是这样的情况只能在造型应用中才会产生
+ */
+ g.grooves.length = 0;
+ }
+ else
+ arrayRemoveIf(g.grooves, subg => !equaln(g.thickness, subg.thickness));
+ }
+ //合并
+ this.GrooveCheckMerge();
+ //修改本实体轮廓
+ if (this.grooves.some(g => equaln(g.thickness, this.thickness))) {
+ if (!this.ContourCheckSubtract(splitEntitys)) {
+ this.Erase();
+ return;
+ }
+ }
+ //修正凹槽轮廓
+ let splitGrooves = [];
+ let thisArea = this.contourCurve.Area;
+ for (let i = 0; i < this.grooves.length; i++) {
+ let g = this.grooves[i];
+ if (equaln(g.thickness, this.thickness))
+ splitGrooves.push(g);
+ else {
+ let gs = this.GrooveCheckContour(g);
+ if (gs.length === 1) {
+ let gg = gs[0];
+ if (gg.grooves.length === 0 && equaln(gg.contourCurve.Area, thisArea)) {
+ //判断正反面
+ let p = gg.Position.applyMatrix4(this.OCSInv);
+ if (equaln(p.z, 0)) {
+ this.thickness -= gg.thickness;
+ let n = this.Normal;
+ n.multiplyScalar(gg.thickness);
+ this._Matrix.elements[12] += n.x;
+ this._Matrix.elements[13] += n.y;
+ this._Matrix.elements[14] += n.z;
+ }
+ else {
+ this.thickness -= gg.thickness;
+ }
+ this.grooves.splice(i, 1);
+ this.GrooveCheckAll(splitEntitys);
+ return;
+ }
+ }
+ splitGrooves.push(...gs);
+ }
+ }
+ this.grooves = splitGrooves;
+ this.Update();
+ }
+ /** 校验内部槽并且自动分裂 */
+ GrooveCheckAllAutoSplit(output = undefined) {
+ let splitEntitys = [];
+ this.GrooveCheckAll(splitEntitys);
+ if (output)
+ output.push(...splitEntitys);
+ else if (this._Owner) {
+ let record = this._Owner.Object;
+ for (let e of splitEntitys) {
+ record.Add(e);
+ e.RepairRelevance();
+ }
+ this.HandleSpliteEntitys(splitEntitys);
+ }
+ }
+ HandleSpliteEntitys(splitEntitys) { }
+ LazyGrooveCheckAll() {
+ if (this.IsNeedGrooveCheck)
+ this.GrooveCheckAllAutoSplit();
+ this.IsLazyGrooveCheck = false;
+ }
+ //#endregion
+ //#region Draw
+ GetPrintObject3D() {
+ let geometry = new LineGeometry.LineGeometry();
+ let lineSegments = new Float32Array(this.EdgeGeometry.attributes.position.array);
+ let instanceBuffer = new three.InstancedInterleavedBuffer(lineSegments, 6, 1);
+ geometry.setAttribute('instanceStart', new three.InterleavedBufferAttribute(instanceBuffer, 3, 0));
+ geometry.setAttribute('instanceEnd', new three.InterleavedBufferAttribute(instanceBuffer, 3, 3));
+ let line = new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
+ let mesh = new three.Mesh(this.MeshGeometry, ColorMaterial.GetPrintConceptualMaterial());
+ return [line, mesh];
+ }
+ InitDrawObject(renderType = RenderType.Wireframe) {
+ if (renderType === RenderType.Wireframe) {
+ return new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex));
+ }
+ else if (renderType === RenderType.Conceptual) {
+ return new three.Object3D().add(new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ else if (renderType === RenderType.Physical) {
+ let mesh = new three.Mesh(this.MeshGeometry, this.MeshMaterial);
+ mesh.castShadow = true;
+ mesh.receiveShadow = true;
+ return mesh;
+ }
+ else if (renderType === RenderType.Jig) {
+ return new three.Object3D().add(...FastWireframe(this));
+ }
+ else if (renderType === RenderType.Print) {
+ return new three.Object3D().add(...this.GetPrintObject3D());
+ }
+ else if (renderType === RenderType.Physical2) {
+ let mesh = new three.Mesh(this.MeshGeometry, this.MeshMaterial);
+ mesh.castShadow = true;
+ mesh.receiveShadow = true;
+ return new three.Object3D().add(mesh, new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ }
+ get UCGenerator() {
+ return boardUVGenerator;
+ }
+ get NeedUpdateRelevanceGroove() {
+ if (!this.__CacheKnifVersion__)
+ return true;
+ for (let k of this.RelevanceKnifs) {
+ if (!k || !k.Object)
+ continue;
+ if (this.__CacheKnifVersion__[k.Index] !== (k.Object).__UpdateVersion__)
+ return true;
+ }
+ return false;
+ }
+ /**
+ * 计算关联拉槽,更新绘制对象(MeshGeometry和EdgeGeometry)
+ */
+ CalcRelevanceGroove() {
+ var _a, _b, _c, _d, _e, _f;
+ //避免Jig实体更新,导致性能暴跌.
+ if (!this.Id)
+ return;
+ this.__CacheKnifVersion__ = {};
+ let knifs = [];
+ this.GetRelevanceKnifes(knifs);
+ if (knifs.length > 0) {
+ for (let k of knifs) //复合实体(五金)的子实体没有id
+ this.__CacheKnifVersion__[(_b = (_a = k.Id) === null || _a === void 0 ? void 0 : _a.Index) !== null && _b !== void 0 ? _b : (_c = k.__TempIndexVersion__) === null || _c === void 0 ? void 0 : _c.Index] = (_e = (_d = k.__TempIndexVersion__) === null || _d === void 0 ? void 0 : _d.Version) !== null && _e !== void 0 ? _e : k.__UpdateVersion__;
+ let tempExtrude = this.Clone();
+ tempExtrude.RelevanceKnifs.length = 0; //避免递归
+ if (!this.ReadFileIng)
+ tempExtrude.__OriginalId__ = this.Id; //在读取文件时不打印日志
+ let output = [tempExtrude];
+ let ok = tempExtrude.Subtract(knifs, output);
+ this.__CacheSplitExtrudes = output;
+ if (ok) {
+ this.__CacheVolume__ = tempExtrude.Volume;
+ let meshs = [];
+ let edges = [];
+ let inv = this.OCSInv;
+ let diff = new three.Matrix4;
+ for (let e2 of output) {
+ diff.multiplyMatrices(inv, e2._Matrix);
+ meshs.push(e2.MeshGeometry.applyMatrix4(diff));
+ edges.push(e2.EdgeGeometry.applyMatrix4(diff));
+ this.__CacheVolume__ += e2.Volume;
+ }
+ if (output.length === 1) {
+ this._MeshGeometry = tempExtrude.MeshGeometry;
+ this._EdgeGeometry = tempExtrude.EdgeGeometry;
+ }
+ else {
+ this._MeshGeometry = BufferGeometryUtils.MergeBufferGeometries(meshs);
+ this._MeshGeometry["IsMesh"] = true;
+ this._EdgeGeometry = BufferGeometryUtils.MergeBufferGeometries(edges);
+ }
+ //我们加入一些拓展信息,以便排钻能够使用(或者其他的,比如发送到效果图?,BBS)(布局视口会直接添加实体到场景,所以我们只在这里设置OriginEntity)
+ for (let i = 0; i < this.__CacheSplitExtrudes.length; i++) {
+ this.__CacheSplitExtrudes[i].objectId = new ObjectId(this.Id.Index * -100 - i);
+ this.__CacheSplitExtrudes[i].__OriginalEnt__ = this;
+ }
+ }
+ else {
+ let id = (_f = this.Id) !== null && _f !== void 0 ? _f : this.__OriginalId__;
+ if (!this.ReadFileIng &&
+ id &&
+ this instanceof Board &&
+ this.__CacheVolume__ !== undefined &&
+ !equaln(this.__CacheVolume__, this.Volume))
+ Log(`${this.Name}(${id.Index})关联槽已逃离!`);
+ this.__CacheVolume__ = undefined;
+ this.__CacheSplitExtrudes = [this];
+ }
+ }
+ else {
+ if (!this.ReadFileIng &&
+ this.Id &&
+ this instanceof Board &&
+ this.__CacheVolume__ !== undefined &&
+ !equaln(this.__CacheVolume__, this.Volume))
+ Log(`${this.Name}(${this.Id.Index})关联槽已逃离或者被清除!`);
+ this.__CacheSplitExtrudes = [this];
+ this.__CacheVolume__ = undefined;
+ }
+ }
+ /**
+ * 如果实体被切割,那么将返回分裂的实体数组,否则返回自身
+ */
+ get SplitExtrudes() {
+ if (this.NeedUpdateRelevanceGroove)
+ this.Update(UpdateDraw.Geometry); //我们先直接更新绘制
+ if (this.NeedUpdateRelevanceGroove) //如果更新失败,那么我们更新这个槽(似乎也证明了我们没有绘制实体)
+ this.CalcRelevanceGroove(); //注意,这也将更新绘制的实体(EdgeGeo,MeshGeo)(如果拆单也用这个,可能会带来性能损耗)
+ return this.__CacheSplitExtrudes;
+ }
+ GetRelevanceKnifes(knifs) {
+ var _a;
+ for (let e of this.RelevanceKnifs) {
+ if (!e.IsErase)
+ knifs.push(e.Object);
+ else if (this.__CacheKnifVersion__)
+ this.__CacheKnifVersion__[e.Index] = (_a = e === null || e === void 0 ? void 0 : e.Object) === null || _a === void 0 ? void 0 : _a.__UpdateVersion__;
+ }
+ }
+ ClearRelevance(en) {
+ if (en) {
+ let oldLen = this.RelevanceKnifs.length;
+ arrayRemoveIf(this.RelevanceKnifs, id => !(id === null || id === void 0 ? void 0 : id.Object) || id.Index === en.Id.Index);
+ if (this.RelevanceKnifs.length !== oldLen)
+ arrayRemoveIf(en.RelevanceMeats, id => !(id === null || id === void 0 ? void 0 : id.Object) || id.Index === this.Id.Index);
+ oldLen = this.RelevanceMeats.length;
+ arrayRemoveIf(this.RelevanceMeats, id => !(id === null || id === void 0 ? void 0 : id.Object) || id.Index === en.Id.Index);
+ if (oldLen !== this.RelevanceMeats.length)
+ arrayRemoveIf(en.RelevanceKnifs, id => !(id === null || id === void 0 ? void 0 : id.Object) || id.Index === this.Id.Index);
+ }
+ else {
+ for (let id of this.RelevanceKnifs) {
+ let en = id.Object;
+ if (en)
+ arrayRemoveIf(en.RelevanceMeats, i => !(i === null || i === void 0 ? void 0 : i.Object) || i.Index === this.Id.Index);
+ }
+ for (let id of this.RelevanceMeats) {
+ let en = id.Object;
+ if (en) {
+ arrayRemoveIf(en.RelevanceKnifs, i => !(i === null || i === void 0 ? void 0 : i.Object) || i.Index === this.Id.Index);
+ en.Update();
+ }
+ }
+ this.RelevanceMeats.length = 0;
+ this.RelevanceKnifs.length = 0;
+ }
+ this.Update();
+ }
+ get MeshGeometry() {
+ if (this._MeshGeometry)
+ return this._MeshGeometry;
+ if (this.thickness <= 0)
+ return new three.BufferGeometry();
+ this.CalcRelevanceGroove();
+ if (this._MeshGeometry)
+ return this._MeshGeometry;
+ let grooves = this.Grooves;
+ if (grooves.every(g => equaln(g.thickness, this.thickness)) || grooves.length === 0) {
+ let contour = this.ContourCurve.Clone();
+ let holes = [];
+ let ocsInv = this.OCSInv;
+ let alMatrix4 = new three.Matrix4();
+ for (let g of grooves) {
+ alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone);
+ let gContour = g.ContourCurve.Clone();
+ gContour.ApplyMatrix(alMatrix4);
+ holes.push(Contour.CreateContour(gContour));
+ }
+ let shape = new Shape(Contour.CreateContour(contour), holes);
+ let extrudeSettings = {
+ steps: 1,
+ bevelEnabled: false,
+ depth: this.Thickness,
+ UVGenerator: this.UCGenerator,
+ };
+ let geo = new three.ExtrudeGeometry(shape.Shape, extrudeSettings);
+ geo.applyMatrix4(contour.OCSNoClone);
+ this.UpdateUV(geo, contour.OCSNoClone);
+ let bgeo = new three.BufferGeometry().fromGeometry(geo);
+ bgeo["IsMesh"] = true;
+ this._MeshGeometry = bgeo;
+ return bgeo;
+ }
+ let builder = new ExtrudeGeometryBuilder(this);
+ this._MeshGeometry = builder.MeshGeometry;
+ this._EdgeGeometry = builder.EdgeGeometry;
+ this.UpdateUV(null, null);
+ return this._MeshGeometry;
+ }
+ get EdgeGeometry() {
+ if (this._EdgeGeometry)
+ return this._EdgeGeometry;
+ this.CalcRelevanceGroove();
+ if (this._EdgeGeometry)
+ return this._EdgeGeometry;
+ if (this.grooves.every(g => equaln(g.thickness, this.thickness)) || this.grooves.length === 0) {
+ let pts = [this.ContourCurve.Shape.getPoints(6).map(AsVector3)];
+ let ocsInv = this.OCSInv;
+ let alMatrix4 = new three.Matrix4();
+ for (let g of this.grooves) {
+ alMatrix4.multiplyMatrices(ocsInv, g.OCSNoClone);
+ let gContour = g.ContourCurve.Clone();
+ gContour.ApplyMatrix(alMatrix4);
+ if (gContour instanceof exports.Polyline)
+ gContour.UpdateMatrixTo(this.contourCurve.OCS);
+ if (gContour instanceof exports.Circle) {
+ let sp = new three.Path();
+ let cen = gContour.Center.applyMatrix4(this.contourCurve.OCSInv);
+ sp.ellipse(cen.x, cen.y, gContour.Radius, gContour.Radius, 0, 2 * Math.PI, false, 0);
+ pts.push(sp.getPoints(6).map(AsVector3));
+ }
+ else
+ pts.push(gContour.Shape.getPoints(6).map(AsVector3));
+ }
+ let geo = GenerateExtrudeEdgeGeometry(pts, this.thickness).applyMatrix4(this.contourCurve.OCSNoClone);
+ this._EdgeGeometry = geo;
+ return geo;
+ }
+ if (this._MeshGeometry) {
+ this._MeshGeometry.dispose();
+ this._MeshGeometry = undefined;
+ }
+ this.MeshGeometry;
+ return this._EdgeGeometry;
+ }
+ UpdateUV(geo, ocs, isRev = false) {
+ var _a;
+ let mat;
+ if (this.Material && this.Material.Object)
+ mat = this.Material.Object;
+ else
+ mat = (_a = this.Db) === null || _a === void 0 ? void 0 : _a.DefaultMaterial;
+ if (mat && mat.IsFull) {
+ if (geo)
+ ScaleUV2(geo, ocs, this.width, this.height, isRev);
+ else
+ this.UpdateBufferGeometryUvs(isRev);
+ }
+ else {
+ if (geo)
+ ScaleUV(geo);
+ }
+ }
+ UpdateBufferGeometryUvs(isRev) {
+ let uvs = this._MeshGeometry.attributes.uv;
+ for (let i = 0; i < uvs.count; i++) {
+ let x = uvs.getX(i) * 1e3;
+ let y = uvs.getY(i) * 1e3;
+ if (isRev)
+ uvs.setXY(i, x / this.height, y / this.width);
+ else
+ uvs.setXY(i, x / this.width, y / this.height);
+ }
+ }
+ DeferUpdate() {
+ if (this.NeedUpdateFlag & UpdateDraw.Matrix) {
+ //如果是Jig实体,那么就算它有关联切割,我们也不更新实体(因为似乎没必要?)
+ if (this.Id && this.RelevanceKnifs.some(id => !id.IsErase))
+ this.NeedUpdateFlag |= UpdateDraw.Geometry;
+ }
+ super.DeferUpdate();
+ }
+ UpdateDrawGeometry() {
+ this.csg = undefined;
+ if (this._EdgeGeometry)
+ this._EdgeGeometry.dispose();
+ this._EdgeGeometry = undefined;
+ if (this._MeshGeometry)
+ this._MeshGeometry.dispose();
+ this._MeshGeometry = undefined;
+ }
+ UpdateDrawObject(renderType, obj) {
+ DisposeThreeObj(obj);
+ Object3DRemoveAll(obj);
+ if (renderType === RenderType.Wireframe) {
+ let l = obj;
+ l.geometry = this.EdgeGeometry;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (renderType === RenderType.Conceptual) {
+ return obj.add(new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ else if (renderType === RenderType.Physical) {
+ let mesh = obj;
+ mesh.geometry = this.MeshGeometry;
+ mesh.material = this.MeshMaterial;
+ }
+ else if (renderType === RenderType.Jig) {
+ obj.add(...FastWireframe(this));
+ }
+ else if (renderType === RenderType.Print) {
+ return obj.add(...this.GetPrintObject3D());
+ }
+ else if (renderType === RenderType.Physical2) {
+ let mesh = new three.Mesh(this.MeshGeometry, this.MeshMaterial);
+ mesh.castShadow = true;
+ mesh.receiveShadow = true;
+ return obj.add(mesh, new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ }
+ UpdateDrawObjectMaterial(renderType, obj) {
+ if (renderType === RenderType.Wireframe) {
+ let l = obj;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (renderType === RenderType.Conceptual) {
+ let mesh = obj.children[0];
+ mesh.material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
+ }
+ else if (renderType === RenderType.Physical2) {
+ let mesh = obj.children[0];
+ mesh.material = this.MeshMaterial;
+ }
+ else {
+ let mesh = obj;
+ mesh.material = this.MeshMaterial;
+ }
+ }
+ UpdateJigMaterial(color = 8) {
+ }
+ //#endregion
+ //#region -------------------------File-------------------------
+ /**
+ * 简化的文件读取和写入,只写入必要的数据,没有id,没有其他版本号
+ */
+ ReadFileLite(file) {
+ this.ReadFileOnly(file);
+ this._Matrix.fromArray(file.Read());
+ }
+ WriteFileLite(file) {
+ this.WriteFileOnly(file);
+ file.Write(this._Matrix.toArray());
+ }
+ ReadFileOnly(file) {
+ let ver = file.Read();
+ this.height = Number(file.Read());
+ this.width = Number(file.Read());
+ this.thickness = Number(file.Read());
+ this.isRect = file.Read();
+ this.contourCurve = file.ReadObject();
+ let grooveCount = file.Read();
+ this.grooves.length = 0;
+ for (let i = 0; i < grooveCount; i++) {
+ if (this.grooves[i] === undefined)
+ this.grooves[i] = new ExtrudeSolid_1();
+ this.grooves[i].ReadFileLite(file);
+ }
+ this.knifeRadius = file.Read();
+ this.groovesAddLength = file.Read();
+ if (ver > 1) {
+ this.groovesAddWidth = file.Read();
+ this.groovesAddDepth = file.Read();
+ }
+ if (ver > 2) {
+ this.RelevanceMeats.length = 0;
+ this.RelevanceKnifs.length = 0;
+ let count = file.Read();
+ for (let index = 0; index < count; index++) {
+ let id = file.ReadSoftObjectId();
+ if (id)
+ this.RelevanceMeats.push(id);
+ }
+ count = file.Read();
+ for (let index = 0; index < count; index++) {
+ let id = file.ReadSoftObjectId();
+ if (id)
+ this.RelevanceKnifs.push(id);
+ }
+ }
+ }
+ WriteFileOnly(file) {
+ file.Write(3);
+ file.Write(this.height);
+ file.Write(this.width);
+ file.Write(this.thickness);
+ file.Write(this.isRect);
+ file.WriteObject(this.ContourCurve);
+ file.Write(this.grooves.length);
+ for (let groove of this.grooves)
+ groove.WriteFileLite(file);
+ file.Write(this.knifeRadius);
+ file.Write(this.groovesAddLength);
+ file.Write(this.groovesAddWidth);
+ file.Write(this.groovesAddDepth);
+ //3
+ file.Write(this.RelevanceMeats.length);
+ for (let id of this.RelevanceMeats)
+ file.WriteSoftObjectId(id);
+ file.Write(this.RelevanceKnifs.length);
+ for (let id of this.RelevanceKnifs)
+ file.WriteSoftObjectId(id);
+ }
+ //对象从文件中读取数据,初始化自身
+ _ReadFile(file) {
+ super._ReadFile(file);
+ this.ReadFileOnly(file);
+ }
+ //对象将自身数据写入到文件.
+ WriteFile(file) {
+ super.WriteFile(file);
+ this.WriteFileOnly(file);
+ }
+};
+ExtrudeSolid = ExtrudeSolid_1 = __decorate([
+ Factory
+], ExtrudeSolid);
+CADFactory.RegisterObjectAlias(ExtrudeSolid, "ExtureSolid");
+function ProjectBoard(knifBoard, projectBoard) {
+ let n1 = knifBoard.Normal;
+ let n2 = projectBoard.Normal;
+ if (!isPerpendicularityTo(n1, n2))
+ return;
+ let p1 = projectBoard.Position;
+ let p2 = n2.clone().multiplyScalar(projectBoard.Thickness).add(p1);
+ let ocsInv = knifBoard.OCSInv;
+ p1.applyMatrix4(ocsInv).setZ(0);
+ p2.applyMatrix4(ocsInv).setZ(0);
+ let dir = new three.Vector3().crossVectors(n1, n2).applyMatrix4(ocsInv.clone().setPosition(ZeroVec));
+ let lineLength = projectBoard.Width + projectBoard.Height; //两边之和大于第三边
+ let pts = [
+ dir.clone().multiplyScalar(lineLength).add(p1),
+ dir.clone().multiplyScalar(-lineLength).add(p1),
+ dir.clone().multiplyScalar(-lineLength).add(p2),
+ dir.clone().multiplyScalar(lineLength).add(p2),
+ ];
+ let pl = new exports.Polyline(pts.map(p => {
+ return { pt: AsVector2(p), bul: 0 };
+ }));
+ pl.CloseMark = true;
+ // pl.ApplyMatrix(knifBoard.OCS);
+ return pl;
+}
+//用于翻转绘制出来的槽
+const OverturnMatrix = new three.Matrix4().makeBasis(YAxis, ZAxis, XAxis);
+
+var CompositeEntity_1;
+let CompositeEntity = CompositeEntity_1 = class CompositeEntity extends Entity {
+ constructor() {
+ super();
+ //如果你需要修改内部实体,则需要写入记录
+ this.Entitys = [];
+ }
+ //#region 绘制
+ // OnlyRenderType = true; //我们现在不需要这样,因为我们每个绘制类型的Object的子实体都有子实体的渲染类型(唯一的缺点可能是渲染速度变慢了?)
+ /**
+ * 初始化绘制的threejs实体,子类型重载该函数初始化绘制实体.
+ */
+ Explode() {
+ return this.Entitys.map(e => {
+ let cloneE = e.Clone();
+ cloneE.Material = e.Material;
+ return cloneE.ApplyMatrix(this.OCS);
+ });
+ }
+ Traverse(callback) {
+ callback(this);
+ for (let en of this.Entitys) {
+ if (en instanceof CompositeEntity_1)
+ en.Traverse(callback);
+ else
+ callback(en);
+ }
+ }
+ get BoundingBox() {
+ let box = new Box3Ext();
+ for (let e of this.Entitys)
+ box.union(e.BoundingBox);
+ return box.applyMatrix4(this.OCS);
+ }
+ InitDrawObject(renderType = RenderType.Wireframe) {
+ /**
+ * 如果复合实体里面有圆,并且使用了拉伸夹点功能,在UpdateDrawObject时,会因为无法得到Jig对象而导致的错误.
+ * 索性我们去掉Jig实体的功能.
+ */
+ if (renderType === RenderType.Jig)
+ return;
+ let object = new three.Object3D();
+ this.UpdateDrawObject(renderType, object);
+ return object;
+ }
+ UpdateDrawObject(renderType, obj) {
+ Object3DRemoveAll(obj);
+ for (let e of this.Entitys) {
+ e.IsEmbedEntity = true;
+ // //内嵌实体在某些时候可能被清理,修复它
+ // if (e.DrawObject.children.length === 0)
+ // e.ClearDraw();
+ let o = e.GetDrawObjectFromRenderType(renderType);
+ o.traverse(obj => obj.userData = {});
+ AddEntityDrawObject(obj, e, renderType);
+ }
+ }
+ get ColorIndex() {
+ return super.ColorIndex;
+ }
+ set ColorIndex(color) {
+ if (color !== this._Color) {
+ this.WriteAllObjectRecord();
+ this._Color = color;
+ this.Traverse(e => {
+ if (e === this)
+ return;
+ // if (e instanceof CompositeEntity) //有点奇怪
+ // e._Color = color;
+ // else
+ e.ColorIndex = color;
+ });
+ }
+ }
+ get Material() {
+ return super.Material;
+ }
+ set Material(id) {
+ super.Material = id;
+ for (let e of this.Entitys)
+ e.Material = id;
+ }
+ UpdateDrawObjectMaterial(renderType, obj) {
+ this.UpdateDrawObject(renderType, obj);
+ }
+ RestoreJigMaterial() {
+ //我们不做任何事情,避免更新材质引起的重绘,因为我们没有实现Jig材质,所以我们也不需要还原它
+ }
+ //#endregion
+ //#region 交互操作
+ /**
+ *
+ * @param snapMode 捕捉模式(单一)
+ * @param pickPoint const
+ * @param lastPoint const
+ * @param viewXform const 最近点捕捉需要这个变量
+ * @returns object snap points
+ */
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ let pts = [];
+ for (let e of this.Entitys) {
+ pts.push(...e.Clone().ApplyMatrix(this.OCS).GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ }
+ return pts;
+ }
+ GetGripPoints() {
+ return this.GetGripOrStretchPoints(DragPointType.Grip);
+ }
+ MoveGripPoints(indexList, vec) {
+ this.WriteAllObjectRecord();
+ this.MoveGripOrStretchPoints(indexList, vec, DragPointType.Grip);
+ }
+ GetStretchPoints() {
+ return this.GetGripOrStretchPoints(DragPointType.Stretch);
+ }
+ /**
+ * 拉伸夹点,用于Stretch命令
+ *
+ * @param {Array} indexList 拉伸点索引列表.
+ * @param {Vector3} vec 移动向量
+ * @memberof Entity
+ */
+ MoveStretchPoints(indexList, vec) {
+ this.WriteAllObjectRecord();
+ this.MoveGripOrStretchPoints(indexList, vec, DragPointType.Stretch);
+ }
+ GetGripOrStretchPoints(type) {
+ let pts = [];
+ for (let e of this.Entitys)
+ pts.push(...(type === DragPointType.Grip ? e.GetGripPoints() : e.GetStretchPoints()));
+ for (let p of pts)
+ p.applyMatrix4(this._Matrix);
+ return pts;
+ }
+ GetStrectchPointCountList(dragType) {
+ let counts = this.Entitys.map(e => {
+ return (dragType === DragPointType.Grip ? e.GetGripPoints() : e.GetStretchPoints()).length;
+ });
+ return counts;
+ }
+ MoveGripOrStretchPoints(indexList, vec, dragType) {
+ this.WriteAllObjectRecord();
+ let counts = this.GetStrectchPointCountList(dragType);
+ if (dragType === DragPointType.Stretch && indexList.length === arraySum(counts)) {
+ this.Position = this.Position.add(vec);
+ return;
+ }
+ vec = vec.clone().applyMatrix4(this.OCSInv.setPosition(0, 0, 0));
+ arraySortByNumber(indexList);
+ let i = 0;
+ let j = 0;
+ let icount = indexList.length;
+ let offset = 0;
+ for (let count of counts) {
+ offset += count;
+ let ilist = [];
+ for (; i < icount; i++) {
+ if (indexList[i] < offset)
+ ilist.push(indexList[i] - offset + count);
+ else
+ break;
+ }
+ let ent = this.Entitys[j];
+ dragType === DragPointType.Grip ? ent.MoveGripPoints(ilist, vec) : ent.MoveStretchPoints(ilist, vec);
+ if (ent instanceof ExtrudeSolid) //取消优化判断this.Objectid,因为这个实体可能被复合在另一个实体中,导致这个id是不存在的,所以我们无法判断它在拽拖.
+ ent.CheckContourCurve();
+ ent.Update();
+ j++;
+ }
+ this.__UpdateVersion__++;
+ //如何绘制对象是克隆的,那么我们将重绘它(避免无法更新)
+ //我们也不大需要下面的判断,我们如果持续的更新它,其实并不会有多大的问题,因为我们总是从缓存里面拿绘制对象
+ // if (this._drawObject && this._drawObject.children[0]?.userData.IsClone)
+ this.Update();
+ }
+ CloneDrawObject(from) {
+ for (let [type, obj] of from._CacheDrawObject) {
+ let oldUserDaata = obj.userData;
+ obj.userData = {};
+ let newObj = obj.clone(true);
+ obj.userData = oldUserDaata;
+ obj.userData.IsClone = true;
+ newObj.matrix = this._Matrix;
+ newObj.userData = { Entity: this };
+ newObj.userData.IsClone = true;
+ this._CacheDrawObject.set(type, newObj);
+ }
+ this.NeedUpdateFlag = UpdateDraw.None;
+ }
+ //#endregion
+ //#region 文件序列化
+ _ReadFile(file) {
+ let v = file.Read();
+ super._ReadFile(file);
+ let count = file.Read();
+ this.Entitys.length = 0;
+ for (let i = 0; i < count; i++) {
+ let ent = file.ReadObject();
+ this.Entitys.push(ent);
+ }
+ }
+ //对象将自身数据写入到文件.
+ WriteFile(file) {
+ file.Write(1);
+ super.WriteFile(file);
+ file.Write(this.Entitys.length);
+ for (let e of this.Entitys)
+ file.WriteObject(e);
+ }
+};
+__decorate([
+ AutoRecord
+], CompositeEntity.prototype, "Entitys", void 0);
+CompositeEntity = CompositeEntity_1 = __decorate([
+ Factory
+], CompositeEntity);
+
+var EWineRackType;
+(function (EWineRackType) {
+ EWineRackType[EWineRackType["Oblique"] = 0] = "Oblique";
+ EWineRackType[EWineRackType["Upright"] = 1] = "Upright";
+})(EWineRackType || (EWineRackType = {}));
+var EWRackArrayType;
+(function (EWRackArrayType) {
+ EWRackArrayType[EWRackArrayType["ByWidth"] = 0] = "ByWidth";
+ EWRackArrayType[EWRackArrayType["ByCount"] = 1] = "ByCount";
+ EWRackArrayType[EWRackArrayType["Fixed"] = 2] = "Fixed";
+})(EWRackArrayType || (EWRackArrayType = {}));
+/**铺满方式 */
+var EFullType;
+(function (EFullType) {
+ EFullType[EFullType["ByHeight"] = 0] = "ByHeight";
+ EFullType[EFullType["ByWidth"] = 1] = "ByWidth";
+ EFullType[EFullType["Symmetry"] = 2] = "Symmetry";
+})(EFullType || (EFullType = {}));
+/**高度优先时靠左还是靠右 */
+var EFullDir;
+(function (EFullDir) {
+ EFullDir[EFullDir["Left"] = 0] = "Left";
+ EFullDir[EFullDir["Right"] = 1] = "Right";
+})(EFullDir || (EFullDir = {}));
+
+var EFindType;
+(function (EFindType) {
+ EFindType[EFindType["Find"] = 0] = "Find";
+ EFindType[EFindType["Modify"] = 1] = "Modify";
+ EFindType[EFindType["FindMaxSize"] = 2] = "FindMaxSize";
+ EFindType[EFindType["FindSplite"] = 3] = "FindSplite";
+ EFindType[EFindType["GetOption"] = 4] = "GetOption";
+ EFindType[EFindType["RemoveModeling"] = 5] = "RemoveModeling";
+ EFindType[EFindType["RemoveSpecialShape"] = 6] = "RemoveSpecialShape";
+ EFindType[EFindType["RemoveModelingAndSpecial"] = 7] = "RemoveModelingAndSpecial";
+ EFindType[EFindType["ModifyHardware"] = 8] = "ModifyHardware";
+})(EFindType || (EFindType = {}));
+var ECompareType;
+(function (ECompareType) {
+ ECompareType["Equal"] = "=";
+ ECompareType["UnEqual"] = "!=";
+ ECompareType["Greater"] = ">=";
+ ECompareType["Less"] = "<=";
+})(ECompareType || (ECompareType = {}));
+
+var ELatticeArrayType;
+(function (ELatticeArrayType) {
+ ELatticeArrayType[ELatticeArrayType["ByWidth"] = 0] = "ByWidth";
+ ELatticeArrayType[ELatticeArrayType["ByCount"] = 1] = "ByCount";
+})(ELatticeArrayType || (ELatticeArrayType = {}));
+
+//门板位置类型
+var DoorPosType;
+(function (DoorPosType) {
+ DoorPosType[DoorPosType["Out"] = 0] = "Out";
+ DoorPosType[DoorPosType["In"] = 1] = "In";
+})(DoorPosType || (DoorPosType = {}));
+var HandleHorPos;
+(function (HandleHorPos) {
+ HandleHorPos[HandleHorPos["Left"] = 0] = "Left";
+ HandleHorPos[HandleHorPos["Right"] = 1] = "Right";
+ HandleHorPos[HandleHorPos["Mid"] = 2] = "Mid";
+})(HandleHorPos || (HandleHorPos = {}));
+var HandleVePos;
+(function (HandleVePos) {
+ HandleVePos[HandleVePos["Top"] = 0] = "Top";
+ HandleVePos[HandleVePos["Bottom"] = 1] = "Bottom";
+ HandleVePos[HandleVePos["Mid"] = 2] = "Mid";
+})(HandleVePos || (HandleVePos = {}));
+//门板开门类型
+var DoorOpenDir;
+(function (DoorOpenDir) {
+ DoorOpenDir["Left"] = "lf";
+ DoorOpenDir["Right"] = "rt";
+ DoorOpenDir["Top"] = "tp";
+ DoorOpenDir["Bottom"] = "bm";
+ DoorOpenDir["None"] = "none";
+})(DoorOpenDir || (DoorOpenDir = {}));
+
+var EMetalsType;
+(function (EMetalsType) {
+ EMetalsType["Metals"] = "\u4E94\u91D1";
+ EMetalsType["Comp"] = "\u7EC4\u4EF6";
+})(EMetalsType || (EMetalsType = {}));
+
+const DefaultLayerBoardConfig = {
+ version: 2,
+ type: BoardType.Layer,
+ name: "层板",
+ frontShrink: 0,
+ leftShrink: 0,
+ rightShrink: 0,
+ calcHeight: "W",
+ isTotalLength: true,
+ boardRelative: BrRelativePos.Div,
+ thickness: 18,
+ count: 1,
+ spaceSize: 300,
+ isActive: false,
+ calcSpaceSize: "0",
+ calcFrontShrink: "0",
+ calcLeftShrink: "0",
+ calcRightShrink: "0",
+};
+Object.freeze(DefaultLayerBoardConfig);
+const DefaultVerticalBoardConfig = {
+ version: 2,
+ type: BoardType.Vertical,
+ name: "立板",
+ frontShrink: 0,
+ bottomShrink: 0,
+ calcWidth: "W",
+ calcHeight: "H",
+ isTotalLength: true,
+ isTotalWidth: true,
+ boardRelative: BrRelativePos.Div,
+ thickness: 18,
+ count: 1,
+ spaceSize: 0,
+ calcSpaceSize: "0",
+ calcBottomShrink: "0",
+ calcFrontShrink: "0",
+};
+Object.freeze(DefaultVerticalBoardConfig);
+const DefaultBehindBoardConfig = {
+ version: 2,
+ type: BoardType.Behind,
+ name: "背板",
+ leftExt: 0,
+ rightExt: 0,
+ topExt: 0,
+ bottomExt: 0,
+ thickness: 18,
+ boardPosition: BehindHeightPositon.AllHeight,
+ calcHeight: "H",
+ moveDist: 0,
+ boardRelative: BrRelativePos.Back,
+ spaceSize: 0,
+ count: 1,
+ calcSpaceSize: "0",
+ calcMoveDist: "0",
+};
+Object.freeze(DefaultBehindBoardConfig);
+const DefaultWineRackConfig = {
+ version: 1,
+ type: EWineRackType.Oblique,
+ arrayType: EWRackArrayType.ByWidth,
+ fullType: EFullType.ByWidth,
+ isFull: false,
+ isLock: false,
+ fullDir: EFullDir.Left,
+ heightCount: 3.5,
+ widthCount: 3.5,
+ isTotalDepth: true,
+ depth: 0,
+ gripWidth: 100,
+ calcDepth: "W",
+ boardThick: 18,
+ grooveWidthAdd: 0,
+ leftEdge: 1,
+ rightEdge: 1,
+ topEdge: 1,
+ bottomEdge: 1,
+ frontCut: 0,
+ leftCut: 0,
+ rightCut: 0,
+ topCut: 0,
+ grooveLengthAdd: 3,
+ isDrawLy: false,
+ isDrawVer: false,
+ brThick2: 18,
+};
+Object.freeze(DefaultWineRackConfig);
+const DefaultTopBoardOption = {
+ version: 2,
+ type: BoardType.Layer,
+ name: "顶板",
+ isDraw: true,
+ thickness: 18,
+ frontDist: 0,
+ behindDistance: 0,
+ isWrapSide: false,
+ useLFData: true,
+ leftExt: 0,
+ rightExt: 0,
+ offset: 0,
+};
+Object.freeze(DefaultTopBoardOption);
+const DefaultBottomBoardOption = {
+ version: 2,
+ type: BoardType.Layer,
+ name: "底板",
+ isDraw: true,
+ thickness: 18,
+ frontDist: 0,
+ behindDistance: 0,
+ isWrapSide: false,
+ useLFData: true,
+ leftExt: 0,
+ rightExt: 0,
+ offset: 80,
+ footThickness: 18,
+ isDrawFooter: true,
+ footBehindShrink: 0,
+ isDrawBackFooter: false,
+ isDrawStrengthenStrip: false,
+ footerOffset: 0,
+ divCount: 1,
+};
+Object.freeze(DefaultBottomBoardOption);
+const DefaultSideBoardOption = {
+ version: 2,
+ type: BoardType.Vertical,
+ name: "",
+ height: 2000,
+ width: 600,
+ thickness: 18,
+ spaceSize: 1200,
+ leftShrink: 0,
+ rightShrink: 0,
+};
+Object.freeze(DefaultSideBoardOption);
+const DefaultSingleBoardOption = {
+ version: 1,
+ name: "层板",
+ type: BoardType.Layer,
+ height: 1200,
+ width: 600,
+ thickness: 18,
+ rotateX: 0,
+ rotateY: 0,
+ rotateZ: 0
+};
+Object.freeze(DefaultSingleBoardOption);
+const DefaultClosingStripOption = {
+ version: 1,
+ type: BoardType.Vertical,
+ name: "收口条",
+ striptype: StripType.H,
+ boardRelative: BrRelativePos.Left,
+ width: 54,
+ thickness: 18,
+ frontShrink: 0,
+};
+Object.freeze(DefaultClosingStripOption);
+const DefaultBoardFindOption = {
+ version: 4,
+ condition: {
+ layer: false,
+ height: false,
+ width: false,
+ thickness: false,
+ useWood: false,
+ useDrill: false,
+ useNail: false,
+ useDoor: false,
+ useDim: false,
+ useSpecial: false,
+ useModeling: false,
+ roomName: false,
+ cabinetName: false,
+ brName: false,
+ material: false,
+ lines: false,
+ bigHoleDir: false,
+ drillType: false,
+ useKeyWord: false,
+ composingFace: false,
+ sealedUp: false,
+ sealedDown: false,
+ sealedLeft: false,
+ sealedRight: false,
+ upDrill: false,
+ downDrill: false,
+ leftDrill: false,
+ rightDrill: false,
+ useZhengFanDrill: false,
+ useChaidan: false,
+ },
+ compareType: {
+ height: ECompareType.Equal,
+ width: ECompareType.Equal,
+ thickness: ECompareType.Equal,
+ roomName: ECompareType.Equal,
+ cabinetName: ECompareType.Equal,
+ brName: ECompareType.Equal,
+ [EBoardKeyList.Mat]: ECompareType.Equal,
+ [EBoardKeyList.Color]: ECompareType.Equal,
+ [EBoardKeyList.BrMat]: ECompareType.Equal,
+ lines: ECompareType.Equal,
+ bigHoleDir: ECompareType.Equal,
+ drillType: ECompareType.Equal,
+ composingFace: ECompareType.Equal,
+ },
+ tolerance: {
+ height: "",
+ width: "",
+ thickness: "",
+ },
+ layer: "0",
+ height: "",
+ width: "",
+ thickness: "",
+ roomName: "",
+ cabinetName: "",
+ brName: "",
+ [EBoardKeyList.BrMat]: "",
+ material: "",
+ color: "",
+ lines: LinesType.Positive,
+ bigHoleDir: FaceDirection.Front,
+ drillType: "",
+ composingFace: ComposingType.Positive,
+ sealedUp: "",
+ sealedDown: "",
+ sealedLeft: "",
+ sealedRight: "",
+ highDrill: [],
+ upDownDrill: [true, true],
+ isClose: false,
+ remarks: Array.from({ length: 10 }, () => ["", ""]),
+ isChaidan: false,
+};
+Object.freeze(DefaultBoardFindOption);
+const DefaultLatticOption = {
+ version: 1,
+ arrayType: ELatticeArrayType.ByWidth,
+ gripWidth: 100,
+ gripDepth: 100,
+ widthCount: 3,
+ depthCount: 4,
+ knifeRad: 3,
+ thickness: 18,
+ arcLen: 50,
+ downDist: 0,
+ space: 0.2,
+ grooveAddWidth: 0.2,
+ upSealed: 1,
+ downSealed: 1,
+ leftSealed: 1,
+ rightSealed: 1,
+ isAuto: true,
+ isChange: true,
+ isOpenCut: false,
+ upCut: 0,
+ downCut: 4,
+};
+Object.freeze(DefaultLatticOption);
+const DefaultDoorOption = {
+ version: 3,
+ col: 2,
+ row: 1,
+ isAllSelect: true,
+ topOffset: 0,
+ bottomOffset: 0,
+ doorPosType: DoorPosType.Out,
+ offset: 0,
+ topExt: 18,
+ bottomExt: 18,
+ leftExt: 18,
+ rightExt: 18,
+ topSpace: 2,
+ bottomSpace: 2,
+ leftSpace: 2,
+ rightSpace: 2,
+ midSpace: 2,
+ thickness: 18,
+ depth: 0,
+ isAuto: true,
+ boardName: "",
+ doorThickness: 18,
+ topBrSeal: 1,
+ bottomBrSeal: 1,
+ leftBrSeal: 1,
+ rightBrSeal: 1,
+ topDoorSeal: 1,
+ bottomDoorSeal: 1,
+ leftDoorSeal: 1,
+ rightDoorSeal: 1,
+ handleAngle: 0,
+ handleHorPos: HandleHorPos.Right,
+ horSpacing: 50,
+ handleVePos: HandleVePos.Mid,
+ veSpacing: 10,
+ hingeCount: 0,
+ hindeTopDist: 0,
+ hindeBottomDist: 0,
+ downOffsetExpr: "0",
+ upOffsetExpr: "0",
+};
+Object.freeze(DefaultDoorOption);
+const DefaultDrawerOption = {
+ version: 4,
+ col: 1,
+ row: 1,
+ isAllSelect: true,
+ topOffset: 0,
+ bottomOffset: 0,
+ doorPosType: DoorPosType.Out,
+ offset: 0,
+ topExt: 18,
+ bottomExt: 18,
+ leftExt: 18,
+ rightExt: 18,
+ topSpace: 2,
+ bottomSpace: 2,
+ leftSpace: 2,
+ rightSpace: 2,
+ midSpace: 2,
+ thickness: 18,
+ depth: 0,
+ isAuto: true,
+ boardName: "",
+ handleAngle: 90,
+ handleHorPos: HandleHorPos.Mid,
+ horSpacing: 10,
+ handleVePos: HandleVePos.Mid,
+ veSpacing: 10,
+ drawerTotalDepth: 0,
+ trackDepth: 0,
+ isAutoSelectTrack: true,
+ isLockTopOffset: false,
+ isLockBottomOffset: false,
+ downOffsetExpr: "0",
+ upOffsetExpr: "0",
+};
+Object.freeze(DefaultDrawerOption);
+const DefaultBoardBatchCurtailOption = {
+ version: 1,
+ type: CurtailType.Total,
+ front: 0,
+ back: 0,
+ left: 0,
+ right: 0,
+ moveBrs: false,
+};
+Object.freeze(DefaultBoardBatchCurtailOption);
+const DefaultLatticeConfig = {
+ arrayType: ELatticeArrayType.ByWidth,
+ gripWidth: 100,
+ gripDepth: 100,
+ widthCount: 3,
+ depthCount: 4,
+ knifeRad: 3,
+ thickness: 18,
+ arcLen: 50,
+ downDist: 0,
+ space: 0.5,
+ grooveAddWidth: 0,
+ upSealed: 1,
+ downSealed: 0,
+ leftSealed: 0,
+ rightSealed: 0,
+ isAuto: true,
+ isChange: true,
+ isOpenCut: false,
+ upCut: 0,
+ downCut: 4,
+};
+Object.freeze(DefaultLatticeConfig);
+const DefaultNailOption = {
+ version: 1,
+ isDraw: true,
+ addCount: 0,
+ dist: 50,
+ isGroup: false,
+ isInBack: false,
+ front: 50,
+ behind: 50,
+ count: 2,
+ rad: 2.5,
+ length: 34,
+ depth: 11
+};
+Object.freeze(DefaultNailOption);
+const DefaultCylinederMetalsOption = {
+ version: 2,
+ rad: 50,
+ height: 200,
+ name: "圆柱体",
+ unit: "",
+ roomName: "",
+ cabinetName: "",
+ costExpr: "L*R*R*3.14",
+ actualExpr: "L*R*R*3.14*3",
+ model: "X-1",
+ factory: "晨丰",
+ brand: "晨丰",
+ spec: "个",
+ count: "1",
+ comments: "",
+ isHole: true,
+};
+Object.freeze(DefaultCylinederMetalsOption);
+const DefaultExtruderMetalsOption = {
+ version: 1,
+ thickness: 100,
+ knifeRad: 0,
+ isHole: true,
+ addLen: 0,
+ name: "拉伸实体",
+ unit: "",
+ roomName: "",
+ cabinetName: "",
+ costExpr: "L*W*H*100",
+ actualExpr: "L*W*H*200",
+ model: "X-1",
+ factory: "晨丰",
+ brand: "晨丰",
+ spec: "个",
+ count: "1",
+ comments: "",
+};
+Object.freeze(DefaultExtruderMetalsOption);
+const DefaultCompositeMetalsOption = {
+ version: 2,
+ type: EMetalsType.Metals,
+ isSplite: false,
+ isSplitePrice: false,
+ name: "复合实体",
+ unit: "",
+ roomName: "",
+ cabinetName: "",
+ costExpr: "L*W*H*100",
+ actualExpr: "L*W*H*300",
+ model: "X-1",
+ factory: "晨丰",
+ brand: "晨丰",
+ spec: "个",
+ count: "1",
+ color: "",
+ material: "",
+ comments: "",
+ isHole: true,
+};
+Object.freeze(DefaultCompositeMetalsOption);
+const DefaultToplineMetalsOption = {
+ version: 3,
+ name: "顶线",
+ unit: "毫米",
+ roomName: "",
+ cabinetName: "",
+ costExpr: "",
+ actualExpr: "",
+ model: "",
+ factory: "",
+ brand: "",
+ spec: "",
+ comments: "",
+ addLen: "0",
+ isHole: false,
+};
+Object.freeze(DefaultToplineMetalsOption);
+const DefaultBoardProcessOption = {
+ version: 3,
+ roomName: "",
+ cabinetName: "",
+ boardName: "",
+ material: "",
+ color: "",
+ lines: LinesType.Positive,
+ bigHoleDir: FaceDirection.Front,
+ drillType: "",
+ composingFace: ComposingType.Arbitrary,
+ highSealed: [],
+ sealedUp: "1",
+ sealedDown: "1",
+ sealedLeft: "1",
+ sealedRight: "1",
+ spliteHeight: "",
+ spliteWidth: "",
+ spliteThickness: "",
+ highDrill: [],
+ frontDrill: true,
+ backDrill: true,
+ remarks: [],
+ useBoardProcessOption: true,
+};
+Object.freeze(DefaultBoardProcessOption);
+const DefaultCurve2RecOption = {
+ version: 1,
+ isSaveMax: false,
+ isSaveSmall: true,
+ width: 90,
+ isAnaly: true,
+ gap: 3
+};
+Object.freeze(DefaultCurve2RecOption);
+const DefaultUpdateInfoOption = {
+ [EBoardKeyList.RoomName]: "",
+ [EBoardKeyList.CabinetName]: "",
+ [EBoardKeyList.Lines]: LinesType.Positive,
+ [EBoardKeyList.BigHole]: FaceDirection.Front,
+ [EBoardKeyList.DrillType]: "",
+ [EBoardKeyList.ComposingFace]: ComposingType.Arbitrary,
+ upDownDrill: [true, true],
+ [EBoardKeyList.UpSealed]: "1",
+ [EBoardKeyList.DownSealed]: "1",
+ [EBoardKeyList.LeftSealed]: "1",
+ [EBoardKeyList.RightSealed]: "1",
+ [EBoardKeyList.KnifeRad]: "3",
+ remarks: Array.from({ length: 10 }, () => ["", ""]),
+ [EBoardKeyList.BrMat]: "",
+ [EBoardKeyList.Mat]: "",
+ [EBoardKeyList.Color]: "",
+ grooveAddDepth: "0",
+ grooveAddLength: "0",
+ grooveAddWidth: "0",
+ highDrill: [],
+ condition: {
+ [EBoardKeyList.RoomName]: false,
+ [EBoardKeyList.CabinetName]: false,
+ [EBoardKeyList.Lines]: true,
+ [EBoardKeyList.BigHole]: true,
+ [EBoardKeyList.DrillType]: true,
+ [EBoardKeyList.ComposingFace]: true,
+ [EBoardKeyList.UpSealed]: true,
+ [EBoardKeyList.DownSealed]: true,
+ [EBoardKeyList.LeftSealed]: true,
+ [EBoardKeyList.RightSealed]: true,
+ useZhengFanDrill: true,
+ remarks: true,
+ [EBoardKeyList.KnifeRad]: true,
+ [EBoardKeyList.Mat]: true,
+ grooveAddDepth: true,
+ grooveAddLength: true,
+ grooveAddWidth: true,
+ upDrill: true,
+ downDrill: true,
+ leftDrill: true,
+ rightDrill: true,
+ }
+};
+Object.freeze(DefaultUpdateInfoOption);
+const DefaultKuGanOption = {
+ count: 1,
+ isHor: false,
+ depth: 0,
+ isDefault: true,
+ leftDist: 0,
+ rightDist: 0,
+};
+Object.freeze(DefaultKuGanOption);
+const DefaultR2bOption = {
+ version: 2,
+ cabinetDeep: 400,
+ cabinetBrThick: 18,
+ cabinetCurtail: 0,
+ backBrThick: 18,
+ backBrBiggerThanHeight: 200,
+ backBrBiggerThanWidth: 200,
+ backBrFrontMove: 0,
+ backBrLeftExtend: 0,
+ backBrRightExtend: 0,
+ backBrUpExtend: 0,
+ backBrDownExtend: 0,
+ verticalBrShrink: 0,
+ layerBrShrink: 0,
+ topBrShrink: 0,
+ bottomBrShrink: 0,
+ groundLineBrShrink: 0,
+ farLeftVerticalBrName: "左侧板",
+ farRightVerticalBrName: "右侧板",
+ topMostLayerBrName: "顶板",
+ bottomMostLayerBrName: "底板",
+ bottomMostBackBrName: "地脚线",
+ stripeBrName: "收口条",
+ cabinetName: "",
+ isfarLeftVerticalBrName: true,
+ isfarRightVerticalBrName: true,
+ istopMostLayerBrName: true,
+ isbottomMostLayerBrName: true,
+ isbottomMostBackBrName: true,
+ isstripeBrName: true,
+ iscabinetName: false,
+ isMultiBackBr: false,
+ grooveOption: {
+ grooveAddLength: "0",
+ grooveAddWidth: "0",
+ grooveAddDepth: "0",
+ knifeRadius: "3",
+ },
+ roomName: "",
+ boardMatName: "",
+ material: "",
+ color: "",
+ drillType: "",
+ sealedDown: "1",
+ sealedLeft: "1",
+ sealedRight: "1",
+ sealedUp: "1",
+ backBrUseTemplate: false,
+ backBrTemplate: null,
+ remarks: Array.from({ length: 12 }, () => ["", ""]),
+ maxThickness: 20,
+ useBrName: true,
+ configName: "",
+ backBrName: "背板",
+};
+Object.freeze(DefaultR2bOption);
+
+var HardwareCompositeEntity_1;
+let HardwareCompositeEntity = HardwareCompositeEntity_1 = class HardwareCompositeEntity extends CompositeEntity {
+ constructor() {
+ super();
+ this.HardwareOption = { ...DefaultCompositeMetalsOption };
+ this.DataList = [];
+ this.RelevanceBoards = [];
+ }
+ GetAllEntity(isHole = false, filter) {
+ let holes = [];
+ for (let e of this.Entitys) {
+ if (e instanceof HardwareCompositeEntity_1) {
+ if (!isHole || e.HardwareOption.isHole)
+ holes.push(...e.GetAllEntity(isHole, filter).map(h => h.ApplyMatrix(this.OCS)));
+ }
+ else {
+ if (!filter || filter(e)) {
+ holes.push(e.Clone().ApplyMatrix(this.OCS));
+ }
+ }
+ }
+ return holes;
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let v = file.Read();
+ this.HardwareOption.type = file.Read();
+ this.HardwareOption.isSplite = file.Read();
+ this.HardwareOption.isSplitePrice = file.Read();
+ this.HardwareOption.color = file.Read();
+ this.HardwareOption.material = file.Read();
+ this.HardwareOption.name = file.Read();
+ this.HardwareOption.roomName = file.Read();
+ this.HardwareOption.cabinetName = file.Read();
+ this.HardwareOption.costExpr = file.Read();
+ this.HardwareOption.actualExpr = file.Read();
+ this.HardwareOption.model = file.Read();
+ this.HardwareOption.factory = file.Read();
+ this.HardwareOption.brand = file.Read();
+ this.HardwareOption.spec = file.Read();
+ this.HardwareOption.count = file.Read();
+ this.HardwareOption.comments = file.Read();
+ this.HardwareOption.unit = file.Read();
+ let count = file.Read();
+ this.DataList.length = 0;
+ for (let i = 0; i < count; i++) {
+ let d = ["", ""];
+ d[0] = file.Read();
+ d[1] = file.Read();
+ this.DataList.push(d);
+ }
+ if (v > 1)
+ this.HardwareOption.isHole = file.Read();
+ if (v >= 3) {
+ let count = file.Read();
+ this.RelevanceBoards.length = 0;
+ for (let i = 0; i < count; i++) {
+ this.RelevanceBoards.push(file.ReadSoftObjectId());
+ }
+ }
+ }
+ //对象将自身数据写入到文件.
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(3);
+ file.Write(this.HardwareOption.type);
+ file.Write(this.HardwareOption.isSplite);
+ file.Write(this.HardwareOption.isSplitePrice);
+ file.Write(this.HardwareOption.color);
+ file.Write(this.HardwareOption.material);
+ file.Write(this.HardwareOption.name);
+ file.Write(this.HardwareOption.roomName);
+ file.Write(this.HardwareOption.cabinetName);
+ file.Write(this.HardwareOption.costExpr);
+ file.Write(this.HardwareOption.actualExpr);
+ file.Write(this.HardwareOption.model);
+ file.Write(this.HardwareOption.factory);
+ file.Write(this.HardwareOption.brand);
+ file.Write(this.HardwareOption.spec);
+ file.Write(this.HardwareOption.count);
+ file.Write(this.HardwareOption.comments);
+ file.Write(this.HardwareOption.unit);
+ file.Write(this.DataList.length);
+ for (let data of this.DataList) {
+ file.Write(data[0]);
+ file.Write(data[1]);
+ }
+ file.Write(this.HardwareOption.isHole);
+ file.Write(this.RelevanceBoards.length);
+ for (let id of this.RelevanceBoards)
+ file.WriteSoftObjectId(id);
+ }
+};
+__decorate([
+ AutoRecord
+], HardwareCompositeEntity.prototype, "HardwareOption", void 0);
+__decorate([
+ AutoRecord
+], HardwareCompositeEntity.prototype, "DataList", void 0);
+__decorate([
+ AutoRecord
+], HardwareCompositeEntity.prototype, "RelevanceBoards", void 0);
+HardwareCompositeEntity = HardwareCompositeEntity_1 = __decorate([
+ Factory
+], HardwareCompositeEntity);
+
+class PointShapeUtils {
+ //方形点表
+ static SquarePts(size) {
+ return [
+ new three.Vector3(-size, -size),
+ new three.Vector3(size, -size),
+ new three.Vector3(size, size),
+ new three.Vector3(-size, size),
+ new three.Vector3(-size, -size),
+ ];
+ }
+ //方形外圈十字直线点表
+ static OutsideLinePts(squareSize, lineLength) {
+ return [
+ //-X
+ new three.Vector3(-squareSize, 0),
+ new three.Vector3(-lineLength, 0),
+ //X
+ new three.Vector3(squareSize, 0),
+ new three.Vector3(lineLength, 0),
+ //Y
+ new three.Vector3(0, squareSize),
+ new three.Vector3(0, lineLength),
+ //-Y
+ new three.Vector3(0, -squareSize),
+ new three.Vector3(0, -lineLength),
+ ];
+ }
+ //十字直线点表
+ static CrossLinePts(lineLength) {
+ return [
+ new three.Vector3(0, -lineLength),
+ new three.Vector3(0, lineLength),
+ new three.Vector3(lineLength, 0),
+ new three.Vector3(-lineLength, 0),
+ ];
+ }
+ static CrossLine3DPts(lineLength) {
+ return [
+ [new three.Vector3(lineLength, 0),
+ new three.Vector3(-lineLength / 2, 0)],
+ [new three.Vector3(0, -lineLength / 2),
+ new three.Vector3(0, lineLength)],
+ [new three.Vector3(0, 0, -lineLength / 2),
+ new three.Vector3(0, 0, lineLength)],
+ ];
+ }
+ static TrianglePts(size) {
+ return [
+ new three.Vector3(size, -size),
+ new three.Vector3(0, size),
+ new three.Vector3(-size, -size),
+ new three.Vector3(size, -size),
+ ];
+ }
+ static CirclePts(size) {
+ let pts = [];
+ let a = Math.PI * 2 / 8;
+ for (let i = 0; i < 9; i++)
+ pts.push(new three.Vector3(Math.sin(a * i) * size, Math.cos(a * i) * size));
+ return pts;
+ }
+ static ObliqueCrossPts(size) {
+ return [new three.Vector3(-size, size), new three.Vector3(size, -size), new three.Vector3(-size, -size), new three.Vector3(size, size)];
+ }
+ static ObliqueCrossLinePts(size) {
+ return [new three.Vector3(-size, size), new three.Vector3(size, -size), new three.Vector3(), new three.Vector3(-size, -size), new three.Vector3(size, size)];
+ }
+ static SandClockPts(size) {
+ return [
+ new three.Vector3(size, size),
+ new three.Vector3(-size, size),
+ new three.Vector3(size, -size),
+ new three.Vector3(-size, -size),
+ new three.Vector3(size, size),
+ ];
+ }
+ static TangentPts(size) {
+ let pts = [
+ new three.Vector3(-size, size),
+ new three.Vector3(size, size),
+ new three.Vector3(size / 2, size),
+ ];
+ let a = Math.PI * 2 / 8;
+ for (let i = 0; i < 9; i++)
+ pts.push(new three.Vector3(Math.sin(a * i + Math.PI / 2) * size, Math.cos(a * i + Math.PI / 2) * size));
+ return pts;
+ }
+ static PerPts(size) {
+ return [
+ new three.Vector3(-size, size),
+ new three.Vector3(-size, -size),
+ new three.Vector3(size, -size),
+ new three.Vector3(0, -size),
+ new three.Vector3(0, 0),
+ new three.Vector3(-size, 0),
+ ];
+ }
+ static LinesDirPts(len, width, lineType) {
+ if (lineType === LinesType.Reverse) {
+ return [
+ new three.Vector3(-len / 2), new three.Vector3(-len / 2 + width / 2, width / 2),
+ new three.Vector3(-len / 2), new three.Vector3(-len / 2 + width / 2, -width / 2),
+ new three.Vector3(-len / 2), new three.Vector3(len / 2),
+ new three.Vector3(len / 2), new three.Vector3(len / 2 - width / 2, width / 2),
+ new three.Vector3(len / 2), new three.Vector3(len / 2 - width / 2, -width / 2),
+ ];
+ }
+ else if (lineType === LinesType.Positive)
+ return [
+ new three.Vector3(0, -len / 2), new three.Vector3(-width / 2, -len / 2 + width / 2),
+ new three.Vector3(0, -len / 2), new three.Vector3(width / 2, -len / 2 + width / 2),
+ new three.Vector3(0, -len / 2), new three.Vector3(0, len / 2),
+ new three.Vector3(0, len / 2), new three.Vector3(-width / 2, len / 2 - width / 2),
+ new three.Vector3(0, len / 2), new three.Vector3(width / 2, len / 2 - width / 2),
+ ];
+ else {
+ let w1 = Math.min(len, width) / 5;
+ return [
+ new three.Vector3(0, len / 2), new three.Vector3(0, -len / 2),
+ new three.Vector3(-width / 2), new three.Vector3(width / 2),
+ new three.Vector3(-width / 2), new three.Vector3(-width / 2 + w1, w1),
+ new three.Vector3(-width / 2), new three.Vector3(-width / 2 + w1, -w1),
+ new three.Vector3(width / 2), new three.Vector3(width / 2 - w1, w1),
+ new three.Vector3(width / 2), new three.Vector3(width / 2 - w1, -w1),
+ new three.Vector3(0, len / 2), new three.Vector3(-w1, len / 2 - w1),
+ new three.Vector3(0, len / 2), new three.Vector3(w1, len / 2 - w1),
+ new three.Vector3(0, -len / 2), new three.Vector3(-w1, -len / 2 + w1),
+ new three.Vector3(0, -len / 2), new three.Vector3(w1, -len / 2 + w1),
+ ];
+ }
+ }
+}
+
+var Board_1;
+/**
+ * 板件实体
+ */
+let Board = Board_1 = class Board extends ExtrudeSolid {
+ constructor() {
+ super();
+ this._Rotation = {
+ x: 0,
+ y: 0,
+ z: 0
+ };
+ this._Name = "";
+ //板件排钻表,与之碰撞板件为key
+ this._DrillList = new Map();
+ this._LayerNails = [];
+ this.RelativeHardware = [];
+ this.OpenDir = BoardOpenDir.None;
+ this._IsChaiDan = true;
+ this.InitBoardData();
+ }
+ /**
+ * 创建一个代理数组,数组改变时被监听
+ */
+ CreateArray() {
+ return new Proxy([], {
+ set: (target, key, value, receiver) => {
+ if (Reflect.get(target, key, receiver) !== value)
+ this.WriteAllObjectRecord();
+ return Reflect.set(target, key, value, receiver);
+ }
+ });
+ }
+ InitBoardData() {
+ let defaultData = {
+ roomName: "",
+ cabinetName: "",
+ boardName: "",
+ material: "",
+ color: "",
+ lines: LinesType.Positive,
+ bigHoleDir: FaceDirection.Front,
+ composingFace: ComposingType.Arbitrary,
+ highSealed: this.CreateArray(),
+ sealedUp: "1",
+ sealedDown: "1",
+ sealedLeft: "1",
+ sealedRight: "1",
+ spliteHeight: "",
+ spliteWidth: "",
+ spliteThickness: "",
+ highDrill: this.CreateArray(),
+ frontDrill: true,
+ backDrill: true,
+ drillType: "",
+ remarks: this.CreateArray(),
+ };
+ this._BoardProcessOption = new Proxy(defaultData, {
+ get: function (target, key, receiver) {
+ return Reflect.get(target, key, receiver);
+ },
+ set: (target, key, value, receiver) => {
+ if (Reflect.get(target, key, receiver) !== value) {
+ this.WriteAllObjectRecord();
+ if (key === "highDrill" || key === "highSealed") {
+ let arr = this.CreateArray();
+ arr.push(...value);
+ target[key] = arr;
+ return true;
+ }
+ let result = Reflect.set(target, key, value, receiver);
+ if (key === EBoardKeyList.Lines)
+ this.Update(UpdateDraw.Geometry);
+ return result;
+ }
+ return true;
+ }
+ });
+ }
+ //初始化板件 来自长宽高
+ InitBoard(length, width, thickness, boardType = BoardType.Layer) {
+ this._BoardType = boardType;
+ if (boardType === BoardType.Layer) {
+ this.ColorIndex = 2;
+ this._Name = "层板";
+ }
+ else if (boardType === BoardType.Vertical) {
+ this.ColorIndex = 11;
+ this._Name = "立板";
+ }
+ else {
+ this.ColorIndex = 3;
+ this._Name = "背板";
+ }
+ let types = [...userConfig.DrillConfigs.keys(), "不排"];
+ let type = types.includes(this.BoardProcessOption.drillType) ? this.BoardProcessOption.drillType : types[0];
+ this._BoardProcessOption.drillType = type;
+ this._BoardProcessOption.highDrill = Array(4).fill(type);
+ this.ConverToRectSolid(width, length, thickness);
+ this.Update(UpdateDraw.Geometry);
+ }
+ static CreateBoard(length, width, thickness, boardType = BoardType.Layer) {
+ let board = new Board_1();
+ board.InitBoard(length, width, thickness, boardType);
+ board.ApplyMatrix(board.RotateMat);
+ board._SpaceOCS.identity();
+ return board;
+ }
+ get DrillList() {
+ return this._DrillList;
+ }
+ get LayerNails() {
+ return this._LayerNails;
+ }
+ AppendNails(ids) {
+ this.WriteAllObjectRecord();
+ this._LayerNails.push(...ids);
+ }
+ ClearLayerNails() {
+ this.WriteAllObjectRecord();
+ for (let nail of this._LayerNails) {
+ if (nail.Object && !nail.IsErase)
+ nail.Object.Erase();
+ }
+ this._LayerNails.length = 0;
+ }
+ /**
+ * 你可以安心的修改它,这样会直接影响到板件,因为板件对这个对象添加了代理.
+ */
+ get BoardProcessOption() {
+ return this._BoardProcessOption;
+ }
+ set BoardProcessOption(obj) {
+ obj.highSealed = obj.highSealed.slice();
+ Object.assign(this._BoardProcessOption, obj);
+ }
+ get NeedUpdateRelevanceGroove() {
+ if (super.NeedUpdateRelevanceGroove)
+ return true;
+ for (let k of this.RelativeHardware) {
+ if (!k || !k.Object)
+ continue;
+ if (this.__CacheKnifVersion__[k.Index] !== (k.Object).__UpdateVersion__)
+ return true;
+ }
+ return false;
+ }
+ GetRelevanceKnifes(knifs) {
+ super.GetRelevanceKnifes(knifs);
+ for (let e of this.RelativeHardware) {
+ if (e.IsErase)
+ continue;
+ let hardware = e.Object;
+ if (hardware instanceof HardwareCompositeEntity) {
+ if (hardware.HardwareOption.isHole) {
+ let holes = hardware.GetAllEntity(true, e => e instanceof ExtrudeHole || e instanceof ExtrudeSolid);
+ for (let i = 0; i < holes.length; i++) {
+ let h = holes[i];
+ let g = h instanceof ExtrudeHole ? h.Convert2ExtrudeSolid() : h;
+ g.__TempIndexVersion__ = { Index: hardware.Id.Index, Version: hardware.__UpdateVersion__ };
+ knifs.push(g);
+ }
+ }
+ }
+ }
+ }
+ ClearRelevance(en) {
+ for (let id of this.RelativeHardware) {
+ let e = id.Object;
+ if (e instanceof HardwareCompositeEntity) {
+ arrayRemoveIf(e.RelevanceBoards, i => !i || i.Index === this.Id.Index);
+ }
+ }
+ this.RelativeHardware.length = 0;
+ super.ClearRelevance(en);
+ }
+ get SplitBoards() {
+ let brs = this.SplitExtrudes;
+ //拆单或者bbs的时候会重新加入最新的原板件的排钻和层板钉数据
+ for (let br of brs) {
+ if (br.__OriginalEnt__) {
+ br._DrillList.clear();
+ br._LayerNails.length = 0;
+ }
+ }
+ return brs;
+ }
+ get BoardModeling() {
+ let models = [];
+ for (let g of this.grooves) {
+ let cu = g.ContourCurve.Clone().ApplyMatrix(this.OCSInv.multiply(g.OCS));
+ let outline = Contour.CreateContour(cu, false);
+ let holes = [];
+ for (let subG of g.Grooves) {
+ let holeCu = subG.ContourCurve.Clone().ApplyMatrix(this.OCSInv.multiply(subG.OCS));
+ holes.push(Contour.CreateContour(holeCu, false));
+ }
+ let s = new Shape(outline, holes);
+ models.push({
+ shape: s,
+ thickness: g.Thickness,
+ dir: equaln(g.Position.applyMatrix4(this.OCSInv).z, 0) && g.Thickness < this.thickness - 1e-6 ? FaceDirection.Back : FaceDirection.Front,
+ knifeRadius: g.KnifeRadius,
+ addLen: g.GroovesAddLength,
+ addWidth: g.GroovesAddWidth,
+ addDepth: g.GroovesAddDepth,
+ });
+ }
+ return models;
+ }
+ set BoardModeling(models) {
+ this.WriteAllObjectRecord();
+ this.grooves.length = 0;
+ for (let model of models) {
+ let g = new ExtrudeSolid();
+ g.OCS = this.OCS;
+ g.ContourCurve = model.shape.Outline.Curve;
+ g.Thickness = model.thickness;
+ g.GroovesAddLength = model.addLen;
+ g.KnifeRadius = model.knifeRadius;
+ for (let hole of model.shape.Holes) {
+ let subG = new ExtrudeSolid();
+ subG.OCS = this.OCS;
+ subG.ContourCurve = hole.Curve;
+ subG.Thickness = model.thickness;
+ g.AppendGroove(subG);
+ }
+ if (model.dir === FaceDirection.Front)
+ g.ApplyMatrix(MoveMatrix(new three.Vector3(0, 0, this.thickness - g.Thickness)));
+ this.grooves.push(g);
+ }
+ this.Update();
+ }
+ get IsChaiDan() {
+ return this._IsChaiDan;
+ }
+ set IsChaiDan(v) {
+ if (this._IsChaiDan !== v) {
+ this.WriteAllObjectRecord();
+ this._IsChaiDan = v;
+ this.Update(UpdateDraw.Geometry);
+ }
+ }
+ ClearBoardModeling() {
+ this.WriteAllObjectRecord();
+ this.grooves.length = 0;
+ this.Update(UpdateDraw.Geometry);
+ }
+ /**
+ * 注意传入的排钻列表,避免指针被引用
+ */
+ AppendDrillList(k, drs) {
+ this.WriteAllObjectRecord();
+ let oldDrs = this._DrillList.get(k);
+ if (oldDrs)
+ oldDrs.push(...drs); //同类型板件时,会触发这里.
+ else
+ this._DrillList.set(k, drs);
+ }
+ ClearDrillList(k) {
+ let drids = this._DrillList.get(k);
+ if (drids) {
+ this.WriteAllObjectRecord();
+ for (let drillents of drids) {
+ for (let objId of drillents) {
+ if (!objId.IsErase)
+ objId.Object.Erase();
+ }
+ }
+ this._DrillList.delete(k);
+ if (k && k.Object) {
+ //必须在这里删除
+ let br = k.Object;
+ br.ClearDrillList(this.Id);
+ }
+ }
+ }
+ ClearAllDrillList() {
+ for (const [id] of this._DrillList) {
+ this.ClearDrillList(id);
+ }
+ }
+ Erase(isErase = true) {
+ if (isErase === this.IsErase)
+ return;
+ super.Erase(isErase);
+ if (!isErase)
+ return;
+ //记录数据,避免下面记录的时候,排钻已经被删除,导致排钻数据被优化掉.
+ this.WriteAllObjectRecord();
+ for (const [, driss] of this._DrillList) {
+ for (let dris of driss)
+ for (let d of dris)
+ if (d && d.Object)
+ d.Object.Erase();
+ }
+ this.ClearLayerNails();
+ }
+ get RotateMat() {
+ let roMat = new three.Matrix4();
+ switch (this._BoardType) {
+ case BoardType.Layer:
+ roMat.makeBasis(new three.Vector3(0, 1, 0), new three.Vector3(-1, 0, 0), new three.Vector3(0, 0, 1));
+ break;
+ case BoardType.Vertical:
+ roMat.makeBasis(new three.Vector3(0, 1, 0), new three.Vector3(0, 0, 1), new three.Vector3(1, 0, 0));
+ break;
+ case BoardType.Behind:
+ roMat.makeBasis(new three.Vector3(1, 0, 0), new three.Vector3(0, 0, 1), new three.Vector3(0, -1, 0));
+ }
+ return roMat;
+ }
+ get Height() {
+ return this.height;
+ }
+ set Height(v) {
+ if (this.ContourCurve instanceof exports.Circle)
+ return;
+ if (!equaln(v, this.height, 1e-2)) {
+ this.WriteAllObjectRecord();
+ let refHeight = this.height / 2;
+ let dist = v - this.height;
+ let contour = Contour.CreateContour(this.ContourCurve, false);
+ let isSuccess = contour.UnEqualProportionScale(refHeight, dist, "y");
+ if (isSuccess) {
+ this.height = v;
+ this.GrooveCheckAllAutoSplit();
+ this.Update();
+ }
+ }
+ }
+ get Width() {
+ return this.width;
+ }
+ set Width(v) {
+ if (this.ContourCurve instanceof exports.Circle)
+ return;
+ if (!equaln(v, this.width, 1e-2)) {
+ this.WriteAllObjectRecord();
+ let refDist = this.width / 2;
+ let dist = v - this.width;
+ let contour = Contour.CreateContour(this.ContourCurve, false);
+ let isSuccess = contour.UnEqualProportionScale(refDist, dist, "x");
+ if (isSuccess) {
+ this.width = v;
+ this.GrooveCheckAllAutoSplit();
+ this.Update();
+ }
+ }
+ }
+ get BoardType() {
+ return this._BoardType;
+ }
+ set BoardType(type) {
+ this.WriteAllObjectRecord();
+ if (type !== this._BoardType) {
+ let spaceCS = this._SpaceOCS.clone();
+ this._BoardType = type;
+ this.ApplyMatrix(this.OCSInv);
+ this.ApplyMatrix(this.RotateMat);
+ this._SpaceOCS.identity();
+ this.ApplyMatrix(spaceCS);
+ this.Update();
+ }
+ }
+ //设置板件类型并且不做任何的事情
+ SetBoardType(type) {
+ this.WriteAllObjectRecord();
+ this._BoardType = type;
+ }
+ //最左下角的点
+ get MinPoint() {
+ switch (this._BoardType) {
+ case BoardType.Layer:
+ return new three.Vector3(0, this.height).applyMatrix4(this.OCS);
+ case BoardType.Vertical:
+ return this.Position;
+ case BoardType.Behind:
+ return new three.Vector3(0, 0, this.thickness).applyMatrix4(this.OCS);
+ }
+ }
+ get MaxPoint() {
+ let pt = new three.Vector3(this.width, this.height, -this.thickness);
+ pt.applyMatrix4(this.OCS);
+ return pt;
+ }
+ get IsRect() {
+ return this.isRect;
+ }
+ get IsSpecialShape() {
+ return !this.isRect;
+ }
+ get HasGroove() {
+ return this.grooves.length > 0;
+ }
+ get Name() {
+ return this._Name;
+ }
+ set Name(n) {
+ this.WriteAllObjectRecord();
+ this._Name = n;
+ }
+ /**
+ * 板件的轮廓,在板件坐标系中的表现方式.
+ */
+ get ContourCurve() {
+ return super.ContourCurve;
+ }
+ set ContourCurve(cu) {
+ if (!this.contourCurve || cu.EndParam !== this.contourCurve.EndParam || !this.BoardProcessOption.drillType) {
+ let defaultType = this._BoardProcessOption.drillType;
+ if (!defaultType) {
+ defaultType = userConfig.DrillConfigs.size > 0 ? [...userConfig.DrillConfigs.keys()][0] : "不排";
+ this._BoardProcessOption.drillType = defaultType;
+ }
+ this._BoardProcessOption.highDrill = Array(cu.EndParam).fill(defaultType);
+ }
+ super.ContourCurve = cu;
+ }
+ Explode() {
+ return Board2Regions(this);
+ // return this.m_Shape.Explode().map(cu => cu.ApplyMatrix(this.OCS));
+ }
+ RotateBoard(rox, roy, roz) {
+ this.WriteAllObjectRecord();
+ this._Rotation.x = rox;
+ this._Rotation.y = roy;
+ this._Rotation.z = roz;
+ let spcocs = this.SpaceOCS;
+ let roMatX = new three.Matrix4().makeRotationX(rox);
+ let roMatY = new three.Matrix4().makeRotationY(roy);
+ let roMatZ = new three.Matrix4().makeRotationZ(roz);
+ this.ApplyMatrix(this.OCSInv)
+ .ApplyMatrix(this.RotateMat)
+ .ApplyMatrix(roMatX)
+ .ApplyMatrix(roMatY)
+ .ApplyMatrix(roMatZ)
+ .ApplyMatrix(spcocs);
+ this._SpaceOCS.copy(spcocs);
+ this.Update();
+ }
+ get Rotation() {
+ return this._Rotation;
+ }
+ ApplyMirrorMatrix(m) {
+ return this;
+ }
+ get UCGenerator() {
+ if (this.BoardProcessOption.lines === LinesType.Positive)
+ return boardUVGenerator;
+ else
+ return boardUVGenerator2;
+ }
+ UpdateUV(geo, ocs, isRev = false) {
+ super.UpdateUV(geo, ocs, this.BoardProcessOption.lines === LinesType.Reverse);
+ }
+ //从一个实体拷贝数据,实体类型必须相同.
+ CopyFrom(obj) {
+ this.WriteAllObjectRecord();
+ let drillBak = this._DrillList;
+ this._DrillList = new Map();
+ let layerNailsBak = this._LayerNails;
+ this._LayerNails = [];
+ super.CopyFrom(obj);
+ this._DrillList = drillBak;
+ this._LayerNails = layerNailsBak;
+ }
+ Clone() {
+ let br = super.Clone();
+ br._DrillList.clear();
+ br._LayerNails.length = 0;
+ br.RelativeHardware.length = 0;
+ return br;
+ }
+ Join(target) {
+ let res = super.Join(target);
+ if (res && target.RelativeHardware) {
+ for (let hw of target.RelativeHardware) {
+ if (!this.RelativeHardware.includes(hw))
+ this.RelativeHardware.push(hw);
+ }
+ }
+ return res;
+ }
+ GetLinesDir() {
+ let l;
+ let len;
+ let width;
+ switch (this.BoardProcessOption.lines) {
+ case LinesType.Positive:
+ len = this.height / 3;
+ width = Math.min(this.width, this.height) / 8;
+ break;
+ case LinesType.Reverse:
+ len = this.width / 2;
+ width = Math.min(this.width, this.height) / 8;
+ break;
+ case LinesType.CanReversal:
+ len = this.height / 3;
+ width = this.width / 2;
+ }
+ l = new three.LineSegments(BufferGeometryUtils.CreateFromPts(PointShapeUtils.LinesDirPts(len, width, this.BoardProcessOption.lines)), ColorMaterial.GetLineMaterial(8));
+ let l1 = l.clone();
+ l1.material = ColorMaterial.GetLineMaterial(7);
+ l.position.set(this.width / 2, this.height / 2, 0);
+ l1.position.set(this.width / 2, this.height / 2, this.thickness);
+ l.updateMatrix();
+ l1.updateMatrix();
+ return [l, l1];
+ }
+ HandleSpliteEntitys(splitEntitys) {
+ let nails = [];
+ for (let nail of this.LayerNails) {
+ if ((nail === null || nail === void 0 ? void 0 : nail.Object) && !nail.IsErase)
+ nails.push(nail);
+ }
+ let record = this._Owner.Object;
+ for (let en of splitEntitys) {
+ let ocsInv = en.OCSInv;
+ let nids = [];
+ let needAddNailEnts = [];
+ nails = nails.filter(id => {
+ let n = id.Object;
+ let position = n.Position.applyMatrix4(ocsInv).setZ(0);
+ if (en.contourCurve.PtInCurve(position)) {
+ let n1 = n.Clone();
+ n1.MId = n.MId;
+ n1.FId = n.FId;
+ if (n.MId === this.Id) {
+ n1.MId = en.Id;
+ needAddNailEnts.push(n1.FId.Object);
+ }
+ if (n.FId === this.Id) {
+ n1.FId = en.Id;
+ needAddNailEnts.push(n1.MId.Object);
+ }
+ n.Erase();
+ record.Add(n1);
+ nids.push(n1.Id);
+ return false;
+ }
+ return true;
+ });
+ en.AppendNails(nids);
+ needAddNailEnts.forEach(e => e.AppendNails(nids));
+ }
+ }
+ InitDrawObject(renderType = RenderType.Wireframe) {
+ let obj = super.InitDrawObject(renderType);
+ this.HandleBoardMaterial(renderType, obj);
+ return obj;
+ }
+ UpdateDrawObject(renderType, obj) {
+ let o = super.UpdateDrawObject(renderType, obj);
+ this.HandleBoardMaterial(renderType, obj);
+ return o;
+ }
+ HandleBoardMaterial(renderType, obj) {
+ if (!this.IsChaiDan) {
+ if (renderType === RenderType.Conceptual || renderType === RenderType.Physical2) {
+ obj.children.length = 1;
+ obj.children[0].material = ColorMaterial.GrayTransparentMeshMaterial;
+ }
+ else if (renderType !== RenderType.Wireframe) {
+ obj.material = ColorMaterial.GrayTransparentMeshMaterial;
+ }
+ }
+ if ((renderType === RenderType.Wireframe || renderType === RenderType.Conceptual) && userConfig.showLines && this.IsChaiDan)
+ obj.add(...this.GetLinesDir());
+ }
+ UpdateDrawObjectMaterial(renderType, obj) {
+ super.UpdateDrawObjectMaterial(renderType, obj);
+ if (!this.IsChaiDan) {
+ if (renderType === RenderType.Conceptual || renderType === RenderType.Physical2) {
+ obj.children[0].material = ColorMaterial.GrayTransparentMeshMaterial;
+ }
+ else if (renderType !== RenderType.Wireframe) {
+ obj.material = ColorMaterial.GrayTransparentMeshMaterial;
+ }
+ }
+ }
+ DeferUpdate() {
+ if (this.NeedUpdateFlag & UpdateDraw.Matrix) {
+ if (this.RelativeHardware.some(id => !id.IsErase))
+ this.NeedUpdateFlag |= UpdateDraw.Geometry;
+ }
+ super.DeferUpdate();
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read();
+ if (ver < 6)
+ this._SpaceOCS.fromArray(file.Read());
+ this._BoardType = file.Read();
+ this._Name = file.Read();
+ //兼容旧版本
+ if (ver > 2) {
+ deserializationBoardData(file, this._BoardProcessOption, ver);
+ }
+ else {
+ let opt = file.Read();
+ this._BoardProcessOption = Object.assign(this._BoardProcessOption, typeof opt === "string" ? JSON.parse(opt) : opt);
+ }
+ //读取排钻列表
+ this._DrillList.clear();
+ let size = file.Read();
+ //没有与任何板件关联的排钻
+ let noRelevancyDrillings = [];
+ for (let i = 0; i < size; i++) {
+ let id = file.ReadObjectId();
+ let drIdList = [];
+ let count = file.Read();
+ for (let i = 0; i < count; i++) {
+ let drIDs = [];
+ let count1 = file.Read();
+ for (let j = 0; j < count1; j++) {
+ let fileId = file.ReadObjectId();
+ fileId && drIDs.push(fileId);
+ }
+ if (drIDs.length > 0)
+ drIdList.push(drIDs);
+ }
+ if (drIdList.length === 0)
+ continue;
+ if (!id)
+ noRelevancyDrillings.push(...drIdList);
+ else
+ this._DrillList.set(id, drIdList);
+ }
+ if (noRelevancyDrillings.length > 0)
+ this._DrillList.set(undefined, noRelevancyDrillings);
+ if (ver > 1) {
+ this._LayerNails.length = 0;
+ let nailsCount = file.Read();
+ for (let i = 0; i < nailsCount; i++) {
+ let objId = file.ReadObjectId();
+ if (objId)
+ this._LayerNails.push(objId);
+ }
+ }
+ if (ver > 4)
+ this._Rotation = { x: file.Read(), y: file.Read(), z: file.Read() };
+ if (ver >= 7) {
+ let count = file.Read();
+ this.RelativeHardware.length = 0;
+ for (let i = 0; i < count; i++) {
+ let objId = file.ReadObjectId();
+ if (objId)
+ this.RelativeHardware.push(objId);
+ }
+ }
+ if (ver >= 8)
+ this.OpenDir = file.Read();
+ if (ver >= 9)
+ this._IsChaiDan = file.Read();
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(9);
+ // file.Write(this._SpaceOCS.toArray()); ver < 6
+ file.Write(this._BoardType);
+ file.Write(this._Name);
+ serializeBoardData(file, this._BoardProcessOption);
+ file.Write(this._DrillList.size);
+ for (let [id, idList] of this._DrillList) {
+ file.WriteObjectId(id);
+ file.Write(idList.length);
+ for (let ids of idList) {
+ file.Write(ids.length);
+ for (let id of ids)
+ file.WriteObjectId(id);
+ }
+ }
+ file.Write(this._LayerNails.length);
+ for (let nail of this._LayerNails) {
+ file.WriteObjectId(nail);
+ }
+ file.Write(this._Rotation.x);
+ file.Write(this._Rotation.y);
+ file.Write(this._Rotation.z);
+ file.Write(this.RelativeHardware.length);
+ for (let id of this.RelativeHardware)
+ file.WriteObjectId(id);
+ file.Write(this.OpenDir);
+ file.Write(this._IsChaiDan);
+ }
+};
+__decorate([
+ AutoRecord
+], Board.prototype, "RelativeHardware", void 0);
+__decorate([
+ AutoRecord
+], Board.prototype, "OpenDir", void 0);
+Board = Board_1 = __decorate([
+ Factory
+], Board);
+
+function FastWireframe(br, color = 0) {
+ color = color || br.ColorIndex;
+ let material = ColorMaterial.GetLineMaterial(color);
+ let thickness = br.Thickness;
+ let cu = br.ContourCurve;
+ let pts = cu.Shape.getPoints(6);
+ let geo = new three.BufferGeometry();
+ let coords = [];
+ let edgeCoords = [];
+ for (let p of pts) {
+ coords.push(p.x, p.y, 0);
+ if (p["_mask_"])
+ edgeCoords.push(p.x, p.y, 0, p.x, p.y, thickness);
+ }
+ for (let p of pts)
+ coords.push(p.x, p.y, thickness);
+ let edgeGeo = new three.BufferGeometry();
+ edgeGeo.setAttribute('position', new three.Float32BufferAttribute(edgeCoords, 3));
+ geo.setAttribute('position', new three.Float32BufferAttribute(coords, 3));
+ let line = new three.Line(geo, material);
+ line.applyMatrix4(cu.OCS);
+ let edge = new three.LineSegments(edgeGeo, material);
+ edge.applyMatrix4(cu.OCS);
+ let result = [line, edge];
+ let ocsInv = br.OCSInv;
+ for (let g of br.Grooves) {
+ let m = ocsInv.clone().multiply(g.OCS);
+ let lines = FastWireframe(g, color);
+ for (let l of lines) {
+ l.applyMatrix4(m);
+ result.push(l);
+ }
+ }
+ return result;
+}
+function FastWireframe2(dr, color = 0) {
+ color = color || dr.ColorIndex;
+ let material = ColorMaterial.GetLineMaterial(color);
+ let height = dr.Height;
+ let cu = dr.ContourCurve;
+ let pts = cu.Shape.getPoints(6);
+ let geo = new three.BufferGeometry();
+ let coords = [];
+ let edgeCoords = [];
+ for (let p of pts) {
+ coords.push(p.x, p.y, 0);
+ if (p["_mask_"])
+ edgeCoords.push(p.x, p.y, 0, p.x, p.y, height);
+ }
+ for (let p of pts)
+ coords.push(p.x, p.y, height);
+ let edgeGeo = new three.BufferGeometry();
+ edgeGeo.setAttribute('position', new three.Float32BufferAttribute(edgeCoords, 3));
+ geo.setAttribute('position', new three.Float32BufferAttribute(coords, 3));
+ let line = new three.Line(geo, material);
+ line.applyMatrix4(cu.OCS);
+ let edge = new three.LineSegments(edgeGeo, material);
+ edge.applyMatrix4(cu.OCS);
+ let result = [line, edge];
+ return result;
+}
+
+let Hole = class Hole extends Entity {
+ get Height() {
+ return this._Height;
+ }
+ set Height(v) {
+ if (this._Height !== v) {
+ this.WriteAllObjectRecord();
+ this._Height = v;
+ this.Update();
+ }
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read(); //1
+ if (ver <= 4) {
+ //临时兼容旧图纸排钻,更新旧图纸后去掉兼容代码
+ file['readIndex']--;
+ }
+ else {
+ this._Height = file.Read();
+ this.FId = file.ReadSoftObjectId();
+ this.MId = file.ReadSoftObjectId();
+ }
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(5); //ver
+ file.Write(this._Height);
+ file.WriteSoftObjectId(this.FId);
+ file.WriteSoftObjectId(this.MId);
+ }
+};
+__decorate([
+ AutoRecord
+], Hole.prototype, "FId", void 0);
+__decorate([
+ AutoRecord
+], Hole.prototype, "MId", void 0);
+Hole = __decorate([
+ Factory
+], Hole);
+
+let ExtrudeHole = class ExtrudeHole extends Hole {
+ constructor() {
+ super(...arguments);
+ this._contourCurve = new exports.Polyline();
+ this._knifeRadius = 3;
+ this.isHole = true;
+ }
+ get KnifeRadius() {
+ return this._knifeRadius;
+ }
+ set KnifeRadius(v) {
+ if (!equaln(v, this._knifeRadius)) {
+ this.WriteAllObjectRecord();
+ this._knifeRadius = v;
+ }
+ }
+ Explode() {
+ return [this.ContourCurve.Clone().ApplyMatrix(this.OCS)];
+ }
+ get ContourCurve() {
+ return this._contourCurve;
+ }
+ set ContourCurve(curve) {
+ if (!curve.IsClose)
+ return;
+ if (curve instanceof exports.Polyline) {
+ curve.CloseMark = true;
+ let pts = curve.LineData;
+ if (equalv2(pts[0].pt, arrayLast(pts).pt))
+ pts.pop();
+ //如果曲线被旋转了,那么修正它的旋转矩阵,避免纹路错误
+ let ocs = curve.OCS;
+ if (!equaln(ocs.elements[0], 1)) // || ocs.elements[9] || ocs.elements[10]
+ {
+ for (let p of pts)
+ Vector2ApplyMatrix4(ocs, p.pt);
+ curve.OCS = new three.Matrix4();
+ }
+ curve.ClearDraw();
+ }
+ this.WriteAllObjectRecord();
+ this._contourCurve = curve;
+ this.CheckContourCurve();
+ this.Update();
+ }
+ CheckContourCurve() {
+ let box = this._contourCurve.BoundingBox;
+ //修正轮廓基点
+ if (!equalv3(box.min, ZeroVec)) {
+ this._contourCurve.Position =
+ this._contourCurve.Position.sub(box.min);
+ let v = box.min.applyMatrix4(this.OCS.setPosition(ZeroVec));
+ this._Matrix.setPosition(this.Position.add(v));
+ }
+ }
+ ApplyScaleMatrix(m) {
+ this.WriteAllObjectRecord();
+ let cu = this.ContourCurve;
+ cu.ApplyMatrix(this.OCS);
+ cu.ApplyMatrix(m);
+ cu.ApplyMatrix(this.OCSInv);
+ this.CheckContourCurve();
+ this.Update();
+ return this;
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ switch (snapMode) {
+ case ObjectSnapMode.End:
+ return this.GetStretchPoints();
+ case ObjectSnapMode.Mid:
+ case ObjectSnapMode.Cen:
+ case ObjectSnapMode.Nea:
+ case ObjectSnapMode.Ext:
+ case ObjectSnapMode.Per:
+ case ObjectSnapMode.Tan:
+ {
+ let contour = this.ContourCurve.Clone();
+ contour.ApplyMatrix(this.OCS);
+ let pts = contour.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform);
+ contour.Position = contour.Position.add(this.Normal.multiplyScalar(this.Height));
+ pts.push(...contour.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ if (snapMode === ObjectSnapMode.Mid)
+ pts.push(...contour.GetStretchPoints().map(p => p.add(this.Normal.multiplyScalar(-this.Height / 2))));
+ return pts;
+ }
+ }
+ return [];
+ }
+ get Shape() {
+ let contour = Contour.CreateContour(this.ContourCurve.Clone(), false);
+ return new Shape(contour);
+ }
+ get BoundingBoxInOCS() {
+ let box = new Box3Ext().copy(this.ContourCurve.BoundingBox);
+ box.max.add(new three.Vector3(0, 0, this.Height));
+ return box;
+ }
+ get BoundingBox() {
+ let box = this.ContourCurve.BoundingBox;
+ box.max.add(new three.Vector3(0, 0, this.Height));
+ box.applyMatrix4(this.OCS);
+ return box;
+ }
+ get EdgeGeometry() {
+ if (this._EdgeGeometry)
+ return this._EdgeGeometry;
+ let pts = [this.ContourCurve.Shape.getPoints(6).map(AsVector3)];
+ this._EdgeGeometry = GenerateExtrudeEdgeGeometry(pts, this.Height).applyMatrix4(this._contourCurve.OCSNoClone);
+ return this._EdgeGeometry;
+ }
+ get MeshGeometry() {
+ if (this._MeshGeometry)
+ return this._MeshGeometry;
+ this._MeshGeometry = this.GeneralMeshGeometry();
+ return this._MeshGeometry;
+ }
+ GeneralMeshGeometry() {
+ let extrudeSettings = {
+ curveSegments: 12,
+ steps: 1,
+ bevelEnabled: false,
+ depth: this.Height,
+ };
+ let geo = new three.ExtrudeGeometry(this.ContourCurve.Shape, extrudeSettings);
+ geo.applyMatrix4(this._contourCurve.OCS);
+ return geo;
+ }
+ GetGripOrStretchPoints(dragType) {
+ let isGrip = dragType === DragPointType.Grip;
+ let pts = isGrip ? this.ContourCurve.GetGripPoints() : this.ContourCurve.GetStretchPoints();
+ let v = new three.Vector3(0, 0, this.Height);
+ pts.push(...pts.map(p => p.clone().add(v)));
+ pts.forEach(p => { p.applyMatrix4(this.OCS); });
+ return pts;
+ }
+ GetStrectchPointCountList(dragType) {
+ return this.ContourCurve.GetDragPointCount(dragType) * 2;
+ }
+ MoveGripOrStretchPoints(indexList, vec, dragType) {
+ this.WriteAllObjectRecord();
+ if (dragType === DragPointType.Stretch && indexList.length === this.GetStrectchPointCountList(dragType)) {
+ this.Position = this.Position.add(vec);
+ return;
+ }
+ arraySortByNumber(indexList);
+ this.MoveGripOrStretchPointsOnly(indexList, vec, dragType);
+ this.CheckContourCurve();
+ this.Update();
+ }
+ IsStretchHeight(indexs) {
+ let count = this.ContourCurve.GetStretchPoints().length;
+ if (indexs.length === count) {
+ let isF = indexs[0] < count;
+ return indexs.every(i => isF === (i < count));
+ }
+ return false;
+ }
+ MoveGripOrStretchPointsOnly(indexList, vec, dragType) {
+ let stretchCount = this.ContourCurve.GetDragPointCount(dragType);
+ if (dragType === DragPointType.Stretch) {
+ //Move
+ if (indexList.length === stretchCount * 2) {
+ this.Position = this.Position.add(vec);
+ return;
+ }
+ //判断是否拉伸厚度
+ if (this.IsStretchHeight(indexList)) {
+ let isFront = indexList[0] < stretchCount;
+ if (indexList.every(v => v < stretchCount === isFront)) {
+ //Change thickness
+ let lvec = vec.clone().applyMatrix4(this.OCSInv.setPosition(ZeroVec));
+ if (isFront) {
+ this.Height -= lvec.z;
+ //移动位置而不改变内部拉槽
+ let v = this.Normal.multiplyScalar(lvec.z);
+ this._Matrix.elements[12] += v.x;
+ this._Matrix.elements[13] += v.y;
+ this._Matrix.elements[14] += v.z;
+ }
+ else {
+ this.Height += lvec.z;
+ }
+ return;
+ }
+ }
+ indexList = arrayClone(indexList);
+ }
+ //修正点的索引
+ for (let i = 0; i < indexList.length; i++) {
+ let index = indexList[i];
+ if (index >= stretchCount) {
+ index -= stretchCount;
+ indexList[i] = index;
+ }
+ }
+ indexList = [...new Set(indexList)];
+ let localVec = vec.clone().applyMatrix4(this.OCSInv.setPosition(ZeroVec));
+ if (dragType === DragPointType.Grip) {
+ if (this.ContourCurve instanceof exports.Polyline
+ && indexList.length === 1
+ && indexList[0] % 2 === 1) {
+ let param = indexList[0] / 2;
+ if (this.ContourCurve.GetBuilgeAt(Math.floor(param)) === 0) {
+ let der = this.ContourCurve.GetFistDeriv(param).normalize();
+ [der.x, der.y] = [der.y, -der.x];
+ let d = localVec.dot(der);
+ localVec.copy(der).multiplyScalar(d);
+ }
+ }
+ this.ContourCurve.MoveGripPoints(indexList, localVec);
+ }
+ else
+ this.ContourCurve.MoveStretchPoints(indexList, localVec);
+ }
+ GetGripPoints() {
+ return this.GetGripOrStretchPoints(DragPointType.Grip);
+ }
+ GetStretchPoints() {
+ return this.GetGripOrStretchPoints(DragPointType.Stretch);
+ }
+ MoveGripPoints(indexList, vec) {
+ this.MoveGripOrStretchPoints(indexList, vec, DragPointType.Grip);
+ }
+ MoveStretchPoints(indexList, vec) {
+ this.MoveGripOrStretchPoints(indexList, vec, DragPointType.Stretch);
+ }
+ Convert2ExtrudeSolid() {
+ let g = new ExtrudeSolid();
+ g.KnifeRadius = this.KnifeRadius;
+ g.SetContourCurve(this.ContourCurve);
+ g.Thickness = this.Height;
+ g.ApplyMatrix(this.OCS);
+ return g;
+ }
+ GetPrintObject3D() {
+ let geometry = new LineGeometry.LineGeometry();
+ let lineSegments = new Float32Array(this.EdgeGeometry.attributes.position.array);
+ let instanceBuffer = new three.InstancedInterleavedBuffer(lineSegments, 6, 1);
+ geometry.setAttribute('instanceStart', new three.InterleavedBufferAttribute(instanceBuffer, 3, 0));
+ geometry.setAttribute('instanceEnd', new three.InterleavedBufferAttribute(instanceBuffer, 3, 3));
+ let line = new Line2.Line2(geometry, ColorMaterial.PrintLineMatrial);
+ let mesh = new three.Mesh(this.MeshGeometry, ColorMaterial.GetPrintConceptualMaterial());
+ return [line, mesh];
+ }
+ InitDrawObject(renderType = RenderType.Wireframe) {
+ if (renderType === RenderType.Wireframe) {
+ return new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex));
+ }
+ else if (renderType === RenderType.Conceptual || renderType === RenderType.Physical || renderType === RenderType.Physical2) {
+ return new three.Object3D().add(new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ else if (renderType === RenderType.Jig) {
+ return new three.Object3D().add(...FastWireframe2(this));
+ }
+ else if (renderType === RenderType.Print) {
+ return new three.Object3D().add(...this.GetPrintObject3D());
+ }
+ }
+ UpdateDrawObject(renderType, obj) {
+ DisposeThreeObj(obj);
+ if (renderType !== RenderType.Wireframe)
+ Object3DRemoveAll(obj);
+ this._EdgeGeometry = undefined;
+ this._MeshGeometry = undefined;
+ this.MeshGeometry;
+ if (renderType === RenderType.Wireframe) {
+ let l = obj;
+ l.geometry = this.EdgeGeometry;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (renderType === RenderType.Print) {
+ obj.add(...this.GetPrintObject3D());
+ }
+ else if (renderType === RenderType.Conceptual || renderType === RenderType.Physical || renderType === RenderType.Physical2) {
+ obj.add(new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ else if (renderType === RenderType.Jig)
+ obj.add(...FastWireframe2(this));
+ return obj;
+ }
+ UpdateDrawObjectMaterial(renderType, obj) {
+ if (renderType === RenderType.Wireframe) {
+ let l = obj;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (renderType !== RenderType.Jig && renderType !== RenderType.Print) {
+ let mesh = obj.children[0];
+ mesh.material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
+ }
+ }
+ get OBB() {
+ let size = this.ContourCurve.BoundingBox.getSize(new three.Vector3).setZ(this.Height);
+ return new OBB(this.OCS, size.multiplyScalar(0.5));
+ }
+ ReadFile(file) {
+ super.ReadFile(file);
+ let ver = file.Read();
+ this._contourCurve = file.ReadObject();
+ this._knifeRadius = file.Read();
+ if (ver > 1) {
+ this.isHole = file.Read();
+ }
+ this.Update();
+ }
+ //对象将自身数据写入到文件.
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(2);
+ file.WriteObject(this._contourCurve);
+ file.Write(this._knifeRadius);
+ file.Write(this.isHole);
+ }
+};
+__decorate([
+ AutoRecord
+], ExtrudeHole.prototype, "isHole", void 0);
+ExtrudeHole = __decorate([
+ Factory
+], ExtrudeHole);
+
+var BoardFaceType;
+(function (BoardFaceType) {
+ BoardFaceType[BoardFaceType["Side"] = 0] = "Side";
+ BoardFaceType[BoardFaceType["NoSide"] = 1] = "NoSide";
+})(BoardFaceType || (BoardFaceType = {}));
+function GetSideFaceMtx(cu, inverseZ = false) {
+ let x = cu.GetFistDeriv(0).normalize();
+ let y = ZAxis;
+ let z = x.clone().cross(y);
+ if (inverseZ)
+ z.negate();
+ let basePt;
+ if ((equaln(x.x, 0) && x.y > 0) || x.x < 0) {
+ x.negate();
+ basePt = cu.EndPoint;
+ }
+ else
+ basePt = cu.StartPoint;
+ //构建面矩阵
+ return new three.Matrix4()
+ .makeBasis(x, y, z)
+ .setPosition(basePt);
+}
+
+function FixIndex$1(index, arr) {
+ let count = (arr instanceof Array) ? arr.length : arr;
+ if (index < 0)
+ return count + index;
+ else if (index >= count)
+ return index - count;
+ else
+ return index;
+}
+
+var CylinderHole_1;
+var GangDrillType;
+(function (GangDrillType) {
+ /**偏心轮 */
+ GangDrillType[GangDrillType["Pxl"] = 0] = "Pxl";
+ /**连接杆 */
+ GangDrillType[GangDrillType["Ljg"] = 1] = "Ljg";
+ /**预埋件 */
+ GangDrillType[GangDrillType["Ymj"] = 2] = "Ymj";
+ /**层板钉 */
+ GangDrillType[GangDrillType["Nail"] = 3] = "Nail";
+ /** 木销 */
+ GangDrillType[GangDrillType["Wood"] = 4] = "Wood";
+ /** 通孔 */
+ GangDrillType[GangDrillType["TK"] = 5] = "TK";
+ GangDrillType[GangDrillType["WoodPXL"] = 6] = "WoodPXL";
+})(GangDrillType || (GangDrillType = {}));
+let TempCircle1 = new exports.Circle();
+let TempCircle2 = new exports.Circle();
+let CylinderHole = CylinderHole_1 = class CylinderHole extends Hole {
+ constructor() {
+ super();
+ this._Radius = 1;
+ this.type = GangDrillType.Pxl;
+ this._Color = 1;
+ }
+ static CreateCylHole(radius, height, type) {
+ let drill = new CylinderHole_1();
+ drill.Height = height;
+ drill._Radius = radius;
+ drill.type = type;
+ return drill;
+ }
+ get Type() {
+ return this.type;
+ }
+ set Type(t) {
+ if (this.type !== t) {
+ this.WriteAllObjectRecord();
+ this.type = t;
+ }
+ }
+ set Radius(r) {
+ if (r !== this._Radius) {
+ this.WriteAllObjectRecord();
+ this._MeshGeometry = null;
+ this._EdgeGeometry = null;
+ this._Radius = r;
+ this.Update();
+ }
+ }
+ get Height() {
+ return super.Height;
+ }
+ set Height(v) {
+ if (this._Height !== v) {
+ this._MeshGeometry = null;
+ this._EdgeGeometry = null;
+ super.Height = v;
+ }
+ }
+ get Radius() {
+ return this._Radius;
+ }
+ get BoundingBox() {
+ let box = new three.Box3(new three.Vector3(-this._Radius, -this._Radius, 0), new three.Vector3(this._Radius, this._Radius, this._Height));
+ return box.applyMatrix4(this.OCS);
+ }
+ get MeshGeometry() {
+ if (this._MeshGeometry)
+ return this._MeshGeometry;
+ this._MeshGeometry = FastDrillingMeshGeometry(this.Radius, this.Height);
+ return this._MeshGeometry;
+ }
+ get EdgeGeometry() {
+ if (this._EdgeGeometry)
+ return this._EdgeGeometry;
+ this._EdgeGeometry = FastDrillingEdgeGeometry(this._Radius, this.Height);
+ return this._EdgeGeometry;
+ }
+ GetGripPoints() {
+ let cir = new exports.Circle(new three.Vector3(), this._Radius);
+ let pts = cir.GetGripPoints();
+ pts.push(...pts.map(p => p.clone().add(new three.Vector3(0, 0, this.Height))));
+ return pts.map(p => p.applyMatrix4(this.OCS));
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ let pts = [];
+ TempCircle1.Radius = this.Radius;
+ TempCircle1.OCS = this._Matrix;
+ TempCircle2.Radius = this.Radius;
+ TempCircle2.OCS = this._Matrix;
+ TempCircle2.Position = TempCircle2.Position.add(this.Normal.multiplyScalar(this.Height));
+ for (let c of [TempCircle2, TempCircle1]) {
+ pts.push(...c.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));
+ }
+ return pts;
+ }
+ InitDrawObject(renderType) {
+ return this.GetObject3DByRenderType(renderType);
+ }
+ GetObject3DByRenderType(renderType) {
+ if (renderType === RenderType.Wireframe)
+ return new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex));
+ else
+ return new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex));
+ }
+ UpdateDrawObject(type, obj) {
+ DisposeThreeObj(obj);
+ Object3DRemoveAll(obj);
+ obj.add(this.GetObject3DByRenderType(type));
+ }
+ UpdateDrawObjectMaterial(type, obj) {
+ if (type === RenderType.Wireframe) {
+ let l = obj;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else {
+ let mesh = obj;
+ mesh.material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
+ }
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read(); //1
+ this._Radius = file.Read();
+ if (ver <= 4) {
+ //临时兼容旧排钻
+ this._Height = file.Read();
+ this.type = file.Read();
+ this.FId = file.ReadSoftObjectId();
+ this.MId = file.ReadSoftObjectId();
+ }
+ else {
+ this.type = file.Read();
+ }
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(5); //ver
+ file.Write(this._Radius);
+ file.Write(this.type);
+ }
+};
+CylinderHole = CylinderHole_1 = __decorate([
+ Factory
+], CylinderHole);
+let cache$1 = new Map();
+let ro = new three.Matrix4();
+ro.makeRotationX(Math.PI / 2);
+function FastDrillingMeshGeometry(radius, height) {
+ let key = `${radius},${height}`;
+ if (cache$1.has(key))
+ return cache$1.get(key);
+ let geo = new three.CylinderBufferGeometry(radius, radius, height, 8, 1);
+ geo.applyMatrix4(ro);
+ geo.translate(0, 0, height / 2);
+ cache$1.set(key, geo);
+ return geo;
+}
+let cache2 = new Map();
+function FastDrillingEdgeGeometry(radius, height) {
+ let key = `${radius},${height}`;
+ if (cache2.has(key))
+ return cache2.get(key);
+ let sp = new three.Shape();
+ sp.ellipse(0, 0, radius, radius, 0, 2 * Math.PI, false, 0);
+ let pts = sp.getPoints(4);
+ let geo = new three.BufferGeometry();
+ let coords = [];
+ for (let i = 0; i < pts.length; i++) {
+ let p = pts[i];
+ let np = pts[FixIndex(i + 1, pts.length)];
+ coords.push(p.x, p.y, 0, np.x, np.y, 0); //bottom
+ coords.push(p.x, p.y, height, np.x, np.y, height); //top
+ coords.push(p.x, p.y, 0, p.x, p.y, height); //edge
+ }
+ geo.setAttribute('position', new three.Float32BufferAttribute(coords, 3));
+ cache2.set(key, geo);
+ return geo;
+}
+CADFactory.RegisterObjectAlias(CylinderHole, "GangDrill");
+
+/**
+ * 使用轮廓和扫描路径构建扫描几何体,实现衣柜中的顶线或者地脚线之类的实体.
+ * 该几何体需要轮廓和路径的起始截面垂直,否则构造的实体将会错误.
+ */
+class SweepGeometry extends three.Geometry {
+ constructor(contour, path) {
+ super();
+ this.edgePts = [];
+ this.AddShape(contour, path);
+ this.computeVertexNormals();
+ this.computeFaceNormals();
+ }
+ AddShape(contour, path) {
+ //路径点表
+ let pathPts2d = path.Shape.getPoints(8);
+ let pathPts = pathPts2d.map(AsVector3);
+ arrayRemoveDuplicateBySort(pathPts, equalv3);
+ for (let p of pathPts)
+ p.applyMatrix4(path.OCS);
+ let shapePts2d = contour.Shape.getPoints(3);
+ if (!three.ShapeUtils.isClockWise(shapePts2d))
+ shapePts2d.reverse();
+ //轮廓点表
+ let shapePts3d = shapePts2d.map(AsVector3);
+ for (let p of shapePts3d)
+ p.applyMatrix4(contour.OCS);
+ let isClosePath = path.IsClose;
+ let verts = []; //所有路径上的轮廓点
+ //计算所有需要的几何点,本质是不断的投影
+ if (isClosePath)
+ verts.push(ProjectionToPlane(shapePts3d, path.Normal, pathPts[0], pathPts[pathPts.length - 2], pathPts[1]));
+ else
+ verts.push(ProjectionToPlane(shapePts3d, path.Normal, pathPts[0], undefined, pathPts[1]));
+ //遍历所有的路径节点进行顶点投射
+ for (let i = 1; i < pathPts.length; i++) {
+ if (i === pathPts.length - 1) {
+ if (isClosePath)
+ verts.push(ProjectionToPlane(shapePts3d, path.Normal, pathPts[i], pathPts[i - 1], pathPts[1]));
+ else
+ verts.push(ProjectionToPlane(shapePts3d, path.Normal, pathPts[i], pathPts[i - 1]));
+ }
+ else {
+ verts.push(ProjectionToPlane(shapePts3d, path.Normal, pathPts[i], pathPts[i - 1], pathPts[i + 1]));
+ }
+ }
+ this.BuildSideFaces(shapePts2d, pathPts2d, pathPts, verts);
+ if (!isClosePath)
+ this.BuildLid(shapePts2d, verts);
+ }
+ BuildSideFaces(shapePts2d, pathPts2d, pathPts, verts) {
+ let addCount = 0; //补充个数
+ shapePts2d[0]["_mask_"] = true;
+ for (let p of shapePts2d)
+ if (p["_mask_"])
+ addCount++;
+ let sumCount = addCount + shapePts2d.length; //实际个数
+ const f4 = (a, b, c, d, uvs) => {
+ let f1 = new three.Face3(a, b, c);
+ let f2 = new three.Face3(b, d, c);
+ this.faces.push(f1, f2);
+ this.faceVertexUvs[0].push([uvs[0].clone(), uvs[1].clone(), uvs[2].clone()], [uvs[1].clone(), uvs[3].clone(), uvs[2].clone()]);
+ };
+ let vs = [0]; //vs 对应 y轴
+ for (let i = 1; i < shapePts2d.length; i++)
+ vs.push((vs[i - 1] + shapePts2d[i].distanceTo(shapePts2d[i - 1]) * 1e-3));
+ let lastStartX = 0;
+ for (let pathIndex = 0; pathIndex < verts.length; pathIndex++) {
+ let pts = verts[pathIndex];
+ let pts2 = verts[FixIndex$1(pathIndex + 1, verts)];
+ let startIndex = this.vertices.length;
+ let pBase = pts[0];
+ let p1 = pathPts[pathIndex];
+ let p2 = pathPts[FixIndex$1(pathIndex + 1, pathPts.length)];
+ let p1Dir = p2.clone().sub(p1).normalize();
+ let tempStartX = 0;
+ for (let contourIndex = 0; contourIndex < shapePts2d.length; contourIndex++) {
+ let p1 = pts[contourIndex];
+ let p2 = pts2[contourIndex];
+ let p2d = shapePts2d[contourIndex];
+ if (pathIndex !== verts.length - 1)
+ if (contourIndex === 0 || p2d["_mask_"])
+ this.edgePts.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
+ if (contourIndex === 0 || p2d["_mask_"])
+ this.vertices.push(p1); //补点
+ if (pathIndex !== verts.length - 1) {
+ let curIndex = this.vertices.length;
+ let nextIndex = startIndex + FixIndex$1(curIndex - startIndex + 1, sumCount);
+ let curIndex2 = curIndex + sumCount;
+ let nextIndex2 = nextIndex + sumCount;
+ let x1 = lastStartX + p1.clone().sub(pBase).dot(p1Dir) * 1e-3;
+ let x2 = lastStartX + pts[FixIndex$1(contourIndex + 1, shapePts2d)].clone().sub(pBase).dot(p1Dir) * 1e-3;
+ let x3 = lastStartX + p2.clone().sub(pBase).dot(p1Dir) * 1e-3;
+ let x4 = lastStartX + pts2[FixIndex$1(contourIndex + 1, shapePts2d)].clone().sub(pBase).dot(p1Dir) * 1e-3;
+ if (contourIndex === 0)
+ tempStartX = x3;
+ let v1 = vs[contourIndex];
+ let v2 = vs[FixIndex$1(contourIndex + 1, vs)];
+ let uvs = [
+ new three.Vector2(v1, x1),
+ new three.Vector2(v2, x2),
+ new three.Vector2(v1, x3),
+ new three.Vector2(v2, x4),
+ ];
+ f4(curIndex, nextIndex, curIndex2, nextIndex2, uvs);
+ }
+ this.vertices.push(p1);
+ }
+ lastStartX = tempStartX;
+ if (pathPts2d[FixIndex$1(pathIndex + 1, verts)]["_mask_"]) {
+ for (let contourIndex = 0; contourIndex < shapePts2d.length; contourIndex++) {
+ let p1 = pts2[contourIndex];
+ let p2d = shapePts2d[contourIndex];
+ if (contourIndex === 0 || p2d["_mask_"])
+ this.vertices.push(p1); //补点
+ this.vertices.push(p1);
+ let p2 = pts2[FixIndex$1(contourIndex + 1, pts2)];
+ this.edgePts.push(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
+ }
+ }
+ }
+ }
+ BuildLid(shapePts2d, verts) {
+ //轮廓三角网格索引
+ let faces = three.ShapeUtils.triangulateShape(shapePts2d, []);
+ for (let v of shapePts2d)
+ v.multiplyScalar(1e-3); //作为uvs
+ let lastIndex = this.vertices.length;
+ this.vertices.push(...verts[0].map(p => p.clone()));
+ this.vertices.push(...verts[verts.length - 1].map(p => p.clone()));
+ for (let i = 0; i < faces.length; i++) {
+ let [a, b, c] = faces[i];
+ this.faces.push(new three.Face3(lastIndex + a, lastIndex + b, lastIndex + c));
+ let uvs = faces[i].map(index => shapePts2d[index].clone());
+ this.faceVertexUvs[0].push(uvs);
+ this.faces.push(new three.Face3(lastIndex + verts[0].length + c, lastIndex + verts[0].length + b, lastIndex + verts[0].length + a));
+ this.faceVertexUvs[0].push(uvs.concat().reverse().map(v => v.clone()));
+ }
+ //构建线框
+ for (let i = 0; i < shapePts2d.length; i++) {
+ let nextIndex = FixIndex$1(i + 1, shapePts2d);
+ let pts1 = verts[0];
+ let p0 = pts1[i];
+ let p1 = pts1[nextIndex];
+ this.edgePts.push(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z);
+ let pts2 = verts[verts.length - 1];
+ p0 = pts2[i];
+ p1 = pts2[nextIndex];
+ this.edgePts.push(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z);
+ }
+ }
+}
+/**
+ * 将轮廓变换到`路径上某个点`.
+ *
+ * @param {Vector3[]} contourPts 原始的轮廓点(在世界坐标系)
+ * @param {Vector3} normal 路径法向量
+ * @param {Vector3} curP 路径上当前点
+ * @param {Vector3} [preP] 路径的前一个点
+ * @param {Vector3} [nextP] 路径下一个点
+ * @returns 变换后的轮廓点表
+ */
+function ProjectionToPlane(contourPts, normal, curP, preP, nextP) {
+ let pts;
+ if (!preP && nextP) {
+ let mat = ContourTransfromToPath(curP, normal, nextP.clone().sub(curP));
+ pts = contourPts.map(p => p.clone().applyMatrix4(mat));
+ }
+ else if (!nextP && preP) {
+ let mat = ContourTransfromToPath(curP, normal, curP.clone().sub(preP));
+ pts = contourPts.map(p => p.clone().applyMatrix4(mat));
+ }
+ else if (nextP && preP) {
+ let dir = curP.clone().sub(preP).normalize();
+ let v2 = nextP.clone().sub(curP).normalize();
+ //角平分线向量
+ let v = dir.clone().sub(v2);
+ //v1v2pm向量
+ let nv1v2 = dir.clone().cross(v2);
+ let norm = nv1v2.cross(v);
+ //角平分线的平面
+ let plane = new PlaneExt(norm, curP);
+ let mat = ContourTransfromToPath(preP, normal, dir);
+ pts = contourPts.map(p => p.clone().applyMatrix4(mat));
+ pts = pts.map(p => plane.intersectLine(new three.Line3(p, p.clone().add(dir)), new three.Vector3(), true));
+ }
+ return pts;
+}
+/**
+ * 计算轮廓变换到`路径上某个点`的矩阵
+ *
+ * @param {Vector3} pt 路径上的点
+ * @param {Vector3} norm 曲线法向量
+ * @param {Vector3} dir 点前进的方向.
+ * @returns {Matrix4}
+ */
+function ContourTransfromToPath(pt, norm, dir) {
+ let vy = norm;
+ let vz = dir.normalize();
+ let vx = vz.clone().cross(vy);
+ let mat = new three.Matrix4();
+ mat.makeBasis(vx, vy, vz);
+ mat.setPosition(pt);
+ return mat;
+}
+
+let SweepSolid = class SweepSolid extends Entity {
+ constructor(contour, pathCurve) {
+ super();
+ this._Contour = contour;
+ this._PathCurve = pathCurve;
+ if (this._Contour && this._Contour.Id)
+ this._Contour = this._Contour.Clone();
+ if (this._Contour && this._PathCurve) {
+ this.TransfromPathToWCS();
+ this.OCS = this._PathCurve.OCS;
+ this._SpaceOCS.copy(this._PathCurve.OCS);
+ this._PathCurve.ApplyMatrix(this._PathCurve.OCSInv);
+ }
+ }
+ get Contour() {
+ return this._Contour;
+ }
+ get Path() {
+ return this._PathCurve;
+ }
+ Reverse() {
+ this.WriteAllObjectRecord();
+ this._PathCurve.Reverse();
+ this.Update();
+ }
+ /**保持路径左下角在0点 */
+ PathTo0() {
+ let min = this._PathCurve.BoundingBox.min;
+ this._PathCurve.Position = this._PathCurve.Position.sub(min);
+ this.OCS = this.OCS.multiply(MoveMatrix(min));
+ }
+ /**
+ * 将轮廓变换到wcs空间,当用户选定某个与扫描线起点相切的轮廓时.
+ */
+ TransfromPathToWCS() {
+ if (equalv3(this._Contour.Normal, new three.Vector3(0, 0, 1)))
+ return;
+ let fDir = this._PathCurve.GetFistDeriv(0);
+ if (isParallelTo(fDir, this._Contour.Normal)) {
+ //构建回家的矩阵
+ let toWcsMat4Inv = new three.Matrix4();
+ let zv = fDir.normalize();
+ let yv = this._PathCurve.Normal;
+ let xv = zv.clone().cross(yv);
+ toWcsMat4Inv.makeBasis(xv, yv, zv);
+ toWcsMat4Inv.setPosition(this._PathCurve.StartPoint);
+ let toWcsMat4 = new three.Matrix4().getInverse(toWcsMat4Inv);
+ this._Contour.ApplyMatrix(toWcsMat4);
+ let z = this._Contour.StartPoint.z;
+ if (IsPointInPolyLine(this._Contour, new three.Vector3(0, 0, z))) {
+ let z = this._Contour.StartPoint.z;
+ this._Contour.ApplyMatrix(MoveMatrix(new three.Vector3(0, 0, -z)));
+ return;
+ }
+ else
+ this._Contour.ApplyMatrix(toWcsMat4Inv);
+ }
+ let lDir = this._PathCurve.GetFistDeriv(this._PathCurve.EndParam);
+ if (isParallelTo(lDir, this._Contour.Normal)) {
+ //再次构建回家的矩阵
+ let toWcsMat4Inv = new three.Matrix4();
+ let zv = lDir.negate().normalize();
+ let yv = this._PathCurve.Normal;
+ let xv = zv.clone().cross(yv);
+ toWcsMat4Inv.makeBasis(xv, yv, zv);
+ toWcsMat4Inv.setPosition(this._PathCurve.EndPoint);
+ let toWcsMat4 = new three.Matrix4().getInverse(toWcsMat4Inv);
+ this._Contour.ApplyMatrix(toWcsMat4);
+ let z = this._Contour.StartPoint.z;
+ if (IsPointInPolyLine(this._Contour, new three.Vector3(0, 0, z))) {
+ let z = this._Contour.StartPoint.z;
+ this._Contour.ApplyMatrix(MoveMatrix(new three.Vector3(0, 0, -z)));
+ this._PathCurve.Reverse();
+ return;
+ }
+ else
+ this._Contour.ApplyMatrix(toWcsMat4);
+ }
+ Log("错误:提供的轮廓没有和路径垂直!");
+ }
+ get MeshGeometry() {
+ if (this._MeshGeometry)
+ return this._MeshGeometry;
+ try {
+ this._MeshGeometry = new SweepGeometry(this._Contour, this._PathCurve);
+ this._EdgeGeometry = new three.BufferGeometry().setAttribute('position', new three.Float32BufferAttribute(this._MeshGeometry.edgePts, 3));
+ this.getLineGeo(this._MeshGeometry.edgePts);
+ this._MeshGeometry.edgePts = undefined;
+ return this._MeshGeometry;
+ }
+ catch (error) {
+ return new three.BoxBufferGeometry(1000, 1000, 1000);
+ }
+ }
+ getLineGeo(pts) {
+ this._lineGeo = new LineGeometry.LineGeometry();
+ let lineSegments = new Float32Array(pts);
+ var instanceBuffer = new three.InstancedInterleavedBuffer(lineSegments, 6, 1);
+ this._lineGeo.setAttribute('instanceStart', new three.InterleavedBufferAttribute(instanceBuffer, 3, 0));
+ this._lineGeo.setAttribute('instanceEnd', new three.InterleavedBufferAttribute(instanceBuffer, 3, 3));
+ }
+ get EdgeGeometry() {
+ if (this._EdgeGeometry)
+ return this._EdgeGeometry;
+ this.MeshGeometry;
+ return this._EdgeGeometry;
+ }
+ InitDrawObject(renderType) {
+ if (renderType === RenderType.Wireframe)
+ return new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex));
+ else if (renderType === RenderType.Conceptual) {
+ return new three.Object3D().add(new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ else if (renderType === RenderType.Physical)
+ return new three.Mesh(this.MeshGeometry, this.MeshMaterial);
+ else if (renderType === RenderType.Print) {
+ let mat2 = ColorMaterial.GetPrintConceptualMaterial();
+ let meshGeo = this.MeshGeometry;
+ let mesh = new three.Mesh(meshGeo, mat2);
+ let line = new Line2.Line2(this._lineGeo, ColorMaterial.PrintLineMatrial);
+ return new three.Object3D().add(line, mesh);
+ }
+ else if (renderType === RenderType.Jig) {
+ return new three.Object3D().add(this._PathCurve.DrawObject);
+ }
+ else if (renderType === RenderType.Physical2) {
+ return new three.Object3D().add(new three.Mesh(this.MeshGeometry, this.MeshMaterial), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ }
+ UpdateDrawGeometry() {
+ this._EdgeGeometry = undefined;
+ this._MeshGeometry = undefined;
+ }
+ UpdateDrawObject(renderType, obj) {
+ DisposeThreeObj(obj);
+ if (renderType === RenderType.Wireframe) {
+ let l = obj;
+ l.geometry = this.EdgeGeometry;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (renderType === RenderType.Conceptual) {
+ Object3DRemoveAll(obj);
+ return obj.add(new three.Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ else if (renderType === RenderType.Physical) {
+ let mesh = obj;
+ mesh.geometry = this.MeshGeometry;
+ mesh.material = this.MeshMaterial;
+ }
+ else if (renderType === RenderType.Jig) {
+ Object3DRemoveAll(obj);
+ obj.add((this._PathCurve.DrawObject));
+ }
+ else if (renderType === RenderType.Physical2) {
+ Object3DRemoveAll(obj);
+ return obj.add(new three.Mesh(this.MeshGeometry, this.MeshMaterial), new three.LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(7)));
+ }
+ }
+ /**
+ * 当实体需要被更新时,更新实体材质
+ */
+ UpdateDrawObjectMaterial(type, obj) {
+ if (type === RenderType.Wireframe) {
+ let l = obj;
+ l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);
+ }
+ else if (type === RenderType.Conceptual) {
+ let mesh = obj.children[0];
+ mesh.material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);
+ }
+ else if (type === RenderType.Physical2) {
+ let mesh = obj.children[0];
+ mesh.material = this.MeshMaterial;
+ }
+ else {
+ let mesh = obj;
+ mesh.material = this.MeshMaterial;
+ }
+ }
+ get BoundingBox() {
+ return new Box3Ext().setFromPoints(this.GetEndPoint());
+ }
+ get OBB() {
+ let box = this.BoundingBox;
+ let size = box.getSize(new three.Vector3);
+ return new OBB(MoveMatrix(box.min), size.multiplyScalar(0.5));
+ }
+ GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform) {
+ switch (snapMode) {
+ case ObjectSnapMode.End:
+ return this.GetEndPoint();
+ case ObjectSnapMode.Mid:
+ case ObjectSnapMode.Cen:
+ case ObjectSnapMode.Nea:
+ case ObjectSnapMode.Ext:
+ case ObjectSnapMode.Per:
+ case ObjectSnapMode.Tan:
+ {
+ let contour = this._PathCurve.Clone();
+ contour.ApplyMatrix(this.OCS);
+ let pts = contour.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform);
+ if (snapMode === ObjectSnapMode.Mid)
+ return [...pts, ...this.GetMidPoints()];
+ return pts;
+ }
+ }
+ return [];
+ }
+ GetGripPoints() {
+ let pts = this._PathCurve.GetGripPoints();
+ for (let p of pts)
+ p.applyMatrix4(this._Matrix);
+ return pts;
+ }
+ GetStretchPoints() {
+ let pts = this._PathCurve.GetStretchPoints();
+ for (let p of pts)
+ p.applyMatrix4(this._Matrix);
+ return pts;
+ }
+ UpdateEndMtx(dir, pos) {
+ let y = this.Normal;
+ let roMat = new three.Matrix4().extractRotation(this.OCS);
+ let z = dir.applyMatrix4(roMat);
+ let x = z.clone().cross(y);
+ tempMatrix1.makeBasis(x, y, z);
+ tempMatrix1.setPosition(pos.applyMatrix4(this.OCS));
+ }
+ GetEndPoint() {
+ let conPts = this._Contour.GetStretchPoints();
+ let cus;
+ if (this._PathCurve instanceof exports.Polyline)
+ cus = this._PathCurve.Explode();
+ else
+ cus = [this._PathCurve];
+ let roMat = new three.Matrix4().extractRotation(this.OCS);
+ const pts = [];
+ for (let i = 0; i < cus.length; i++) {
+ let l1 = cus[i];
+ let l2;
+ if (this._PathCurve.IsClose) {
+ l2 = cus[FixIndex(i + 1, cus.length)];
+ }
+ else {
+ l2 = cus[i + 1];
+ if (i === 0) {
+ this.UpdateEndMtx(l1.GetFistDeriv(0).normalize(), l1.StartPoint);
+ pts.push(...conPts.map(p => p.clone().applyMatrix4(tempMatrix1)));
+ }
+ }
+ let p = l1.EndPoint;
+ let d1 = l1.GetFistDeriv(1).normalize();
+ this.UpdateEndMtx(d1.clone(), p);
+ if (l2) {
+ let d2 = l2.GetFistDeriv(0).normalize().applyMatrix4(roMat);
+ d1.applyMatrix4(roMat);
+ d2.add(d1).normalize();
+ if (isParallelTo(d1, d2)) {
+ if (l1 instanceof exports.Line && l2 instanceof exports.Line) ;
+ else {
+ let ps = conPts.map(p => p.clone().applyMatrix4(tempMatrix1));
+ pts.push(...ps);
+ }
+ continue;
+ }
+ p.copy(l1.EndPoint);
+ //角平分线的平面;
+ let plane = new PlaneExt(d2, p.applyMatrix4(this.OCS));
+ let ps = conPts.map(p => p.clone().applyMatrix4(tempMatrix1));
+ pts.push(...ps.map(p => plane.intersectLine(new three.Line3(p.clone().sub(d1.clone().multiplyScalar(-100)), p.clone().add(d1)), new three.Vector3(), true)));
+ }
+ else {
+ pts.push(...conPts.map(p => p.clone().applyMatrix4(tempMatrix1)));
+ }
+ }
+ return pts;
+ }
+ GetMidPoints() {
+ let conPts = this._Contour.GetStretchPoints();
+ const pts = [];
+ for (let i = 0.5; i < this._PathCurve.EndParam; i++) {
+ let p = this._PathCurve.GetPointAtParam(i);
+ let d1 = this._PathCurve.GetFistDeriv(i).normalize();
+ this.UpdateEndMtx(d1, p);
+ pts.push(...conPts.map(p => p.clone().applyMatrix4(tempMatrix1)));
+ }
+ return pts;
+ }
+ MoveGripPoints(indexList, vec) {
+ this.WriteAllObjectRecord();
+ this.IfPathIsLineThenZ0Vector(vec);
+ this._PathCurve.MoveGripPoints(indexList, vec.clone().applyMatrix4(new three.Matrix4().extractRotation(this.OCSInv)));
+ this.Update();
+ }
+ //如果路径是直线,我们在这里避免vec传递z轴信息
+ IfPathIsLineThenZ0Vector(vec) {
+ if (this._PathCurve instanceof exports.Line) {
+ let ocsinv = this._PathCurve.OCSInv.setPosition(0, 0, 0);
+ vec.applyMatrix4(ocsinv).setZ(0);
+ vec.applyMatrix4(this._PathCurve.OCSNoClone);
+ }
+ }
+ MoveStretchPoints(indexList, vec) {
+ this.WriteAllObjectRecord();
+ this.IfPathIsLineThenZ0Vector(vec);
+ this._PathCurve.MoveStretchPoints(indexList, vec.clone().applyMatrix4(new three.Matrix4().extractRotation(this.OCSInv)));
+ this.Update();
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read(); //1
+ this._Contour = file.ReadObject();
+ this._PathCurve = file.ReadObject();
+ if (this._Contour instanceof Spline || this._PathCurve instanceof Spline) {
+ this._isErase = true;
+ Log("放样实体是样条线生成的,自动删除它!");
+ }
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(1); //ver
+ file.WriteObject(this._Contour);
+ file.WriteObject(this._PathCurve);
+ }
+};
+SweepSolid = __decorate([
+ Factory
+], SweepSolid);
+
+let HardwareTopline = class HardwareTopline extends SweepSolid {
+ constructor() {
+ super(...arguments);
+ this.HardwareOption = { ...DefaultToplineMetalsOption };
+ this.DataList = [];
+ this._contourRotation = 0;
+ }
+ get ContourRotation() {
+ return this._contourRotation;
+ }
+ get Contours() {
+ var _a, _b;
+ let c = this.Path;
+ let conBox = this.Contour.BoundingBox;
+ let cMin = conBox.min;
+ let cMax = conBox.max;
+ let y = ZAxis;
+ let z = c.GetFistDeriv(0).normalize();
+ let x = z.clone().cross(y);
+ let mat = new three.Matrix4().makeBasis(x, y, z);
+ mat.setPosition(c.StartPoint);
+ [cMin, cMax].forEach(p => p.applyMatrix4(mat).setZ(0));
+ let closePt = c.GetClosestPointTo(cMin, false);
+ let offset = cMin.distanceTo(closePt);
+ let dir = GetPointAtCurveDir(this.Path, cMin);
+ let cus = this.Path.GetOffsetCurves(offset * dir);
+ let l1 = (_a = cus[0]) !== null && _a !== void 0 ? _a : this.Path;
+ closePt = c.GetClosestPointTo(cMax, false);
+ offset = cMax.distanceTo(closePt);
+ dir = GetPointAtCurveDir(this.Path, cMax);
+ cus = this.Path.GetOffsetCurves(offset * dir);
+ let l2 = (_b = cus[0]) !== null && _b !== void 0 ? _b : this.Path;
+ return [l1, l2];
+ }
+ get MaxPath() {
+ let [l1, l2] = this.Contours;
+ return l1.Length > l2.Length ? l1 : l2;
+ }
+ get MaxLength() {
+ let [l1, l2] = this.Contours;
+ return Math.max(l1.Length, l2.Length);
+ }
+ set ContourRotation(ro) {
+ if (ro === this._contourRotation)
+ return;
+ let diffRo = ro - this._contourRotation;
+ this._contourRotation = ro;
+ let mat = new three.Matrix4().makeRotationZ(diffRo);
+ this.Contour.ApplyMatrix(mat);
+ this.Update();
+ }
+ _ReadFile(file) {
+ super._ReadFile(file);
+ let ver = file.Read(); //1
+ this._contourRotation = file.Read();
+ this.HardwareOption.addLen = file.Read();
+ this.HardwareOption.name = file.Read();
+ this.HardwareOption.roomName = file.Read();
+ this.HardwareOption.cabinetName = file.Read();
+ this.HardwareOption.costExpr = file.Read();
+ this.HardwareOption.actualExpr = file.Read();
+ this.HardwareOption.model = file.Read();
+ this.HardwareOption.factory = file.Read();
+ this.HardwareOption.brand = file.Read();
+ this.HardwareOption.spec = file.Read();
+ this.HardwareOption.comments = file.Read();
+ let count = file.Read();
+ this.DataList.length = 0;
+ for (let i = 0; i < count; i++) {
+ let d = ["", ""];
+ d[0] = file.Read();
+ d[1] = file.Read();
+ this.DataList.push(d);
+ }
+ }
+ WriteFile(file) {
+ super.WriteFile(file);
+ file.Write(1); //ver
+ file.Write(this._contourRotation);
+ file.Write(this.HardwareOption.addLen);
+ file.Write(this.HardwareOption.name);
+ file.Write(this.HardwareOption.roomName);
+ file.Write(this.HardwareOption.cabinetName);
+ file.Write(this.HardwareOption.costExpr);
+ file.Write(this.HardwareOption.actualExpr);
+ file.Write(this.HardwareOption.model);
+ file.Write(this.HardwareOption.factory);
+ file.Write(this.HardwareOption.brand);
+ file.Write(this.HardwareOption.spec);
+ file.Write(this.HardwareOption.comments);
+ file.Write(this.DataList.length);
+ for (let data of this.DataList) {
+ file.Write(data[0]);
+ file.Write(data[1]);
+ }
+ }
+};
+__decorate([
+ AutoRecord
+], HardwareTopline.prototype, "HardwareOption", void 0);
+__decorate([
+ AutoRecord
+], HardwareTopline.prototype, "DataList", void 0);
+HardwareTopline = __decorate([
+ Factory
+], HardwareTopline);
+
+var Intent;
+(function (Intent) {
+ Intent["NONE"] = "none";
+ Intent["PRIMARY"] = "primary";
+ Intent["SUCCESS"] = "success";
+ Intent["WARNING"] = "warning";
+ Intent["DANGER"] = "danger";
+})(Intent || (Intent = {}));
+const ToasterInjectFunctions = [];
+function Toaster(option) {
+ for (let f of ToasterInjectFunctions)
+ f(option);
+}
+
+class LookOverBoardInfosTool {
+ constructor() {
+ this.drillTypeMap = new Map();
+ this.sealMap = new Map();
+ this.boardMap = new Map();
+ }
+ GetCount(brs) {
+ let drillCount = [];
+ let sealCount = [];
+ let hardwareCount = [];
+ let areaCount = [];
+ this.drillTypeMap.clear();
+ this.sealMap.clear();
+ this.Update(brs);
+ if (this.drillTypeMap.size > 0)
+ for (let [k, v] of this.drillTypeMap) {
+ if (v[0] instanceof Hole)
+ if (k === "木销")
+ drillCount.push({ name: k, count: v.length });
+ else if (k === "层板钉")
+ drillCount.push({ name: k, count: v.length });
+ else
+ drillCount.push({ name: k, count: v.length });
+ else {
+ this.ParseHardwareCount(k, v, hardwareCount);
+ }
+ }
+ hardwareCount.sort((h1, h2) => h1.name.localeCompare(h2.name));
+ //加入封边信息
+ for (let [k, v] of this.sealMap) {
+ sealCount.push({ name: k.toString() + "mm封边条", count: v / 1000, unit: "米" });
+ }
+ for (let [k, bs] of this.boardMap) {
+ areaCount.push({
+ entity: bs[0],
+ count: bs.length,
+ count2: this.GetBoardsArea(bs)
+ });
+ }
+ return { drillCount, hardwareCount, sealCount, areaCount };
+ }
+ ;
+ Update(ens) {
+ var _a, _b, _c;
+ //计算排钻个数
+ const addDrillToMap = (spiteName, d) => {
+ if (!this.drillTypeMap.has(spiteName))
+ this.drillTypeMap.set(spiteName, [d]);
+ else {
+ let ds = this.drillTypeMap.get(spiteName);
+ if (!ds.includes(d))
+ ds.push(d);
+ }
+ };
+ const brsProps = [];
+ const hardwares = [];
+ for (let e of ens) {
+ if (e instanceof Board)
+ brsProps.push(e);
+ else
+ hardwares.push(e);
+ }
+ for (let h of hardwares) {
+ let { name, unit, factory, spec, model, brand } = h.HardwareOption;
+ addDrillToMap(`${name},${unit},${factory},${this.ParseSpec(h, spec)},${model},${brand}`, h);
+ }
+ this.UpdateBoardMap(brsProps);
+ for (let b of brsProps) {
+ let dlist = b.DrillList;
+ if (equaln(b.ContourCurve.Area, 0)) {
+ Toaster({
+ message: `${b.BoardProcessOption.roomName} ${b.BoardProcessOption.cabinetName} ${b.Name}轮廓有有问题,请检查`,
+ timeout: 3000,
+ intent: Intent.DANGER,
+ });
+ continue;
+ }
+ for (let [id, idList] of dlist) {
+ for (let ids of idList) {
+ for (let objId of ids) {
+ let gd = objId.Object;
+ if (!(gd === null || gd === void 0 ? void 0 : gd.IsErase)) {
+ if (gd instanceof CylinderHole)
+ switch (gd.Type) {
+ case GangDrillType.Ljg:
+ let spiteName = (_c = (_b = (_a = gd.GroupId) === null || _a === void 0 ? void 0 : _a.Object) === null || _b === void 0 ? void 0 : _b.Name) !== null && _c !== void 0 ? _c : "未命名";
+ //读取拆单名
+ addDrillToMap(spiteName, gd);
+ break;
+ case GangDrillType.Wood:
+ addDrillToMap("木销", gd);
+ break;
+ }
+ else {
+ //TODO:统计自定义排钻
+ if (gd instanceof ExtrudeHole) {
+ let name = gd.GroupId.Object.Name;
+ let ents = gd.GroupId.Object.Entitys;
+ addDrillToMap(name, ents[0].Object);
+ }
+ }
+ }
+ }
+ }
+ }
+ // 被复制的层板钉暂未加入LayerNails数组 等做好关联后解除注释
+ if (b.LayerNails.length > 0)
+ for (let objId of b.LayerNails) {
+ if (!(objId === null || objId === void 0 ? void 0 : objId.IsErase))
+ addDrillToMap("层板钉", objId.Object);
+ }
+ //分析五金
+ for (const mId of b.RelativeHardware) {
+ let metal = mId === null || mId === void 0 ? void 0 : mId.Object;
+ if (metal && !metal.IsErase && metal.HardwareOption) {
+ let { name, unit, factory, spec, model, brand } = metal.HardwareOption;
+ addDrillToMap(`${name},${unit},${factory},${this.ParseSpec(metal, spec)},${model},${brand}`, metal);
+ }
+ }
+ //封边 目前仅厚度,长度两个参数
+ let sealData = Production.GetBoardSealingData(b);
+ for (let data of sealData) {
+ if (equaln(0, data.size))
+ continue;
+ let len = this.sealMap.get(data.size);
+ if (!len)
+ this.sealMap.set(data.size, data.length);
+ else
+ this.sealMap.set(data.size, len += data.length);
+ }
+ }
+ }
+ ;
+ ParseSpec(en, spec, len) {
+ let size = en instanceof three.Vector3 ? en : en.BoundingBoxInOCS.getSize(new three.Vector3);
+ return ParseExpr(spec, { L: len !== null && len !== void 0 ? len : size.x, W: size.y, H: size.z }) || "[ 无 ]";
+ }
+ ParseHardwareCount(k, v, hardwareCount) {
+ if (v.length > 0) {
+ if (!(v[0] instanceof HardwareTopline)) {
+ let count2 = v.reduce((v, d) => {
+ var _a;
+ let size = d.BoundingBoxInOCS.getSize(new three.Vector3);
+ let c = (_a = safeEval(d.HardwareOption.count, { L: size.x, W: size.y, H: size.z })) !== null && _a !== void 0 ? _a : 0;
+ return v + c;
+ }, 0);
+ hardwareCount.push({ name: k.split(",")[0], count: v.length, entity: v[0], count2: FixedNotZero(count2, 2) });
+ }
+ else {
+ let map = new Map();
+ let name = k.split(",")[0];
+ let addLen = v[0].HardwareOption.addLen;
+ for (let d of v) {
+ let e = d;
+ let path = e.MaxPath;
+ let cus = path instanceof exports.Polyline ? path.Explode() : [path];
+ for (let cu of cus) {
+ let len = parseFloat(FixedNotZero(cu.Length, 2));
+ if (map.has(len)) {
+ map.set(len, map.get(len) + 1);
+ }
+ else {
+ map.set(len, 1);
+ }
+ }
+ }
+ for (let [len, count] of map) {
+ let count2 = parseFloat(FixedNotZero(len + parseFloat(addLen), 2));
+ hardwareCount.push({ name, count, entity: v[0], count2, length: count2 });
+ }
+ }
+ }
+ }
+ UpdateBoardMap(brs) {
+ this.boardMap.clear();
+ for (let b of brs) {
+ let thickness = this.GetBoardThickness(b);
+ let brMat = b.BoardProcessOption[EBoardKeyList.BrMat];
+ let mat = b.BoardProcessOption[EBoardKeyList.Mat];
+ let color = b.BoardProcessOption[EBoardKeyList.Color];
+ let key = `${thickness}-${brMat}-${mat}-${color}`;
+ let list = this.boardMap.get(key);
+ if (!list) {
+ list = [];
+ this.boardMap.set(key, list);
+ }
+ list.push(b);
+ }
+ }
+ GetBoardThickness(br) {
+ let size = Production.GetSpiteSize(br);
+ if (size)
+ return FixedNotZero(size.spliteThickness, 2);
+ else
+ return FixedNotZero(br.Thickness, 2);
+ }
+ GetBoardsArea(brs) {
+ return brs.reduce((area, b) => {
+ let size = Production.GetSpiteSize(b);
+ let ar;
+ if (size)
+ ar = size.spliteHeight * size.spliteWidth / 1e6;
+ else
+ ar = b.Width * b.Height / 1e6;
+ ar = parseFloat(ar.toFixed(3));
+ return area + ar;
+ }, 0).toFixed(2);
+ }
+}
+const lookOverBoardInfosTool = new LookOverBoardInfosTool();
+
+var DrillingFace;
+(function (DrillingFace) {
+ //正反面时,使用Front和Back
+ DrillingFace[DrillingFace["Front"] = 0] = "Front";
+ DrillingFace[DrillingFace["Back"] = 1] = "Back";
+})(DrillingFace || (DrillingFace = {}));
+var Production;
+(function (Production) {
+ /**获取板件拆单数据 */
+ function GetBoardSplitOrderData(br) {
+ let sealedContour = GetSealedBoardContour(br, true);
+ if (!sealedContour || equaln(sealedContour.Area, 0)) {
+ Toaster({
+ message: br.Name + " 轮廓错误,可能存在轮廓自交,请检查后重新拆单",
+ timeout: 8000,
+ intent: Intent.DANGER,
+ });
+ return undefined;
+ }
+ let outline = GetSealedBoardContour(br, false);
+ if (!outline || equaln(outline.Area, 0)) {
+ Toaster({
+ message: br.Name + "扣除封边轮廓有误,请检查后重新拆单",
+ timeout: 8000,
+ intent: Intent.DANGER,
+ });
+ return;
+ }
+ let offsetTanslation = outline.BoundingBox.min;
+ outline.Position = outline.Position.sub(offsetTanslation);
+ let outlinePtsBul = ConverToPolylineAndSplitArc(outline);
+ //外轮廓去掉最后的闭合点
+ outlinePtsBul.pts.pop();
+ outlinePtsBul.buls.pop();
+ let size = outline.BoundingBox.getSize(new three.Vector3);
+ //不扣除封边的轮廓信息
+ let originOutlinePtsBul = ConverToPolylineAndSplitArc(sealedContour);
+ originOutlinePtsBul.pts.pop();
+ originOutlinePtsBul.buls.pop();
+ let { modeling, sideModeling } = GetBoardModelingData(br, offsetTanslation);
+ let boardContour;
+ if (GetSpiteSize(br))
+ boardContour = ConverToPolylineAndSplitArc(br.ContourCurve);
+ return {
+ info: GetBoardInfo(br, size),
+ originOutlin: originOutlinePtsBul,
+ outline: outlinePtsBul,
+ sealing: GetBoardSealingData(br),
+ modeling,
+ holes: GetBoardHolesData(br, offsetTanslation, sealedContour),
+ sideModeling,
+ offsetTanslation,
+ metalsData: GetBoardMetals(br),
+ boardContour,
+ originModelingData: GetOriginBoardModelingData(br)
+ };
+ }
+ Production.GetBoardSplitOrderData = GetBoardSplitOrderData;
+ function GetBoardInfo(br, size) {
+ let data = br.BoardProcessOption;
+ let param = { L: br.Height, W: br.Width, H: br.Thickness };
+ let spliteHeight = safeEval(data.spliteHeight, param);
+ let spliteWidth = safeEval(data.spliteWidth, param);
+ let spliteThickness = safeEval(data.spliteThickness, param);
+ let isRect = (!isNaN(spliteHeight) && !isNaN(spliteWidth) && !isNaN(spliteThickness)) || !br.IsSpecialShape;
+ return {
+ id: br.Id.Index,
+ name: br.Name,
+ [EBoardKeyList.RoomName]: data[EBoardKeyList.RoomName],
+ [EBoardKeyList.CabinetName]: data[EBoardKeyList.CabinetName],
+ [EBoardKeyList.Mat]: data[EBoardKeyList.Mat],
+ [EBoardKeyList.BrMat]: data[EBoardKeyList.BrMat],
+ [EBoardKeyList.Color]: data[EBoardKeyList.Color],
+ [EBoardKeyList.Lines]: data[EBoardKeyList.Lines],
+ [EBoardKeyList.DrillType]: data[EBoardKeyList.DrillType],
+ spliteHeight: spliteHeight ? spliteHeight.toString() : "",
+ spliteThickness: spliteThickness ? spliteThickness.toString() : "",
+ spliteWidth: spliteWidth ? spliteWidth.toString() : "",
+ isRect,
+ remarks: data.remarks.slice(),
+ kaiLiaoWidth: size.x,
+ kaiLiaoHeight: size.y,
+ openDir: br.OpenDir,
+ };
+ }
+ Production.GetBoardInfo = GetBoardInfo;
+ /**
+ * 转换成多段线并且将圆弧打断(大于1/4的话)
+ */
+ function ConverToPolylineAndSplitArc(cu, isOutline = true, isSplite = true) {
+ let ptsBuls;
+ if (cu instanceof exports.Circle) {
+ let pl = ConverCircleToPolyline(cu);
+ ptsBuls = pl.PtsBuls;
+ }
+ else {
+ if (isOutline && cu.IsClose && cu.Normal.z * cu.Area2 < 0)
+ cu.Reverse();
+ if (isSplite)
+ ptsBuls = SplitePolylineAtArc(cu);
+ else
+ ptsBuls = cu.PtsBuls;
+ }
+ let ocs = cu.OCS;
+ if (!equaln(ocs.elements[0], 1)
+ || !equaln(ocs.elements[9], 0)
+ || !equaln(ocs.elements[10], 0)) {
+ for (let i = 0; i < ptsBuls.pts.length; i++) {
+ Vector2ApplyMatrix4(ocs, ptsBuls.pts[i]);
+ ptsBuls.buls[i] *= cu.Normal.z;
+ }
+ }
+ return ptsBuls;
+ }
+ function ConverCircleToPolyline(cir) {
+ let arcs = cir.GetSplitCurves([0, 0.25, 0.5, 0.75]);
+ let pl = new exports.Polyline();
+ pl.OCS = cir.OCS;
+ for (let arc of arcs)
+ pl.Join(arc);
+ return pl;
+ }
+ Production.ConverCircleToPolyline = ConverCircleToPolyline;
+ const SPLITBUL = Math.tan(Math.PI / 8);
+ function GetSpliteCount(allAngle) {
+ return Math.ceil(Math.abs(allAngle) / Math.PI * 2);
+ }
+ /** 打断多段线超过1/4圆的圆弧*/
+ function SplitePolylineAtArc(cu, isSplite = true) {
+ let ptsBuls = cu.PtsBuls;
+ let ocsInv = cu.OCSInv;
+ let result = { pts: [], buls: [] };
+ if (ptsBuls.pts.length === 0)
+ return result;
+ for (let i = 0; i < ptsBuls.buls.length - 1; i++) {
+ let bul = ptsBuls.buls[i];
+ if (Math.abs(bul) > SPLITBUL + 1e-8 && isSplite) {
+ let allAngle = Math.atan(bul) * 4;
+ let splitCount = GetSpliteCount(allAngle);
+ let arc = cu.GetCurveAtIndex(i);
+ let paramDiv = 1 / splitCount;
+ let newBul = Math.tan((allAngle / splitCount) / 4);
+ for (let i = 0; i < splitCount; i++) {
+ let param = i * paramDiv;
+ let p = arc.GetPointAtParam(param).applyMatrix4(ocsInv);
+ let p2 = AsVector2(p);
+ //暂时不处理0长度段
+ {
+ result.pts.push(p2);
+ result.buls.push(newBul);
+ }
+ }
+ }
+ else {
+ //暂时不处理0长度段
+ {
+ result.pts.push(ptsBuls.pts[i]);
+ result.buls.push(ptsBuls.buls[i]);
+ }
+ }
+ }
+ result.pts.push(arrayLast(ptsBuls.pts));
+ result.buls.push(arrayLast(ptsBuls.buls));
+ //测试是否存在无效的边(0长度边)
+ // for (let i = 1; i < result.pts.length; i++)
+ // {
+ // if (equalv2(result.pts[i], result.pts[i - 1], 0.01))
+ // alert("存在无效的边");
+ // }
+ return result;
+ }
+ Production.SplitePolylineAtArc = SplitePolylineAtArc;
+ /**
+ * 获取封边数据
+ * 封边数据未统一逆时针顺序,用于拆单
+ * */
+ function GetBoardSealingData(br) {
+ let sealCus = GetBoardSealingCurves(br);
+ let highSeal = GetBoardHighSeal(br, sealCus);
+ let sealData = [];
+ for (let i = 0; i < sealCus.length; i++) {
+ let sealCu = sealCus[i];
+ let data = highSeal[i];
+ let cus = [];
+ if (sealCu instanceof exports.Polyline)
+ cus.push(...sealCu.Explode());
+ else
+ cus.push(sealCu);
+ for (let cu of cus) {
+ if (cu instanceof exports.Line) {
+ sealData.push(Object.assign({}, data, { length: cu.Length }));
+ }
+ else if (cu instanceof exports.Arc) {
+ let splitCount = GetSpliteCount(cu.AllAngle);
+ let len = 2 * Math.PI * cu.Radius / 4;
+ for (let i = 0; i < splitCount; i++) {
+ let arcLen = i !== splitCount - 1 ? len : cu.Length - (splitCount - 1) * len;
+ sealData.push(Object.assign({}, data, { length: arcLen }));
+ }
+ }
+ else if (cu instanceof exports.Circle) {
+ let length = 2 * Math.PI * cu.Radius / 4;
+ sealData.push(...Array.from({ length: 4 }, () => {
+ return { ...data, length };
+ }));
+ }
+ }
+ }
+ if (br.ContourCurve instanceof exports.Polyline && br.ContourCurve.Area2 < 0)
+ sealData.reverse();
+ return sealData;
+ }
+ Production.GetBoardSealingData = GetBoardSealingData;
+ function GetMetalTotalEntitys(md, isHole = false, filter) {
+ let holes = [];
+ if (isHole && !md.HardwareOption.isHole)
+ return [];
+ for (let e of md.Entitys) {
+ if (e instanceof HardwareCompositeEntity) {
+ if (!isHole || md.HardwareOption.isHole)
+ holes.push(...GetMetalTotalEntitys(e, isHole, filter).map(h => h.ApplyMatrix(md.OCS)));
+ }
+ else {
+ if (!filter || filter(e)) {
+ holes.push(e.Clone().ApplyMatrix(md.OCS));
+ }
+ }
+ }
+ return holes;
+ }
+ Production.GetMetalTotalEntitys = GetMetalTotalEntitys;
+ function GetOriginBoardModelingData(br) {
+ const tool = FeedingToolPath.GetInstance();
+ const getModelings = (ms) => {
+ var _a;
+ let data = [];
+ for (let m of ms) {
+ let cu = m.shape.Outline.Curve;
+ if (cu instanceof exports.Circle && cu.Radius < userConfig.chaidanOption.modeling2HoleRad + 1e-6)
+ continue;
+ if (userConfig.chaidanOption.useDefaultRad)
+ m.knifeRadius = userConfig.chaidanOption.radius;
+ data.push({
+ outline: ConverToPolylineAndSplitArc(cu.Clone(), false, false),
+ holes: m.shape.Holes.map(h => ConverToPolylineAndSplitArc(h.Curve.Clone(), false, false)),
+ thickness: m.thickness + ((_a = m.addDepth) !== null && _a !== void 0 ? _a : 0),
+ dir: m.dir,
+ knifeRadius: m.knifeRadius,
+ });
+ }
+ return data;
+ };
+ let allModeling = GetModelingFromCustomDrill(br);
+ let modeling = getModelings([...br.BoardModeling, ...allModeling.modeling]);
+ let sideModeling = getModelings(allModeling.sideModeling);
+ return { modeling, sideModeling };
+ }
+ Production.GetOriginBoardModelingData = GetOriginBoardModelingData;
+ function GetBoardModelingData(br, offsetTanslation) {
+ const tool = FeedingToolPath.GetInstance();
+ const tMtx = MoveMatrix(offsetTanslation.clone().negate());
+ const getModelings = (ms, isSide) => {
+ var _a;
+ let data = [];
+ for (let m of ms) {
+ let cu = m.shape.Outline.Curve;
+ if (cu instanceof exports.Circle && cu.Radius < userConfig.chaidanOption.modeling2HoleRad + 1e-6)
+ continue;
+ if (userConfig.chaidanOption.useDefaultRad)
+ m.knifeRadius = userConfig.chaidanOption.radius;
+ let paths = tool.GetModelFeedPath(br, m);
+ if (!isSide)
+ paths.forEach(path => path.ApplyMatrix(tMtx));
+ let feeding = paths.map((c) => ConverToPolylineAndSplitArc(c, false));
+ if (feeding.length > 0)
+ data.push({
+ feeding,
+ thickness: m.thickness + ((_a = m.addDepth) !== null && _a !== void 0 ? _a : 0),
+ dir: m.dir,
+ knifeRadius: m.knifeRadius,
+ });
+ else {
+ Toaster({
+ message: "板件有造型或者自定义排钻无法加工,请运行造型检测命令确认",
+ timeout: 5000,
+ intent: Intent.DANGER,
+ key: "造型加工错误"
+ });
+ }
+ }
+ return data;
+ };
+ let allModeling = GetModelingFromCustomDrill(br);
+ let modeling = getModelings([...br.BoardModeling, ...allModeling.modeling], false).filter(f => f.feeding.length > 0);
+ let sideModeling = getModelings(allModeling.sideModeling, true).filter(f => f.feeding.length > 0);
+ return { modeling, sideModeling };
+ }
+ Production.GetBoardModelingData = GetBoardModelingData;
+ /**获取板件的轮廓
+ *有拆单尺寸返回矩形
+ *用于拆单的轮廓统一逆时针 */
+ function GetSpliteOutline(br, isSplite) {
+ let con = GetSpliteOutlineBySpliteSize(br);
+ if (con)
+ return con;
+ con = br.ContourCurve;
+ if (con instanceof exports.Circle) {
+ return con;
+ }
+ let cus = con.Explode();
+ MergeCurvelist(cus);
+ let pl = exports.Polyline.Combine(cus, LINK_FUZZ);
+ if (isSplite && pl.Area2 < 0)
+ pl.Reverse();
+ return pl;
+ }
+ Production.GetSpliteOutline = GetSpliteOutline;
+ function GetSpliteBoards(en) {
+ let bs = en.SplitBoards;
+ for (let b of bs) {
+ if (b.__OriginalEnt__) {
+ for (let [k, ds] of en.DrillList)
+ b.AppendDrillList(k, ds);
+ b.AppendNails(en.LayerNails);
+ }
+ }
+ return bs;
+ }
+ Production.GetSpliteBoards = GetSpliteBoards;
+ function GetSpiteSize(br) {
+ let param = { L: br.Height, W: br.Width, H: br.Thickness };
+ let spliteHeight = safeEval(br.BoardProcessOption.spliteHeight, param);
+ let spliteWidth = safeEval(br.BoardProcessOption.spliteWidth, param);
+ let spliteThickness = safeEval(br.BoardProcessOption.spliteThickness, param);
+ if (spliteHeight && spliteWidth && spliteThickness)
+ return {
+ spliteHeight, spliteWidth, spliteThickness
+ };
+ else
+ return;
+ }
+ Production.GetSpiteSize = GetSpiteSize;
+ function GetSpliteOutlineBySpliteSize(br) {
+ let size = GetSpiteSize(br);
+ if (size)
+ return new exports.Polyline().RectangleFrom2Pt(new three.Vector3, new three.Vector3(size.spliteWidth, size.spliteHeight));
+ return null;
+ }
+ Production.GetSpliteOutlineBySpliteSize = GetSpliteOutlineBySpliteSize;
+ /**孔信息,侧孔的z 均为 从上到下距离 */
+ function GetBoardHolesData(br, offsetTanslation, sealedContour) {
+ let data = {
+ frontBackHoles: [],
+ sideHoles: []
+ };
+ let brNormal = br.Normal;
+ // 性能优化的解析板件网洞类
+ // new ParseBoardHoleData(br, offsetTanslation, sealedContour);
+ for (let [, driss] of br.DrillList) {
+ for (let dris of driss) {
+ for (let dId of dris) {
+ if (!dId || dId.IsErase)
+ continue;
+ let d = dId.Object;
+ if (d instanceof ExtrudeHole)
+ ParseExtrudeHoles(d, br, offsetTanslation, data, sealedContour);
+ else
+ ParseCylHoles(d, br, offsetTanslation, data, sealedContour);
+ }
+ }
+ }
+ if (br.RelativeHardware) {
+ for (let dId of br.RelativeHardware) {
+ if (dId.IsErase)
+ continue;
+ let d = dId.Object;
+ let holes = [];
+ if (d instanceof HardwareCompositeEntity) {
+ holes.push(...GetMetalTotalEntitys(d, true, (e) => e instanceof Hole));
+ }
+ for (let h of holes) {
+ if (h instanceof ExtrudeHole)
+ ParseExtrudeHoles(h, br, offsetTanslation, data, sealedContour);
+ else
+ ParseCylHoles(h, br, offsetTanslation, data, sealedContour);
+ }
+ }
+ }
+ let modelings = br.BoardModeling;
+ for (let nid of br.LayerNails) {
+ if (!nid || !nid.Object || nid.IsErase)
+ continue;
+ let nail = nid.Object;
+ if (!isParallelTo(nail.Normal, brNormal))
+ continue;
+ let sp = nail.Position.applyMatrix4(br.OCSInv);
+ let nor = nail.Normal.multiplyScalar(nail.Height);
+ let ep = nail.Position.add(nor).applyMatrix4(br.OCSInv);
+ let [z0, z1] = sp.z < ep.z ? [sp.z, ep.z] : [ep.z, sp.z];
+ if (Math.max(z0, 0) < Math.min(z1, br.Thickness) - 1e-6
+ && br.ContourCurve.PtInCurve(sp.setZ(0))
+ && modelings.every(m => !m.shape.Outline.Curve.PtInCurve(sp))) {
+ let face = !equalv3(nail.Normal, brNormal, 1e-3) ? DrillingFace.Front : DrillingFace.Back;
+ let depth = Math.min(z1, br.Thickness) - Math.max(z0, 0);
+ data.frontBackHoles.push({
+ type: nail.Type,
+ position: sp.sub(offsetTanslation),
+ radius: nail.Radius,
+ depth,
+ face,
+ });
+ }
+ }
+ for (let m of modelings) {
+ let cu = m.shape.Outline.Curve;
+ if (cu instanceof exports.Circle && cu.Radius < userConfig.chaidanOption.modeling2HoleRad + 1e-6) {
+ let center = cu.Center.setZ(0).sub(offsetTanslation);
+ data.frontBackHoles.push({
+ type: GangDrillType.Pxl,
+ position: center,
+ radius: cu.Radius,
+ depth: m.thickness,
+ face: m.dir
+ });
+ }
+ }
+ return data;
+ }
+ Production.GetBoardHolesData = GetBoardHolesData;
+ /**拆单那边需要把侧孔 z 坐标转换为从上到下 */
+ function InvertPosition(pos, thickness) {
+ pos.z = thickness - pos.z;
+ }
+ /**分析常规排钻 */
+ function ParseCylHoles(d, br, offsetTanslation, data, outline) {
+ let processData = br.BoardProcessOption;
+ let brNormal = br.Normal;
+ let roMat = new three.Matrix4().extractRotation(br.OCSInv);
+ let position = d.Position.applyMatrix4(br.OCSInv);
+ let holes = data.frontBackHoles;
+ let face;
+ let isPush = false;
+ let endPt;
+ let depth = d.Height;
+ let diffMat = br.OCSInv.multiply(d.OCS);
+ let x = new three.Vector3().setFromMatrixColumn(diffMat, 0);
+ let angle = angleTo(XAxis, x);
+ if (d.Type === GangDrillType.Pxl || d.Type === GangDrillType.WoodPXL) {
+ if (isParallelTo(d.Normal, brNormal)) {
+ if (position.x <= 0 || position.x >= br.Width || position.y <= 0 || position.y >= br.Height || !outline.PtInCurve(position.clone().setZ(0)))
+ return;
+ position.sub(offsetTanslation);
+ face = processData[EBoardKeyList.BigHole];
+ isPush = true;
+ }
+ }
+ else if (d.Type === GangDrillType.Ljg || d.Type === GangDrillType.Wood) {
+ if (!isParallelTo(d.Normal, brNormal)) {
+ let z = position.z;
+ let line = new exports.Line(position.clone().setZ(0), position.clone().setZ(0).add(d.Normal.multiplyScalar(d.Height).applyMatrix4(roMat)));
+ let pt = outline.IntersectWith(line, 0)[0];
+ if (!pt) {
+ return;
+ }
+ position = pt.clone().setZ(z);
+ for (let p of [line.StartPoint, line.EndPoint]) {
+ if (outline.PtInCurve(p)) {
+ endPt = p.setZ(z);
+ break;
+ }
+ }
+ if (!endPt) {
+ console.warn("排钻位置有问题");
+ return;
+ }
+ holes = data.sideHoles;
+ face = Math.floor(outline.GetParamAtPoint(pt));
+ isPush = true;
+ depth = position.distanceTo(endPt);
+ angle = undefined;
+ InvertPosition(position, br.Thickness);
+ InvertPosition(endPt, br.Thickness);
+ }
+ else if (d.Type === GangDrillType.Wood) {
+ if (!outline.PtInCurve(position.clone().setZ(0)))
+ return;
+ face = position.z > 0 ? FaceDirection.Front : FaceDirection.Back;
+ holes = data.frontBackHoles;
+ if (position.z > 0) {
+ let z1 = position.z - d.Height;
+ if (z1 > 0 && z1 < br.Thickness) {
+ depth = br.Thickness - z1;
+ isPush = true;
+ }
+ }
+ else {
+ let z1 = position.z + d.Height;
+ if (z1 > 0 && z1 < br.Thickness) {
+ depth = z1;
+ isPush = true;
+ }
+ }
+ position.sub(offsetTanslation);
+ }
+ }
+ else {
+ if (isParallelTo(d.Normal, br.Normal)) {
+ if (position.x <= 0 || position.x >= br.Width || position.y <= 0 || position.y >= br.Height)
+ return;
+ position.sub(offsetTanslation);
+ holes = data.frontBackHoles;
+ face = !equalv3(d.Normal, brNormal, 1e-3) ? 0 : 1;
+ isPush = true;
+ }
+ }
+ isPush && holes.push({
+ type: d.Type,
+ position,
+ radius: d.Radius,
+ depth,
+ face,
+ endPt,
+ angle
+ });
+ }
+ /**分析自定义圆柱排钻 */
+ function ParseExtrudeHoles(d, br, offsetTanslation, data, outline) {
+ if (!d.isHole)
+ return;
+ let brNormal = br.Normal;
+ let cir = d.ContourCurve;
+ if (cir instanceof exports.Circle) {
+ let diffMtx = br.OCSInv.multiply(d.OCS);
+ let nor = d.Normal;
+ let sp = cir.Center.applyMatrix4(diffMtx);
+ let ep = cir.Center.add(new three.Vector3(0, 0, d.Height)).applyMatrix4(diffMtx);
+ let x = new three.Vector3().setFromMatrixColumn(diffMtx, 0);
+ if (isParallelTo(nor, brNormal)) {
+ let z0 = Math.min(sp.z, ep.z);
+ let z1 = Math.max(sp.z, ep.z);
+ let p = sp.clone().setZ(0).sub(offsetTanslation);
+ if (Math.max(z0, 0) < Math.min(z1, br.Thickness) - 1e-6 && outline.PtInCurve(p)) {
+ let depth = z0 < 1e-2 ? z1 : br.Thickness - z0;
+ if (depth > 1e-2)
+ data.frontBackHoles.push({
+ type: GangDrillType.Pxl,
+ position: z0 < 1e-6 ? p : p.setZ(br.Thickness),
+ radius: cir.Radius,
+ depth,
+ face: z0 < 1e-6 ? DrillingFace.Back : DrillingFace.Front,
+ angle: angleTo(XAxis, x),
+ });
+ }
+ }
+ else {
+ let oldZ = sp.z;
+ let [minX, maxX] = sp.x < ep.x ? [sp.x, ep.x] : [ep.x, sp.x];
+ let [minY, maxY] = sp.y < ep.y ? [sp.y, ep.y] : [ep.y, sp.y];
+ if (sp.z > cir.Radius
+ && sp.z < br.Thickness - cir.Radius
+ && Math.max(minX, 0) < Math.min(br.Width, maxX) + 1e-6
+ && Math.max(minY, 0) < Math.min(br.Height, maxY) + 1e-6) {
+ sp.setZ(0);
+ ep.setZ(0);
+ let line = new exports.Line(sp, ep);
+ let pt = outline.IntersectWith(line, 0)[0];
+ if (!pt) {
+ console.error("排钻嵌在板件内部");
+ return;
+ }
+ let position = pt.clone().setZ(oldZ);
+ let endPt;
+ let face = Math.floor(outline.GetParamAtPoint(pt));
+ for (let p of [line.StartPoint, line.EndPoint]) {
+ if (outline.PtInCurve(p)) {
+ endPt = p.setZ(oldZ);
+ break;
+ }
+ }
+ if (!endPt)
+ return;
+ let depth = position.distanceTo(endPt);
+ if (equaln(depth, 0, 1e-2))
+ return;
+ InvertPosition(position, br.Thickness);
+ InvertPosition(endPt, br.Thickness);
+ data.sideHoles.push({
+ type: GangDrillType.Ljg,
+ endPt,
+ position,
+ radius: cir.Radius,
+ depth,
+ face,
+ });
+ }
+ }
+ }
+ }
+ function GetBoardMetals(br) {
+ let mids = br.RelativeHardware;
+ let metalsData = {
+ metals: 0,
+ comp: 0
+ };
+ for (let id of mids) {
+ if (!id || id.IsErase)
+ continue;
+ let metals = id.Object;
+ if (!metals.HardwareOption)
+ continue;
+ if (metals.HardwareOption.type === EMetalsType.Metals) {
+ metalsData.metals++;
+ }
+ else {
+ metalsData.comp++;
+ }
+ }
+ return metalsData;
+ }
+ function GetHardwareCompositeData(en) {
+ let size = en.BoundingBoxInOCS.getSize(new three.Vector3);
+ let data = { ...en.HardwareOption };
+ const actualVal = safeEval(data.actualExpr, { L: size.x, W: size.y, H: size.z });
+ data.actualExpr = actualVal ? actualVal.toString() : data.actualExpr;
+ data.spec = ParseExpr(data.spec, { L: size.x, W: size.y, H: size.z });
+ data.count = (safeEval(data.count, { L: size.x, W: size.y, H: size.z }) || 0).toString();
+ let metalData = {
+ metalsOption: data,
+ dataList: en.DataList,
+ children: [],
+ };
+ if (en instanceof HardwareCompositeEntity && (en.HardwareOption.isSplite || en.HardwareOption.isSplitePrice)) {
+ if (en.Entitys.every(e => !(e instanceof HardwareCompositeEntity || e instanceof HardwareTopline)))
+ return metalData;
+ for (let e of en.Entitys) {
+ if (e instanceof HardwareCompositeEntity) {
+ let d = GetHardwareCompositeData(e);
+ metalData.children.push(d);
+ }
+ else if (e instanceof HardwareTopline) {
+ metalData.children.push(...GetHardwareToplineData(e));
+ }
+ }
+ }
+ return metalData;
+ }
+ Production.GetHardwareCompositeData = GetHardwareCompositeData;
+ function GetHardwareToplineData(en) {
+ let data = { ...en.HardwareOption };
+ let datas = [];
+ let map = new Map();
+ let addLen = en.HardwareOption.addLen;
+ let path = en.MaxPath;
+ let cus = path instanceof exports.Polyline ? path.Explode() : [path];
+ let size = en.BoundingBoxInOCS.getSize(new three.Vector3);
+ for (let cu of cus) {
+ let len = parseFloat(FixedNotZero(cu.Length, 2));
+ if (map.has(len)) {
+ map.set(len, map.get(len) + 1);
+ }
+ else {
+ map.set(len, 1);
+ }
+ }
+ for (let [len, count] of map) {
+ let totalLength = parseFloat(FixedNotZero(len + parseFloat(addLen), 2));
+ let width = parseFloat(FixedNotZero(size.y, 2));
+ let height = parseFloat(FixedNotZero(size.z, 2));
+ for (let i = 0; i < count; i++) {
+ let d = { ...en.HardwareOption };
+ const actualVal = safeEval(data.actualExpr, { L: totalLength, W: width, H: height });
+ d.actualExpr = actualVal ? actualVal.toString() : d.actualExpr;
+ d.spec = ParseExpr(data.spec, { L: totalLength, W: width, H: height });
+ datas.push({
+ metalsOption: d,
+ dataList: en.DataList,
+ length: totalLength,
+ children: [],
+ });
+ }
+ }
+ return datas;
+ }
+ Production.GetHardwareToplineData = GetHardwareToplineData;
+ /**获取排钻数量 */
+ function GetTotalDrillCount(brs) {
+ return lookOverBoardInfosTool.GetCount(brs);
+ }
+ Production.GetTotalDrillCount = GetTotalDrillCount;
+ function GetCabSize(brList) {
+ let brMap = new Map();
+ //根据柜名房名分类
+ for (let b of brList) {
+ let k = b.BoardProcessOption[EBoardKeyList.RoomName] + '-' + b.BoardProcessOption[EBoardKeyList.CabinetName];
+ if (brMap.has(k))
+ brMap.get(k).push(b);
+ else
+ brMap.set(k, [b]);
+ }
+ let sizeData = new Map();
+ for (let [k, brs] of brMap) {
+ let ocsInv = brs[0].SpaceOCSInv;
+ let box = new three.Box3();
+ let size = new three.Vector3();
+ for (let b of brs) {
+ sizeData.set(b, size);
+ box.union(b.GetBoundingBoxInMtx(ocsInv));
+ }
+ box.getSize(size);
+ }
+ return sizeData;
+ }
+ Production.GetCabSize = GetCabSize;
+})(Production || (Production = {}));
+
+/**
+ *曲线列表分段
+ * @l-arc-l,l-arc-arc-l,l-arc-l-arc-l....
+ */
+function ParagraphCulist(cus) {
+ let newCulist = [];
+ let usedCu = new WeakSet();
+ //归类曲线,返回归类是否成功
+ const paragraph = (cu, originCu, cuList, isBack) => {
+ const cuIsLine = cu instanceof exports.Line;
+ const originCuIsLine = originCu instanceof exports.Line;
+ if (usedCu.has(cu))
+ return false;
+ if (originCuIsLine !== cuIsLine) {
+ if (originCuIsLine &&
+ !isParallelTo(originCu.GetFistDeriv(0), cu.GetFistDeriv(0))
+ && !isParallelTo(originCu.GetFistDeriv(0), cu.GetFistDeriv(1))) {
+ return false;
+ }
+ if (cuIsLine
+ && !isParallelTo(originCu.GetFistDeriv(1), cu.GetFistDeriv(0))
+ && !isParallelTo(originCu.GetFistDeriv(0), cu.GetFistDeriv(0))) {
+ return false;
+ }
+ }
+ else if (cuIsLine) {
+ //共线且相连的直线分为一组 #I11T1Z
+ if (!isParallelTo(cu.GetFistDeriv(0).normalize(), originCu.GetFistDeriv(0).normalize()))
+ return false;
+ let pts = [originCu.StartPoint, originCu.EndPoint];
+ let pts2 = [cu.StartPoint, cu.EndPoint];
+ if (pts.every(p => pts2.every(p2 => !equalv3(p, p2, 1e-6))))
+ return false;
+ }
+ if (isBack)
+ cuList.push(cu);
+ else
+ cuList.unshift(cu);
+ usedCu.add(cu);
+ return true;
+ };
+ let caclCus = cus.slice().filter(c => !equaln(c.Length, 0));
+ while (caclCus.length > 0) {
+ let originCu = caclCus.shift();
+ if (usedCu.has(originCu))
+ continue;
+ let originCus = [originCu];
+ usedCu.add(originCu);
+ //往后搜索
+ for (let i = 0; i < caclCus.length; i++) {
+ if (!paragraph(caclCus[i], originCu, originCus, true))
+ break;
+ originCu = caclCus[i];
+ }
+ //只有第一条才需要往前搜索
+ if (caclCus.length === cus.length - 1) {
+ originCu = originCus[0];
+ //往前搜索
+ for (let i = caclCus.length - 1; i >= 0; i--) {
+ if (!paragraph(caclCus[i], originCu, originCus, false))
+ break;
+ originCu = caclCus[i];
+ }
+ }
+ newCulist.push(originCus);
+ }
+ cus.length = 0;
+ //同组多条曲线连接为多段线
+ for (let g of newCulist) {
+ if (g.length === 1)
+ cus.push(g[0]);
+ else {
+ let pl = new exports.Polyline();
+ for (let c of g) {
+ pl.Join(c);
+ }
+ cus.push(pl);
+ }
+ }
+}
+/**
+ *计算封边
+ */
+function CalcEdgeSealing(cus) {
+ if (cus.length <= 1)
+ return;
+ let oldLine;
+ let firstLine = cus[0].Clone();
+ for (let i = 0; i < cus.length; i++) {
+ let frontLine = cus[i];
+ let laterIndex = FixIndex(i + 1, cus);
+ let laterLine = cus[laterIndex];
+ if (!frontLine || !laterLine) {
+ alert("获取封边错误,请提供图纸给相关人员");
+ return;
+ }
+ let dist = frontLine.EndPoint.distanceToSquared(laterLine.StartPoint);
+ if (dist < LINK_FUZZ ** 2)
+ continue;
+ let refLine = oldLine !== null && oldLine !== void 0 ? oldLine : frontLine;
+ let refLine2 = i === cus.length - 1 ? firstLine : laterLine;
+ let iPts = refLine.IntersectWith(refLine2, IntersectOption.ExtendBoth);
+ let tPts = iPts.filter(p => refLine.PtOnCurve(p)
+ && refLine2.PtOnCurve(p));
+ let iPt = SelectNearP(tPts.length > 0 ? tPts : iPts, frontLine.EndPoint);
+ if (!iPt) {
+ alert("获取封边错误,请提供图纸给相关人员");
+ return;
+ }
+ let par = frontLine.GetParamAtPoint(iPt);
+ if (par < 0) {
+ cus.splice(i, 1);
+ i -= 2;
+ if (i < -1)
+ i = -1;
+ }
+ else
+ frontLine.EndPoint = iPt;
+ oldLine = equalv3(iPt, laterLine.EndPoint) ? laterLine.Clone() : null;
+ par = laterLine.GetParamAtPoint(iPt);
+ if (par > 1) {
+ cus.splice(laterIndex, 1);
+ i -= 1;
+ }
+ else
+ laterLine.StartPoint = iPt;
+ }
+}
+function GetBoardHighSeal(br, sealcus) {
+ let highSeals = br.BoardProcessOption.highSealed.slice();
+ let sealDown = parseFloat(br.BoardProcessOption[EBoardKeyList.DownSealed]);
+ let sealUp = parseFloat(br.BoardProcessOption[EBoardKeyList.UpSealed]);
+ let sealLeft = parseFloat(br.BoardProcessOption[EBoardKeyList.LeftSealed]);
+ let sealRight = parseFloat(br.BoardProcessOption[EBoardKeyList.RightSealed]);
+ //若未设置高级封边,把上下左右封边存入高级封边
+ if (sealcus.length !== highSeals.length || !br.IsSpecialShape) {
+ highSeals.length = 0;
+ let dir = Math.sign(br.ContourCurve.Area2);
+ for (let c of sealcus) {
+ let derv = c.GetFistDeriv(0).multiplyScalar(dir);
+ let an = angle(derv);
+ if (equaln(an, 0) || (an < Math.PI / 4 + 1e-8 && an > Math.PI * 7 / 4))
+ highSeals.push({ size: sealDown });
+ else if (an > Math.PI / 4 && an < Math.PI * 3 / 4 + 1e-8)
+ highSeals.push({ size: sealRight });
+ else if (an > Math.PI * 3 / 4 && an < Math.PI * 5 / 4 + 1e-8)
+ highSeals.push({ size: sealUp });
+ else
+ highSeals.push({ size: sealLeft });
+ }
+ }
+ return highSeals;
+}
+/**偏移前后曲线起点没改变 */
+function OffsetOutlineSpNotChange(oldcu, newCu) {
+ if (!newCu)
+ return false;
+ let sDerv = oldcu.GetFistDeriv(0).normalize();
+ let eDerv = oldcu.GetFistDeriv(oldcu.EndParam).normalize().negate();
+ sDerv.add(eDerv).normalize();
+ let mDerv = newCu.StartPoint.sub(oldcu.StartPoint).normalize();
+ return oldcu.EndParam === (newCu === null || newCu === void 0 ? void 0 : newCu.EndParam) && isParallelTo(mDerv, sDerv);
+}
+/**
+ * 获取板件封边轮廓线段数组
+ * 消除共线的数据,不改变轮廓方向
+ * isOffset-是否偏移轮廓用于查看
+ * */
+function GetBoardSealingCurves(br, isOffset = false) {
+ let cu = Production.GetSpliteOutlineBySpliteSize(br);
+ if (cu)
+ return cu.Explode();
+ let cus = [];
+ cu = Production.GetSpliteOutline(br, false);
+ if (isOffset) {
+ let dir = Math.sign(cu.Area2);
+ let newCu = cu.GetOffsetCurves(-1 * dir)[0];
+ if (OffsetOutlineSpNotChange(cu, newCu))
+ cu = newCu;
+ }
+ if (cu instanceof exports.Circle)
+ return [cu.Clone()];
+ else {
+ cus = cu.Explode();
+ if (br.IsSpecialShape)
+ ParagraphCulist(cus);
+ return cus;
+ }
+}
+/**
+ * 获取板件轮廓
+ * 结果轮廓拆单用,统一逆时针数据
+ * hasSealing 轮廓是否包含封边
+ * 用户计算拆单侧孔面id
+ */
+function GetSealedBoardContour(br, hasSealing) {
+ if (equaln(br.ContourCurve.Area, 0))
+ return;
+ let offsetCus = [];
+ let cus = GetBoardSealingCurves(br);
+ let highSeals = GetBoardHighSeal(br, cus);
+ let dir = Math.sign(br.ContourCurve.Area2);
+ if (hasSealing) {
+ for (let c of cus) {
+ if (c instanceof exports.Polyline)
+ offsetCus.push(...c.Explode());
+ else
+ offsetCus.push(c);
+ }
+ }
+ else {
+ if (cus[0] instanceof exports.Circle)
+ dir = 1;
+ for (let i = 0; i < cus.length; i++) {
+ let cs;
+ if (highSeals[i].size === 0)
+ cs = [cus[i].Clone()];
+ else
+ cs = cus[i].GetOffsetCurves(-highSeals[i].size * dir);
+ for (let c of cs) {
+ if (c instanceof exports.Polyline)
+ offsetCus.push(...c.Explode());
+ else
+ offsetCus.push(c);
+ }
+ }
+ }
+ if (offsetCus.length === 1 && offsetCus[0] instanceof exports.Circle)
+ return offsetCus[0];
+ CalcEdgeSealing(offsetCus);
+ let pl = exports.Polyline.Combine(offsetCus, LINK_FUZZ);
+ if (dir < 0)
+ pl.Reverse();
+ return pl;
+}
+
+/**
+ * 优化走刀路径,连接偏移后的曲线数组
+ * @param offsetCus 偏移后的曲线组
+ * @param originShape 原始走刀形状
+ * @param rad 刀半径
+ * @returns tool path
+ */
+function OptimizeToolPath(offsetCus, originShape, rad) {
+ var _a;
+ // 去掉最外轮廓
+ let outline = offsetCus.shift();
+ let plList = [];
+ let noCloseCus = [];
+ for (let cu of offsetCus) {
+ if (!cu.IsClose) {
+ noCloseCus.push(cu);
+ continue;
+ }
+ if (cu instanceof exports.Polyline) {
+ //轮廓朝下的逆时针轮廓需要翻转
+ //如果走刀不止一条,第一刀为顺时针,其余为逆时针
+ if (cu.IsClose) {
+ if (offsetCus.length === 1) {
+ if (cu.Normal.z * cu.Area2 < 0)
+ cu.Reverse();
+ }
+ else if ((cu.Normal.z * cu.Area2 < 0) === (cu !== offsetCus[0]))
+ cu.Reverse();
+ }
+ plList.push(cu);
+ }
+ else if (cu instanceof exports.Circle) {
+ let c = ConverCircleToPolyline(cu);
+ if (offsetCus.length > 1 && cu === offsetCus[0])
+ c.Reverse();
+ c.ColorIndex = cu.ColorIndex;
+ plList.push(c);
+ }
+ else
+ console.warn("错误形状");
+ }
+ if (noCloseCus.length > 0) {
+ let culist = [];
+ noCloseCus.forEach(c => {
+ if (c instanceof exports.Polyline)
+ culist.push(...c.Explode());
+ else
+ culist.push(c);
+ });
+ //移除相等的曲线避免重复走刀
+ RempveEqualCurves(culist);
+ let groups = curveLinkGroup(culist);
+ for (let g of groups) {
+ let pl = exports.Polyline.Combine(g);
+ pl.ColorIndex = noCloseCus[0].ColorIndex;
+ plList.push(pl);
+ }
+ }
+ let dir = GetCurveToInDir(outline);
+ let cantIntCur = [outline];
+ cantIntCur.push(...GetOffsetCurves(outline, rad * dir));
+ if (originShape.Holes.length > 0) {
+ for (let h of originShape.Holes) {
+ let dir = Math.sign(h.Curve.Area2);
+ if (h.Curve instanceof exports.Circle)
+ dir = 1;
+ cantIntCur.push(h.Curve, ...GetOffsetCurves(h.Curve, rad * dir));
+ }
+ }
+ //曲线统一起点
+ ChangePlListStartPt(plList);
+ //对多段线进行排序,按最起始点远近排序
+ SortPlByStartPt(plList);
+ let result = [];
+ let firstPl = plList[0];
+ firstPl.CloseMark = false;
+ for (let i = 1; i < plList.length; i++) {
+ let ePt = firstPl.EndPoint;
+ let isDisVail;
+ if (((_a = plList[i].TempData) === null || _a === void 0 ? void 0 : _a.isOut) && !equalv3(ePt, plList[i].StartPoint))
+ isDisVail = true;
+ else {
+ let refLine = new exports.Line(ePt, plList[i].StartPoint);
+ isDisVail = cantIntCur.some(c => c.IntersectWith(refLine, 0).length > 1);
+ }
+ if (isDisVail) {
+ result.push(firstPl);
+ firstPl = plList[i];
+ firstPl.CloseMark = false;
+ }
+ else {
+ let alMat = matrixAlignCoordSys(plList[i].OCS, firstPl.OCS);
+ let cuPtsBul = plList[i].PtsBuls;
+ for (let i = 0; i < cuPtsBul.pts.length; i++) {
+ //坐标系对齐
+ let p = cuPtsBul.pts[i];
+ p.copy(AsVector2(AsVector3(p).applyMatrix4(alMat)));
+ firstPl.LineData.push({ pt: p, bul: cuPtsBul.buls[i] });
+ }
+ }
+ }
+ result.push(firstPl);
+ return result;
+}
+/**
+* 设定走刀路径起始点
+* 为了统一刀路起点,最外轮廓左左点为起始点,其余轮廓以最接近最外轮廓起始点的点左起始点
+* @param plList
+*/
+function ChangePlListStartPt(plList) {
+ let firstPl = plList[0];
+ if (firstPl.IsClose) {
+ let minP = undefined;
+ let compare = comparePoint("xy");
+ for (let p of firstPl.GetStretchPoints()) {
+ if (!minP)
+ minP = p;
+ else if (compare(minP, p) === 1)
+ minP = p;
+ }
+ let par = firstPl.GetParamAtPoint(minP);
+ firstPl.ResetStartPoint(par);
+ }
+ let firstSpt = firstPl.StartPoint;
+ for (let i = 1; i < plList.length; i++) {
+ let pl = plList[i];
+ if (pl.IsClose) {
+ let pts = pl.GetStretchPoints().sort((p1, p2) => {
+ let dist1 = p1.distanceToSquared(firstSpt);
+ let dist2 = p2.distanceToSquared(firstSpt);
+ return dist1 - dist2;
+ });
+ let par = pl.GetParamAtPoint(pts[0]);
+ pl.ResetStartPoint(par);
+ }
+ else {
+ let sPt = pl.StartPoint;
+ let ePt = pl.EndPoint;
+ let dist1 = sPt.distanceToSquared(firstSpt);
+ let dist2 = ePt.distanceToSquared(firstSpt);
+ if (dist1 > dist2)
+ pl.Reverse();
+ }
+ }
+}
+/**
+ * 排序多段线数组,按照起点之间的距离
+ */
+function SortPlByStartPt(pls) {
+ if (pls.length <= 1)
+ return pls;
+ let result = [pls[0]];
+ let usedPl = new WeakSet([pls[0]]);
+ let p = pls[0].StartPoint;
+ while (true) {
+ if (pls.length === result.length)
+ break;
+ let vaildPl;
+ let minDist = Infinity;
+ for (let pl of pls) {
+ if (usedPl.has(pl))
+ continue;
+ let dist = pl.StartPoint.distanceToSquared(p);
+ if (dist < minDist) {
+ minDist = dist;
+ vaildPl = pl;
+ }
+ }
+ p = vaildPl.StartPoint;
+ result.push(vaildPl);
+ usedPl.add(vaildPl);
+ }
+ pls.length = 0;
+ pls.push(...result);
+}
+function RempveEqualCurves(cus) {
+ let needRemoveCurve = new Set();
+ for (let i = 0; i < cus.length; i++) {
+ let cu1 = cus[i];
+ if (needRemoveCurve.has(cu1))
+ continue;
+ for (let j = i + 1; j < cus.length; j++) {
+ let cu2 = cus[j];
+ if (needRemoveCurve.has(cu2))
+ continue;
+ if (equalCurve(cu1, cu2)) {
+ needRemoveCurve.add(cu2);
+ }
+ }
+ }
+ arrayRemoveIf(cus, (c) => needRemoveCurve.has(c));
+}
+function GetOffsetCurves(cu, dist) {
+ if (cu instanceof exports.Polyline)
+ return cu.GetFeedingToolPath(dist);
+ else
+ return cu.GetOffsetCurves(dist);
+}
+/** 获得曲线内偏移方向*/
+function GetCurveToInDir(cu) {
+ return cu.IsClockWise ? 1 : -1;
+}
+
+/**
+ *计算走刀工具类
+ */
+class FeedingToolPath extends Singleton {
+ /**
+ * 处理形状,内偏移
+ * @param shape 造型Shape
+ * @param knifRadius 刀半径/偏移距离
+ * @param [isOut=true] 是否是最外轮廓,如果是,洞需要外偏移一个刀半径,多段线偏移保留不闭合轮廓
+ */
+ HandleShape(shape, knifRadius, isOut = true) {
+ let outline = shape.Outline.Curve;
+ if (isOut)
+ outline = outline.Clone();
+ let dir = GetCurveToInDir(outline);
+ let offsetCus = [outline];
+ //获得形状外孔轮廓
+ let holes = [];
+ /**用于判断孤岛是否与外轮廓相交 */
+ let holeOffsetCus = [];
+ for (let h of shape.Holes) {
+ if (!isOut)
+ holes.push(h.Clone());
+ else {
+ let dir = -GetCurveToInDir(h.Curve);
+ let cus;
+ if (h.Curve instanceof exports.Circle)
+ cus = h.Curve.GetOffsetCurves(knifRadius * dir);
+ else
+ cus = h.Curve.GetFeedingToolPath(knifRadius * dir);
+ holeOffsetCus.push(...h.Curve.GetOffsetCurves(knifRadius * dir).filter(c => c.IsClose));
+ holes.push(...this.GetContours(cus, offsetCus));
+ }
+ }
+ let offsetDist = 0;
+ let isRect = IsRect(outline).isRect;
+ while (true) {
+ if ((!isOut || offsetDist >= knifRadius) && isRect)
+ offsetDist += knifRadius * 2;
+ else
+ offsetDist += knifRadius;
+ let retCus = [];
+ let tempOffsetCus = GetOffsetCurves(outline, offsetDist * dir);
+ retCus.push(...tempOffsetCus);
+ //最后一次内偏移如果是矩形,需在偏移一个刀半径避免没切到中心
+ if (retCus.length === 0 && isRect) {
+ offsetDist -= knifRadius;
+ retCus.push(...GetOffsetCurves(outline, offsetDist * dir));
+ }
+ if (retCus.length === 0)
+ break;
+ //是否和孤岛相交
+ let isInt = false;
+ for (let c of retCus) {
+ if (holes.length > 0) {
+ isInt = holes.some(h => h.Curve.IntersectWith(c, 0).length > 0 || h.CuInOutline(c));
+ if (isInt)
+ break;
+ }
+ if (isOut && offsetDist === knifRadius)
+ c.TempData = { isOut: true };
+ offsetCus.push(c);
+ }
+ if (isInt) {
+ //洞形状管理器
+ let holesMg = new ShapeManager();
+ if (isOut)
+ holes = Shape.mergeContours(holes, false); //#I1MUQD 正好擦边的孔不合并
+ holesMg.AppendShapeList(holes.map(h => new Shape(h)));
+ let shapeMg = new ShapeManager();
+ let cons = this.GetContours(retCus, offsetCus);
+ shapeMg.AppendShapeList(cons.map(c => new Shape(c)));
+ shapeMg.BoolOper(holesMg, exports.BoolOpeartionType.Subtract);
+ for (let s of shapeMg.ShapeList) {
+ if (isOut && tempOffsetCus.length > 1)
+ s.Outline.Curve.TempData = { isOut: true };
+ offsetCus.push(...this.HandleShape(s, knifRadius, false));
+ }
+ break;
+ }
+ }
+ let vailHoles = [];
+ for (let i = 0; i < holes.length; i++) {
+ let h = holes[i];
+ //如果加工洞外圈和最外轮廓相交,则去掉
+ if (h.Curve.IntersectWith(outline, 0).length > 0)
+ continue;
+ let isVail = true;
+ //若最外轮廓内偏移一个刀半径的曲线 和最内轮廓相交或者被包含,则去掉.且不与洞曲线相等
+ if (isOut) {
+ let outlineOffsetCus = outline.GetOffsetCurves(dir * knifRadius).filter(c => c.IsClose);
+ let outlineCus = GetOffsetCurves(outline, dir * knifRadius);
+ let ho = holeOffsetCus[i];
+ let maxArea = Math.max(...outlineOffsetCus.map(c => c.Area));
+ for (let j = 0; j < outlineOffsetCus.length; j++) {
+ let c = outlineOffsetCus[j];
+ if (h.Curve.IntersectWith(outlineCus[j], 0).length > 0) {
+ if (!(equalCurve(ho, c) || isTargetCurInOrOnSourceCur(c, h.Curve))) {
+ isVail = false;
+ break;
+ }
+ else if (isTargetCurInOrOnSourceCur(h.Curve, c)) {
+ offsetCus.push(c);
+ isVail = false;
+ break;
+ }
+ }
+ else if (ho.Area > maxArea) {
+ isVail = false;
+ break;
+ }
+ }
+ }
+ if (isVail)
+ vailHoles.push(h);
+ }
+ offsetCus.push(...vailHoles.map(h => h.Curve));
+ return offsetCus;
+ }
+ /**用于测试走刀路径 */
+ TestCalcPath(br, isCd = false) {
+ let modelings = br.BoardModeling;
+ let allModeling = GetModelingFromCustomDrill(br);
+ modelings.push(...allModeling.modeling);
+ if (isCd && userConfig.chaidanOption.useDefaultRad)
+ modelings.forEach(m => m.knifeRadius = userConfig.chaidanOption.radius);
+ let cus = this.CalcPath(modelings, br);
+ //不同走刀路径区分颜色
+ cus.forEach((c, i) => c.ColorIndex = (i + 1 === 8 || i + 1 === 18 || i + 1 === 19) ? i + 2 : i + 1);
+ let outline = br.ContourCurve;
+ let dir = Math.sign(outline.Area2);
+ let sideOutlines = [];
+ //优化侧面造型模拟走刀位置
+ for (let m of allModeling.sideModeling) {
+ let c = outline.GetCurveAtIndex(m.dir);
+ let derv = c.GetFistDeriv(0);
+ if (dir < 0)
+ derv.negate();
+ let mat = MoveMatrix(dir > 0 ? c.StartPoint : c.EndPoint)
+ .multiply(new three.Matrix4().makeRotationZ(angleTo(XAxis, derv)))
+ .multiply(MoveMatrix(new three.Vector3(0, -br.Thickness)));
+ m.shape.ApplyMatrix(mat);
+ let pl = new exports.Polyline().RectangleFrom2Pt(new three.Vector3(), new three.Vector3(c.Length, br.Thickness));
+ pl.ColorIndex = 6;
+ pl.ApplyMatrix(mat);
+ sideOutlines.push(pl);
+ }
+ cus.push(...this.CalcPath(allModeling.sideModeling, br));
+ //加入板件轮廓
+ cus.unshift(br.ContourCurve.Clone());
+ if (cus.length === 1)
+ return cus;
+ //加入造型外轮廓和洞
+ for (let { shape, thickness } of modelings) {
+ let outline = shape.Outline.Curve.Clone();
+ outline.Position = outline.Position.setZ(0);
+ outline.ColorIndex = 8;
+ cus.push(outline);
+ if (thickness < br.Thickness) {
+ cus.push(...shape.Holes.map(h => {
+ let c = h.Curve.Clone();
+ c.Position = c.Position.setZ(0);
+ c.ColorIndex = 8;
+ return c;
+ }));
+ }
+ }
+ cus.push(...sideOutlines);
+ return cus;
+ }
+ /**
+ * 计算走刀路径
+ */
+ CalcPath(modelings, br) {
+ let cus = [];
+ for (let m of modelings) {
+ cus.push(...this.GetModelFeedPath(br, m));
+ }
+ return cus;
+ }
+ GetModelFeedPath(br, m) {
+ const brThickness = br.Thickness;
+ let cus = [];
+ let { shape, thickness, knifeRadius, addLen, addWidth, addDepth } = m;
+ if (!knifeRadius)
+ knifeRadius = 3;
+ if (addDepth)
+ thickness += addDepth;
+ shape = shape.Clone();
+ shape.Z0();
+ this.GrooveAddSize(shape, addLen, addWidth);
+ this.HandleThoughGroove(br, shape, knifeRadius);
+ if (thickness >= brThickness) {
+ //通孔只切一刀
+ let outline = shape.Outline.Curve;
+ let dir = GetCurveToInDir(outline);
+ let paths;
+ if (outline instanceof exports.Circle)
+ outline = ConverCircleToPolyline(outline);
+ paths = outline.GetFeedingToolPath(dir * knifeRadius);
+ for (let path of paths) {
+ if (dir < 0)
+ path.Reverse();
+ if (!path.IsClockWise)
+ alert("程序错误:全深网洞加工数据并不为逆时针!");
+ }
+ cus.push(...paths);
+ }
+ else {
+ let offsetCus = this.HandleShape(shape, knifeRadius);
+ if (offsetCus.length > 1)
+ cus.push(...OptimizeToolPath(offsetCus, shape, knifeRadius));
+ }
+ return cus;
+ }
+ GrooveAddSize(shape, addLen, addWidth) {
+ shape.Outline.Curve.Position = shape.Outline.Curve.Position.setZ(0);
+ //若是矩形,应用槽加长
+ if (addLen > 0 || addWidth > 0) {
+ let curveData = IsRect(shape.Outline.Curve);
+ if (curveData.isRect) {
+ let box = curveData.box;
+ let size = curveData.size;
+ if (size.x > size.y) {
+ box.max.add(new three.Vector3(addLen / 2, addWidth / 2));
+ box.min.add(new three.Vector3(-addLen / 2, -addWidth / 2));
+ }
+ else {
+ box.max.add(new three.Vector3(addWidth / 2, addLen / 2));
+ box.min.add(new three.Vector3(-addWidth / 2, -addLen / 2));
+ }
+ let pl = new exports.Polyline().RectangleFrom2Pt(box.min, box.max).ApplyMatrix(curveData.OCS);
+ shape.Outline = Contour.CreateContour(pl);
+ }
+ }
+ }
+ GetContours(cus, retCus) {
+ let cons = [];
+ for (let c of cus) {
+ if (c.IsClose) {
+ cons.push(Contour.CreateContour(c));
+ }
+ else {
+ let expCus = c.Explode();
+ let regParse = new RegionParse(expCus);
+ //分析封闭包围区域
+ const parseRoute = (routeSet) => {
+ for (let routes of routeSet) {
+ let cs = routes.map(r => r.curve);
+ let c = Contour.CreateContour(cs, false);
+ if (c && c.Area > 1e-3)
+ cons.push(c);
+ }
+ };
+ parseRoute(regParse.RegionsOutline);
+ parseRoute(regParse.RegionsInternal);
+ for (let c of expCus) {
+ if (!regParse.GetCueveUsed(c)) {
+ retCus.push(c);
+ }
+ }
+ }
+ }
+ return cons;
+ }
+ CheckModeling(br) {
+ let errorIndexs = [];
+ let modelings = br.BoardModeling;
+ for (let i = 0; i < modelings.length; i++) {
+ if (userConfig.chaidanOption.useDefaultRad)
+ modelings[i].knifeRadius = userConfig.chaidanOption.radius;
+ let cus = this.GetModelFeedPath(br, modelings[i]);
+ if (cus.length === 0)
+ errorIndexs.push(i);
+ }
+ return errorIndexs;
+ }
+ CheckCustomHole(br) {
+ let { modeling, sideModeling } = GetModelingFromCustomDrill(br);
+ let errHoles = [];
+ for (let m of [...modeling, ...sideModeling]) {
+ let cu = m.shape.Outline.Curve;
+ if (cu instanceof exports.Circle && cu.Radius < userConfig.chaidanOption.modeling2HoleRad + 1e-6)
+ continue;
+ if (userConfig.chaidanOption.useDefaultRad)
+ m.knifeRadius = userConfig.chaidanOption.radius;
+ let cus = this.GetModelFeedPath(br, m);
+ if (cus.length === 0)
+ errHoles.push(m.originEn);
+ }
+ return errHoles;
+ }
+ HandleThoughGroove(br, shape, knifeRadius) {
+ let brCon = br.ContourCurve;
+ let outline = shape.Outline.Curve;
+ if (outline instanceof exports.Circle)
+ return;
+ let cus = outline.Explode();
+ MergeCurvelist(cus);
+ let hasChange = false;
+ for (let i = 0; i < cus.length; i++) {
+ let c = cus[i];
+ if (c instanceof exports.Line) {
+ let mp = c.Midpoint;
+ if (brCon.PtOnCurve(mp)) {
+ hasChange = true;
+ let cs = c.GetOffsetCurves(knifeRadius);
+ cus[i] = cs[0];
+ let fline = cus[FixIndex$1(i - 1, cus.length)];
+ let isAddLine = false;
+ if (fline instanceof exports.Line) {
+ let intPts = fline.IntersectWith2(cs[0], 3);
+ if (intPts.length === 0) {
+ console.error("未知错误情况");
+ return;
+ }
+ if (intPts[0].thisParam >= 0 && intPts[0].argParam <= 1) {
+ fline.EndPoint = intPts[0].pt;
+ cs[0].StartPoint = intPts[0].pt;
+ }
+ else {
+ isAddLine = true;
+ }
+ }
+ else {
+ isAddLine = true;
+ }
+ if (isAddLine) {
+ let newLine = new exports.Line(fline.EndPoint, cs[0].StartPoint);
+ if (i === 0) {
+ cus.push(newLine);
+ }
+ else {
+ cus.splice(i, 0, newLine);
+ i++;
+ }
+ }
+ let backLine = cus[FixIndex$1(i + 1, cus.length)];
+ isAddLine = false;
+ if (backLine instanceof exports.Line) {
+ let intPts = backLine.IntersectWith2(cs[0], 3);
+ if (intPts.length === 0) {
+ return;
+ }
+ if (intPts[0].thisParam <= 1 && intPts[0].argParam >= 0) {
+ backLine.StartPoint = intPts[0].pt;
+ cs[0].EndPoint = intPts[0].pt;
+ }
+ else {
+ isAddLine = true;
+ }
+ }
+ else {
+ isAddLine = true;
+ }
+ if (isAddLine) {
+ let newLine = new exports.Line(cs[0].EndPoint, backLine.StartPoint);
+ if (i + 1 === cus.length) {
+ cus.unshift(newLine);
+ }
+ else {
+ cus.splice(i + 1, 0, newLine);
+ i++;
+ }
+ }
+ }
+ }
+ }
+ if (hasChange) {
+ let con = Contour.CreateContour(exports.Polyline.Combine(cus));
+ if (con)
+ shape.Outline = con;
+ else
+ console.error("错误");
+ }
+ }
+}
+function GetModelingFromCustomDrill(br) {
+ let normal = br.Normal;
+ let outline = GetSealedBoardContour(br, true);
+ let modeling = [];
+ let sideModeling = [];
+ const holes = [];
+ let bbox = br.BoundingBoxInOCS;
+ let holeBoxMap = new WeakMap();
+ for (let [, idss] of br.DrillList) {
+ for (let ids of idss) {
+ for (let id of ids) {
+ if ((id === null || id === void 0 ? void 0 : id.Object) && !id.Object.IsErase && id.Object instanceof ExtrudeHole && id.Object.isHole) {
+ if (!(id.Object.ContourCurve instanceof exports.Circle)) {
+ let en = id.Object;
+ let enBox = en.GetBoundingBoxInMtx(br.OCSInv);
+ holeBoxMap.set(en, enBox);
+ if (enBox.clone().intersect(bbox).isSolid(0.1))
+ holes.push(id.Object);
+ }
+ }
+ else
+ break;
+ }
+ }
+ }
+ for (let en of holes) {
+ let box = holeBoxMap.get(en);
+ let max = box.max;
+ let min = box.min;
+ let dir;
+ let shape = en.Shape;
+ let diff = br.OCSInv.multiply(en.OCS);
+ shape.ApplyMatrix(diff);
+ let thickness;
+ if (isParallelTo(normal, en.Normal)) {
+ if (min.z > br.Thickness - 1e-6)
+ continue;
+ //在板件的世界,0.01的误差应该不能被看出来,所以我们允许0.01的容差(这样应该是没问题的)
+ //也避免了一些二维转三维出现的缝隙排钻不能被拆解的问题
+ if (max.z >= br.Thickness - 1e-2) //较大的容差(0.01)
+ {
+ dir = FaceDirection.Front;
+ shape.Position = shape.Position.setZ(min.z);
+ thickness = br.Thickness - min.z;
+ }
+ else if (min.z < 1e-2) //较大的容差
+ {
+ dir = FaceDirection.Back;
+ thickness = max.z;
+ }
+ else
+ continue;
+ if (thickness > +1e-6 && isTargetCurInOrOnSourceCur(outline, shape.Outline.Curve.Clone().Z0())) {
+ modeling.push({
+ shape,
+ thickness,
+ dir,
+ knifeRadius: en.KnifeRadius,
+ addLen: 0,
+ originEn: en,
+ });
+ }
+ }
+ else {
+ if (min.z <= 0 || max.z >= br.Thickness)
+ continue;
+ let spt = en.Position.applyMatrix4(br.OCSInv).setZ(0);
+ if (outline.PtOnCurve(spt))
+ continue;
+ let line = new exports.Line(spt, en.Position.add(en.Normal.multiplyScalar(en.Height)).applyMatrix4(br.OCSInv).setZ(0));
+ let pt = outline.IntersectWith(line, 0)[0];
+ if (!pt)
+ continue;
+ let index = Math.floor(outline.GetParamAtPoint(pt));
+ let thickness = line.StartPoint.distanceTo(pt);
+ let shape = en.Shape.ApplyMatrix(en.OCS).ApplyMatrix(br.OCSInv);
+ let vec = line.GetFistDeriv(0).normalize().multiplyScalar(thickness);
+ shape.Position = shape.Position.add(vec);
+ let cu = outline.GetCurveAtIndex(index);
+ shape.ApplyMatrix(new three.Matrix4().getInverse(GetSideFaceMtx(cu)));
+ sideModeling.push({
+ shape,
+ thickness,
+ dir: index,
+ knifeRadius: en.KnifeRadius,
+ addLen: 0,
+ originEn: en,
+ });
+ }
+ }
+ return { modeling, sideModeling };
+}
+
+function SimplifyPolyline(polyline) {
+ let curves = polyline.Explode();
+ let oldCount = curves.length;
+ curves = arrayRemoveDuplicateBySort(curves, (c1, c2) => {
+ return c1.Join(c2) !== Status.False;
+ });
+ if (oldCount === curves.length)
+ return;
+ polyline.Erase();
+ if (curves.length === 1)
+ return curves[0];
+ else {
+ let pl = new exports.Polyline;
+ for (let cu of curves)
+ pl.Join(cu);
+ return pl;
+ }
+}
+
exports.CADFiler = CADFiler;
+exports.FeedingToolPath = FeedingToolPath;
exports.IsPtsAllOutOrOnReg = IsPtsAllOutOrOnReg;
+exports.IsRect = IsRect;
+exports.SimplifyPolyline = SimplifyPolyline;
exports.TempPolyline = TempPolyline;
exports.isTargetCurInOrOnSourceCur = isTargetCurInOrOnSourceCur;
//# sourceMappingURL=api.cjs.js.map
diff --git a/api.cjs.js.map b/api.cjs.js.map
index d84c243..3bde718 100644
--- a/api.cjs.js.map
+++ b/api.cjs.js.map
@@ -1 +1 @@
-{"version":3,"file":"api.cjs.js","sources":["../src/DatabaseServices/CADFactory.ts","../src/DatabaseServices/AllObjectData.ts","../src/DatabaseServices/AutoRecord.ts","../src/DatabaseServices/EraseEntityData.ts","../src/DatabaseServices/CADObject.ts","../src/DatabaseServices/ObjectId.ts","../src/ApplicationServices/HostApplicationServices.ts","../src/Common/Dispose.ts","../src/Geometry/CoordinateSystem.ts","../src/Common/StoreageKeys.ts","../src/Common/Utils.ts","../src/Geometry/GeUtils.ts","../src/Common/Matrix4Utils.ts","../src/Common/Status.ts","../src/GraphicsSystem/RenderType.ts","../src/Common/SystemEnum.ts","../src/Editor/UserConfig.ts","../src/Geometry/Box.ts","../src/DatabaseServices/Entity/Entity.ts","../src/DatabaseServices/CADFiler.ts","../src/GLSL/GoochShader.ts","../src/Common/ColorPalette.ts","../src/Common/ArrayExt.ts","../src/Editor/ObjectSnapMode.ts","../src/Geometry/BufferGeometryUtils.ts","../src/DatabaseServices/Shape2.ts","../src/Geometry/Matrix2.ts","../src/Geometry/RotateUV.ts","../src/ApplicationServices/mesh/createBoard.ts","../src/Geometry/CurveMap.ts","../src/Geometry/RegionParse.ts","../src/GraphicsSystem/BoolOperateUtils.ts","../src/DatabaseServices/Entity/Curve.ts","../src/DatabaseServices/Contour.ts","../src/Geometry/Plane.ts","../src/DatabaseServices/Entity/Ellipse.ts","../src/DatabaseServices/Entity/Line.ts","../src/Geometry/SortEntityByBox.ts","../src/GraphicsSystem/OffsetPolyline.ts","../src/DatabaseServices/PointInPolyline.ts","../src/DatabaseServices/Entity/DragPointType.ts","../src/DatabaseServices/Entity/Polyline.ts","../src/GraphicsSystem/IntersectWith.ts","../src/DatabaseServices/Entity/Circle.ts","../src/Geometry/Count.ts","../src/Geometry/Orbit.ts","../src/Common/CurveUtils.ts","../src/DatabaseServices/Entity/Arc.ts"],"sourcesContent":["\r\n/**\r\n * CAD对象工厂,通过注册 和暴露的创建方法,动态创建对象\r\n */\r\nexport class CADFactory\r\n{\r\n private constructor() { }\r\n private objectNameMap = new Map();\r\n private static factory = new CADFactory();\r\n static RegisterObject(C: any)\r\n {\r\n this.factory.objectNameMap.set(C.name, C);\r\n }\r\n static RegisterObjectAlias(C: any, name: string)\r\n {\r\n this.factory.objectNameMap.set(name, C);\r\n }\r\n static CreateObject(name: string): any\r\n {\r\n let C = this.factory.objectNameMap.get(name);\r\n if (C) return new C();\r\n }\r\n}\r\n\r\n//可以通过添加装饰器 在类前面(@Factory),自动注册工厂的序列化\r\nexport function Factory(target: Object)\r\n{\r\n CADFactory.RegisterObject(target);\r\n}\r\n","import { Factory } from './CADFactory';\r\nimport { CADFiler } from './CADFiler';\r\nimport { ISerialize } from './ISerialize';\r\nimport { CADObject } from './CADObject';\r\n\r\n/**\r\n * 保存对象创建或者修改时的所有数据记录\r\n */\r\n@Factory\r\nexport class AllObjectData implements ISerialize\r\n{\r\n file: CADFiler;\r\n constructor(obj?: CADObject)\r\n {\r\n this.file = new CADFiler();\r\n if (obj)\r\n obj.WriteFile(this.file);\r\n }\r\n //#region -------------------------File-------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n //对象从文件中读取数据,初始化自身\r\n ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();\r\n let data = file.Read();\r\n this.file.Data = data;\r\n return this;\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(1);\r\n file.Write(this.file.Data);\r\n return this;\r\n }\r\n}\r\n","\r\n\r\nexport const ISPROXYKEY = \"_isProxy\";\r\n\r\n/**\r\n * 自动对CADObject的属性添加属性记录器,自动调用 `WriteAllObjectRecord`\r\n * 如果属性是数组,那么自动添加`Proxy`.\r\n * 可以使用`ISPROXYKEY`覆盖这个函数的代理行为(使用CADObject.CreateProxyArray快速覆盖)\r\n *\r\n * @param target\r\n * @param property\r\n * @param [descriptor]\r\n */\r\nexport function AutoRecord(\r\n target: { WriteAllObjectRecord: () => void; },\r\n property: string,\r\n descriptor?: PropertyDecorator)\r\n{\r\n let privateKey = '__' + property;\r\n Object.defineProperty(target, property,\r\n {\r\n set: function (value)\r\n {\r\n if (value instanceof Array)\r\n {\r\n if (!this[privateKey])\r\n {\r\n if (value[ISPROXYKEY])\r\n this[privateKey] = value;\r\n else\r\n this[privateKey] = new Proxy(value, {\r\n set: (target, key, value, receiver) =>\r\n {\r\n if (Reflect.get(target, key, receiver) !== value)\r\n this.WriteAllObjectRecord();\r\n return Reflect.set(target, key, value, receiver);\r\n },\r\n get: (target, key, receiver) =>\r\n {\r\n if (key === ISPROXYKEY)\r\n return true;\r\n //实体先被删除后在触发length = xxx\r\n if (key === \"splice\" || key === \"pop\" || key === \"shift\")\r\n this.WriteAllObjectRecord();\r\n return Reflect.get(target, key, receiver);\r\n }\r\n });\r\n }\r\n else\r\n {\r\n let arr = this[privateKey] as Array;\r\n arr.length = 0;\r\n arr.push(...value);\r\n }\r\n }\r\n else\r\n {\r\n let oldv = this[privateKey];\r\n if (oldv !== value)\r\n {\r\n this.WriteAllObjectRecord();\r\n this[privateKey] = value;\r\n }\r\n }\r\n },\r\n get: function ()\r\n {\r\n return this[privateKey];\r\n },\r\n enumerable: true,\r\n configurable: true\r\n }\r\n );\r\n}\r\n","import { Factory } from './CADFactory';\r\nimport { CADFiler } from './CADFiler';\r\nimport { ISerialize } from './ISerialize';\r\n@Factory\r\nexport class EraseEntityData implements ISerialize\r\n{\r\n ReadFile(file: CADFiler): this\r\n {\r\n this.isErase = file.Read();\r\n return this;\r\n }\r\n WriteFile(file: CADFiler): this\r\n {\r\n file.Write(this.isErase);\r\n return this;\r\n }\r\n constructor(public isErase = true)\r\n {\r\n }\r\n}\r\n","import { iaop } from 'xaop';\r\nimport { AllObjectData } from './AllObjectData';\r\nimport { ISPROXYKEY } from './AutoRecord';\r\nimport { CADFactory } from './CADFactory';\r\nimport { CADFiler } from './CADFiler';\r\nimport { CommandHistoryRecord } from './CommandHistoryRecord';\r\nimport { Database } from './Database';\r\nimport { EraseEntityData } from './EraseEntityData';\r\nimport { ISerialize } from './ISerialize';\r\nimport { ObjectId } from './ObjectId';\r\n\r\nexport abstract class CADObject\r\n{\r\n protected _Owner: ObjectId;\r\n /**\r\n * 用于储存临时数据\r\n */\r\n public TempData: any;\r\n\r\n //下面的三个数据由Rect2Board使用\r\n __CacheBox__: any;\r\n __CacheBoard__: any;\r\n __CacheSize__: any;\r\n __CachePolyline__: any;\r\n\r\n set Owner(owner: ObjectId)\r\n {\r\n this._Owner = owner;\r\n }\r\n get Owner()\r\n {\r\n return this._Owner;\r\n }\r\n\r\n Destroy()\r\n {\r\n //在效果图同步反应器中,需要知道被删除的实体的id,所以不删除这个属性\r\n // this.objectId = undefined;\r\n this._db = undefined;\r\n }\r\n\r\n //对象被彻底遗弃\r\n GoodBye(): any\r\n {\r\n this.Destroy();\r\n this.Erase(true);\r\n }\r\n\r\n /**\r\n * 当实体异步更新绘制实体完成后触发这个函数.\r\n * Application通过注入的方式得知这个事件,刷新视图显示.\r\n */\r\n @iaop\r\n AsyncUpdated()\r\n {\r\n }\r\n\r\n //-------------------------DB-------------------------\r\n protected _db: Database;\r\n get Db(): Database\r\n {\r\n return this._db;\r\n }\r\n\r\n //对象在加入数据库时,必须指定一个源数据库,否则无法读取引用id.\r\n SetDefaultDb(db: Database)\r\n {\r\n if (!this._db)\r\n this._db = db;\r\n else\r\n console.warn(\"重复设置默认Database!\");\r\n\r\n return this;\r\n }\r\n\r\n //private 私有的方法,暴露给Db的添加对象,方法使用.\r\n //只用对象加入到db中,我们才初始化ObjectId.\r\n //从db池中分配id给自身使用. 除非你创建对象往db里面加,否则不要调用该方法\r\n SetOwnerDatabase(db: Database)\r\n {\r\n if (!this._db)\r\n {\r\n this._db = db;\r\n this.objectId = db.AllocateId();\r\n this.objectId.Object = this;\r\n }\r\n else\r\n console.warn(\"重复设置源Database!\");\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * WblockClone 的时候,id是db分配的,此刻我们只需要设置它的db\r\n */\r\n SetDatabase(db: Database)\r\n {\r\n this._db = db;\r\n }\r\n\r\n //-------------------------DB End-------------------------\r\n\r\n // -------------------------isErase-------------------------\r\n protected _isErase: boolean = false;\r\n get IsErase(): boolean\r\n {\r\n return this._isErase;\r\n }\r\n Erase(isErase: boolean = true)\r\n {\r\n if (isErase === this._isErase)\r\n return;\r\n let undoData = this.UndoRecord();\r\n if (undoData)\r\n undoData.CreateEraseHistory(this, isErase);\r\n this._isErase = isErase;\r\n }\r\n //-------------------------isErase End-------------------------\r\n\r\n // -------------------------id-------------------------\r\n\r\n //操作这个需要谨慎!\r\n objectId: ObjectId;\r\n\r\n get Id(): ObjectId\r\n {\r\n return this.objectId;\r\n }\r\n\r\n // -------------------------id End-------------------------\r\n\r\n // -------------------------File-------------------------\r\n\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n //对象从文件中读取数据,初始化自身\r\n ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();\r\n //write Id;\r\n let id = file.ReadObjectId();\r\n if (!this.objectId && id)//避免CopyFrom时错误的修改自身Id\r\n {\r\n this.objectId = id;\r\n id.Object = this;\r\n }\r\n this._isErase = file.Read();\r\n if (ver > 1)\r\n this.Owner = file.ReadObjectId();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(2);\r\n file.WriteObjectId(this.objectId);\r\n file.Write(this._isErase);\r\n file.WriteObjectId(this.Owner);\r\n }\r\n //局部撤销\r\n ApplyPartialUndo(undoData: ISerialize)\r\n {\r\n if (undoData instanceof AllObjectData)\r\n {\r\n undoData.file.database = this._db;\r\n undoData.file.Reset();\r\n this.ReadFile(undoData.file);\r\n }\r\n else if (undoData instanceof EraseEntityData)\r\n {\r\n this.Erase(undoData.isErase);\r\n }\r\n }\r\n\r\n //撤销所保存的位置\r\n UndoRecord(): CommandHistoryRecord\r\n {\r\n if (this._db && this.objectId)\r\n return this._db.hm.UndoData;\r\n }\r\n //写入所有的对象数据 以便还原对象\r\n WriteAllObjectRecord(): boolean\r\n {\r\n let undoData = this.UndoRecord();\r\n if (undoData)\r\n {\r\n undoData.WriteObjectSnapshoot(this);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n //复制出一个实体,如果存在关联,则指向原关联实体\r\n Clone(): this\r\n {\r\n let newObject = CADFactory.CreateObject(this.constructor.name) as this;\r\n\r\n //备份\r\n let bakId = this.objectId;\r\n this.objectId = undefined;\r\n\r\n let file = new CADFiler();\r\n file.database = this._db;\r\n this.WriteFile(file);\r\n file.Reset();\r\n newObject.ReadFile(file);\r\n\r\n newObject.objectId = undefined;\r\n newObject._db = undefined;\r\n\r\n this.objectId = bakId;\r\n return newObject;\r\n }\r\n\r\n DeepClone(\r\n ownerObject: CADObject,\r\n cloneObejct: CADObject,\r\n idMaping: Map = undefined,\r\n isPrimary = true\r\n ): this\r\n {\r\n return this;\r\n }\r\n\r\n //从一个实体拷贝数据,实体类型必须相同.\r\n CopyFrom(obj: CADObject)\r\n {\r\n let idBak = this.objectId;\r\n let ownerBak = this._Owner;\r\n this.WriteAllObjectRecord();\r\n let f = new CADFiler();\r\n obj.WriteFile(f);\r\n this.ReadFile(f);\r\n this.objectId = idBak;\r\n this._Owner = ownerBak;\r\n }\r\n\r\n //-------------------------File End-------------------------\r\n\r\n //Utils\r\n /**\r\n * 配合 `@AutoRecord` 使用\r\n * 使用这个方法来覆盖AutoRecord的监听行为.\r\n * 这个行为只能用来监听实体添加和实体修改.\r\n * 实体删除行为暂时无法监听\r\n * @param setCallback 设置新的实体到数组时的回调函数\r\n */\r\n protected CreateProxyArray(setCallback: (v: any) => void)\r\n {\r\n return new Proxy([], {\r\n set: (target, key, value, receiver) =>\r\n {\r\n if (Reflect.get(target, key, receiver) !== value)\r\n {\r\n this.WriteAllObjectRecord();\r\n setCallback(value);\r\n }\r\n return Reflect.set(target, key, value, receiver);\r\n },\r\n get: (target, key, receiver) =>\r\n {\r\n if (key === ISPROXYKEY)\r\n return true;\r\n //实体先被删除后在触发length = xxx\r\n if (key === \"splice\" || key === \"pop\" || key === \"shift\")\r\n {\r\n this.WriteAllObjectRecord();\r\n setCallback(undefined);\r\n }\r\n return Reflect.get(target, key, receiver);\r\n }\r\n });\r\n }\r\n}\r\n","import { CADObject } from './CADObject';\r\n\r\nexport enum RelevancyType\r\n{\r\n General = 0,\r\n Soft = 1,\r\n Hard = 2,\r\n}\r\n\r\n/*\r\nCADObject对象拥有Id属性,用来记录引用关系.\r\n通过id可以得到对应的关联实体,或者记录实体的关联关系.\r\n\r\nObjectId必须使用 Database分配(db里面会存id的列表,以便同时更新id指向实体)\r\n\r\n*/\r\nexport class ObjectId\r\n{\r\n _RelevancyType = RelevancyType.General;\r\n constructor(private index = 0, private obj?: CADObject)\r\n {\r\n }\r\n\r\n get IsErase(): boolean\r\n {\r\n return !this.obj || this.obj.IsErase;\r\n }\r\n set Object(obj: CADObject)\r\n {\r\n this.obj = obj;\r\n }\r\n get Object(): CADObject\r\n {\r\n return this.obj;\r\n }\r\n get Index(): number\r\n {\r\n return this.index;\r\n }\r\n set Index(index: number)\r\n {\r\n this.index = index;\r\n }\r\n}\r\n","import { ApplicationService } from './Application';\r\nimport { MeshBasicMaterial, MeshStandardMaterial } from 'three';\r\n\r\ninterface IHostApplicationServices\r\n{\r\n Application?: ApplicationService;\r\n DefaultMeshMaterial?: MeshBasicMaterial | MeshStandardMaterial;\r\n UseShadow?: boolean;\r\n ShowHistoryLog?: boolean;\r\n}\r\n\r\nexport let HostApplicationServices: IHostApplicationServices = { ShowHistoryLog: true };\r\n","import { Object3D } from \"three\";\r\n\r\n/**\r\n * 销毁Object对象的Geometry,并不会销毁材质.\r\n */\r\nexport function DisposeThreeObj(obj: Object3D)\r\n{\r\n for (let o of obj.children)\r\n {\r\n let oany = o as any;\r\n //文字的geometry缓存保留下来\r\n if (oany.geometry && oany.geometry.name !== \"Text\")\r\n oany.geometry.dispose();\r\n DisposeThreeObj(o);\r\n o.parent = null;\r\n o.dispatchEvent({ type: \"removed\" });\r\n }\r\n obj.children.length = 0;\r\n return obj;\r\n}\r\n\r\nexport function Object3DRemoveAll(obj: Object3D)\r\n{\r\n for (let o of obj.children)\r\n {\r\n o.parent = null;\r\n o.dispatchEvent({ type: \"removed\" });\r\n }\r\n obj.children.length = 0;\r\n return obj;\r\n}\r\n","import { Matrix4, Vector3 } from 'three';\r\n\r\n/**\r\n * 坐标系运算.\r\n */\r\nexport class CoordinateSystem\r\n{\r\n Postion: Vector3;\r\n XAxis: Vector3;\r\n YAxis: Vector3;\r\n ZAxis: Vector3;\r\n\r\n constructor(postion?: Vector3, xAxis?: Vector3, yAxis?: Vector3, zAxis?: Vector3)\r\n {\r\n this.Postion = postion || new Vector3(0, 0, 0);\r\n this.XAxis = xAxis || new Vector3(1, 0, 0);\r\n this.YAxis = yAxis || new Vector3(0, 1, 0);\r\n this.ZAxis = zAxis || new Vector3(0, 0, 1);\r\n }\r\n\r\n applyMatrix4(mat4: Matrix4)\r\n {\r\n this.Postion.applyMatrix4(mat4);\r\n let roMat = mat4.clone().setPosition(new Vector3());\r\n this.XAxis.applyMatrix4(roMat);\r\n this.YAxis.applyMatrix4(roMat);\r\n this.ZAxis.applyMatrix4(roMat);\r\n return this;\r\n }\r\n\r\n getMatrix4(): Matrix4\r\n {\r\n let m = new Matrix4();\r\n m.makeBasis(this.XAxis, this.YAxis, this.ZAxis);\r\n m.setPosition(this.Postion);\r\n return m;\r\n }\r\n CopyForm(mat4: Matrix4)\r\n {\r\n this.Postion.setFromMatrixPosition(mat4);\r\n mat4.extractBasis(this.XAxis, this.YAxis, this.ZAxis);\r\n return this;\r\n }\r\n\r\n extractBasis(xAxisA: Vector3, yAxisA: Vector3, zAxisA: Vector3)\r\n {\r\n xAxisA.copy(this.XAxis);\r\n yAxisA.copy(this.YAxis);\r\n zAxisA.copy(this.ZAxis);\r\n }\r\n copy(cs: CoordinateSystem): CoordinateSystem\r\n {\r\n this.Postion.copy(cs.Postion);\r\n this.XAxis.copy(cs.XAxis);\r\n this.YAxis.copy(cs.YAxis);\r\n this.ZAxis.copy(cs.ZAxis);\r\n return this;\r\n }\r\n clone()\r\n {\r\n let r = new CoordinateSystem();\r\n r.Postion = this.Postion.clone();\r\n r.XAxis = this.XAxis.clone();\r\n r.YAxis = this.YAxis.clone();\r\n r.ZAxis = this.ZAxis.clone();\r\n return r;\r\n }\r\n}\r\n","export enum StoreageKeys\r\n{\r\n IsLogin = \"isLogin\",\r\n PlatSession = \"platSession\",\r\n PlatToken = \"platToken\",\r\n UserName = \"userName\",\r\n UserPhone = \"userPhone\",\r\n RenderType = \"renderType\",\r\n ExactDrill = \"openExactDrill\",\r\n ConfigName = \"configName_\",\r\n IsNewErp = \"isNewErp\",\r\n RoomName = \"roomName\",\r\n LastOpenFileId = \"lastfid\",\r\n Uid = \"uid\",\r\n Goods = \"Goods_\",\r\n DrillTemp = \"drilltemp_\",\r\n DrillReactor = \"drillRreactor\",\r\n kjlConfig = \"kjl\",\r\n}\r\n","import { Object3D } from \"three\";\r\nimport { Entity } from \"../DatabaseServices/Entity/Entity\";\r\nimport { equaln } from \"../Geometry/GeUtils\";\r\nimport { safeEval } from \"./eval\";\r\nimport { StoreageKeys } from \"./StoreageKeys\";\r\nimport { ObjectId } from \"../DatabaseServices/ObjectId\";\r\n\r\n//仅数字构成的3位字符串(不以0开头)\r\nexport const digitStrReg = /^[^0\\D]\\d{0,2}$/;\r\nexport const commandReg = /[^A-Za-z0-9]/g;\r\n//仅可输入英文\r\nexport const onlyEnExpReg = /[^A-Za-z]/g;\r\n/**替换收口条柜名后缀 */\r\nexport const ClosingStripReg = /[左|右|上]{1}收口$/;\r\nexport const FileFormatReg = /^\\[(\\d+,){5}[(true)|(false)].+\\]$/;\r\n\r\n/**扣除封边是否相连和连接共用精度 */\r\nexport const LINK_FUZZ = 1e-3;\r\n\r\nexport function IsNumber(keyCode: number)\r\n{\r\n return (keyCode >= 48 && keyCode <= 57) || (keyCode >= 96 && keyCode <= 105);\r\n}\r\nexport function IsChar(keyCode: number)\r\n{\r\n return keyCode >= 65 && keyCode <= 90;\r\n}\r\nexport function isLetter(s: string)\r\n{\r\n let code = s.charCodeAt(0);\r\n return (code >= 97 && code <= 122) || (code >= 65 && code <= 90);\r\n}\r\nexport function isNum(s: string)\r\n{\r\n return !isNaN(safeEval(s));\r\n}\r\n\r\nexport function clamp(value: number, min: number, max: number)\r\n{\r\n return Math.max(min, Math.min(max, value));\r\n}\r\n\r\nexport function FixIndex(index: number, arr: Array | number)\r\n{\r\n let count = (arr instanceof Array) ? arr.length : arr;\r\n if (index < 0)\r\n return count + index;\r\n else if (index >= count)\r\n return index - count;\r\n else\r\n return index;\r\n}\r\n//格式化日期\r\nexport function formateDate(date: Date, fmt: string)\r\n{\r\n let o = {\r\n \"M+\": date.getMonth() + 1, //月份\r\n \"d+\": date.getDate(), //日\r\n \"h+\": date.getHours(), //小时\r\n \"m+\": date.getMinutes(), //分\r\n \"s+\": date.getSeconds(), //秒\r\n \"q+\": Math.floor((date.getMonth() + 3) / 3), //季度\r\n \"S\": date.getMilliseconds() //毫秒\r\n };\r\n //如:yyyy\r\n if (/(y+)/.test(fmt))\r\n {\r\n fmt = fmt.replace(RegExp.$1, (date.getFullYear().toString()).substr(4 - RegExp.$1.length));\r\n }\r\n //yyyy-MM-dd hh:mm:ss\r\n for (let k in o)\r\n {\r\n if (new RegExp(\"(\" + k + \")\").test(fmt))\r\n {\r\n fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\r\n }\r\n }\r\n return fmt;\r\n}\r\n\r\n//判断v在v1和v2之间.(v1>v2 or v2>v1)\r\nexport function isBetweenNums(v1: number, v2: number, v: number, fuzz = 1e-8)\r\n{\r\n if (v1 > v2) [v1, v2] = [v2, v1];\r\n return equaln(v, clamp(v, v1, v2), fuzz);\r\n}\r\n\r\n//深复制对象数组\r\nexport function sliceDeep(arr: object[], start?: number, end?: number): object[]\r\n{\r\n return arr.slice(start, end).map((obj) => Object.assign({}, obj));\r\n}\r\n\r\nfunction fallbackCopyTextToClipboard(text)\r\n{\r\n let textArea = document.createElement(\"textarea\");\r\n textArea.value = text;\r\n document.body.appendChild(textArea);\r\n textArea.focus();\r\n textArea.select();\r\n\r\n try\r\n {\r\n let successful = document.execCommand('copy');\r\n } catch (err)\r\n {\r\n }\r\n document.body.removeChild(textArea);\r\n}\r\nexport async function copyTextToClipboard(text: string)\r\n{\r\n if (!navigator[\"clipboard\"])\r\n {\r\n fallbackCopyTextToClipboard(text);\r\n return;\r\n }\r\n return await navigator[\"clipboard\"].writeText(text);\r\n}\r\n\r\n//ref: https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript\r\n\r\n/**\r\n * 读取剪切板的字符串\r\n */\r\nexport async function readClipboardText()\r\n{\r\n if (navigator[\"clipboard\"])\r\n return await navigator[\"clipboard\"].readText();\r\n return \"\";\r\n}\r\n\r\n//使用定点表示法来格式化一个数,小数点后面不尾随0. 如 FixedNotZero(1.1 , 3) => 1.1\r\nexport function FixedNotZero(v: number | string, fractionDigits: number = 0)\r\n{\r\n if (typeof v === \"string\")\r\n v = parseFloat(v);\r\n if (isNaN(v)) return \"\";\r\n if (equaln(v, 0)) return \"0\";\r\n let str = v.toFixed(fractionDigits);\r\n let commonIndex = str.indexOf(\".\");\r\n if (commonIndex !== -1)\r\n {\r\n let zeroCount = 0;\r\n let strCount = str.length;\r\n for (let l = strCount; l--;)\r\n {\r\n if (str[l] === \"0\")\r\n zeroCount++;\r\n else\r\n break;\r\n }\r\n if (zeroCount > 0)\r\n {\r\n if (zeroCount === (strCount - commonIndex - 1))\r\n zeroCount++;\r\n return str.slice(0, strCount - zeroCount);\r\n }\r\n }\r\n return str;\r\n}\r\n\r\n/**\r\n * To fixed\r\n * @param v\r\n * @param [fractionDigits]\r\n * @returns\r\n */\r\nexport function ToFixed(v: number, fractionDigits: number = 5)\r\n{\r\n if (equaln(v, 0, Math.pow(0.1, fractionDigits))) return \"0\";\r\n return v.toFixed(fractionDigits);\r\n}\r\n\r\nexport function GetEntity(obj: Object3D): Entity | undefined\r\n{\r\n while (obj)\r\n {\r\n if (obj.userData.Entity)\r\n return obj.userData.Entity;\r\n\r\n obj = obj.parent;\r\n }\r\n}\r\n\r\nexport function IsEntity(obj: Object3D): boolean\r\n{\r\n return GetEntity(obj) instanceof Entity;\r\n}\r\n\r\nexport function IsNoErase(id: ObjectId): boolean\r\n{\r\n return id && !id.IsErase;\r\n}\r\n\r\n/**\r\n * 原图地址转换为对应缩略图地址\r\n */\r\nexport function getThumbsUrl(url: string)\r\n{\r\n return url ? url.replace(/\\/\\w*\\.\\w*$/, mat => \"/thumbs\" + mat.replace(\".\", \"_100.\")) : \"\";\r\n}\r\n\r\n/**\r\n * 快速判断a是不是被修改了\r\n */\r\nexport function equalObject(a: Object, b: Object)\r\n{\r\n for (let key in a)\r\n {\r\n if (a[key] !== b[key])\r\n return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport function cloneObject(a: T): T\r\n{\r\n return Object.assign({}, a);\r\n}\r\n\r\nexport function Uint8ArrayToBase64(bytes: Uint8Array)\r\n{\r\n let binary = \"\";\r\n let len = bytes.byteLength;\r\n for (let i = 0; i < len; i++)\r\n binary += String.fromCharCode(bytes[i]);\r\n return window.btoa(binary);\r\n}\r\n\r\n/**转换服务端获取的文件大小 */\r\nexport function getFileSize(size: number)\r\n{\r\n let units = [\"B\", \"KB\", \"MB\", \"GB\"];\r\n for (let u of units)\r\n {\r\n if (size > 1 && size < 1024)\r\n return FixedNotZero(size, 2) + u;\r\n else\r\n size /= 1024;\r\n }\r\n}\r\n\r\nexport function GetIndexDBID(id: string)\r\n{\r\n return localStorage.getItem(StoreageKeys.Uid) + \":\" + id;\r\n}\r\n\r\nexport function FixDigits(v: number, fractionDigits = 2)\r\n{\r\n return parseFloat(v.toFixed(fractionDigits));\r\n}\r\n","import { Box3, BufferGeometry, Geometry, Line, Matrix4, Mesh, Object3D, Vector, Vector2, Vector3 } from 'three';\r\nimport { ToFixed } from '../Common/Utils';\r\n\r\nexport const IdentityMtx4 = new Matrix4();\r\nexport const ZeroVec = new Vector3();\r\nexport const XAxis = new Vector3(1, 0, 0);\r\nexport const XAxisN = new Vector3(-1, 0, 0);\r\nexport const YAxis = new Vector3(0, 1, 0);\r\nexport const YAxisN = new Vector3(0, -1, 0);\r\nexport const ZAxis = new Vector3(0, 0, 1);\r\n\r\nexport function AsVector2(p: { x: number, y: number; })\r\n{\r\n return new Vector2(p.x, p.y);\r\n}\r\nexport function AsVector3(p: { x: number, y: number, z?: number; })\r\n{\r\n return new Vector3(p.x, p.y, p.z);\r\n}\r\n\r\n/**\r\n * 判断一维线段a和b是否存在交集\r\n */\r\nexport function isIntersect(amin: number, amax: number, bmin: number, bmax: number, eps = 0)\r\n{\r\n return Math.max(amin, bmin) < Math.min(amax, bmax) + eps;\r\n}\r\n\r\nexport function isIntersect2(a1: number, a2: number, b1: number, b2: number, eps = 0)\r\n{\r\n if (a1 > a2) [a1, a2] = [a2, a1];\r\n if (b1 > b2) [b1, b2] = [b2, b1];\r\n return Math.max(a1, b1) < Math.min(a2, b2) + eps;\r\n}\r\n\r\n/**\r\n * 旋转一个点,旋转中心在原点\r\n * @param {Vector3} p 点\r\n * @param {number} a 角度.\r\n * @returns {Vector3} 返回pt不拷贝.\r\n */\r\nexport function rotatePoint(p: Vector3, a: number): Vector3\r\n{\r\n let s = Math.sin(a);\r\n let c = Math.cos(a);\r\n\r\n let x = p.x * c - p.y * s;\r\n let y = p.x * s + p.y * c;\r\n\r\n p.x = x;\r\n p.y = y;\r\n return p;\r\n}\r\n\r\nexport function equaln(v1: number, v2: number, fuzz = 1e-5)\r\n{\r\n return Math.abs(v1 - v2) <= fuzz;\r\n}\r\n\r\nexport function equalnn(dis = 5)\r\n{\r\n let fuzz = 0.1 ** dis;\r\n return function (v1: number, v2: number)\r\n {\r\n return Math.abs(v1 - v2) <= fuzz;\r\n };\r\n}\r\n\r\ninterface P2\r\n{\r\n x: number; y: number;\r\n}\r\n\r\nexport function equalv3(v1: Vector3, v2: Vector3, fuzz = 1e-8)\r\n{\r\n return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz) && equaln(v1.z, v2.z, fuzz);\r\n}\r\nexport function equalv2(v1: P2, v2: P2, fuzz = 1e-8)\r\n{\r\n return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz);\r\n}\r\n\r\n/**\r\n * 按照极坐标的方式移动一个点\r\n *\r\n * @export\r\n * @template\r\n * @param {T} v 向量(2d,3d)\r\n * @param {number} an 角度\r\n * @param {number} dis 距离\r\n * @returns {T}\r\n */\r\nexport function polar(v: T, an: number, dis: number): T\r\n{\r\n v.x += Math.cos(an) * dis;\r\n v.y += Math.sin(an) * dis;\r\n return v;\r\n}\r\n\r\nexport function angle(v: Vector3 | Vector2)\r\n{\r\n let angle = Math.atan2(v.y, v.x);\r\n if (equaln(angle, 0, 1e-8)) return 0;\r\n if (angle < 0) angle += Math.PI * 2;\r\n return angle;\r\n}\r\n\r\n/**\r\n * 求两个向量的夹角,顺时针为负,逆时针为正\r\n *\r\n * @param {Vector3} v1\r\n * @param {Vector3} v2\r\n * @param {Vector3} [ref] 参考向量,如果为世界坐标系则为0,0,1\r\n * @returns\r\n */\r\nexport function angleTo(v1: Vector3, v2: Vector3, ref: Vector3 = new Vector3(0, 0, 1))\r\n{\r\n if (!ref.equals(new Vector3(0, 0, 1)))\r\n {\r\n ref = ref.clone();\r\n v1 = v1.clone();\r\n v2 = v2.clone();\r\n //任意轴坐标系. 使用相机的构造矩阵.\r\n ref.multiplyScalar(-1);\r\n let up = getLoocAtUpVec(ref);\r\n let refOcs = new Matrix4();\r\n refOcs.lookAt(ZeroVec, ref, up);\r\n let refOcsInv = new Matrix4().getInverse(refOcs);\r\n v1.applyMatrix4(refOcsInv);\r\n v2.applyMatrix4(refOcsInv);\r\n v1.z = 0;\r\n v2.z = 0;\r\n }\r\n if (v1.equals(ZeroVec) || v2.equals(ZeroVec))\r\n return 0;\r\n let cv = new Vector3().crossVectors(v1, v2).normalize();\r\n return cv.z === 0 ? v1.angleTo(v2) : v1.angleTo(v2) * cv.z;\r\n}\r\n\r\nexport function getLoocAtUpVec(dir: Vector3): Vector3\r\n{\r\n if (dir.equals(ZeroVec))\r\n {\r\n throw (\"zero vector\");\r\n }\r\n let norm = dir.clone().normalize();\r\n if (norm.equals(ZAxis))\r\n {\r\n return new Vector3(0, 1, 0);\r\n }\r\n else if (norm.equals(ZAxis.clone().negate()))\r\n {\r\n return new Vector3(0, -1, 0);\r\n }\r\n else\r\n {\r\n let xv: Vector3 = new Vector3();\r\n xv.crossVectors(ZAxis, norm);\r\n\r\n let up = new Vector3();\r\n up.crossVectors(norm, xv);\r\n return up;\r\n }\r\n}\r\n\r\nexport function createLookAtMat4(dir: Vector3): Matrix4\r\n{\r\n let up = getLoocAtUpVec(dir);\r\n let mat = new Matrix4();\r\n mat.lookAt(ZeroVec, dir, up);\r\n return mat;\r\n}\r\n\r\n/**\r\n * 判断2个向量是不是平行,尽量传入单位向量,才能保证计算精度\r\n */\r\nexport function isParallelTo(v1: Vector3, v2: Vector3, fuzz = 1e-8): boolean\r\n{\r\n return v1.clone().cross(v2).lengthSq() < fuzz;\r\n}\r\n\r\n/**\r\n * 垂直向量\r\n */\r\nexport function isPerpendicularityTo(v1: Vector3, v2: Vector3, fuzz = 1e-8)\r\n{\r\n return equaln(v1.dot(v2), 0, fuzz);\r\n}\r\n\r\nexport function ptToString(v: Vector3, fractionDigits: number = 3): string\r\n{\r\n return v.toArray().map(o => ToFixed(o, fractionDigits)).join(\",\");\r\n}\r\n\r\nexport function midPoint(v1: Vector3, v2: Vector3): Vector3\r\n{\r\n return v1.clone().add(v2).multiplyScalar(0.5);\r\n}\r\nexport function midPoint2(v1: Vector2, v2: Vector2): Vector2\r\n{\r\n return v1.clone().add(v2).multiplyScalar(0.5);\r\n}\r\n\r\n/**\r\n * 获得Three对象的包围盒.\r\n * @param obj\r\n * @param [updateMatrix] 是否应该更新对象矩阵\r\n * @returns box\r\n */\r\nexport function GetBox(obj: Object3D, updateMatrix?: boolean): Box3\r\n{\r\n let box = new Box3();\r\n if (updateMatrix) obj.updateMatrixWorld(false);\r\n if (!obj.visible) return box;\r\n\r\n obj.traverseVisible(o =>\r\n {\r\n if (!o.visible) return;\r\n //@ts-ignore\r\n let geo = o.geometry as BufferGeometry;\r\n if (geo)\r\n {\r\n if (!geo.boundingBox)\r\n geo.computeBoundingBox();\r\n let geoBox = geo.boundingBox.clone().applyMatrix4(o.matrixWorld);\r\n if (geoBox.max.z > 1e5)\r\n console.log();\r\n box.union(geoBox);\r\n }\r\n });\r\n return box;\r\n}\r\n\r\nexport function GetBoxArr(arr: Array): Box3\r\n{\r\n let box = new Box3();\r\n for (let o of arr)\r\n {\r\n let b = GetBox(o);\r\n if (!b.isEmpty())\r\n box.union(b);\r\n }\r\n return box;\r\n}\r\n\r\nexport function MoveMatrix(v: Vector3): Matrix4\r\n{\r\n return new Matrix4().setPosition(v);\r\n}\r\n\r\n//获得输入点在2线组成的4个区间的位置\r\nexport function getPtPostion(sp: Vector3, ep: Vector3, c: Vector3, inPt: Vector3)\r\n{\r\n let l1 = sp.clone().sub(c);\r\n let l2 = ep.clone().sub(c);\r\n let l3 = l1.clone().negate();\r\n let l4 = l2.clone().negate();\r\n let inputLine = inPt.clone().sub(c);\r\n let ang1 = angleTo(l1, l2);\r\n let ang2 = Math.PI;\r\n let ang3 = ang2 + Math.abs(ang1);\r\n let inputAng = angleTo(l1, inputLine);\r\n if (ang1 * inputAng < 0)\r\n inputAng = (Math.PI * 2 - Math.abs(inputAng));\r\n ang1 = Math.abs(ang1);\r\n inputAng = Math.abs(inputAng);\r\n if (inputAng <= ang1)\r\n return { sp, ep };\r\n else if (inputAng > ang1 && inputAng <= ang2)\r\n return { sp: c.clone().add(l3), ep };\r\n else if (inputAng > ang2 && inputAng <= ang3)\r\n return { sp: c.clone().add(l3), ep: c.clone().add(l4) };\r\n else\r\n return { sp, ep: c.clone().add(l4) };\r\n}\r\nexport function angleAndX(v: Vector3 | Vector2)\r\n{\r\n return v.x ? Math.atan(v.y / v.x) : Math.PI / 2;\r\n}\r\n\r\n/**\r\n * 将角度调整为0-2pi之间\r\n */\r\nexport function clampRad(an: number)\r\n{\r\n an = an % (Math.PI * 2);\r\n if (an < 0) an += Math.PI * 2;\r\n return an;\r\n}\r\n\r\nexport function updateGeometry(l: Line | Mesh, geometry: Geometry | BufferGeometry)\r\n{\r\n let geo = l.geometry as Geometry;\r\n geo.dispose();\r\n l.geometry = geometry;\r\n geometry.computeBoundingSphere();\r\n}\r\n\r\nexport function UpdateBoundingSphere(obj: Object3D)\r\n{\r\n //@ts-ignore\r\n let geo = obj.geometry as Geometry;\r\n if (geo)\r\n geo.computeBoundingSphere();\r\n}\r\n\r\n\r\nexport type compareVectorFn = (v1: Vector, v2: Vector3) => number;\r\n\r\nconst comparePointCache: Map = new Map();\r\n\r\n/**\r\n * 构建返回一个用来排序的函数.根据key创建排序规则.\r\n *\r\n * 当key = \"xyz\" 时,点集按 x从小到大,y从小到大 z从小到大\r\n * key = \"X\" 时,点集按 x从大到小\r\n * 以此类推.\r\n *\r\n * 例子:\r\n * let pts:Vector3[] =...;\r\n * pts.sort(comparePoint(\"x\")); //x从小到大排序\r\n * pts.sort(comparePoint(\"zX\")); //z从小到大 x从大到小\r\n *\r\n * @export\r\n * @param {string} sortKey\r\n * @returns {compareVectorFn}\r\n */\r\nexport function comparePoint(sortKey: string): compareVectorFn\r\n{\r\n if (comparePointCache.has(sortKey))\r\n return comparePointCache.get(sortKey);\r\n\r\n let sortIndex = [];\r\n\r\n const keys = ['x', 'X', 'y', 'Y', 'z', 'Z'];\r\n for (let char of sortKey)\r\n {\r\n let index = keys.indexOf(char);\r\n\r\n let i2 = index / 2;\r\n let ci = Math.floor(i2);\r\n sortIndex.push([ci, i2 > ci ? 1 : -1]);\r\n }\r\n\r\n let compareFunction = (v1: Vector, v2: Vector3): number =>\r\n {\r\n if (!v1) return -1;\r\n if (!v2) return 1;\r\n for (let s of sortIndex)\r\n {\r\n let vv1 = v1.getComponent(s[0]);\r\n let vv2 = v2.getComponent(s[0]);\r\n if (equaln(vv1, vv2)) continue;\r\n if (vv2 > vv1) return s[1];\r\n else return -s[1];\r\n }\r\n return 0;\r\n };\r\n\r\n comparePointCache.set(sortKey, compareFunction);\r\n return compareFunction;\r\n}\r\n\r\n/**\r\n *计算各轴旋转角度\r\n */\r\nexport function GetEulerAngle(x: Vector3, y: Vector3, z: Vector3)\r\n{\r\n let roY = Math.atan2(x.z, Math.sqrt(x.x ** 2 + x.y ** 2)) * -180 / Math.PI;\r\n let roZ = Math.atan2(x.y, x.x);\r\n let vec = YAxis.clone();\r\n let roMat = new Matrix4().makeRotationZ(roZ);\r\n roZ *= 180 / Math.PI;\r\n vec.applyMatrix4(roMat);\r\n let roX = Math.atan2(z.dot(vec), y.dot(vec)) * -180 / Math.PI;\r\n return { roX, roY, roZ };\r\n}\r\n\r\n/**\r\n * 方形框捕捉\r\n * @param sqCenter 正方形点\r\n * @param snapPt 被捕捉的点\r\n * @param size 捕捉框大小\r\n */\r\nexport function SnapPoint(sqCenter: Vector3, snapPt: Vector3, size: number): boolean\r\n{\r\n return Math.abs(sqCenter.x - snapPt.x) < size\r\n && Math.abs(sqCenter.y - snapPt.y) < size;\r\n}\r\n\r\nexport function SelectNearP(pts: Vector3[], refPt: Vector3): Vector3\r\n{\r\n if (pts.length > 1)\r\n {\r\n let dist1 = refPt.distanceToSquared(pts[0]);\r\n let dist2 = refPt.distanceToSquared(pts[1]);\r\n return dist1 <= dist2 ? pts[0] : pts[1];\r\n }\r\n return pts[0];\r\n}\r\n\r\nexport function IsBetweenA2B(n: number, A: number, B: number)\r\n{\r\n return n >= A && n <= B;\r\n}\r\n","import { Matrix4, Vector2, Vector3 } from 'three';\r\nimport { CoordinateSystem } from '../Geometry/CoordinateSystem';\r\nimport { equaln, isParallelTo } from '../Geometry/GeUtils';\r\n\r\n/**\r\n * 设置矩阵的某列的向量\r\n * @param {Matrix4} mat 矩阵\r\n * @param {number} col 列索引,0x 1y 2z 3org\r\n * @param {Vector3} v 向量或点\r\n */\r\nexport function matrixSetVector(mat: Matrix4, col: number, v: Vector3)\r\n{\r\n let index = col * 4;\r\n mat.elements[index] = v.x;\r\n mat.elements[index + 1] = v.y;\r\n mat.elements[index + 2] = v.z;\r\n}\r\n\r\n/**\r\n * 返回矩阵,该坐标系将坐标系与原点的坐标系映射为坐标系,\r\n * 并将坐标系与X轴坐标系,\r\n * Y轴坐标轴以及Z轴坐标系统之间的坐标系统坐标系统的原点坐标系和原点坐标系统坐标轴的坐标系分别设置为XAxis,YAxis和ZAxis\r\n * @returns {Matrix4} 返回新的矩阵\r\n */\r\nexport function matrixAlignCoordSys(matrixFrom: Matrix4, matrixTo: Matrix4): Matrix4\r\n{\r\n return new Matrix4().getInverse(matrixTo).multiply(matrixFrom);\r\n}\r\n\r\n/**\r\n * 判断2个矩形共面\r\n * @param {Matrix4} matrixFrom\r\n * @param {Matrix4} matrixTo\r\n * @returns {boolean} 2个矩阵共面\r\n */\r\nexport function matrixIsCoplane(matrixFrom: Matrix4, matrixTo: Matrix4, fuzz = 1e-5): boolean\r\n{\r\n let nor1 = new Vector3().setFromMatrixColumn(matrixFrom, 2);\r\n let nor2 = new Vector3().setFromMatrixColumn(matrixTo, 2);\r\n\r\n //法线共面\r\n if (!isParallelTo(nor1, nor2))\r\n return false;\r\n\r\n //高共面\r\n let pt = new Vector3().setFromMatrixPosition(matrixTo);\r\n //变换到自身对象坐标系.\r\n pt.applyMatrix4(new Matrix4().getInverse(matrixFrom));\r\n\r\n return equaln(pt.z, 0, fuzz);\r\n}\r\n\r\n//构造缩放矩阵\r\nexport function matrixScale(scale: number, center?: Vector3)\r\n{\r\n let scaleMat = new Matrix4().makeScale(scale, scale, scale);\r\n if (center)\r\n scaleMat.setPosition(center.clone().multiplyScalar(1 - scale));\r\n return scaleMat;\r\n}\r\n\r\n/**\r\n * 设置旋转矩阵,不改变矩阵的基点\r\n */\r\nexport function setRotationOnAxis(mtx: Matrix4, axis: Vector3, ro: number)\r\n{\r\n let pos = new Vector3().setFromMatrixPosition(mtx);\r\n mtx.makeRotationAxis(axis, ro);\r\n mtx.setPosition(pos);\r\n return mtx;\r\n}\r\n\r\n/**\r\n * 修正镜像后矩阵\r\n */\r\nexport function reviseMirrorMatrix(mtx: Matrix4): Matrix4\r\n{\r\n let cs = new CoordinateSystem().applyMatrix4(mtx);\r\n cs.YAxis.negate();\r\n mtx.copy(cs.getMatrix4());\r\n return mtx;\r\n}\r\n\r\nlet cacheVec: Vector3;\r\nexport function Vector2ApplyMatrix4(mtx: Matrix4, vec: Vector2)\r\n{\r\n if (!cacheVec) cacheVec = new Vector3();\r\n\r\n cacheVec.x = vec.x;\r\n cacheVec.y = vec.y;\r\n\r\n cacheVec.applyMatrix4(mtx);\r\n\r\n vec.x = cacheVec.x;\r\n vec.y = cacheVec.y;\r\n}\r\nexport function GetMirrorMat(v: Vector3)\r\n{\r\n let mirrorMat = new Matrix4();\r\n let xAxis = new Vector3(1 - 2 * v.x ** 2, -2 * v.x * v.y, -2 * v.x * v.z);\r\n let yAxis = new Vector3(-2 * v.x * v.y, 1 - 2 * v.y ** 2, -2 * v.y * v.z);\r\n let zAxis = new Vector3(-2 * v.x * v.z, -2 * v.y * v.z, 1 - 2 * v.z ** 2);\r\n mirrorMat.makeBasis(xAxis, yAxis, zAxis);\r\n return mirrorMat;\r\n}\r\n\r\nexport function ApplyMatrix4IgnorePosition(vec: { x: number, y: number, z: number; }, m: Matrix4)\r\n{\r\n let { x, y, z } = vec;\r\n let e = m.elements;\r\n vec.x = e[0] * x + e[4] * y + e[8] * z;\r\n vec.y = e[1] * x + e[5] * y + e[9] * z;\r\n vec.z = e[2] * x + e[6] * y + e[10] * z;\r\n return vec;\r\n}\r\n\r\n/**\r\n * 把变换矩阵展平成2d矩阵,避免出现三维坐标.\r\n */\r\nexport function MatrixPlanarizere(mtx: Matrix4, z0 = true)\r\n{\r\n mtx.elements[2] = 0;\r\n mtx.elements[6] = 0;\r\n mtx.elements[8] = 0;\r\n mtx.elements[9] = 0;\r\n mtx.elements[10] = Math.sign(mtx.elements[10]);\r\n\r\n if (z0)\r\n mtx.elements[14] = 0;\r\n\r\n return mtx;\r\n}\r\n\r\nexport const tempMatrix1 = new Matrix4;\r\n","\r\n\r\n\r\nexport enum Status\r\n{\r\n False = 0,\r\n True = 1,\r\n Canel = -1,\r\n\r\n ConverToCircle = 101,\r\n\r\n DuplicateRecordName = 102,\r\n}\r\n\r\nexport enum UpdateDraw\r\n{\r\n None = 0,\r\n Matrix = 1,\r\n Geometry = 2,\r\n Material = 4,\r\n All = ~(~0 << 6)\r\n}\r\n\r\n/**\r\n * WblockClne时,遇到重复记录的操作方式\r\n */\r\nexport enum DuplicateRecordCloning\r\n{\r\n Ignore = 1,\r\n Replace = 2,\r\n Rename = 3,\r\n}\r\n","/**\r\n * 场景的渲染类型.\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum RenderType\r\n{\r\n /**\r\n * 线框模式\r\n */\r\n Wireframe = 1,\r\n\r\n /**\r\n * 概念\r\n */\r\n Conceptual = 2,\r\n\r\n\r\n /**\r\n * 物理着色PBR\r\n */\r\n Physical = 3,\r\n\r\n Jig = 4,\r\n Print = 5,\r\n /**物理带线框 */\r\n Physical2 = 6,\r\n}\r\n","export enum AAType\r\n{\r\n FXAA = 0,//快速近似抗锯齿(性能更好)\r\n SMAA = 1,//多重采样抗锯齿(质量更好)\r\n}\r\n\r\nexport enum ViewDirType\r\n{\r\n FS = 0,\r\n YAS = 1,\r\n ZS = 2,\r\n YS = 3,\r\n QS = 4,\r\n HS = 5,\r\n XN = 6,\r\n}\r\n","import { RenderType } from \"../GraphicsSystem/RenderType\";\r\nimport { DrillingOption } from \"../UI/Store/drillInterface\";\r\nimport { observable, toJS } from \"mobx\";\r\nimport { StoreageKeys } from \"../Common/StoreageKeys\";\r\nimport { IWineRackOption } from \"../UI/Store/WineRackInterface\";\r\nimport { IBaseOption, IGrooveOption } from \"../UI/Store/BoardInterface\";\r\nimport { IConfigStore } from \"../UI/Store/BoardStore\";\r\nimport { IConfigOption } from \"../UI/Components/Board/UserConfig\";\r\nimport { AAType, ViewDirType } from \"../Common/SystemEnum\";\r\n\r\nexport interface IMaxSizeProps extends IBaseOption\r\n{\r\n height: number;\r\n width: number;\r\n isShow: boolean;\r\n}\r\n\r\nexport interface ISystemConfig extends IBaseOption\r\n{\r\n aaType: AAType;\r\n maxHightightCount: number;\r\n snapSize: number;\r\n}\r\n\r\nexport interface ICursorConfig extends IBaseOption\r\n{\r\n D2: number;\r\n D3: number;\r\n}\r\n\r\nexport class UserConfig implements IConfigStore\r\n{\r\n private readonly _version = 10;\r\n _renderType: RenderType = RenderType.Wireframe;\r\n @observable maxSize: IMaxSizeProps = {\r\n isShow: false,\r\n height: 2440,\r\n width: 1220,\r\n };\r\n @observable private _drillConfigs: Map = new Map();\r\n @observable openDrillingReactor = true;\r\n @observable openAutoCuttingReactor = true;\r\n /**打开将检测排钻是否在板件内*/\r\n @observable openExactDrill = true;\r\n winerackConfig: IWineRackOption;\r\n userConfigName: { [key: string]: string; } = {};\r\n private modeling2HoleRad = 20; //圆造型小于等于该值拆成孔数据\r\n @observable isAdmin = false;\r\n @observable kjlConfig: IGrooveOption = {\r\n grooveAddLength: \"0\",\r\n grooveAddWidth: \"0\",\r\n grooveAddDepth: \"1\",\r\n };\r\n @observable SystemConfig: ISystemConfig = {\r\n maxHightightCount: 15000,\r\n snapSize: 15,\r\n aaType: AAType.FXAA\r\n };\r\n @observable viewDirType: ViewDirType = ViewDirType.XN;\r\n @observable useCtrlRotate = true;\r\n @observable cursorSize: ICursorConfig = {\r\n D2: 1000,\r\n D3: 100,\r\n };\r\n @observable autoSaveConfig = {\r\n enable: true,\r\n time: 1,\r\n };\r\n @observable showLines = false;\r\n @observable keepConfig = false;\r\n @observable autoClearHistory = true;\r\n @observable chaidanOption = {\r\n changXiuBian: 6,\r\n duanXiuBian: 6,\r\n useDefaultRad: false,\r\n radius: 2.5,\r\n modeling2HoleRad: 20, //圆造型小于等于该值拆成孔数据\r\n isCheckInterfere: false,\r\n };\r\n @observable autoLines = false;\r\n dimTextHeight = 60;\r\n constructor()\r\n {\r\n this.Init();\r\n }\r\n Init()\r\n {\r\n let type = localStorage.getItem(StoreageKeys.RenderType);\r\n if (type)\r\n this._renderType = parseFloat(type);\r\n }\r\n set RenderType(t: RenderType)\r\n {\r\n if (t !== this._renderType)\r\n {\r\n this._renderType = t;\r\n this.SetRenderTypeEvent();\r\n\r\n localStorage.setItem(StoreageKeys.RenderType, t.toString());\r\n }\r\n }\r\n\r\n get RenderType() { return this._renderType; }\r\n\r\n SetRenderTypeEvent() { }\r\n get DrillConfigs()\r\n {\r\n return this._drillConfigs || new Map();\r\n }\r\n set DrillConfigs(config: Map)\r\n {\r\n observable(this._drillConfigs).replace(config);\r\n this.SetDrillConfigsEvent();\r\n }\r\n SetDrillConfigsEvent() { }\r\n configName = \"default\";\r\n configsNames: string[] = [];\r\n InitOption()\r\n {\r\n this.openDrillingReactor = true;\r\n this.openAutoCuttingReactor = true;\r\n Object.assign(this.maxSize, {\r\n height: 2440,\r\n width: 1220\r\n });\r\n Object.assign(this.kjlConfig, {\r\n grooveAddLength: \"0\",\r\n grooveAddWidth: \"0\",\r\n grooveAddDepth: \"1\"\r\n });\r\n Object.assign(this.chaidanOption, {\r\n changXiuBian: 6,\r\n duanXiuBian: 6,\r\n useDefaultRad: false,\r\n radius: 2.5,\r\n modeling2HoleRad: 20,\r\n });\r\n this.dimTextHeight = 60;\r\n }\r\n SaveConfig()\r\n {\r\n return {\r\n option: {\r\n version: this._version,\r\n openDrillingReactor: this.openDrillingReactor,\r\n openAutoCuttingReactor: this.openAutoCuttingReactor,\r\n maxSize: toJS(this.maxSize),\r\n kjlConfig: toJS(this.kjlConfig),\r\n systemConfig: toJS(this.SystemConfig),\r\n viewDirType: this.viewDirType,\r\n useCtrlRotate: this.useCtrlRotate,\r\n cursorSize: toJS(this.cursorSize),\r\n autoSaveConfig: toJS(this.autoSaveConfig),\r\n showLines: this.showLines,\r\n keepConfig: this.keepConfig,\r\n autoClearHistory: this.autoClearHistory,\r\n chaidanOption: toJS(this.chaidanOption),\r\n autoLines: this.autoLines,\r\n dimTextHeight: this.dimTextHeight,\r\n }\r\n };\r\n }\r\n UpdateOption(config: IConfigOption)\r\n {\r\n this.openDrillingReactor = config.option.openDrillingReactor;\r\n this.openAutoCuttingReactor = config.option.openAutoCuttingReactor;\r\n Object.assign(this.maxSize, config.option.maxSize);\r\n Object.assign(this.kjlConfig, config.option.kjlConfig);\r\n this.modeling2HoleRad = config.option.modeling2HoleRad;\r\n\r\n if (config.option.version > 1)\r\n {\r\n Object.assign(this.SystemConfig, config.option.systemConfig);\r\n }\r\n if (config.option.version > 2)\r\n {\r\n this.viewDirType = config.option.viewDirType;\r\n this.useCtrlRotate = config.option.useCtrlRotate;\r\n }\r\n\r\n if (config.option.version > 3)\r\n {\r\n Object.assign(this.cursorSize, config.option.cursorSize);\r\n }\r\n if (config.option.version > 4)\r\n {\r\n Object.assign(this.autoSaveConfig, config.option.autoSaveConfig);\r\n }\r\n if (config.option.version > 5)\r\n {\r\n this.showLines = config.option.showLines;\r\n }\r\n if (config.option.version > 6)\r\n {\r\n this.keepConfig = config.option.keepConfig;\r\n }\r\n if (config.option.version > 7)\r\n {\r\n this.autoClearHistory = config.option.autoClearHistory;\r\n }\r\n if (config.option.version > 8)\r\n {\r\n Object.assign(this.chaidanOption, config.option.chaidanOption);\r\n this.autoLines = config.option.autoLines;\r\n }\r\n else\r\n this.chaidanOption.modeling2HoleRad = this.modeling2HoleRad;\r\n\r\n if (config.option.version > 9)\r\n this.dimTextHeight = config.option.dimTextHeight;\r\n }\r\n}\r\n\r\nexport const userConfig = new UserConfig();\r\n","import { Vector3, Box3 } from 'three';\r\n\r\n/**\r\n * 盒子的切割类型\r\n */\r\nexport enum SplitType\r\n{\r\n X = 0,\r\n Y = 1,\r\n Z = 2,\r\n}\r\n\r\n/**\r\n * 扩展Box3,添加切割方法,体积等\r\n */\r\nexport class Box3Ext extends Box3\r\n{\r\n TempData: any;\r\n get Volume()\r\n {\r\n let size = this.getSize(new Vector3());\r\n return size.x * size.y * size.z;\r\n }\r\n\r\n //每个轴的大小必须大于最小的size\r\n isSolid(minSize = 1)\r\n {\r\n return this.getSize(new Vector3()).toArray().every(x => x > minSize);\r\n }\r\n substract(b: Box3Ext, spaceType: SplitType)\r\n {\r\n let interBox = this.clone().intersect(b) as this;\r\n if (interBox.isEmpty() || !interBox.isSolid())\r\n return [this];\r\n\r\n let p1 = interBox.min.clone().setComponent(spaceType, this.min.getComponent(spaceType));\r\n let p2 = interBox.max.clone().setComponent(spaceType, interBox.min.getComponent(spaceType));\r\n\r\n let p3 = interBox.min.clone().setComponent(spaceType, interBox.max.getComponent(spaceType));\r\n let p4 = interBox.max.clone().setComponent(spaceType, this.max.getComponent(spaceType));\r\n\r\n return [\r\n new Box3Ext(p1, p2),\r\n new Box3Ext(p3, p4)\r\n ].filter(b => b.isSolid());\r\n }\r\n clampSpace(b2: Box3Ext, splitType: SplitType)\r\n {\r\n let interBox = this.clone();\r\n interBox.min.max(b2.min);\r\n interBox.max.min(b2.max);\r\n interBox.min.setComponent(splitType, Math.min(this.max.getComponent(splitType), b2.max.getComponent(splitType)));\r\n interBox.max.setComponent(splitType, Math.max(this.min.getComponent(splitType), b2.min.getComponent(splitType)));\r\n return interBox;\r\n }\r\n intersectsBox(box: Box3, fuzz = 1e-8): boolean\r\n {\r\n return IntersectsBox(this, box, fuzz);\r\n }\r\n}\r\n\r\nexport function IntersectsBox(box1: Box3, box2: Box3, fuzz = 1e-6): boolean\r\n{\r\n return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz ||\r\n box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz ||\r\n box2.max.z < box1.min.z - fuzz || box2.min.z > box1.max.z + fuzz ? false : true;\r\n}\r\n\r\n/**盒子二维面是否相交 */\r\nexport function IntersectBox2(box1: Box3, box2: Box3, fuzz = 1e-3)\r\n{\r\n return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz ||\r\n box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz ? false : true;\r\n}\r\n","import { Box3, Material, Matrix3, Matrix4, MeshStandardMaterial, Object3D, Vector3 } from 'three';\r\nimport { iaop } from 'xaop';\r\nimport { HostApplicationServices } from '../../ApplicationServices/HostApplicationServices';\r\nimport { DisposeThreeObj, Object3DRemoveAll } from '../../Common/Dispose';\r\nimport { matrixIsCoplane, MatrixPlanarizere } from '../../Common/Matrix4Utils';\r\nimport { UpdateDraw } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { userConfig } from '../../Editor/UserConfig';\r\nimport { Box3Ext } from '../../Geometry/Box';\r\nimport { equaln, equalv3, UpdateBoundingSphere, IdentityMtx4 } from '../../Geometry/GeUtils';\r\nimport { IntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { AutoRecord } from '../AutoRecord';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { CADObject } from '../CADObject';\r\nimport { ObjectId } from '../ObjectId';\r\nimport { PhysicalMaterialRecord } from '../PhysicalMaterialRecord';\r\n\r\n/**\r\n * Entity 是所有图元的基类,绘制的实体都集成该类.\r\n */\r\n@Factory\r\nexport class Entity extends CADObject\r\n{\r\n\r\n IsEmbedEntity = false;\r\n\r\n /**\r\n * 该实体的只有一个渲染类型,任何渲染类型都一个样\r\n */\r\n protected OnlyRenderType = false;\r\n protected _CacheDrawObject = new Map();\r\n //材质id\r\n protected materialId: ObjectId;\r\n protected _Color: number = 7;\r\n\r\n //自身坐标系\r\n protected _Matrix = new Matrix4();\r\n\r\n //模块空间的标系\r\n protected _SpaceOCS: Matrix4 = new Matrix4();\r\n __CacheRenderType__: RenderType;\r\n get SpaceOCS()\r\n {\r\n return this._SpaceOCS.clone();\r\n }\r\n get SpaceOCSInv()\r\n {\r\n return new Matrix4().getInverse(this._SpaceOCS);\r\n }\r\n set SpaceOCS(m: Matrix4)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._SpaceOCS.copy(m);\r\n }\r\n\r\n protected _Visible = true;\r\n\r\n @AutoRecord GroupId: ObjectId;\r\n @AutoRecord Template: ObjectId;\r\n //加工组\r\n @AutoRecord ProcessingGroupList: ObjectId[] = [];\r\n\r\n /**\r\n * 当AutoUpdate为false时,记录需要更新的标志.\r\n * 以便延迟更新时找到相应的更新标志.\r\n */\r\n NeedUpdateFlag: UpdateDraw = UpdateDraw.None;\r\n AutoUpdate = true;\r\n\r\n set Material(materialId: ObjectId)\r\n {\r\n this.WriteAllObjectRecord();\r\n this.materialId = materialId;\r\n this.Update();\r\n }\r\n\r\n get Material()\r\n {\r\n return this.materialId;\r\n }\r\n\r\n set ColorIndex(color: number)\r\n {\r\n if (color !== this._Color)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Color = color;\r\n this.Update(UpdateDraw.Material);\r\n }\r\n }\r\n get ColorIndex(): number\r\n {\r\n return this._Color;\r\n }\r\n /**\r\n * 炸开实体\r\n */\r\n Explode(): Entity[] { return []; }\r\n\r\n /**\r\n * 返回对象的包围框.\r\n */\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3();\r\n }\r\n\r\n /**\r\n * 返回对象在自身坐标系下的Box\r\n */\r\n get BoundingBoxInOCS(): Box3Ext\r\n {\r\n let mtxBak = this._Matrix;\r\n this._Matrix = IdentityMtx4;\r\n let box = this.BoundingBox;\r\n this._Matrix = mtxBak;\r\n return new Box3Ext().copy(box);\r\n }\r\n\r\n GetBoundingBoxInMtx(mtx: Matrix4): Box3Ext\r\n {\r\n return this.BoundingBoxInOCS.applyMatrix4(this.OCS.premultiply(mtx));\r\n }\r\n\r\n get BoundingBoxInSpaceCS(): Box3Ext\r\n {\r\n return this.GetBoundingBoxInMtx(this.SpaceOCSInv);\r\n }\r\n\r\n get OCS(): Matrix4\r\n {\r\n return this._Matrix.clone();\r\n }\r\n\r\n get OCSNoClone()\r\n {\r\n return this._Matrix;\r\n }\r\n\r\n //直接设置实体的矩阵,谨慎使用该函数,没有更新实体.\r\n set OCS(mat4: Matrix4)\r\n {\r\n this._Matrix.copy(mat4);\r\n }\r\n get Normal(): Vector3\r\n {\r\n return new Vector3().setFromMatrixColumn(this._Matrix, 2);\r\n }\r\n get Position(): Vector3\r\n {\r\n return new Vector3().setFromMatrixPosition(this._Matrix);\r\n }\r\n\r\n set Position(pt: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n let moveX = pt.x - this._Matrix.elements[12];\r\n let moveY = pt.y - this._Matrix.elements[13];\r\n let moveZ = pt.z - this._Matrix.elements[14];\r\n this._Matrix.setPosition(pt);\r\n this._SpaceOCS.elements[12] += moveX;\r\n this._SpaceOCS.elements[13] += moveY;\r\n this._SpaceOCS.elements[14] += moveZ;\r\n this.Update(UpdateDraw.Matrix);\r\n }\r\n\r\n //Z轴归0\r\n Z0()\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Matrix.elements[14] = 0;\r\n this.Update(UpdateDraw.Matrix);\r\n return this;\r\n }\r\n\r\n //坐标系二维化\r\n MatrixPlanarizere()\r\n {\r\n let z = this._Matrix.elements[10];\r\n if (equaln(Math.abs(z), 1, 1e-4))\r\n {\r\n this.WriteAllObjectRecord();\r\n MatrixPlanarizere(this._Matrix, false);\r\n }\r\n return this;\r\n }\r\n\r\n get OCSInv(): Matrix4\r\n {\r\n return new Matrix4().getInverse(this._Matrix);\r\n }\r\n\r\n /**\r\n * 与指定实体是否共面.\r\n */\r\n IsCoplaneTo(e: Entity): boolean\r\n {\r\n return matrixIsCoplane(this._Matrix, e.OCS, 1e-4);\r\n }\r\n\r\n /**\r\n * 测试两个实体的包围盒是否相交.\r\n */\r\n BoundingBoxIntersectWith(en: Entity): boolean\r\n {\r\n let box = this.BoundingBox;\r\n let box2 = en.BoundingBox;\r\n return box && box2 && box.intersectsBox(box2);\r\n }\r\n\r\n //#region Draw\r\n\r\n ClearDraw()\r\n {\r\n if (this._drawObject)\r\n {\r\n DisposeThreeObj(this._drawObject);\r\n this._drawObject = undefined;\r\n }\r\n\r\n for (let [, obj] of this._CacheDrawObject)\r\n DisposeThreeObj(obj);\r\n this._CacheDrawObject.clear();\r\n return this;\r\n }\r\n ClearDrawOfJig()\r\n {\r\n let jig = this._CacheDrawObject.get(RenderType.Jig);\r\n if (jig)\r\n this._CacheDrawObject.delete(RenderType.Jig);\r\n for (let [type, obj] of this._CacheDrawObject)\r\n DisposeThreeObj(obj);\r\n this._CacheDrawObject.clear();\r\n if (jig)\r\n this._CacheDrawObject.set(RenderType.Jig, jig);\r\n }\r\n\r\n _drawObject: Object3D;\r\n\r\n get DrawObject()\r\n {\r\n if (this._drawObject)\r\n return this._drawObject;\r\n\r\n this._drawObject = new Object3D();\r\n if (!this.IsEmbedEntity)\r\n this._drawObject.userData.Entity = this;\r\n if (this.IsVisible)\r\n {\r\n this._CurRenderType = this.__CacheRenderType__ ?? userConfig.RenderType;\r\n let obj = this.GetDrawObjectFromRenderType(this._CurRenderType);\r\n if (obj) this._drawObject.add(obj);\r\n }\r\n else\r\n this._drawObject.visible = false;\r\n return this._drawObject;\r\n }\r\n\r\n get JigObject()\r\n {\r\n let obj = this.GetDrawObjectFromRenderType(RenderType.Jig);\r\n if (obj && !this.IsEmbedEntity)\r\n obj.userData.Entity = this;\r\n return obj;\r\n }\r\n DestroyJigObject()\r\n {\r\n let obj = this._CacheDrawObject.get(RenderType.Jig);\r\n if (obj)\r\n {\r\n this._CacheDrawObject.delete(RenderType.Jig);\r\n DisposeThreeObj(obj);\r\n if (obj.parent)\r\n obj.parent.remove(obj);\r\n }\r\n }\r\n\r\n //当前绘制类型,在.DrawObject 和 UpdateRenderType中初始化和更新\r\n protected _CurRenderType: RenderType;\r\n UpdateRenderType(type: RenderType)\r\n {\r\n if (this._CurRenderType !== type)\r\n {\r\n this._CurRenderType = type;\r\n if ((this.OnlyRenderType && this.DrawObject.children.length > 0) || !this.Visible) return;\r\n Object3DRemoveAll(this.DrawObject);\r\n let obj = this.GetDrawObjectFromRenderType(type);\r\n if (obj) this.DrawObject.add(obj);\r\n }\r\n }\r\n\r\n GetDrawObjectFromRenderType(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n if (this.OnlyRenderType)\r\n {\r\n if (renderType === RenderType.Jig)\r\n return;\r\n renderType = this.__CacheRenderType__ ?? userConfig.RenderType;\r\n }\r\n\r\n if (this._CacheDrawObject.has(renderType))\r\n {\r\n return this._CacheDrawObject.get(renderType);\r\n }\r\n else\r\n {\r\n let drawObj = this.InitDrawObject(renderType);\r\n if (drawObj === undefined) return;\r\n\r\n //矩阵直接使用指针,因为已经关闭自动更新,所以矩阵不会被Object3D修改.\r\n drawObj.matrixAutoUpdate = false;\r\n drawObj.matrix = this._Matrix;\r\n drawObj.updateMatrixWorld(true);\r\n drawObj.traverse(UpdateBoundingSphere);\r\n\r\n if (!this.IsEmbedEntity)\r\n drawObj.userData.Entity = this;\r\n\r\n this._CacheDrawObject.set(renderType, drawObj);\r\n return drawObj;\r\n }\r\n }\r\n\r\n /**\r\n * 初始化绘制的threejs实体,子类型重载该函数初始化绘制实体.\r\n */\r\n protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n return undefined;\r\n }\r\n\r\n //实体绘制更新版本号\r\n __UpdateVersion__ = 0;\r\n\r\n /**\r\n * 当实体数据改变时,绘制的实体必须做出改变.供框架调用\r\n */\r\n @iaop\r\n Update(mode = UpdateDraw.All)\r\n {\r\n this.__UpdateVersion__++;\r\n this.NeedUpdateFlag |= mode;\r\n if (this.AutoUpdate)\r\n this.DeferUpdate();\r\n }\r\n\r\n //三维实体总是一起生成线框实体和网格实体,这个通知更新,然后统一更新就好了\r\n //避免重复更新\r\n UpdateDrawGeometry() { }\r\n\r\n DeferUpdate()\r\n {\r\n let mode = this.NeedUpdateFlag;\r\n if (mode === 0) return;\r\n\r\n if (mode & UpdateDraw.Geometry && this._CacheDrawObject.size > 0)\r\n this.UpdateDrawGeometry();\r\n\r\n this.UpdateVisible();\r\n\r\n let isJigIng = this._CacheDrawObject.has(RenderType.Jig);\r\n for (let [type, obj] of this._CacheDrawObject)\r\n {\r\n if (isJigIng && type !== RenderType.Jig)\r\n continue;\r\n\r\n if (mode & UpdateDraw.Geometry)\r\n {\r\n if (obj.userData.IsClone)\r\n {\r\n let parent = obj.parent;\r\n DisposeThreeObj(obj);\r\n this._CacheDrawObject.delete(type);\r\n let newObj = this.GetDrawObjectFromRenderType(type);\r\n if (parent)\r\n {\r\n parent.remove(obj);\r\n parent.add(newObj);\r\n }\r\n obj = newObj;\r\n }\r\n else\r\n this.UpdateDrawObject(type, obj);\r\n }\r\n\r\n if (mode & UpdateDraw.Material)\r\n this.UpdateDrawObjectMaterial(type, obj);\r\n\r\n if (mode & UpdateDraw.Matrix || mode & UpdateDraw.Geometry)\r\n {\r\n obj.updateMatrixWorld(true);\r\n if (this.Id)//如果这个是Jig实体,那么我们更新这个盒子球似乎也没有意义\r\n obj.traverse(UpdateBoundingSphere);\r\n }\r\n\r\n }\r\n this.NeedUpdateFlag = UpdateDraw.None;\r\n }\r\n\r\n /**\r\n * 当实体需要更新时,需要重载该方法,实现实体更新\r\n */\r\n UpdateDrawObject(type: RenderType, en: Object3D)\r\n {\r\n\r\n }\r\n\r\n /**\r\n * 当实体需要被更新时,更新实体材质\r\n */\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material?: Material)\r\n {\r\n\r\n }\r\n\r\n protected get MeshMaterial()\r\n {\r\n if (this.materialId && this.materialId.Object)\r\n return (this.materialId.Object).Material as MeshStandardMaterial;\r\n return HostApplicationServices.DefaultMeshMaterial;\r\n }\r\n\r\n /**\r\n * 更新实体Jig状态时的材质\r\n */\r\n UpdateJigMaterial(color = 8)\r\n {\r\n }\r\n RestoreJigMaterial()\r\n {\r\n for (let [type, en] of this._CacheDrawObject)\r\n this.UpdateDrawObjectMaterial(type, en);\r\n }\r\n get Visible()\r\n {\r\n return this._Visible;\r\n }\r\n set Visible(v: boolean)\r\n {\r\n if (v !== this._Visible)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Visible = v;\r\n this.UpdateVisible();\r\n }\r\n }\r\n\r\n private get IsVisible()\r\n {\r\n return !this._isErase && this._Visible;\r\n }\r\n\r\n UpdateVisible()\r\n {\r\n if (this._drawObject)\r\n {\r\n this._drawObject.visible = this.IsVisible;\r\n if (this.IsVisible)\r\n this.UpdateRenderType(this.__CacheRenderType__ ?? userConfig.RenderType);\r\n }\r\n }\r\n\r\n //#endregion\r\n\r\n GoodBye()\r\n {\r\n super.GoodBye();\r\n if (this._drawObject && this._drawObject.parent)\r\n this._drawObject.parent.remove(this._drawObject);\r\n this.ClearDraw();\r\n }\r\n\r\n Erase(isErase: boolean = true)\r\n {\r\n if (isErase === this._isErase)\r\n return;\r\n this.__UpdateVersion__++;\r\n super.Erase(isErase);\r\n this.UpdateVisible();\r\n this.EraseEvent(isErase);\r\n }\r\n\r\n @iaop\r\n EraseEvent(isErase: boolean)\r\n {\r\n\r\n }\r\n /**\r\n * 使用统一的方法设置对象的矩阵.\r\n * 需要对缩放矩形进行重载.避免对象矩阵不是单位矩阵\r\n */\r\n ApplyMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n if (equaln(m.getMaxScaleOnAxis(), 1))\r\n {\r\n let xA = new Vector3();\r\n let yA = new Vector3();\r\n let zA = new Vector3();\r\n m.extractBasis(xA, yA, zA);\r\n this._Matrix.multiplyMatrices(m, this._Matrix);\r\n this._SpaceOCS.multiplyMatrices(m, this._SpaceOCS);\r\n if (!equalv3(xA.clone().cross(yA).normalize(), zA))\r\n this.ApplyMirrorMatrix(m);\r\n else\r\n this.Update(UpdateDraw.Matrix);\r\n }\r\n else\r\n {\r\n this.ApplyScaleMatrix(m);\r\n }\r\n return this;\r\n }\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n return this;\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n return [];\r\n }\r\n\r\n MoveGripPoints(indexList: number[], vec: Vector3)\r\n {\r\n\r\n }\r\n\r\n /**\r\n *\r\n * @param snapMode 捕捉模式(单一)\r\n * @param pickPoint const\r\n * @param lastPoint const\r\n * @param viewXform const 最近点捕捉需要这个变量\r\n * @returns object snap points\r\n */\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n return [];\r\n }\r\n\r\n GetStretchPoints(): Array\r\n {\r\n return [];\r\n }\r\n\r\n /**\r\n * 拉伸夹点,用于Stretch命令\r\n *\r\n * @param {Array} indexList 拉伸点索引列表.\r\n * @param {Vector3} vec 移动向量\r\n * @memberof Entity\r\n */\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n\r\n }\r\n IntersectWith(curve: Entity, intType: IntersectOption): Vector3[] { return; }\r\n\r\n //#region -------------------------File-------------------------\r\n\r\n Clone(): this\r\n {\r\n let ent = super.Clone();\r\n ent._CurRenderType = this._CurRenderType;\r\n ent.Template = undefined;\r\n ent.CloneDrawObject(this);\r\n return ent;\r\n }\r\n\r\n CloneDrawObject(from: this)\r\n {\r\n for (let [type, obj] of from._CacheDrawObject)\r\n {\r\n let oldUserDaata = obj.userData;\r\n obj.traverse(o => o.userData = {});\r\n let newObj = obj.clone();\r\n obj.userData = oldUserDaata;\r\n obj.userData.IsClone = true;\r\n\r\n newObj.matrix = this._Matrix;\r\n newObj.userData = { Entity: this };\r\n newObj.userData.IsClone = true;\r\n this._CacheDrawObject.set(type, newObj);\r\n }\r\n this.NeedUpdateFlag = UpdateDraw.None;\r\n }\r\n\r\n static __ReadFileIng__: boolean;\r\n __ReadFileIng__: boolean;\r\n\r\n get ReadFileIng()\r\n {\r\n return this.__ReadFileIng__ || Entity.__ReadFileIng__;\r\n }\r\n\r\n /**\r\n * 从文件读取,序列化自身,如果需要,重载_ReadFile\r\n */\r\n ReadFile(file: CADFiler)\r\n {\r\n this.__ReadFileIng__ = true;\r\n this._ReadFile(file);\r\n this.Update();\r\n this.__ReadFileIng__ = false;\r\n }\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();\r\n super.ReadFile(file);\r\n this._Color = file.Read();\r\n this.materialId = file.ReadHardObjectId();\r\n this._Matrix.fromArray(file.Read());\r\n\r\n if (ver === 2)\r\n this.Owner = file.ReadObjectId();\r\n\r\n if (ver > 3)\r\n this.Template = file.ReadObjectId();\r\n\r\n if (ver > 4)\r\n this.GroupId = file.ReadHardObjectId();\r\n\r\n if (ver > 5)\r\n this._Visible = file.Read();\r\n if (ver > 6)\r\n this._SpaceOCS.fromArray(file.Read());\r\n if (ver > 7)\r\n {\r\n let count = file.Read();\r\n this.ProcessingGroupList.length = 0;\r\n for (let i = 0; i < count; i++)\r\n this.ProcessingGroupList.push(file.ReadHardObjectId());\r\n }\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(8);\r\n super.WriteFile(file);\r\n file.Write(this._Color);\r\n file.WriteHardObjectId(this.materialId);\r\n file.Write(this._Matrix.toArray());\r\n file.WriteObjectId(this.Template);\r\n file.WriteHardObjectId(this.GroupId);\r\n file.Write(this._Visible);\r\n file.Write(this._SpaceOCS.toArray());\r\n\r\n file.Write(this.ProcessingGroupList.length);\r\n for (let id of this.ProcessingGroupList)\r\n file.WriteHardObjectId(id);\r\n }\r\n //局部撤销\r\n ApplyPartialUndo(undoData: CADObject)\r\n {\r\n super.ApplyPartialUndo(undoData);\r\n }\r\n\r\n CopyFrom(obj: CADObject)\r\n {\r\n let templateIdBak = this.Template;\r\n super.CopyFrom(obj);\r\n this.Update();\r\n this.Template = templateIdBak;\r\n }\r\n\r\n //#endregion\r\n}\r\n","import { CADFactory } from './CADFactory';\r\nimport { CADObject } from './CADObject';\r\nimport { Database } from './Database';\r\nimport { ISerialize } from './ISerialize';\r\nimport { ObjectId } from './ObjectId';\r\nimport { Entity } from './Entity/Entity';\r\n\r\n/**\r\n * CAD文件数据\r\n */\r\nexport class CADFiler\r\n{\r\n database: Database;\r\n private readIndex: number = 0;\r\n constructor(protected _datas: any[] = [])\r\n {\r\n }\r\n\r\n Destroy()\r\n {\r\n delete this._datas;\r\n delete this.readIndex;\r\n }\r\n\r\n get Data(): any[]\r\n {\r\n return this._datas;\r\n }\r\n\r\n set Data(data: any[])\r\n {\r\n this._datas = data;\r\n this.Reset();\r\n }\r\n\r\n Clear()\r\n {\r\n this._datas.length = 0;\r\n return this.Reset();\r\n }\r\n Reset()\r\n {\r\n this.readIndex = 0;\r\n return this;\r\n }\r\n\r\n WriteString(str: string)\r\n {\r\n this._datas.push(str);\r\n return this;\r\n }\r\n\r\n ReadString(): string\r\n {\r\n return this._datas[this.readIndex++] as string;\r\n }\r\n\r\n WriteObject(obj: ISerialize)\r\n {\r\n if (!obj)\r\n {\r\n this.Write(\"\");\r\n return;\r\n }\r\n this.WriteString(obj.constructor.name);\r\n obj.WriteFile(this);\r\n\r\n return this;\r\n }\r\n\r\n ReadObject(obj?: T): T\r\n {\r\n let className = this.ReadString();\r\n if (className)\r\n {\r\n if (obj === undefined)\r\n {\r\n obj = CADFactory.CreateObject(className);\r\n if (this.database !== undefined && obj instanceof CADObject)\r\n obj.SetDefaultDb(this.database);\r\n }\r\n obj.ReadFile(this);\r\n return obj;\r\n }\r\n }\r\n\r\n CloneObjects(objects: CADObject[], clonedObjects: CADObject[] = [])\r\n {\r\n for (let o of objects)\r\n this.WriteObject(o);\r\n let count = objects.length;\r\n for (let i = 0; i < count; i++)\r\n {\r\n let obj = this.ReadObject();\r\n if (obj instanceof Entity)\r\n obj.CloneDrawObject(objects[i] as Entity);\r\n clonedObjects.push(obj);\r\n }\r\n\r\n return clonedObjects;\r\n }\r\n\r\n Write(data: any)\r\n {\r\n if (data instanceof ObjectId)\r\n this._datas.push(data.Index);\r\n else\r\n this._datas.push(data);\r\n\r\n return this;\r\n }\r\n\r\n Read(): any\r\n {\r\n return this._datas[this.readIndex++];\r\n }\r\n\r\n ReadArray(count: number): any[]\r\n {\r\n let arr = this._datas.slice(this.readIndex, this.readIndex + count);\r\n this.readIndex += count;\r\n return arr;\r\n }\r\n\r\n //------------------------ID序列化------------------------\r\n /*\r\n Id关联分为三种情况:\r\n 1.普通关联:关联对象未被拷贝时,关联到空对象.\r\n 2.软关联 :关联对象未被拷贝时,关联到原先的对象.\r\n 3.硬关联 :对象被拷贝时,被关联的对象必须也被拷贝.\r\n */\r\n\r\n //-------1.普通关联\r\n WriteObjectId(id: ObjectId): this\r\n {\r\n if (id)\r\n this.Write(id.Index);\r\n else\r\n this.Write(0);\r\n return this;\r\n }\r\n\r\n ReadObjectId(): ObjectId\r\n {\r\n let index = this.Read();\r\n if (this.database)\r\n return this.database.GetObjectId(index, true);\r\n }\r\n\r\n //-------2.软关联\r\n WriteSoftObjectId(id: ObjectId): this\r\n {\r\n return this.WriteObjectId(id);\r\n }\r\n ReadSoftObjectId(): ObjectId\r\n {\r\n return this.ReadObjectId();\r\n }\r\n\r\n //-------3.硬关联\r\n WriteHardObjectId(id: ObjectId): this\r\n {\r\n return this.WriteObjectId(id);\r\n }\r\n ReadHardObjectId()\r\n {\r\n return this.ReadObjectId();\r\n }\r\n\r\n //序列化\r\n ToString()\r\n {\r\n return JSON.stringify(this._datas);\r\n }\r\n FromString(str: string)\r\n {\r\n this._datas = JSON.parse(str);\r\n }\r\n}\r\n","import { ShaderMaterialParameters, Vector3 } from \"three\";\r\n\r\n//https://github.com/arefin86/arefin86.github.io/blob/master/js/shaders/GoochShader.js\r\nexport function GetGoochShader()\r\n{\r\n return {\r\n uniforms: {\r\n \"LightPosition\": { type: \"v3\", value: new Vector3(-200, 0, 200) },\r\n \"SurfaceColor\": { type: \"v3\", value: new Vector3(1.0, 1.0, 0.) },\r\n \"WarmColor\": { type: \"v3\", value: new Vector3(1.0, 0.5, 0.0) },\r\n \"CoolColor\": { type: \"v3\", value: new Vector3(0, 0, 0.7) },\r\n \"DiffuseWarm\": { type: \"f\", value: 0.45 },\r\n \"DiffuseCool\": { type: \"f\", value: 0.1 }\r\n },\r\n\r\n vertexShader: require(\"./Goodch2.vs\"),\r\n fragmentShader: require(\"./Goodch2.fs\")\r\n };\r\n}\r\n\r\nexport function GetGoodShaderSimple(color: Vector3 = new Vector3): ShaderMaterialParameters\r\n{\r\n return {\r\n uniforms: {\r\n \"SurfaceColor\": { value: color }\r\n },\r\n vertexShader: require(\"./GoodchSimple.vs\"),\r\n fragmentShader: require(\"./GoodchSimple.fs\"),\r\n\r\n polygonOffset: true,\r\n polygonOffsetFactor: 1,\r\n polygonOffsetUnits: 1\r\n };\r\n}\r\n","import { Color, DoubleSide, LineBasicMaterial, LineDashedMaterial, MeshBasicMaterial, ShaderMaterial, Vector3 } from 'three';\r\nimport { GetGoodShaderSimple } from '../GLSL/GoochShader';\r\nimport { LineMaterial } from 'three/examples/jsm/lines/LineMaterial';\r\n\r\nconst ColorPalette = [\r\n [255, 0, 0, 255], //----- 0 - lets make it red for an example\r\n //[255, 255, 255, 255],//----- 0 - ByBlock - White\r\n [255, 0, 0, 255], //----- 1 - Red\r\n // [255, 0, 0, 255], //----- 1 - Red\r\n [255, 255, 0, 255], //----- 2 - Yellow\r\n [0, 255, 0, 255], //----- 3 - Green\r\n [0, 255, 255, 255], //----- 4 - Cyan\r\n [0, 0, 255, 255], //----- 5 - Blue\r\n [255, 0, 255, 255], //----- 6 - Magenta\r\n // [255, 0, 0, 255], //----- 7 - More red Red\r\n // [255, 0, 0, 255], //----- 8 - More red Red\r\n // [255, 0, 0, 255], //----- 9 - More red Red\r\n [255, 255, 255, 255],//----- 7 - White\r\n [128, 128, 128, 255],//----- 8\r\n [192, 192, 192, 255],//----- 9\r\n [255, 0, 0, 255], //----- 10\r\n [255, 127, 127, 255],//----- 11\r\n [165, 0, 0, 255], //----- 12\r\n [165, 82, 82, 255], //----- 13\r\n [127, 0, 0, 255], //----- 14\r\n [127, 63, 63, 255], //----- 15\r\n [76, 0, 0, 255], //----- 16\r\n [76, 38, 38, 255], //----- 17\r\n [38, 0, 0, 255], //----- 18\r\n [38, 19, 19, 255], //----- 19\r\n [255, 63, 0, 255], //----- 20\r\n [255, 159, 127, 255],//----- 21\r\n [165, 41, 0, 255], //----- 22\r\n [165, 103, 82, 255], //----- 23\r\n [127, 31, 0, 255], //----- 24\r\n [127, 79, 63, 255], //----- 25\r\n [76, 19, 0, 255], //----- 26\r\n [76, 47, 38, 255], //----- 27\r\n [38, 9, 0, 255], //----- 28\r\n [38, 23, 19, 255], //----- 29\r\n [255, 127, 0, 255], //----- 30\r\n [255, 191, 127, 255],//----- 31\r\n [165, 82, 0, 255], //----- 32\r\n [165, 124, 82, 255], //----- 33\r\n [127, 63, 0, 255], //----- 34\r\n [127, 95, 63, 255], //----- 35\r\n [76, 38, 0, 255], //----- 36\r\n [76, 57, 38, 255], //----- 37\r\n [38, 19, 0, 255], //----- 38\r\n [38, 28, 19, 255], //----- 39\r\n [255, 191, 0, 255], //----- 40\r\n [255, 223, 127, 255],//----- 41\r\n [165, 124, 0, 255], //----- 42\r\n [165, 145, 82, 255], //----- 43\r\n [127, 95, 0, 255], //----- 44\r\n [127, 111, 63, 255], //----- 45\r\n [76, 57, 0, 255], //----- 46\r\n [76, 66, 38, 255], //----- 47\r\n [38, 28, 0, 255], //----- 48\r\n [38, 33, 19, 255], //----- 49\r\n [255, 255, 0, 255], //----- 50\r\n [255, 255, 127, 255],//----- 51\r\n [165, 165, 0, 255], //----- 52\r\n [165, 165, 82, 255], //----- 53\r\n [127, 127, 0, 255], //----- 54\r\n [127, 127, 63, 255], //----- 55\r\n [76, 76, 0, 255], //----- 56\r\n [76, 76, 38, 255], //----- 57\r\n [38, 38, 0, 255], //----- 58\r\n [38, 38, 19, 255], //----- 59\r\n [191, 255, 0, 255], //----- 60\r\n [223, 255, 127, 255],//----- 61\r\n [124, 165, 0, 255], //----- 62\r\n [145, 165, 82, 255], //----- 63\r\n [95, 127, 0, 255], //----- 64\r\n [111, 127, 63, 255], //----- 65\r\n [57, 76, 0, 255], //----- 66\r\n [66, 76, 38, 255], //----- 67\r\n [28, 38, 0, 255], //----- 68\r\n [33, 38, 19, 255], //----- 69\r\n [127, 255, 0, 255], //----- 70\r\n [191, 255, 127, 255],//----- 71\r\n [82, 165, 0, 255], //----- 72\r\n [124, 165, 82, 255], //----- 73\r\n [63, 127, 0, 255], //----- 74\r\n [95, 127, 63, 255], //----- 75\r\n [38, 76, 0, 255], //----- 76\r\n [57, 76, 38, 255], //----- 77\r\n [19, 38, 0, 255], //----- 78\r\n [28, 38, 19, 255], //----- 79\r\n [63, 255, 0, 255], //----- 80\r\n [159, 255, 127, 255],//----- 81\r\n [41, 165, 0, 255], //----- 82\r\n [103, 165, 82, 255], //----- 83\r\n [31, 127, 0, 255], //----- 84\r\n [79, 127, 63, 255], //----- 85\r\n [19, 76, 0, 255], //----- 86\r\n [47, 76, 38, 255], //----- 87\r\n [9, 38, 0, 255], //----- 88\r\n [23, 38, 19, 255], //----- 89\r\n [0, 255, 0, 255], //----- 90\r\n [127, 255, 127, 255],//----- 91\r\n [0, 165, 0, 255], //----- 92\r\n [82, 165, 82, 255], //----- 93\r\n [0, 127, 0, 255], //----- 94\r\n [63, 127, 63, 255], //----- 95\r\n [0, 76, 0, 255], //----- 96\r\n [38, 76, 38, 255], //----- 97\r\n [0, 38, 0, 255], //----- 98\r\n [19, 38, 19, 255], //----- 99\r\n [0, 255, 63, 255], //----- 100\r\n [127, 255, 159, 255],//----- 101\r\n [0, 165, 41, 255], //----- 102\r\n [82, 165, 103, 255], //----- 103\r\n [0, 127, 31, 255], //----- 104\r\n [63, 127, 79, 255], //----- 105\r\n [0, 76, 19, 255], //----- 106\r\n [38, 76, 47, 255], //----- 107\r\n [0, 38, 9, 255], //----- 108\r\n [19, 38, 23, 255], //----- 109\r\n [0, 255, 127, 255], //----- 110\r\n [127, 255, 191, 255],//----- 111\r\n [0, 165, 82, 255], //----- 112\r\n [82, 165, 124, 255], //----- 113\r\n [0, 127, 63, 255], //----- 114\r\n [63, 127, 95, 255], //----- 115\r\n [0, 76, 38, 255], //----- 116\r\n [38, 76, 57, 255], //----- 117\r\n [0, 38, 19, 255], //----- 118\r\n [19, 38, 28, 255], //----- 119\r\n [0, 255, 191, 255], //----- 120\r\n [127, 255, 223, 255],//----- 121\r\n [0, 165, 124, 255], //----- 122\r\n [82, 165, 145, 255], //----- 123\r\n [0, 127, 95, 255], //----- 124\r\n [63, 127, 111, 255], //----- 125\r\n [0, 76, 57, 255], //----- 126\r\n [38, 76, 66, 255], //----- 127\r\n [0, 38, 28, 255], //----- 128\r\n [19, 38, 33, 255], //----- 129\r\n [0, 255, 255, 255], //----- 130\r\n [127, 255, 255, 255],//----- 131\r\n [0, 165, 165, 255], //----- 132\r\n [82, 165, 165, 255], //----- 133\r\n [0, 127, 127, 255], //----- 134\r\n [63, 127, 127, 255], //----- 135\r\n [0, 76, 76, 255], //----- 136\r\n [38, 76, 76, 255], //----- 137\r\n [0, 38, 38, 255], //----- 138\r\n [19, 38, 38, 255], //----- 139\r\n [0, 191, 255, 255], //----- 140\r\n [127, 223, 255, 255],//----- 141\r\n [0, 124, 165, 255], //----- 142\r\n [82, 145, 165, 255], //----- 143\r\n [0, 95, 127, 255], //----- 144\r\n [63, 111, 127, 255], //----- 145\r\n [0, 57, 76, 255], //----- 146\r\n [38, 66, 76, 255], //----- 147\r\n [0, 28, 38, 255], //----- 148\r\n [19, 33, 38, 255], //----- 149\r\n [0, 127, 255, 255], //----- 150\r\n [127, 191, 255, 255],//----- 151\r\n [0, 82, 165, 255], //----- 152\r\n [82, 124, 165, 255], //----- 153\r\n [0, 63, 127, 255], //----- 154\r\n [63, 95, 127, 255], //----- 155\r\n [0, 38, 76, 255], //----- 156\r\n [38, 57, 76, 255], //----- 157\r\n [0, 19, 38, 255], //----- 158\r\n [19, 28, 38, 255], //----- 159\r\n [0, 63, 255, 255], //----- 160\r\n [127, 159, 255, 255],//----- 161\r\n [0, 41, 165, 255], //----- 162\r\n [82, 103, 165, 255], //----- 163\r\n [0, 31, 127, 255], //----- 164\r\n [63, 79, 127, 255], //----- 165\r\n [0, 19, 76, 255], //----- 166\r\n [38, 47, 76, 255], //----- 167\r\n [0, 9, 38, 255], //----- 168\r\n [19, 23, 38, 255], //----- 169\r\n [0, 0, 255, 255], //----- 170\r\n [127, 127, 255, 255],//----- 171\r\n [0, 0, 165, 255], //----- 172\r\n [82, 82, 165, 255], //----- 173\r\n [0, 0, 127, 255], //----- 174\r\n [63, 63, 127, 255], //----- 175\r\n [0, 0, 76, 255], //----- 176\r\n [38, 38, 76, 255], //----- 177\r\n [0, 0, 38, 255], //----- 178\r\n [19, 19, 38, 255], //----- 179\r\n [63, 0, 255, 255], //----- 180\r\n [159, 127, 255, 255],//----- 181\r\n [41, 0, 165, 255], //----- 182\r\n [103, 82, 165, 255], //----- 183\r\n [31, 0, 127, 255], //----- 184\r\n [79, 63, 127, 255], //----- 185\r\n [19, 0, 76, 255], //----- 186\r\n [47, 38, 76, 255], //----- 187\r\n [9, 0, 38, 255], //----- 188\r\n [23, 19, 38, 255], //----- 189\r\n [127, 0, 255, 255], //----- 190\r\n [191, 127, 255, 255],//----- 191\r\n [82, 0, 165, 255], //----- 192\r\n [124, 82, 165, 255], //----- 193\r\n [63, 0, 127, 255], //----- 194\r\n [95, 63, 127, 255], //----- 195\r\n [38, 0, 76, 255], //----- 196\r\n [57, 38, 76, 255], //----- 197\r\n [19, 0, 38, 255], //----- 198\r\n [28, 19, 38, 255], //----- 199\r\n [191, 0, 255, 255], //----- 200\r\n [223, 127, 255, 255],//----- 201\r\n [124, 0, 165, 255], //----- 202\r\n [145, 82, 165, 255], //----- 203\r\n [95, 0, 127, 255], //----- 204\r\n [111, 63, 127, 255], //----- 205\r\n [57, 0, 76, 255], //----- 206\r\n [66, 38, 76, 255], //----- 207\r\n [28, 0, 38, 255], //----- 208\r\n [33, 19, 38, 255], //----- 209\r\n [255, 0, 255, 255], //----- 210\r\n [255, 127, 255, 255],//----- 211\r\n [165, 0, 165, 255], //----- 212\r\n [165, 82, 165, 255], //----- 213\r\n [127, 0, 127, 255], //----- 214\r\n [127, 63, 127, 255], //----- 215\r\n [76, 0, 76, 255], //----- 216\r\n [76, 38, 76, 255], //----- 217\r\n [38, 0, 38, 255], //----- 218\r\n [38, 19, 38, 255], //----- 219\r\n [255, 0, 191, 255], //----- 220\r\n [255, 127, 223, 255],//----- 221\r\n [165, 0, 124, 255], //----- 222\r\n [165, 82, 145, 255], //----- 223\r\n [127, 0, 95, 255], //----- 224\r\n [127, 63, 111, 255], //----- 225\r\n [76, 0, 57, 255], //----- 226\r\n [76, 38, 66, 255], //----- 227\r\n [38, 0, 28, 255], //----- 228\r\n [38, 19, 33, 255], //----- 229\r\n [255, 0, 127, 255], //----- 230\r\n [255, 127, 191, 255],//----- 231\r\n [165, 0, 82, 255], //----- 232\r\n [165, 82, 124, 255], //----- 233\r\n [127, 0, 63, 255], //----- 234\r\n [127, 63, 95, 255], //----- 235\r\n [76, 0, 38, 255], //----- 236\r\n [76, 38, 57, 255], //----- 237\r\n [38, 0, 19, 255], //----- 238\r\n [38, 19, 28, 255], //----- 239\r\n [255, 0, 63, 255], //----- 240\r\n [255, 127, 159, 255],//----- 241\r\n [165, 0, 41, 255], //----- 242\r\n [165, 82, 103, 255], //----- 243\r\n [127, 0, 31, 255], //----- 244\r\n [127, 63, 79, 255], //----- 245\r\n [76, 0, 19, 255], //----- 246\r\n [76, 38, 47, 255], //----- 247\r\n [38, 0, 9, 255], //----- 248\r\n [38, 19, 23, 255], //----- 249\r\n [84, 84, 84, 255], //----- 250\r\n [118, 118, 118, 255],//----- 251\r\n [152, 152, 152, 255],//----- 252\r\n [186, 186, 186, 255],//----- 253\r\n [220, 220, 220, 255],//----- 254\r\n [255, 255, 255, 255],//----- 255\r\n [0, 0, 0, 0] //----- ByLayer - White\r\n];\r\n\r\nexport const LINE_WIDTH = 2;\r\n\r\n//颜色材质,对于二维图像来说可能有用,应该不对三维对象使用该材质\r\nexport class ColorMaterial\r\n{\r\n private constructor() { }\r\n private static _LineMaterialMap = new Map();\r\n private static _BasicMaterialMap = new Map();\r\n static GetLineMaterial(color: number): LineBasicMaterial\r\n {\r\n if (this._LineMaterialMap.has(color))\r\n return this._LineMaterialMap.get(color);\r\n let mat = new LineBasicMaterial({ color: this.GetColor(color) });\r\n this._LineMaterialMap.set(color, mat);\r\n return mat;\r\n }\r\n\r\n static GetBasicMaterial(color: number): MeshBasicMaterial\r\n {\r\n if (this._BasicMaterialMap.has(color))\r\n return this._BasicMaterialMap.get(color);\r\n let mtl = new MeshBasicMaterial({ color: this.GetColor(color) });\r\n this._BasicMaterialMap.set(color, mtl);\r\n return mtl;\r\n }\r\n\r\n private static _BasicDoubleSideMaterialMap = new Map();\r\n static GetBasicMaterialDoubleSide(color: number): MeshBasicMaterial\r\n {\r\n if (this._BasicDoubleSideMaterialMap.has(color))\r\n return this._BasicDoubleSideMaterialMap.get(color);\r\n let mtl = new MeshBasicMaterial({ color: this.GetColor(color), side: DoubleSide });\r\n this._BasicDoubleSideMaterialMap.set(color, mtl);\r\n return mtl;\r\n }\r\n\r\n private static _ConceptualMaterial: Map = new Map();\r\n static GetConceptualMaterial(color: number)\r\n {\r\n if (this._ConceptualMaterial.has(color))\r\n return this._ConceptualMaterial.get(color);\r\n\r\n let shaderParams = GetGoodShaderSimple(\r\n new Vector3().fromArray(this.GetColor(color).toArray())\r\n );\r\n let mtl = new ShaderMaterial(shaderParams);\r\n this._ConceptualMaterial.set(color, mtl);\r\n return mtl;\r\n }\r\n private static _printConceptualMaterial: ShaderMaterial;\r\n static GetPrintConceptualMaterial()\r\n {\r\n if (!this._printConceptualMaterial)\r\n {\r\n this._printConceptualMaterial = new ShaderMaterial({\r\n uniforms: {\r\n \"SurfaceColor\": { value: [1.0, 1.0, 1.0] }\r\n },\r\n vertexShader: require(\"../GLSL/GoodchSimple.vs\"),\r\n fragmentShader: require(\"../GLSL/GoodchSimple2.fs\"),\r\n polygonOffset: true,\r\n polygonOffsetFactor: 1,\r\n polygonOffsetUnits: LINE_WIDTH\r\n });\r\n }\r\n return this._printConceptualMaterial;\r\n }\r\n\r\n private static _BasicTransparentMaterialMap: Map = new Map();\r\n static GetBasicMaterialTransparent(color: number, opacity: number)\r\n {\r\n let key = `${color},${opacity}`;\r\n let mat = this._BasicTransparentMaterialMap.get(key);\r\n if (mat) return mat;\r\n mat = new MeshBasicMaterial({ transparent: true, opacity: opacity, side: DoubleSide });\r\n this._BasicTransparentMaterialMap.set(key, mat);\r\n return mat;\r\n }\r\n\r\n private static _BasicTransparentMaterialMap2: Map = new Map();\r\n static GetBasicMaterialTransparent2(color: number, opacity: number)\r\n {\r\n let key = `${color},${opacity}`;\r\n let mat = this._BasicTransparentMaterialMap2.get(key);\r\n if (mat) return mat;\r\n mat = new MeshBasicMaterial({ transparent: true, opacity: opacity });\r\n this._BasicTransparentMaterialMap2.set(key, mat);\r\n return mat;\r\n }\r\n\r\n static GetColor(color: number)\r\n {\r\n let rgb = ColorPalette[color];\r\n if (rgb)\r\n return new Color(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255);\r\n\r\n //避免无法获得到颜色而产生的错误\r\n return new Color();\r\n }\r\n\r\n //橡皮筋材质: 黄色 点划线\r\n static RubberBandMaterial = new LineDashedMaterial({\r\n color: 0xF0B41E,\r\n dashSize: 20,\r\n gapSize: 8,\r\n });\r\n\r\n //极轴材质: 绿色 点划线\r\n static SnapAxisMaterial = new LineDashedMaterial({\r\n color: 0x008B00,\r\n dashSize: 5,\r\n gapSize: 5\r\n });\r\n static PrintLineMatrial = new LineMaterial({\r\n\r\n color: 0x000000,\r\n linewidth: LINE_WIDTH / 1000,\r\n dashed: false\r\n });\r\n static GrayTransparentMeshMaterial = new MeshBasicMaterial({\r\n color: 0xcccccc,\r\n transparent: true,\r\n opacity: 0.3,\r\n });\r\n static TransparentMeshMaterial = new MeshBasicMaterial({\r\n transparent: true,\r\n opacity: 0,\r\n });\r\n static TransparentLineMaterial = new MeshBasicMaterial({\r\n transparent: true,\r\n opacity: 0,\r\n });\r\n}\r\n","/**\r\n * 删除数组中指定的元素,返回数组本身\r\n * @param {Array} arr 需要操作的数组\r\n * @param {*} el 需要移除的元素\r\n */\r\nexport function arrayRemove(arr: Array, el: T): Array\r\n{\r\n let j = 0;\r\n for (let i = 0, l = arr.length; i < l; i++)\r\n {\r\n if (arr[i] !== el)\r\n {\r\n arr[j++] = arr[i];\r\n }\r\n }\r\n arr.length = j;\r\n\r\n return arr;\r\n}\r\n\r\n\r\nexport function arrayRemoveOnce(arr: Array, el: T): Array\r\n{\r\n let index = arr.indexOf(el);\r\n if (index !== -1)\r\n arr.splice(index, 1);\r\n return arr;\r\n}\r\n\r\n/**\r\n * 删除通过函数校验的元素\r\n * @param {(e: T) => boolean} checkFuntion 校验函数\r\n */\r\nexport function arrayRemoveIf(arr: Array, checkFuntion: (e: T) => boolean): Array\r\n{\r\n let j = 0;\r\n for (let i = 0, l = arr.length; i < l; i++)\r\n {\r\n if (!checkFuntion(arr[i]))\r\n {\r\n arr[j++] = arr[i];\r\n }\r\n }\r\n arr.length = j;\r\n\r\n return arr;\r\n}\r\n\r\nexport function arrayFirst(arr: Array): T\r\n{\r\n return arr[0];\r\n}\r\n\r\nexport function arrayLast(arr: { [key: number]: T, length: number; }): T\r\n{\r\n return arr[arr.length - 1];\r\n}\r\n\r\n/**\r\n * 根据数值从小到大排序数组\r\n * @param {Array} arr\r\n * @returns {Array} 返回自身\r\n */\r\nexport function arraySortByNumber(arr: Array): Array\r\n{\r\n arr.sort(sortNumberCompart);\r\n return arr;\r\n}\r\n\r\n/**\r\n * 对排序好的数组进行去重操作\r\n * @param {(e1, e2) => boolean} [checkFuction] 校验对象相等函数\r\n * @returns {Array} 返回自身\r\n */\r\nexport function arrayRemoveDuplicateBySort(arr: Array, checkFuction: (e1: T, e2: T) => boolean = checkEqual): Array\r\n{\r\n if (arr.length < 2) return arr;\r\n let j = 1;\r\n for (let i = 1, l = arr.length; i < l; i++)\r\n if (!checkFuction(arr[j - 1], arr[i]))\r\n arr[j++] = arr[i];\r\n arr.length = j;\r\n return arr;\r\n}\r\n\r\n//原地更新数组,注意这个函数并不会比map快.\r\nexport function arrayMap(arr: Array, mapFunc: (v: T) => T): Array\r\n{\r\n for (let i = 0, count = arr.length; i < count; i++)\r\n arr[i] = mapFunc(arr[i]);\r\n return arr;\r\n}\r\n\r\nfunction sortNumberCompart(e1: any, e2: any)\r\n{\r\n return e1 - e2;\r\n}\r\n\r\nfunction checkEqual(e1: any, e2: any): boolean\r\n{\r\n return e1 === e2;\r\n}\r\n\r\n/**\r\n * 改变数组的值顺序\r\n * @param arr 需要改变初始值位置的数组\r\n * @param index //将index位置以后的值放到起始位置\r\n */\r\nexport function changeArrayStartIndex(arr: T[], index: number): T[]\r\n{\r\n arr.unshift(...arr.splice(index));\r\n return arr;\r\n}\r\n\r\nexport function equalArray(a: T[], b: T[], checkF = checkEqual)\r\n{\r\n if (a === b) return true;\r\n if (a.length !== b.length) return false;\r\n for (var i = 0; i < a.length; ++i)\r\n if (!checkF(a[i], b[i])) return false;\r\n return true;\r\n}\r\n\r\nexport function arrayClone(arr: T[]): T[]\r\n{\r\n return arr.slice();\r\n}\r\n\r\n//https://jsperf.com/merge-array-implementations/30\r\nexport function arrayPushArray(arr1: T[], arr2: T[]): T[]\r\n{\r\n let arr1Length = arr1.length;\r\n let arr2Length = arr2.length;\r\n arr1.length = arr1Length + arr2Length;\r\n for (let i = 0; i < arr2Length; i++)\r\n arr1[arr1Length + i] = arr2[i];\r\n\r\n return arr1;\r\n}\r\n\r\nexport function arraySum(arr: number[])\r\n{\r\n let sum = 0;\r\n for (let n of arr) sum += n;\r\n return sum;\r\n}\r\n\r\nexport function FilterSet(s: Set, fn: (el: T) => boolean): Set\r\n{\r\n let ns = new Set();\r\n for (let el of s)\r\n {\r\n if (fn(el))\r\n ns.add(el);\r\n }\r\n return ns;\r\n}\r\n","\r\n/**\r\n * OSMODE\r\n */\r\nexport enum ObjectSnapMode\r\n{\r\n None = 0, //无\r\n End = 1, //端点\r\n Mid = 2, //中点\r\n Cen = 4, //圆心\r\n Node = 8,//节点\r\n Qua = 16,//象限点\r\n Int = 32,//交点\r\n Ins = 64,//插入点\r\n Per = 128,//垂足\r\n Tan = 256,//切点\r\n Nea = 512,//最近点\r\n NotEntitySnap = 1024,//清除所有对象捕捉\r\n App = 2048,//外观交点\r\n Ext = 4096,//延伸\r\n Par = 8192,//平行\r\n Axis = 16384,//极轴\r\n All = ~(~0 << 15) - 1024,\r\n}\r\n","import { BufferGeometry, Vector3, BufferAttribute, ShapeGeometry, Shape } from \"three\";\r\n\r\nexport namespace BufferGeometryUtils\r\n{\r\n export function CreateFromPts(pts: Vector3[]): BufferGeometry\r\n {\r\n return new BufferGeometry().setFromPoints(pts);\r\n }\r\n\r\n /**\r\n * 更新BufferGeometry的顶点\r\n * @param geo\r\n * @param pts\r\n * @returns 当成功时返回true,更新失败时返回false\r\n */\r\n export function UpdatePts(geo: BufferGeometry, pts: Vector3[]): boolean\r\n {\r\n let bf = geo.getAttribute(\"position\") as BufferAttribute;\r\n if (bf === undefined)\r\n geo.setFromPoints(pts);\r\n else if (bf.count >= pts.length)\r\n {\r\n bf.copyVector3sArray(pts);\r\n bf.needsUpdate = true;\r\n geo.drawRange.count = pts.length;\r\n }\r\n else\r\n return false;\r\n\r\n return true;\r\n }\r\n\r\n let arrowGeometry: ShapeGeometry;\r\n export function ArrowGeometry()\r\n {\r\n if (arrowGeometry)\r\n return arrowGeometry;\r\n else\r\n {\r\n let arrowShape = new Shape();\r\n arrowShape.lineTo(-0.5, -1.8);\r\n arrowShape.lineTo(0.5, -1.8);\r\n arrowGeometry = new ShapeGeometry(arrowShape);\r\n arrowGeometry.computeBoundingBox();\r\n return arrowGeometry;\r\n }\r\n }\r\n\r\n export function MergeBufferGeometries(geometries: BufferGeometry[], useGroups: boolean = false): BufferGeometry\r\n {\r\n if (geometries.length === 0)\r\n return new BufferGeometry();\r\n let isIndexed = geometries[0].index !== null;\r\n\r\n let attributesUsed = new Set(Object.keys(geometries[0].attributes));\r\n let morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));\r\n\r\n let attributes = {};\r\n let morphAttributes = {};\r\n\r\n let morphTargetsRelative = geometries[0].morphTargetsRelative;\r\n\r\n let mergedGeometry = new BufferGeometry();\r\n\r\n let offset = 0;\r\n\r\n for (let i = 0; i < geometries.length; ++i)\r\n {\r\n\r\n let geometry = geometries[i];\r\n\r\n // ensure that all geometries are indexed, or none\r\n\r\n if (isIndexed !== (geometry.index !== null)) return null;\r\n\r\n // gather attributes, exit early if they're different\r\n\r\n for (let name in geometry.attributes)\r\n {\r\n\r\n if (!attributesUsed.has(name)) continue;\r\n\r\n if (attributes[name] === undefined) attributes[name] = [];\r\n\r\n attributes[name].push(geometry.attributes[name]);\r\n\r\n }\r\n\r\n // gather morph attributes, exit early if they're different\r\n\r\n if (morphTargetsRelative !== geometry.morphTargetsRelative) return null;\r\n\r\n for (let name in geometry.morphAttributes)\r\n {\r\n\r\n if (!morphAttributesUsed.has(name)) continue;\r\n\r\n if (morphAttributes[name] === undefined) morphAttributes[name] = [];\r\n\r\n morphAttributes[name].push(geometry.morphAttributes[name]);\r\n\r\n }\r\n\r\n // gather .userData\r\n\r\n mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];\r\n mergedGeometry.userData.mergedUserData.push(geometry.userData);\r\n\r\n if (useGroups)\r\n {\r\n\r\n let count: number;\r\n\r\n if (isIndexed)\r\n {\r\n\r\n count = geometry.index.count;\r\n\r\n } else if (geometry.attributes.position !== undefined)\r\n {\r\n\r\n count = geometry.attributes.position.count;\r\n\r\n } else\r\n {\r\n\r\n return null;\r\n\r\n }\r\n\r\n mergedGeometry.addGroup(offset, count, i);\r\n\r\n offset += count;\r\n\r\n }\r\n\r\n }\r\n\r\n // merge indices\r\n\r\n if (isIndexed)\r\n {\r\n\r\n let indexOffset = 0;\r\n let mergedIndex = [];\r\n\r\n for (let i = 0; i < geometries.length; ++i)\r\n {\r\n\r\n let index = geometries[i].index;\r\n\r\n for (let j = 0; j < index.count; ++j)\r\n {\r\n\r\n mergedIndex.push(index.getX(j) + indexOffset);\r\n\r\n }\r\n\r\n indexOffset += geometries[i].attributes.position.count;\r\n\r\n }\r\n\r\n mergedGeometry.setIndex(mergedIndex);\r\n\r\n }\r\n\r\n // merge attributes\r\n\r\n for (let name in attributes)\r\n {\r\n\r\n let mergedAttribute = MergeBufferAttributes(attributes[name]);\r\n\r\n if (!mergedAttribute) return null;\r\n\r\n mergedGeometry.setAttribute(name, mergedAttribute);\r\n\r\n }\r\n\r\n // merge morph attributes\r\n\r\n for (let name in morphAttributes)\r\n {\r\n\r\n let numMorphTargets = morphAttributes[name][0].length;\r\n\r\n if (numMorphTargets === 0) break;\r\n\r\n mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};\r\n mergedGeometry.morphAttributes[name] = [];\r\n\r\n for (let i = 0; i < numMorphTargets; ++i)\r\n {\r\n\r\n let morphAttributesToMerge: any[] = [];\r\n\r\n for (let j = 0; j < morphAttributes[name].length; ++j)\r\n {\r\n\r\n morphAttributesToMerge.push(morphAttributes[name][j][i]);\r\n\r\n }\r\n\r\n let mergedMorphAttribute = MergeBufferAttributes(morphAttributesToMerge);\r\n\r\n if (!mergedMorphAttribute) return null;\r\n\r\n mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);\r\n\r\n }\r\n\r\n }\r\n\r\n return mergedGeometry;\r\n\r\n }\r\n\r\n export function MergeBufferAttributes(attributes: BufferAttribute[]): BufferAttribute\r\n {\r\n let TypedArray;\r\n let itemSize: number;\r\n let normalized: boolean;\r\n let arrayLength = 0;\r\n\r\n for (let i = 0; i < attributes.length; ++i)\r\n {\r\n\r\n let attribute = attributes[i];\r\n\r\n if (TypedArray === undefined) TypedArray = attribute.array.constructor;\r\n if (TypedArray !== attribute.array.constructor) return null;\r\n\r\n if (itemSize === undefined) itemSize = attribute.itemSize;\r\n if (itemSize !== attribute.itemSize) return null;\r\n\r\n if (normalized === undefined) normalized = attribute.normalized;\r\n if (normalized !== attribute.normalized) return null;\r\n\r\n arrayLength += attribute.array.length;\r\n\r\n }\r\n\r\n let array = new TypedArray(arrayLength);\r\n let offset = 0;\r\n\r\n for (let i = 0; i < attributes.length; ++i)\r\n {\r\n\r\n array.set(attributes[i].array, offset);\r\n\r\n offset += attributes[i].array.length;\r\n\r\n }\r\n\r\n return new BufferAttribute(array, itemSize, normalized);\r\n\r\n }\r\n\r\n}\r\n","import { EllipseCurve, Shape, Vector2 } from \"three\";\r\nimport { clamp } from \"../Common/Utils\";\r\nimport { equalv2 } from \"../Geometry/GeUtils\";\r\n\r\nexport class Shape2 extends Shape\r\n{\r\n getPoints(divisions: number = 12)\r\n {\r\n divisions = divisions || 12;\r\n let points = [], last: Vector2;\r\n for (let i = 0, curves = this.curves; i < curves.length; i++)\r\n {\r\n let curve = curves[i];\r\n //@ts-ignore\r\n let resolution = (curve && curve.isEllipseCurve) ? clamp(curve.getLength() / 20, divisions * 2, 60)\r\n //@ts-ignore\r\n : (curve && (curve.isLineCurve || curve.isLineCurve3)) ? 1\r\n //@ts-ignore\r\n : (curve && curve.isSplineCurve) ? divisions * curve.points.length\r\n : divisions;\r\n\r\n let pts = curve.getPoints(resolution);\r\n\r\n for (let j = 0; j < pts.length; j++)\r\n {\r\n let point = pts[j];\r\n if (last && equalv2(last, point, 1e-4))\r\n continue; // ensures no consecutive points are duplicates\r\n\r\n points.push(point);\r\n last = point;\r\n\r\n if (j === pts.length - 1)\r\n point[\"_mask_\"] = true;\r\n }\r\n }\r\n if (this.autoClose\r\n && points.length > 1\r\n && !points[points.length - 1].equals(points[0]))\r\n {\r\n points.push(points[0]);\r\n }\r\n return points;\r\n }\r\n\r\n\r\n absellipse(aX: number, aY: number, xRadius: number, yRadius: number, aStartAngle: number, aEndAngle: number, aClockwise: boolean, aRotation: number): this\r\n {\r\n let curve = new EllipseCurve(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation);\r\n\r\n /*\r\n if (this.curves.length > 0)\r\n {\r\n // if a previous curve is present, attempt to join\r\n let firstPoint = curve.getPoint(0);\r\n if (!equalv2(firstPoint, this.currentPoint))\r\n {\r\n this.lineTo(firstPoint.x, firstPoint.y);\r\n }\r\n }\r\n */\r\n\r\n this.curves.push(curve);\r\n\r\n let lastPoint = curve.getPoint(1);\r\n this.currentPoint.copy(lastPoint);\r\n\r\n return this;\r\n }\r\n}\r\n","import { Vector2, Vector3, Matrix4 } from \"three\";\r\n\r\nexport class Matrix2\r\n{\r\n //column-major\r\n el = [1, 0, 0, 1]; //ix iy jx jy [a c b d]\r\n\r\n set(ix: number, iy: number, jx: number, jy: number)\r\n {\r\n this.el[0] = ix;\r\n this.el[1] = iy;\r\n this.el[2] = jx;\r\n this.el[3] = jy;\r\n }\r\n\r\n applyVector(vec: Vector2 | Vector3)\r\n {\r\n let x = vec.x;\r\n let y = vec.y;\r\n let e = this.el;\r\n vec.x = e[0] * x + e[2] * y;\r\n vec.y = e[1] * x + e[3] * y;\r\n return this;\r\n }\r\n\r\n fromMatrix4(mtx4: Matrix4)\r\n {\r\n this.set(mtx4.elements[0], mtx4.elements[1],\r\n mtx4.elements[3], mtx4.elements[4]\r\n );\r\n }\r\n\r\n setRotate(theta: number): this\r\n {\r\n let c = Math.cos(theta);\r\n let s = Math.sin(theta);\r\n this.set(c, s, -s, c);\r\n return this;\r\n }\r\n\r\n //自我求逆矩阵,返回自身\r\n invert(): this\r\n {\r\n //ref:https://www.mathsisfun.com/algebra/matrix-inverse.html\r\n let [a, c, b, d] = this.el;\r\n let det = 1 / (a * d - b * c);\r\n this.set(d * det, -c * det,\r\n -b * det, a * det\r\n );\r\n return this;\r\n }\r\n}\r\n","import { Matrix2 } from './Matrix2';\r\n\r\nlet r = new Matrix2();\r\nexport function RotateUVs(geo: THREE.Geometry)\r\n{\r\n r.set(0, -1,\r\n 1, 0);\r\n\r\n for (let uvs of geo.faceVertexUvs)\r\n {\r\n for (let uv of uvs)\r\n {\r\n for (let v of uv)\r\n r.applyVector(v);\r\n }\r\n }\r\n geo.uvsNeedUpdate = true;\r\n}\r\n","import { ExtrudeGeometry, Matrix4, Mesh, Shape, Vector2 } from 'three';\r\nimport { Shape2 } from '../../DatabaseServices/Shape2';\r\nimport { AsVector3, equaln, polar } from '../../Geometry/GeUtils';\r\nimport { RotateUVs } from '../../Geometry/RotateUV';\r\n\r\nexport namespace CreateBoardUtil\r\n{\r\n //解析二维圆弧\r\n export class Arc2d\r\n {\r\n _StartAn: number;\r\n _EndAn: number;\r\n _StartPoint: Vector2;\r\n _EndPoint: Vector2;\r\n _Center: Vector2;\r\n _Radius: number;\r\n constructor(p1: Vector2, p2: Vector2, bul: number)\r\n {\r\n this._StartPoint = p1.clone();\r\n this._EndPoint = p2.clone();\r\n\r\n let vec: Vector2 = p2.clone().sub(p1);\r\n let len = vec.length();\r\n let an = vec.angle();\r\n this._Radius = len / Math.sin(2 * Math.atan(bul)) / 2;\r\n let allAngle = Math.atan(bul) * 4;\r\n let delDis = bul * len / 2;\r\n let toDis = this._Radius - delDis;\r\n an += Math.PI * 0.5;\r\n\r\n this._Center = p1.clone().add(p2);\r\n this._Center.multiplyScalar(0.5);\r\n\r\n polar(this._Center, an, toDis);\r\n\r\n this._StartAn = p1.clone().sub(this._Center).angle();\r\n this._EndAn = p2.clone().sub(this._Center).angle();\r\n if (bul < 0)\r\n {\r\n //一个神奇的特性 它需要这么做\r\n this._StartAn -= Math.PI;\r\n this._EndAn -= Math.PI;\r\n }\r\n }\r\n }\r\n\r\n\r\n //创建轮廓 通过点表和凸度\r\n export function CreatePath(pts: Vector2[], buls: number[]): Shape\r\n {\r\n let shape = new Shape2();\r\n if (pts.length === 0) return shape;\r\n let firstPt = pts[0];\r\n\r\n shape.moveTo(firstPt.x, firstPt.y);\r\n for (let i = 0; i < pts.length - 1; i++)\r\n {\r\n let nextPt = pts[i + 1];\r\n if (equaln(buls[i], 0, 1e-8))\r\n {\r\n shape.lineTo(nextPt.x, nextPt.y);\r\n }\r\n else\r\n {\r\n let pt = pts[i];\r\n //参考\r\n //http://www.dorodnic.com/blog/tag/three-js/ 绘制一个齿轮\r\n //https://www.kirupa.com/html5/drawing_circles_canvas.htm //html5\r\n let arc2 = new Arc2d(pt, nextPt, buls[i]);\r\n let cen = arc2._Center;\r\n shape.absarc(cen.x, cen.y, arc2._Radius, arc2._StartAn, arc2._EndAn, buls[i] < 0);\r\n }\r\n }\r\n return shape;\r\n }\r\n\r\n //创建板件 暂时这么写\r\n export function createBoard(boardData: object)\r\n {\r\n var pts: Vector2[] = new Array();\r\n var buls: number[] = new Array();\r\n var boardPts = boardData[\"Pts\"];\r\n var boardBuls = boardData[\"Buls\"];\r\n\r\n let boardHeight = boardData[\"H\"];\r\n\r\n var boardMat = new Matrix4();\r\n var matInv: Matrix4 = new Matrix4();\r\n //InitBoardMat\r\n {\r\n\r\n var xD = AsVector3(boardData[\"XVec\"]);\r\n var yD = AsVector3(boardData[\"YVec\"]);\r\n var ZD = AsVector3(boardData[\"ZVec\"]);\r\n var pBase = AsVector3(boardData[\"BasePoint\"]).multiplyScalar(0.001);\r\n\r\n boardMat.makeBasis(xD, yD, ZD);\r\n boardMat.setPosition(pBase);\r\n matInv.getInverse(boardMat);\r\n }\r\n\r\n for (let i = 0; i < boardPts.length; i++)\r\n {\r\n var pt = AsVector3(boardPts[i]).multiplyScalar(0.001);\r\n pt.applyMatrix4(matInv);\r\n pts.push(new Vector2(pt.x, pt.y));\r\n buls.push(boardBuls[i]);\r\n }\r\n\r\n var sp = CreatePath(pts, buls);\r\n var extrudeSettings = {\r\n steps: 1,\r\n bevelEnabled: false,\r\n amount: boardHeight * 0.001\r\n };\r\n\r\n var ext = new ExtrudeGeometry(sp, extrudeSettings);\r\n ext.translate(0, 0, -boardHeight * 0.001);\r\n ext.applyMatrix4(boardMat);\r\n\r\n if (boardData[\"BoardName\"] === \"地脚线\")\r\n {\r\n RotateUVs(ext);\r\n }\r\n\r\n var mesh = new Mesh(ext);\r\n return mesh;\r\n }\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { angle, clampRad, equalv3 } from \"./GeUtils\";\r\n\r\n//顶点\r\nexport interface Vertice\r\n{\r\n //位置\r\n position: Vector3;\r\n //路径\r\n routes: Route[];\r\n}\r\n\r\n//路线\r\nexport interface Route\r\n{\r\n curve: Curve; //路线的曲线\r\n from: Vertice;\r\n to: Vertice; //终点的点\r\n length: number;\r\n isReverse: boolean;\r\n an?: number; //角度\r\n\r\n s: Vector3;\r\n e: Vector3;\r\n}\r\n\r\n/**\r\n * 曲线连接图\r\n * 所有的顶点和边的关系\r\n */\r\nexport class CurveMap\r\n{\r\n constructor(\r\n public numdimensions = 4,\r\n public _RemoveSortLine = false,\r\n private multiplier = 10 ** numdimensions,\r\n ) { }\r\n\r\n /*\r\n 节点图.\r\n 每个节点对应下一个路口的路线表.\r\n 路口表使用逆时针排序,起始角度使用正x轴.\r\n */\r\n _VerticeMap = new Map();\r\n\r\n _Vertices: Vertice[] = [];\r\n\r\n /**\r\n * 得到节点图的所有站点列表\r\n */\r\n get Stands(): Vertice[]\r\n {\r\n return this._Vertices;\r\n }\r\n\r\n /**\r\n * @param curve\r\n * @param [isArc=curve instanceof Arc]\r\n * @param [removeDuplicate=false]\r\n * @returns 加入成功?\r\n */\r\n AddCurveToMap(curve: Curve, isArc: boolean = curve instanceof Arc, removeDuplicate: boolean = false, parseAngle = false): boolean\r\n {\r\n let sp = curve.StartPoint;\r\n let ep = curve.EndPoint;\r\n let startS = this.GetOnlyVertice(sp);\r\n let endS = this.GetOnlyVertice(ep);\r\n\r\n //在面域分析中,路线指向同一个顶点已经没有意义了\r\n if (this._RemoveSortLine && startS === endS)\r\n return false;\r\n\r\n if (removeDuplicate)//删除重复\r\n {\r\n let index = startS.routes.findIndex(r =>\r\n {\r\n if (r.to === endS && r.curve.constructor.name === curve.constructor.name)\r\n {\r\n if (isArc)\r\n return equalv3(curve.GetPointAtParam(0.5), r.curve.GetPointAtParam(0.5));\r\n return true;\r\n }\r\n });\r\n if (index !== -1) return false;\r\n }\r\n\r\n let length = curve.Length;\r\n curve.TempData = 0;\r\n\r\n let routeS2E: Route = { curve, isReverse: false, length, from: startS, to: endS, s: sp, e: ep };\r\n let routeE2S: Route = { curve, isReverse: true, length, from: endS, to: startS, e: sp, s: ep };\r\n\r\n if (!isArc && parseAngle)\r\n {\r\n let an = angle(endS.position.clone().sub(startS.position));\r\n routeS2E.an = an;\r\n routeE2S.an = clampRad(an + Math.PI);\r\n }\r\n startS.routes.push(routeS2E);\r\n endS.routes.push(routeE2S);\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * 获得唯一的顶点\r\n */\r\n GetOnlyVertice(p: Vector3): Vertice\r\n {\r\n let gp = this.GenerateP(p);\r\n if (this._VerticeMap.has(gp))\r\n return this._VerticeMap.get(gp);\r\n\r\n let vertice: Vertice = { position: gp, routes: [] };\r\n this._VerticeMap.set(p, vertice);\r\n this._Vertices.push(vertice);\r\n return vertice;\r\n }\r\n\r\n _LookupTable: { [key: string]: Vector3; } = {};\r\n\r\n /**\r\n * 生成一个唯一的向量.\r\n */\r\n GenerateP(p: Vector3): Vector3\r\n {\r\n let key = \"\";\r\n let els = p.toArray();\r\n for (let n of els)\r\n {\r\n let valueQuantized = Math.round(n * this.multiplier);\r\n key += valueQuantized + '/';\r\n }\r\n\r\n if (key in this._LookupTable)\r\n return this._LookupTable[key];\r\n\r\n let hashparts = els.map((el) =>\r\n {\r\n let q0 = Math.floor(el * this.multiplier);\r\n let q1 = q0 + 1;\r\n return ['' + q0 + '/', '' + q1 + '/'];\r\n });\r\n\r\n let numelements = els.length;\r\n let numhashes = 1 << numelements;\r\n for (let hashmask = 0; hashmask < numhashes; ++hashmask)\r\n {\r\n let hashmaskShifted = hashmask;\r\n key = '';\r\n hashparts.forEach(function (hashpart)\r\n {\r\n key += hashpart[hashmaskShifted & 1];\r\n hashmaskShifted >>= 1;\r\n });\r\n this._LookupTable[key] = p;\r\n }\r\n return p;\r\n }\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { arrayLast, arrayRemoveIf, arrayRemoveOnce } from \"../Common/ArrayExt\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { Polyline } from \"../DatabaseServices/Entity/Polyline\";\r\nimport { CurveMap, Route, Vertice } from \"./CurveMap\";\r\nimport { angle } from \"./GeUtils\";\r\n\r\n//区域的路线表 表示了一个区域\r\ntype RegionRouteS = Route[][];\r\n\r\n/**\r\n面域分析,基于最小循环图重新实现的版本,拓展了实现求最大轮廓。\r\n当最大轮廓=最小轮廓时,只绘制最大轮廓(独立轮廓无分裂)。\r\n\r\n算法只实现去重模式,业务场景应该没有非去重模式。\r\n如果需要非去重模式,那么应该获取到多个CurveMap,然后对多个CurveMap进行面域分析,得出多个重叠的面域。\r\n */\r\nexport class RegionParse\r\n{\r\n //区域列表 通常是外轮廓\r\n RegionsOutline: RegionRouteS = [];\r\n //区域列表 通常是内轮廓\r\n RegionsInternal: RegionRouteS = [];\r\n\r\n //碎线 曲线进入到这里会被炸开.\r\n ExpLineMap: Map = new Map();\r\n\r\n private _CurveCount: number;\r\n\r\n /**\r\n * @param cuList 请不要传递圆和椭圆.\r\n * @param [numDimensions=3] 精度:小数点后个数\r\n * @param [removeDuplicate=true] 删除重复(现在必须是true,请不要修改它)\r\n */\r\n constructor(cuList: Curve[], public numDimensions = 3, private removeDuplicate = true)\r\n {\r\n //需要搜索的站\r\n let vertices = this.GenerateVerticeMap(cuList);\r\n\r\n //移除细丝\r\n while (true)\r\n {\r\n let v = vertices.find(v => v.routes.length < 2);\r\n if (v) this.RemoveFilamentAt(v, vertices);\r\n else break;\r\n }\r\n let lowerVertice: Vertice;\r\n while (vertices.length > 0)\r\n {\r\n lowerVertice = lowerVertice?.routes.length > 1 ? lowerVertice : this.FindLowerLeftStand(vertices);\r\n let minWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Min);\r\n let maxWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Max);\r\n\r\n this.RemoveEdge(minWalk[0]);\r\n this.RemoveFilamentAt(minWalk[0].from, vertices);\r\n this.RemoveFilamentAt(minWalk[0].to, vertices);\r\n\r\n minWalk = ReduceWalk(minWalk);\r\n maxWalk = ReduceWalk(maxWalk);\r\n if (maxWalk.length > 1)\r\n {\r\n this.RegionsOutline.push(maxWalk);\r\n if (minWalk.length === maxWalk.length && minWalk.every((w1, index) => w1 === maxWalk[index]))//大小重叠\r\n {\r\n //直接remove,不用计算引用个数\r\n for (let w of minWalk)\r\n {\r\n this.RemoveEdge(w);\r\n this.RemoveFilamentAt(w.from, vertices);\r\n this.RemoveFilamentAt(w.to, vertices);\r\n }\r\n continue;//继续循环\r\n }\r\n else\r\n for (let w of maxWalk)\r\n w.curve.TempData = 1;\r\n }\r\n\r\n if (minWalk.length > 1)// && minWalk.every(w => (w.curve.TempData) < 2) 没有重复线应该不会被用2次\r\n {\r\n this.RegionsInternal.push(minWalk);\r\n for (let w of minWalk)\r\n {\r\n w.curve.TempData++;\r\n if (w.curve.TempData === 2)\r\n {\r\n this.RemoveEdge(w);\r\n this.RemoveFilamentAt(w.from, vertices);\r\n this.RemoveFilamentAt(w.to, vertices);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n RemoveFilamentAt(v: Vertice, vertices: Vertice[])\r\n {\r\n let current = v;\r\n while (current && current.routes.length < 2)\r\n {\r\n vertices = arrayRemoveOnce(vertices, current);\r\n let r = current.routes[0];\r\n if (r)\r\n {\r\n this.RemoveEdge(r);\r\n current = r.to;\r\n }\r\n else\r\n current = undefined;\r\n }\r\n }\r\n\r\n RemoveEdge(r: Route)\r\n {\r\n let index = r.from.routes.findIndex(rr => rr.curve === r.curve);\r\n if (index !== -1)\r\n r.from.routes.splice(index, 1);\r\n\r\n index = r.to.routes.findIndex(rr => rr.curve === r.curve);\r\n if (index !== -1)\r\n r.to.routes.splice(index, 1);\r\n }\r\n\r\n /**\r\n * 找到最下方并且最左边的站 yx\r\n */\r\n private FindLowerLeftStand(vertices: Vertice[]): Vertice\r\n {\r\n return vertices.reduce((m, v) =>\r\n {\r\n let dy = v.position.y - m.position.y;\r\n if (dy < 0) return v;\r\n if (dy > 0) return m;\r\n return v.position.x - m.position.x < 0 ? v : m;\r\n });\r\n }\r\n\r\n /**\r\n * 构造路线图. 每个节点对应下一个路口的路线表. 路口表使用逆时针排序,起始角度使用正x轴.\r\n * @returns 所有的顶点\r\n */\r\n private GenerateVerticeMap(curveList: Curve[]): Array\r\n {\r\n let curveMap = new CurveMap(this.numDimensions, true);\r\n\r\n //将多段线炸开\r\n let plcus: Curve[] = [];\r\n arrayRemoveIf(curveList, c =>\r\n {\r\n if (c instanceof Polyline)\r\n {\r\n let cus = c.Explode();\r\n\r\n //如果为圆弧,提前打断\r\n let arcs: Arc[] = [];\r\n arrayRemoveIf(cus, c =>\r\n {\r\n if (c.Length < 1e-5) return true;\r\n\r\n if (c instanceof Arc)\r\n {\r\n let arcBrs = this.BreakArc(c);\r\n for (let arc of arcBrs)\r\n arcs.push(arc);\r\n }\r\n\r\n return false;\r\n });\r\n //加入到计算\r\n cus.push(...arcs);\r\n\r\n this.ExpLineMap.set(c, cus);\r\n plcus.push(...cus);\r\n return true;\r\n }\r\n return false;\r\n });\r\n curveList.push(...plcus);\r\n\r\n this._CurveCount = curveList.length;\r\n\r\n for (let cu of curveList)\r\n {\r\n //由于圆弧可能导致最低点计算错误的问题.\r\n if (cu instanceof Arc)\r\n {\r\n let arcs = this.BreakArc(cu);\r\n if (arcs.length > 1)\r\n {\r\n arcs.forEach(a => curveMap.AddCurveToMap(a, true, this.removeDuplicate, true));\r\n this.ExpLineMap.set(cu, arcs);\r\n continue;\r\n }\r\n else\r\n curveMap.AddCurveToMap(cu, true, this.removeDuplicate, true);\r\n }\r\n else\r\n curveMap.AddCurveToMap(cu, false, this.removeDuplicate, true);\r\n }\r\n\r\n //排序,根据角度逆时针排序.\r\n for (let v of curveMap._Vertices)\r\n {\r\n let minLength = Infinity;\r\n for (let r of v.routes)\r\n if (r.length < minLength) minLength = r.length;\r\n for (let r of v.routes)\r\n CalcRouteAngle(r, minLength * 0.2);\r\n v.routes.sort((r1, r2) => r1.an - r2.an);\r\n }\r\n return curveMap.Stands;\r\n }\r\n\r\n private BreakArc(arc: Arc): Arc[]\r\n {\r\n let underPt = arc.Center.add(new Vector3(0, -arc.Radius));\r\n let param = arc.GetParamAtPoint(underPt);\r\n if (param > 0.01 && param < 0.99)\r\n return arc.GetSplitCurves(param);\r\n else\r\n return [arc];\r\n }\r\n\r\n /**\r\n * 曲线是否已经被算法使用\r\n */\r\n GetCueveUsed(cu: Curve): boolean\r\n {\r\n if (this.ExpLineMap.has(cu))\r\n {\r\n let use = this.ExpLineMap.get(cu).some(c => c.TempData > 0);\r\n if (!use)\r\n this.ExpLineMap.delete(cu);\r\n return use;\r\n }\r\n else\r\n return cu.TempData > 0;\r\n }\r\n}\r\n\r\nfunction CalcRouteAngle(r: Route, length: number)\r\n{\r\n if (r.an !== undefined) return;\r\n let cu = r.curve;\r\n let p = r.isReverse ?\r\n cu.GetPointAtParam(cu.GetParamAtDist(r.length - length))\r\n : cu.GetPointAtParam(cu.GetParamAtDist(length));\r\n r.an = angle(p.sub(r.from.position));\r\n}\r\n\r\nenum WalkType\r\n{\r\n Min = 1,\r\n Max = -1,\r\n}\r\n\r\nfunction ClosedWalkFrom(startVertice: Vertice, maxRoute: number, type = WalkType.Min): Route[]\r\n{\r\n let walk: Route[] = [];\r\n let curVertice: Vertice = startVertice;\r\n let preRoute: Route;\r\n // console.log(\"start\", type, startVertice.position.toArray());\r\n do\r\n {\r\n let route = GetNextRoute(curVertice, preRoute, type);\r\n if (type === WalkType.Max && route.curve.TempData > 0)\r\n return [];\r\n // console.log(route.to.position.toArray());\r\n walk.push(route);\r\n [curVertice, preRoute] = [route.to, route];\r\n if (walk.length > maxRoute * 2)\r\n throw \"超过计算次数限制\";\r\n }\r\n while (curVertice !== startVertice);\r\n\r\n return walk;\r\n}\r\n\r\n/**\r\n * 删除中途回路\r\n */\r\nfunction ReduceWalk(w: Route[]): Route[]\r\n{\r\n if (w.length === 0) return w;\r\n //未构成回路,直接回家\r\n if (w[0].curve === arrayLast(w).curve) return [];\r\n\r\n for (let i = 0; i < w.length; i++)\r\n {\r\n let r1 = w[i];\r\n for (let j = w.length; j--;)\r\n {\r\n if (i === j) break;\r\n let r2 = w[j];\r\n if (r1.to === r2.to)\r\n {\r\n if (j > i)\r\n w.splice(i + 1, j - i);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return w;\r\n}\r\n\r\nfunction GetNextRoute(v: Vertice, prev?: Route, type: WalkType = WalkType.Min): Route\r\n{\r\n if (!prev)\r\n return arrayLast(v.routes); //顺时针 cw \\|/ 从左往右\r\n\r\n //逆时针 ccw 往左\r\n let index = v.routes.findIndex(r => r.curve === prev.curve);\r\n let newIndex = FixIndex(index + 1 * type, v.routes);\r\n return v.routes[newIndex];\r\n}\r\n","import { Vector3 } from 'three';\r\nimport { Circle } from '../DatabaseServices/Entity/Circle';\r\nimport { Curve } from '../DatabaseServices/Entity/Curve';\r\nimport { Ellipse } from '../DatabaseServices/Entity/Ellipse';\r\nimport { Polyline } from '../DatabaseServices/Entity/Polyline';\r\nimport { IntersectOption } from './IntersectWith';\r\n\r\nexport enum BoolOpeartionType\r\n{\r\n Intersection = 0,\r\n Union = 1,\r\n Subtract = 2\r\n}\r\n\r\nconst fuzz = 1e-3;\r\nlet fuzzV3 = new Vector3(fuzz, fuzz, fuzz);\r\n\r\n//判断曲线是否在源封闭曲线内\r\nexport function isTargetCurInOrOnSourceCur(sourceCur: Polyline | Circle | Ellipse, targetCur: Curve)\r\n{\r\n if (!sourceCur.BoundingBox.expandByVector(fuzzV3).containsBox(targetCur.BoundingBox))\r\n return false;\r\n\r\n let cus: Curve[] = [];\r\n if (targetCur instanceof Polyline)\r\n cus = targetCur.Explode();\r\n else\r\n cus = [targetCur];\r\n\r\n return cus.every(c =>\r\n {\r\n let pts = getIntPtContextPts(sourceCur, c);\r\n if (pts.length <= 1)\r\n pts.push(c.StartPoint, c.EndPoint);\r\n return IsPtsAllInOrOnReg(sourceCur, pts);\r\n });\r\n}\r\n\r\n//获取交点处上下距0.01par的点\r\nfunction getIntPtContextPts(sourceCur: Curve, cu: Curve, pts: Vector3[] = [])\r\n{\r\n let interPts = cu.IntersectWith(sourceCur, IntersectOption.OnBothOperands);\r\n if (interPts.length > 0)\r\n {\r\n let pars = interPts.map(pt => cu.GetParamAtPoint(pt));\r\n for (let par of pars)\r\n {\r\n if (par >= 0.02)\r\n pts.push(cu.GetPointAtParam(par - 0.01));\r\n\r\n if (par <= (cu.EndParam - 0.02))\r\n pts.push(cu.GetPointAtParam(par + 0.01));\r\n }\r\n }\r\n return pts;\r\n}\r\n//判断点点是否全部都在封闭区域内或者在曲线上\r\nfunction IsPtsAllInOrOnReg(sourceReg: Polyline | Circle | Ellipse, pts: Vector3[])\r\n{\r\n return pts.every(pt =>\r\n {\r\n //是否点在封闭曲线内\r\n return sourceReg.PtOnCurve(pt) || sourceReg.PtInCurve(pt);\r\n });\r\n}\r\n\r\n//判断点是否全部都在封闭区域外或者在曲线上\r\nexport function IsPtsAllOutOrOnReg(sourceReg: Polyline | Circle, pts: Vector3[])\r\n{\r\n return pts.every(pt =>\r\n {\r\n //是否点在封闭曲线内\r\n return sourceReg.PtOnCurve(pt) || !sourceReg.PtInCurve(pt);\r\n });\r\n}\r\n","import { Line, Material, Object3D, Shape, Vector3 } from 'three';\r\nimport { arrayRemoveDuplicateBySort, arraySortByNumber } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { Status } from '../../Common/Status';\r\nimport { equaln, equalv3 } from '../../Geometry/GeUtils';\r\nimport { IntersectOption, IntersectResult } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { DragPointType } from './DragPointType';\r\nimport { Entity } from './Entity';\r\n\r\nexport enum ExtendType\r\n{\r\n /**\r\n * 前后都不延伸\r\n */\r\n None = 0,\r\n /**\r\n * 只允许延伸前面\r\n */\r\n Front = 1,\r\n /**\r\n * 只允许延伸后面\r\n */\r\n Back = 2,\r\n /**\r\n * 前后延伸\r\n */\r\n Both = 3,\r\n}\r\n\r\n/**\r\n * 曲线的基类,子类请实现以下方法.\r\n */\r\n@Factory\r\nexport abstract class Curve extends Entity\r\n{\r\n constructor()\r\n {\r\n super();\r\n }\r\n\r\n get Is2D()\r\n {\r\n return equaln(this._Matrix.elements[14], 0);\r\n }\r\n\r\n get StartPoint(): Vector3 { return; }\r\n set StartPoint(v: Vector3) { return; }\r\n get StartParam(): number { return; }\r\n get EndPoint(): Vector3 { return; }\r\n set EndPoint(v: Vector3) { return; }\r\n\r\n /** 曲线中点 */\r\n get Midpoint()\r\n {\r\n return this.GetPointAtParam(this.MidParam);\r\n }\r\n\r\n get MidParam()\r\n {\r\n if (this.EndParam === 1)\r\n return 0.5;\r\n else\r\n return this.GetParamAtDist(this.Length * 0.5);\r\n }\r\n\r\n get EndParam(): number { return; }\r\n get Area(): number { return 0; }\r\n /**\r\n *获得曲线的面积,逆时针为正,顺时针为负.\r\n */\r\n get Area2(): number { return 0; }\r\n get Length(): number { return 0; }\r\n get IsClose(): boolean { return false; }\r\n /** 曲线为顺时针 */\r\n get IsClockWise(): boolean { return this.Area2 < 0; }\r\n\r\n abstract get Shape(): Shape;\r\n\r\n GetPointAtParam(param: number): Vector3 { return; }\r\n GetPointAtDistance(distance: number): Vector3 { return; }\r\n GetDistAtParam(param: number): number { return; }\r\n GetDistAtPoint(pt: Vector3): number { return; }\r\n GetParamAtPoint(pt: Vector3): number { return; }\r\n GetParamAtPoint2(pt: Vector3): number { return this.GetParamAtPoint(pt); }\r\n\r\n GetParamAtDist(d: number): number { return; }\r\n\r\n /**\r\n * 返回曲线在指定位置的一阶导数(在wcs内)\r\n *\r\n * @param {(number | Vector3)} param\r\n * @returns {Vector3}\r\n * @memberof Curve\r\n */\r\n GetFistDeriv(param: number | Vector3): Vector3 { return; }\r\n GetFistDerivAngle(param: number | Vector3): number\r\n {\r\n let d = this.GetFistDeriv(param);\r\n return Math.atan2(d.y, d.x);\r\n }\r\n\r\n /**\r\n * 返回切割曲线后的结果.总是从起点开始切割,并且按顺序返回曲线.\r\n * @param {(number[] | number)} param\r\n * @returns {Array}\r\n */\r\n GetSplitCurves(param: number[] | number): Array { return; }\r\n //未完善\r\n GetCurveAtParamRange(startParam: number, EndParam: number): Array { return; }\r\n GetSplitCurvesByPts(pt: Vector3[] | Vector3): Array\r\n {\r\n let pts = Array.isArray(pt) ? pt : [pt];\r\n let pars = pts.map(p => this.GetParamAtPoint(p));\r\n return this.GetSplitCurves(pars);\r\n }\r\n protected SplitParamSort(param: number[] | number): number[]\r\n {\r\n if (Array.isArray(param))\r\n {\r\n param = param.filter(p => this.ParamOnCurve(p));\r\n if (param.length === 0)\r\n return [];\r\n param.push(0, this.EndParam);\r\n arraySortByNumber(param);\r\n arrayRemoveDuplicateBySort(param, (e1, e2) => equaln(e1, e2, 1e-7));\r\n return param;\r\n }\r\n else if (this.ParamOnCurve(param))\r\n return [0, param, this.EndParam];\r\n else\r\n return [];\r\n }\r\n Extend(newParam: number) { }\r\n /**\r\n * 连接曲线到本曲线,如果成功返回true\r\n * @param {Curve} cu 需要连接的曲线\r\n * @returns {boolean} 连接成功\r\n * @memberof Curve\r\n */\r\n Join(cu: Curve, allowGap = false, tolerance = 1e-4): Status { return Status.False; }\r\n\r\n //翻转曲线.首尾调换.\r\n Reverse(): this { return this; }\r\n\r\n //点在曲线上\r\n PtOnCurve(pt: Vector3, fuzz = 1e-6): boolean\r\n {\r\n return equalv3(this.StartPoint, pt, fuzz) || equalv3(this.EndPoint, pt, fuzz) || this.ParamOnCurve(this.GetParamAtPoint(pt));\r\n }\r\n\r\n //点在曲线中,不在起点或者终点.\r\n PtOnCurve2(pt: Vector3): boolean\r\n {\r\n return !(equalv3(this.StartPoint, pt, 1e-6) || equalv3(this.EndPoint, pt, 1e-6)) && this.ParamOnCurve(this.GetParamAtPoint(pt), 0);\r\n }\r\n\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n return this.PtOnCurve(p, fuzz);\r\n }\r\n\r\n //参数在曲线上 容差,1e-6\r\n ParamOnCurve(param: number, fuzz = 1e-6): boolean { return !isNaN(param) && param >= -fuzz && param <= this.EndParam + fuzz; }\r\n GetOffsetCurves(offsetDist: number): Array { return; }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { return; }\r\n\r\n /**\r\n * 曲线相交点\r\n */\r\n IntersectWith(curve: Curve, intType: IntersectOption, tolerance = 1e-6): Vector3[]\r\n {\r\n return this.IntersectWith2(curve, intType, tolerance).map(r => r.pt);\r\n }\r\n\r\n /**\r\n * 曲线相交点和点的参数\r\n */\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-6): IntersectResult[] { return []; }\r\n\r\n\r\n /**\r\n * 拽托点个数\r\n */\r\n GetDragPointCount(drag: DragPointType): number { return 0; }\r\n\r\n //------------------绘制相关------------------\r\n //重载\r\n protected OnlyRenderType = true;\r\n\r\n /**\r\n * 重载:更新实体材质\r\n */\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material?: Material)\r\n {\r\n let m = obj as Line;\r\n m.material = material || ColorMaterial.GetLineMaterial(this._Color);\r\n }\r\n\r\n UpdateJigMaterial(color = 8)\r\n {\r\n for (let [type, obj] of this._CacheDrawObject)\r\n {\r\n this.UpdateDrawObjectMaterial(type, obj, ColorMaterial.GetLineMaterial(color));\r\n }\r\n }\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { arrayLast, arrayRemoveDuplicateBySort } from \"../Common/ArrayExt\";\r\nimport { curveLinkGroup, equalCurve } from \"../Common/CurveUtils\";\r\nimport { Status } from \"../Common/Status\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\nimport { IntersectBox2 } from \"../Geometry/Box\";\r\nimport { Route } from \"../Geometry/CurveMap\";\r\nimport { equaln, equalv3 } from \"../Geometry/GeUtils\";\r\nimport { RegionParse } from \"../Geometry/RegionParse\";\r\nimport { isTargetCurInOrOnSourceCur } from \"../GraphicsSystem/BoolOperateUtils\";\r\nimport { IntersectOption } from \"../GraphicsSystem/IntersectWith\";\r\nimport { Arc } from \"./Entity/Arc\";\r\nimport { Circle } from \"./Entity/Circle\";\r\nimport { Curve } from \"./Entity/Curve\";\r\nimport { Polyline } from \"./Entity/Polyline\";\r\n\r\nlet cache = new WeakMap();\r\n\r\nconst COMBINE_FUZZ = 1e-2;\r\n\r\nexport class Contour\r\n{\r\n private _Curve: Polyline | Circle;\r\n\r\n protected SetCurve(cu: Polyline | Circle)\r\n {\r\n if (cu instanceof Polyline)\r\n {\r\n if (cu.Area2 < 0)\r\n cu.Reverse();\r\n }\r\n this._Curve = cu;\r\n }\r\n /**会将传入的闭合轮廓改为逆时针 */\r\n static CreateContour(cus: Curve[] | Polyline | Circle, needLink = true)\r\n {\r\n if (cus instanceof Curve)\r\n {\r\n if (cus.IsClose)\r\n {\r\n let c = new Contour();\r\n c.SetCurve(cus);\r\n return c;\r\n }\r\n return;\r\n }\r\n\r\n let closeCurve = Contour.Combine(cus, needLink, COMBINE_FUZZ) as Polyline | Circle;\r\n if (closeCurve && closeCurve.IsClose)\r\n {\r\n if (closeCurve instanceof Polyline && closeCurve.CloseMark === false)\r\n {\r\n closeCurve.CloseMark = true;\r\n closeCurve.RemoveVertexAt(closeCurve.NumberOfVertices - 1);\r\n }\r\n\r\n let c = new Contour();\r\n c.SetCurve(closeCurve);\r\n return c;\r\n }\r\n }\r\n get Curve(): Polyline | Circle\r\n {\r\n return this._Curve;\r\n }\r\n get Area()\r\n {\r\n return this._Curve.Area;\r\n }\r\n get BoundingBox()\r\n {\r\n return this._Curve.BoundingBox;\r\n }\r\n /**\r\n * 不等比例缩放\r\n * @param {number} ref 缩放参考值,大于该值的点缩放\r\n * @param {number} dist 缩放距离\r\n * @param {string} dir x y z\r\n */\r\n UnEqualProportionScale(ref: number, dist: number, dir: \"x\" | \"y\")\r\n {\r\n let cu = this._Curve;\r\n if (cu instanceof Polyline)\r\n {\r\n let lineData = cu.LineData;\r\n let length = lineData.length;\r\n let p = cu.Position[dir];\r\n\r\n let moveIndexs: number[] = [];\r\n for (let i = 0; i < length; i++)\r\n {\r\n if (lineData[i].pt[dir] + p > ref)\r\n moveIndexs.push(i);\r\n }\r\n let moveVec = new Vector3();\r\n moveVec[dir] = dist;\r\n cu.MoveStretchPoints(moveIndexs, moveVec);\r\n return true;\r\n }\r\n return false;\r\n }\r\n Clone()\r\n {\r\n return Contour.CreateContour([this._Curve.Clone()]);\r\n }\r\n //交集:结果数组为空则失败\r\n IntersectionBoolOperation(target: Contour): Contour[]\r\n {\r\n if (!IntersectBox2(this.BoundingBox, target.BoundingBox))\r\n return [];\r\n let resultCus = this.GetIntersetAndUnionList(target);\r\n return Contour.GetAllContour(resultCus.intersectionList);\r\n }\r\n //并集:结果轮廓数组长度大于2,则失败.等于1则成功.\r\n UnionBoolOperation(target: Contour): { contours: Contour[], holes: Contour[]; }\r\n {\r\n let resultCus = this.GetIntersetAndUnionList(target);\r\n\r\n //快速\r\n if (resultCus.unionList.every(c => c.IsClose))\r\n return {\r\n contours: Contour.GetAllContour(resultCus.unionList),\r\n holes: [],\r\n };\r\n\r\n //并集后的线段表如果有共线的直接合并起来\r\n let cus: Curve[] = [];\r\n for (let pl of resultCus.unionList)\r\n {\r\n if (pl instanceof Polyline)\r\n cus.push(...pl.Explode());\r\n else\r\n cus.push(pl);\r\n }\r\n let cuGroups = curveLinkGroup(cus);\r\n for (let g of cuGroups)\r\n {\r\n for (let i = 0; i < g.length; i++)\r\n {\r\n let c1 = g[i];\r\n let nextI = FixIndex(i + 1, g);\r\n let c2 = g[nextI];\r\n\r\n let status = c1.Join(c2);\r\n if (status === Status.True)\r\n {\r\n g.splice(nextI, 1);\r\n i--;\r\n }\r\n else if (status === Status.ConverToCircle)\r\n {\r\n g.length = 0;\r\n let a = c1 as Arc;\r\n g.push(new Circle(a.Center, a.Radius));\r\n break;\r\n }\r\n }\r\n }\r\n let allContour = Contour.GetAllContour(cuGroups);\r\n if (allContour.length < 2)\r\n {\r\n return {\r\n contours: allContour,\r\n holes: [],\r\n };\r\n }\r\n else\r\n {\r\n let cache = new WeakMap();\r\n for (let c of allContour)\r\n cache.set(c, c.Area);\r\n allContour.sort((a, b) => cache.get(b) - cache.get(a));\r\n return {\r\n contours: [allContour[0]],\r\n holes: allContour.slice(1)\r\n };\r\n }\r\n\r\n }\r\n //差集:等于0完全被减去\r\n SubstactBoolOperation(target: Contour): Contour[]\r\n {\r\n let subtractList = this.GetSubtractList(target);\r\n\r\n //纯网洞\r\n if (subtractList.every(c => c.IsClose))\r\n return Contour.GetAllContour(subtractList);\r\n\r\n let regParse = new RegionParse(subtractList, 2);\r\n\r\n let contours: Contour[] = [];\r\n //分析封闭包围区域\r\n const parseRoute = (routeSet: Array[]) =>\r\n {\r\n for (let routes of routeSet)\r\n {\r\n let cs: Curve[] = routes.map(r => r.curve);\r\n let c = Contour.CreateContour(cs, false);\r\n if (c\r\n && !equalCurve(c.Curve, this.Curve)\r\n && !equalCurve(c.Curve, target.Curve)\r\n && c.Area > 1e-3)\r\n contours.push(c);\r\n }\r\n };\r\n parseRoute(regParse.RegionsOutline);\r\n parseRoute(regParse.RegionsInternal);\r\n\r\n return contours;\r\n }\r\n /**\r\n * 计算与目标轮廓布尔运算后的结果曲线.\r\n */\r\n GetIntersetAndUnionList(target: Contour): { intersectionList: Curve[], unionList: Curve[]; }\r\n {\r\n let intersectionList: Curve[] = [];\r\n let unionList: Curve[] = [];\r\n\r\n let sourceOutline = this._Curve;\r\n let targetOutline = target.Curve;\r\n let isEqualNormal = equalv3(sourceOutline.Normal, targetOutline.Normal, 1e-3);\r\n\r\n let interPts = sourceOutline.IntersectWith2(targetOutline, IntersectOption.OnBothOperands, COMBINE_FUZZ);\r\n\r\n let sourceContainerTarget = this.CuInOutline(targetOutline);\r\n let targetContainerSource = target.CuInOutline(sourceOutline);\r\n\r\n //包含.相交.分离(三种状态)\r\n if (sourceContainerTarget)//源包含目标\r\n {\r\n intersectionList.push(targetOutline);\r\n unionList.push(sourceOutline);\r\n }\r\n else if (targetContainerSource)//目标包含源\r\n {\r\n unionList.push(targetOutline);\r\n intersectionList.push(sourceOutline);\r\n }\r\n else if (interPts.length <= 1)//分离\r\n {\r\n unionList.push(sourceOutline, targetOutline);\r\n }\r\n else//相交 interPts.length > 0\r\n {\r\n let pars1 = interPts.map(r => r.thisParam);\r\n let pars2 = interPts.map(r => r.argParam);\r\n\r\n let sourceCus: Array = sourceOutline.GetSplitCurves(pars1);\r\n let targetCus: Array = targetOutline.GetSplitCurves(pars2);\r\n\r\n for (let pl of sourceCus)\r\n {\r\n let hasEqualCus = false;\r\n for (let i = 0; i < targetCus.length; i++)\r\n {\r\n let cu = targetCus[i];\r\n hasEqualCus = fastEqualCurve(cu, pl);\r\n if (hasEqualCus)\r\n {\r\n //方向相同\r\n if (\r\n equalv3(cu.GetFistDeriv(cu.EndParam * 0.5).normalize(), pl.GetFistDeriv(pl.EndParam * 0.5).normalize(), 1e-3)\r\n === isEqualNormal\r\n )\r\n {\r\n unionList.push(pl);\r\n intersectionList.push(pl);\r\n }\r\n targetCus.splice(i, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (hasEqualCus)\r\n continue;\r\n\r\n if (target.CuInOutline(pl))\r\n intersectionList.push(pl);\r\n else\r\n unionList.push(pl);\r\n }\r\n\r\n for (let pl of targetCus)\r\n {\r\n if (this.CuInOutline(pl))\r\n intersectionList.push(pl);\r\n else\r\n unionList.push(pl);\r\n }\r\n\r\n //特殊的分离\r\n if (intersectionList.length === 0 && unionList.length === (sourceCus.length + targetCus.length))\r\n {\r\n return { intersectionList, unionList: [sourceOutline, targetOutline] };\r\n }\r\n }\r\n return { intersectionList, unionList };\r\n }\r\n GetSubtractList(target: Contour): Polyline[]\r\n {\r\n let sourceOutline = this._Curve as Polyline;\r\n let targetOutline = target.Curve as Polyline;\r\n\r\n let isEqualNormal = equalv3(sourceOutline.Normal, targetOutline.Normal, 1e-3);\r\n\r\n let interPts = sourceOutline.IntersectWith2(targetOutline, IntersectOption.OnBothOperands, COMBINE_FUZZ);\r\n\r\n if (interPts.length <= 1)\r\n {\r\n //反包含\r\n if (fastCurveInCurve2(targetOutline, sourceOutline) || equalCurve(targetOutline, sourceOutline))\r\n return [];\r\n //包含\r\n if (fastCurveInCurve2(sourceOutline, targetOutline))\r\n return [sourceOutline, targetOutline];\r\n else//分离\r\n return [sourceOutline];\r\n }\r\n\r\n //相交\r\n let subtractList: Polyline[] = [];\r\n let sourceCus = sourceOutline.GetSplitCurves(interPts.map(r => r.thisParam)) as Polyline[];\r\n let targetCus = targetOutline.GetSplitCurves(interPts.map(r => r.argParam)) as Polyline[];\r\n\r\n for (let pl of sourceCus)\r\n {\r\n let plMidParam = pl.MidParam;\r\n let plDir = pl.GetFistDeriv(plMidParam).normalize();\r\n\r\n let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl));\r\n if (index !== -1)\r\n {\r\n let cu = targetCus[index];\r\n let cuMidParam = cu.MidParam;\r\n let cuDir = cu.GetFistDeriv(cuMidParam).normalize();\r\n\r\n if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3))//不同向\r\n subtractList.push(pl);\r\n\r\n targetCus.splice(index, 1);\r\n\r\n continue;\r\n }\r\n if (!fastCurveInCurve(targetOutline, pl))\r\n subtractList.push(pl);\r\n }\r\n\r\n //源对象没有被破坏\r\n let sourceNotBreak = subtractList.length === sourceCus.length;\r\n\r\n for (let pl of targetCus)\r\n if (fastCurveInCurve(sourceOutline, pl))\r\n subtractList.push(pl);\r\n\r\n if (sourceNotBreak && subtractList.length === sourceCus.length)\r\n return [sourceOutline];\r\n\r\n return subtractList;\r\n }\r\n GetSubtractListByMoreTargets(targets: Contour[])\r\n {\r\n let { holes, subtractList } = this.GetSubListWithCus(targets);\r\n\r\n //纯网洞\r\n if (subtractList.every(c => c.IsClose))\r\n return {\r\n holes: holes.map(h => Contour.CreateContour(h)),\r\n outlines: Contour.GetAllContour(subtractList)\r\n };\r\n\r\n let regParse = new RegionParse(subtractList, 2);\r\n\r\n let contours: Contour[] = [];\r\n //分析封闭包围区域\r\n const parseRoute = (routeSet: Array[]) =>\r\n {\r\n for (let routes of routeSet)\r\n {\r\n let cs: Curve[] = routes.map(r => r.curve);\r\n let c = Contour.CreateContour(cs, false);\r\n if (c\r\n && !equalCurve(c.Curve, this.Curve)\r\n && targets.every(target => !equalCurve(c.Curve, target.Curve))\r\n && c.Area > 1e-3)\r\n contours.push(c);\r\n }\r\n };\r\n parseRoute(regParse.RegionsOutline);\r\n parseRoute(regParse.RegionsInternal);\r\n\r\n return {\r\n holes: holes.map(h => Contour.CreateContour(h)),\r\n outlines: contours\r\n };\r\n\r\n }\r\n GetSubListWithCus(targets: Contour[])\r\n {\r\n let sourceOutline = this._Curve as Polyline;\r\n let subtractList: Polyline[] = [];\r\n let holes: Polyline[] = [];\r\n let intPars: number[] = [];\r\n let cuMap = new Map();\r\n\r\n let outBox = sourceOutline.BoundingBox;\r\n\r\n for (let con of targets)\r\n {\r\n const targetOutline = con.Curve as Polyline;\r\n\r\n if (!IntersectBox2(outBox, targetOutline.BoundingBox))\r\n continue;\r\n\r\n let pts = sourceOutline.IntersectWith2(con.Curve, IntersectOption.OnBothOperands, COMBINE_FUZZ);\r\n if (pts.length <= 1)\r\n {\r\n //反包含\r\n if (fastCurveInCurve2(targetOutline, sourceOutline) || equalCurve(targetOutline, sourceOutline))\r\n return { holes, subtractList };\r\n //包含\r\n if (fastCurveInCurve2(sourceOutline, targetOutline))\r\n holes.push(targetOutline);\r\n else//分离\r\n {\r\n\r\n }\r\n }\r\n else\r\n {\r\n intPars.push(...pts.map(r => r.thisParam));\r\n cuMap.set(targetOutline, pts.map(r => r.argParam));\r\n }\r\n }\r\n intPars.sort((a, b) => a - b);\r\n arrayRemoveDuplicateBySort(intPars, (e1, e2) => equaln(e1, e2, 1e-8));\r\n let sourceCus = sourceOutline.GetSplitCurves(intPars) as Polyline[];\r\n let targetCus: Polyline[] = [];\r\n\r\n let targetMap = new WeakMap();\r\n\r\n let isEqualNormal: boolean;\r\n\r\n for (let [c, pars] of cuMap)\r\n {\r\n let cus = c.GetSplitCurves(pars) as Polyline[];\r\n cus.forEach(cu => targetMap.set(cu, c));\r\n targetCus.push(...cus);\r\n }\r\n\r\n for (let pl of sourceCus)\r\n {\r\n let plMidParam = pl.MidParam;\r\n let plDir = pl.GetFistDeriv(plMidParam).normalize();\r\n\r\n let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl, 0.05));\r\n if (index !== -1)\r\n {\r\n let cu = targetCus[index];\r\n isEqualNormal = equalv3(sourceOutline.Normal, targetMap.get(cu).Normal, 1e-3);\r\n let cuMidParam = cu.MidParam;\r\n let cuDir = cu.GetFistDeriv(cuMidParam).normalize();\r\n\r\n if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3))//不同向\r\n subtractList.push(pl);\r\n\r\n targetCus.splice(index, 1);\r\n\r\n continue;\r\n }\r\n\r\n if (targets.every(t => !fastCurveInCurve(t.Curve as Polyline, pl)))\r\n subtractList.push(pl);\r\n }\r\n\r\n //源对象没有被破坏\r\n let sourceNotBreak = subtractList.length === sourceCus.length;\r\n\r\n for (let pl of targetCus)\r\n if (fastCurveInCurve(sourceOutline, pl))\r\n subtractList.push(pl);\r\n\r\n if (sourceNotBreak && subtractList.length === sourceCus.length)\r\n return { subtractList: [sourceOutline], holes };\r\n\r\n return { subtractList, holes };\r\n\r\n }\r\n /**\r\n * 获得全部闭合曲线\r\n * @若传入二维曲线数据,将默认子数组为闭合曲线段\r\n */\r\n static GetAllContour(cus: Curve[] | Curve[][]): Contour[]\r\n {\r\n if (cus.length === 0)\r\n return [];\r\n\r\n let cuGroups: Curve[][];\r\n if (Array.isArray(cus[0]))\r\n cuGroups = cus as Curve[][];\r\n else\r\n cuGroups = curveLinkGroup(cus as Curve[]);\r\n\r\n let contours: Contour[] = [];\r\n\r\n for (let g of cuGroups)\r\n contours.push(Contour.CreateContour(g, false));\r\n return contours.filter(c => c !== undefined && !equaln(c.Area, 0, 1e-6));\r\n }\r\n /**\r\n * 合并曲线组成为多段线\r\n * @param cus 曲线组\r\n * @param [needLink=true] 需要解析成首尾连接状态\r\n * @returns 单一曲线,如果返回超过1个,其他的将被遗弃.\r\n */\r\n static Combine(cus: Curve[], needLink = true, tolerance = 1e-3): Curve\r\n {\r\n if (cus.length === 0) return undefined;\r\n\r\n let groups = needLink ? curveLinkGroup(cus) : [cus];\r\n for (let g of groups)\r\n {\r\n if (g.length === 1)\r\n return g[0].Clone();\r\n else\r\n {\r\n if (cache.has(g))\r\n return cache.get(g);\r\n\r\n let gclone = g.map(c => c.Clone());\r\n\r\n arrayRemoveDuplicateBySort(gclone, (cu1: Curve, cu2: Curve) => cu1.Join(cu2, false, tolerance) === Status.True);\r\n\r\n if (gclone.length > 1 && gclone[0].Join(arrayLast(gclone), false, tolerance))\r\n gclone.pop();\r\n\r\n let pl = Polyline.Combine(gclone, tolerance);\r\n\r\n cache.set(g, pl);\r\n\r\n return pl;\r\n }\r\n }\r\n }\r\n get Shape(): THREE.Shape\r\n {\r\n return this._Curve.Shape;\r\n }\r\n CuInOutline(targetCur: Curve)\r\n {\r\n return isTargetCurInOrOnSourceCur(this._Curve, targetCur);\r\n }\r\n Equal(tar: Contour)\r\n {\r\n return equalCurve(this._Curve, tar._Curve);\r\n }\r\n}\r\n\r\n/**\r\n * 对于轮廓切割后的曲线判断相同,使用这个函数进行快速判断\r\n */\r\nfunction fastEqualCurve(c1: Curve, c2: Curve, tolerance = 1e-3)\r\n{\r\n let sp1 = c1.StartPoint;\r\n let ep1 = c1.EndPoint;\r\n let sp2 = c2.StartPoint;\r\n let ep2 = c2.EndPoint;\r\n\r\n if (!(\r\n (equalv3(sp1, sp2, tolerance) && equalv3(ep1, ep2, tolerance))\r\n || (equalv3(sp1, ep2, tolerance) && equalv3(ep1, sp2, tolerance))\r\n ))\r\n return false;\r\n\r\n return equalv3(c1.Midpoint, c2.Midpoint, tolerance);\r\n}\r\n\r\n\r\n//对于双多段线互相切割后的结果,快速判断曲线是否在另一条曲线内部\r\nfunction fastCurveInCurve(sourceCu: Polyline, targetCu: Polyline)\r\n{\r\n return sourceCu.PtInCurve(targetCu.GetPointAtParam(targetCu.EndParam * 0.5));\r\n}\r\n\r\nfunction fastCurveInCurve2(sourceCu: Polyline, targetCu: Polyline)\r\n{\r\n return sourceCu.PtInCurve(targetCu.StartPoint) &&\r\n sourceCu.PtInCurve(targetCu.GetPointAtParam(targetCu.EndParam * 0.5));\r\n}\r\n","import { Line3, Plane, Ray, Vector3 } from \"three\";\r\n\r\nexport class PlaneExt extends Plane\r\n{\r\n constructor(normal = new Vector3(0, 0, 1), constant?: number | Vector3)\r\n {\r\n super(normal);\r\n if (typeof constant === \"number\")\r\n this.constant = constant;\r\n else if (constant)\r\n this.constant = -this.normal.dot(constant);\r\n }\r\n\r\n intersectLine(line: Line3, optionalTarget = new Vector3(), extendLine = false): Vector3\r\n {\r\n let v1 = new Vector3();\r\n\r\n let direction = line.delta(v1);\r\n\r\n let denominator = this.normal.dot(direction);\r\n\r\n if (denominator === 0)\r\n {\r\n // line is coplanar, return origin\r\n if (this.distanceToPoint(line.start) === 0)\r\n {\r\n return optionalTarget.copy(line.start);\r\n }\r\n // Unsure if this is the correct method to handle this case.\r\n return undefined;\r\n }\r\n\r\n let t = - (line.start.dot(this.normal) + this.constant) / denominator;\r\n //If you not extendLine,check intersect point in Line\r\n if (!extendLine && (t < -1e-6 || t > 1))\r\n {\r\n return undefined;\r\n }\r\n\r\n return optionalTarget.copy(direction).multiplyScalar(t).add(line.start);\r\n }\r\n intersectRay(ray: Ray, optionalTarget?: Vector3, extendLine?: boolean): Vector3\r\n {\r\n // 从射线初始位置\r\n let line = new Line3(ray.origin.clone(), ray.origin.clone().add(ray.direction));\r\n return this.intersectLine(line, optionalTarget, extendLine);\r\n }\r\n}\r\n","import { Box3, BufferGeometry, Matrix3, Matrix4, Object3D, Shape, Vector3, Line as TLine, MathUtils } from 'three';\r\nimport { arrayLast, arrayRemoveDuplicateBySort } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { getDeterminantFor2V, getArcOrCirNearPts, getTanPtsOnEllipse, Pts2Polyline } from '../../Common/CurveUtils';\r\nimport { Status } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { angle, equaln, equalv3, MoveMatrix, rotatePoint, angleTo, AsVector2, AsVector3 } from '../../Geometry/GeUtils';\r\nimport { IntersectEllipse, IntersectEllipseAndCircleOrArc, IntersectEllipseAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Arc } from './Arc';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { Circle } from './Circle';\r\nimport { Curve } from './Curve';\r\nimport { Line } from './Line';\r\nimport { Polyline } from './Polyline';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\n\r\n@Factory\r\nexport class Ellipse extends Curve\r\n{\r\n private _radX: number;\r\n private _radY: number;\r\n private _rotate: number;\r\n private _startAngle = 0;\r\n private _endAngle = Math.PI * 2;\r\n constructor(\r\n center?: Vector3,\r\n radX: number = 1e-3,\r\n radY: number = 1e-3,\r\n angle: number = 0)\r\n {\r\n super();\r\n center && this._Matrix.setPosition(center);\r\n this._radX = radX;\r\n this._radY = radY;\r\n this._rotate = angle;\r\n }\r\n get StartParam(): number\r\n {\r\n return 0;\r\n }\r\n get EndParam(): number\r\n {\r\n return 1;\r\n }\r\n get StartPoint()\r\n {\r\n return this.GetPointAtParam(0);\r\n }\r\n get EndPoint()\r\n {\r\n return this.GetPointAtParam(1);\r\n }\r\n get Shape(): Shape\r\n {\r\n let sp = new Shape();\r\n sp.ellipse(0, 0, this._radX, this._radY, this._startAngle, this._endAngle, false, this._rotate);\r\n return sp;\r\n }\r\n get IsClose(): boolean\r\n {\r\n return equaln(this.TotalAngle, Math.PI * 2);\r\n }\r\n get Center()\r\n {\r\n return new Vector3().setFromMatrixPosition(this._Matrix);\r\n }\r\n set Center(v: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Matrix.setPosition(v);\r\n this.Update();\r\n }\r\n get RadX()\r\n {\r\n return this._radX;\r\n }\r\n set RadX(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._radX = v;\r\n this.Update();\r\n }\r\n get RadY()\r\n {\r\n return this._radY;\r\n }\r\n set RadY(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._radY = v;\r\n this.Update();\r\n }\r\n get Rotation()\r\n {\r\n return this._rotate;\r\n }\r\n set Rotation(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._rotate = v;\r\n this.Update();\r\n }\r\n get StartAngle()\r\n {\r\n return this._startAngle;\r\n }\r\n get EndAngle()\r\n {\r\n return this._startAngle;\r\n }\r\n set StartAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._startAngle = v;\r\n this.Update();\r\n }\r\n set EndAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._endAngle = v;\r\n this.Update();\r\n }\r\n get Length()\r\n {\r\n let a = this._radX;\r\n let b = this._radY;\r\n return Math.PI * Math.abs(3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b))) * this.TotalAngle / Math.PI * 0.5;\r\n }\r\n get Area()\r\n {\r\n let area = Math.PI * this._radX * this._radY;\r\n let an = this._endAngle - this._startAngle;\r\n if (an < 0)\r\n an = Math.PI * 2 + an;\r\n area *= an / Math.PI * 0.5;\r\n let area2 = Math.abs(\r\n getDeterminantFor2V(\r\n AsVector2(this.StartPoint.sub(this.Center)),\r\n AsVector2(this.EndPoint.sub(this.Center)))\r\n ) / 2;\r\n if (an < Math.PI)\r\n area -= area2;\r\n else\r\n area += area2;\r\n return area;\r\n }\r\n get TotalAngle()\r\n {\r\n let totolAngle = this._endAngle - this._startAngle;\r\n if (totolAngle < 0)\r\n totolAngle = Math.PI * 2 + totolAngle;\r\n return totolAngle;\r\n }\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3().setFromPoints(this.GetGripPoints());\r\n }\r\n PtInCurve(pt: Vector3)\r\n {\r\n let p = rotatePoint(pt.clone().sub(this.Center), -this.Rotation);\r\n return p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2 < 1;\r\n }\r\n PtOnCurve(pt: Vector3)\r\n {\r\n if (this.PtOnEllipse(pt))\r\n {\r\n let a = this.GetCircleAngleAtPoint(pt);\r\n return a <= this.TotalAngle + 1e-6;\r\n }\r\n return false;\r\n }\r\n PtOnEllipse(pt: Vector3)\r\n {\r\n let p = rotatePoint(pt.clone().applyMatrix4(this.OCSInv), -this.Rotation);\r\n return equaln(p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2, 1, 1e-3);\r\n }\r\n GetPointAtParam(param: number)\r\n {\r\n let an = this.TotalAngle * param + this._startAngle;\r\n\r\n if (an > Math.PI)\r\n an -= 2 * Math.PI;\r\n\r\n let a = this.RadX;\r\n let b = this.RadY;\r\n let pt = new Vector3(a * Math.cos(an), b * Math.sin(an), 0);\r\n\r\n pt.applyMatrix4(new Matrix4().makeRotationZ(this._rotate));\r\n\r\n return pt.applyMatrix4(this.OCS);\r\n }\r\n GetParamAtPoint(pt?: Vector3)\r\n {\r\n if (!this.PtOnEllipse(pt))\r\n {\r\n return NaN;\r\n }\r\n let an = this.GetCircleAngleAtPoint(pt);\r\n let par = an / this.TotalAngle;\r\n\r\n if (this.IsClose || par < 1 + 1e-6)\r\n return par;\r\n else\r\n {\r\n let diffPar = Math.PI * 2 / this.TotalAngle - 1;\r\n if (par - 1 < diffPar / 2)\r\n return par;\r\n else\r\n return par - 1 - diffPar;\r\n }\r\n }\r\n GetPointAtDistance(distance: number)\r\n {\r\n let param = distance / this.Length;\r\n return this.GetPointAtParam(param);\r\n }\r\n GetDistAtParam(param: number)\r\n {\r\n return this.Length * param;\r\n }\r\n GetDistAtPoint(pt: Vector3)\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n return this.GetDistAtParam(param);\r\n }\r\n GetParamAtDist(d: number)\r\n {\r\n return d / this.Length;\r\n }\r\n GetAngleAtParam(par: number)\r\n {\r\n let pt = this.GetPointAtParam(par).applyMatrix4(this.OCSInv).applyMatrix4(new Matrix4().makeRotationZ(-this.Rotation));\r\n return angle(pt) + this._startAngle;\r\n }\r\n GetCircleAngleAtPoint(pt: Vector3)\r\n {\r\n pt = pt.clone().applyMatrix4(this.OCSInv);\r\n let an = angle(pt) - this._rotate;\r\n if (an < 0)\r\n an = Math.PI * 2 - an;\r\n if (an > Math.PI * 2)\r\n an -= Math.PI * 2;\r\n let dist = pt.length();\r\n let k = dist * Math.cos(an) / this._radX;\r\n if (Math.abs(k) > 1)\r\n k = Math.floor(Math.abs(k)) * Math.sign(k);\r\n if (Math.abs(an) <= Math.PI)\r\n an = Math.acos(k);\r\n else\r\n an = Math.PI * 2 - Math.acos(k);\r\n\r\n an -= this._startAngle;\r\n\r\n if (an < 0)\r\n an = Math.PI * 2 + an;\r\n return an;\r\n }\r\n\r\n GetFistDeriv(pt: number | Vector3)\r\n {\r\n if (typeof pt === \"number\")\r\n pt = this.GetPointAtParam(pt);\r\n else\r\n pt = pt.clone();\r\n\r\n let refPts = this.GetGripPoints();\r\n\r\n let p = pt.clone().applyMatrix4(this.OCSInv).applyMatrix4(new Matrix4().makeRotationZ(-this._rotate));\r\n let vec = new Vector3();\r\n if (equalv3(pt, refPts[0]))\r\n vec.set(0, 1, 0);\r\n else if (equalv3(pt, refPts[1]))\r\n {\r\n vec.set(0, -1, 0);\r\n }\r\n else if (p.y > 0)\r\n {\r\n let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);\r\n vec.set(-1, -k, 0);\r\n }\r\n else\r\n {\r\n let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);\r\n vec.set(1, k, 0);\r\n }\r\n vec.applyMatrix4(new Matrix4().makeRotationZ(this._rotate));\r\n\r\n return vec.applyMatrix4(new Matrix4().extractRotation(this.OCS));\r\n }\r\n GetClosestPointTo(p: Vector3, extend: boolean): Vector3\r\n {\r\n //参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/\r\n let ro = new Matrix4().makeRotationZ(this._rotate);\r\n let roInv = new Matrix4().getInverse(ro);\r\n let pt = p.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(roInv);\r\n let px = pt.x;\r\n let py = pt.y;\r\n let t = angle(pt);\r\n let a = this._radX;\r\n let b = this._radY;\r\n let x: number, y: number;\r\n for (let i = 0; i < 3; i++)\r\n {\r\n x = a * Math.cos(t);\r\n y = b * Math.sin(t);\r\n let ex = (a ** 2 - b ** 2) * Math.cos(t) ** 3 / a;\r\n let ey = (b * b - a * a) * Math.sin(t) ** 3 / b;\r\n let rx = x - ex;\r\n let ry = y - ey;\r\n let qx = px - ex;\r\n let qy = py - ey;\r\n\r\n let r = Math.sqrt(ry ** 2 + rx ** 2);\r\n let q = Math.sqrt(qy ** 2 + qx ** 2);\r\n\r\n let dc = r * Math.asin((rx * qy - ry * qx) / (r * q));\r\n let dt = dc / Math.sqrt(a * a + b * b - x * x - y * y);\r\n\r\n t += dt;\r\n }\r\n let retPt = new Vector3(x, y).applyMatrix4(ro).applyMatrix4(this.OCS);\r\n if (this.IsClose || extend)\r\n {\r\n return retPt;\r\n }\r\n else if (this.PtOnCurve(retPt))\r\n {\r\n return retPt;\r\n }\r\n else\r\n {\r\n let d1 = p.distanceToSquared(this.StartPoint);\r\n let d2 = p.distanceToSquared(this.EndPoint);\r\n return d1 < d2 ? this.StartPoint : this.EndPoint;\r\n }\r\n }\r\n GetOffsetCurves(offsetDist: number)\r\n {\r\n if ((offsetDist + Math.min(this._radX, this._radY)) > 0)\r\n {\r\n let el = this.Clone();\r\n el.RadX = this._radX + offsetDist;\r\n el.RadY = this._radY + offsetDist;\r\n return [el];\r\n }\r\n return [];\r\n }\r\n GetSplitCurves(param: number[] | number)\r\n {\r\n let params: number[];\r\n if (param instanceof Array)\r\n {\r\n params = param.filter(p => this.ParamOnCurve(p));\r\n params.sort((a1, a2) => a2 - a1);//从大到小\r\n }\r\n else\r\n params = [param];\r\n\r\n //补上最后一个到第一个的弧\r\n if (this.IsClose)\r\n params.unshift(arrayLast(params));\r\n else\r\n {\r\n params.unshift(1);\r\n params.push(0);\r\n }\r\n arrayRemoveDuplicateBySort(params);\r\n\r\n let anglelist = params.map(param => this.TotalAngle * param + this._startAngle);\r\n let elllist: this[] = [];\r\n for (let i = 0; i < anglelist.length - 1; i++)\r\n {\r\n let sa = anglelist[i];\r\n let ea = anglelist[i + 1];\r\n let el = this.Clone();\r\n if (!equaln(sa, ea, 1e-6))\r\n {\r\n el.StartAngle = ea;\r\n el.EndAngle = equaln(sa, 0) ? Math.PI * 2 : sa;\r\n elllist.push(el);\r\n }\r\n }\r\n return elllist;\r\n }\r\n Join(el: Ellipse)\r\n {\r\n if (this.IsClose || el.IsClose || !this.IsCoplaneTo(el) || !equalv3(el.Center, this.Center))\r\n return Status.False;\r\n\r\n let status = Status.False;\r\n\r\n if (equaln(this._endAngle, this._startAngle))\r\n {\r\n this.EndAngle = this._endAngle;\r\n status = Status.True;\r\n }\r\n else if (equaln(this._startAngle, el._endAngle))\r\n {\r\n this.StartAngle = el._startAngle;\r\n status = Status.True;\r\n }\r\n if (status === Status.True && !this.IsClose && equaln(this._startAngle, this._endAngle))\r\n {\r\n this.StartAngle = 0;\r\n this.EndAngle = Math.PI * 2;\r\n }\r\n return status;\r\n }\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n {\r\n let pts = this.GetGripPoints();\r\n return pts;\r\n }\r\n case ObjectSnapMode.Cen:\r\n return [this.Center];\r\n case ObjectSnapMode.Nea:\r\n {\r\n return getArcOrCirNearPts(this, pickPoint, viewXform);\r\n }\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))\r\n return [];\r\n return [this.GetClosestPointTo(lastPoint, false)];\r\n }\r\n case ObjectSnapMode.Tan:\r\n {\r\n //TODO:过某点获取椭圆全部切点\r\n if (lastPoint)\r\n {\r\n return getTanPtsOnEllipse(this, lastPoint);\r\n }\r\n }\r\n default:\r\n return [];\r\n }\r\n }\r\n IntersectWith2(curve: Curve, intType: IntersectOption)\r\n {\r\n //TODO:优化椭圆和椭圆,椭圆和圆相交\r\n if (curve instanceof Line)\r\n {\r\n return SwapParam(IntersectEllipseAndLine(curve, this, reverseIntersectOption(intType)));\r\n }\r\n else if (curve instanceof Circle || curve instanceof Arc)\r\n {\r\n return IntersectEllipseAndCircleOrArc(this, curve, intType);\r\n }\r\n else if (curve instanceof Polyline)\r\n {\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, intType));\r\n }\r\n else if (curve instanceof Ellipse)\r\n {\r\n return IntersectEllipse(this, curve, intType);\r\n }\r\n else\r\n return [];\r\n }\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n let line = new TLine(this.UpdateGeometry(), ColorMaterial.GetLineMaterial(this._Color));\r\n this.UpdateDrawObject(renderType, line);\r\n return line;\r\n }\r\n UpdateDrawObject(type: RenderType, obj: Object3D)\r\n {\r\n let geo = (obj as TLine).geometry as BufferGeometry;\r\n this.UpdateGeometry(geo);\r\n }\r\n //更新Geometry\r\n private UpdateGeometry(geo?: BufferGeometry)\r\n {\r\n if (!geo)\r\n geo = new BufferGeometry();\r\n let curve = this.Shape;\r\n geo.setFromPoints(curve.getPoints(60));\r\n return geo;\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n return this.GetGripPoints();\r\n }\r\n GetGripPoints(): Array\r\n {\r\n let tmpMat4 = new Matrix4().makeRotationZ(this.Rotation);\r\n let pts = [\r\n new Vector3(this._radX, 0),\r\n new Vector3(-this._radX, 0),\r\n new Vector3(0, this._radY),\r\n new Vector3(0, -this._radY)\r\n ].map(p => p.applyMatrix4(tmpMat4).applyMatrix4(this.OCS));\r\n\r\n if (!equaln(0, this._startAngle))\r\n pts.push(this.StartPoint);\r\n if (!equaln(0, this._endAngle))\r\n pts.push(this.EndPoint);\r\n\r\n pts.push(this.Center);\r\n return pts;\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.ApplyMatrix(MoveMatrix(vec));\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n let pts = this.GetStretchPoints();\r\n\r\n if (indexList.length > 0)\r\n {\r\n let p = pts[indexList[0]].clone();\r\n p.add(vec);\r\n\r\n if (indexList[0] <= 1)\r\n this.RadX = p.distanceTo(this.Center);\r\n else if (indexList[0] <= 3)\r\n this.RadY = p.distanceTo(this.Center);\r\n else\r\n {\r\n let p1 = pts[indexList[0]];\r\n //TODO:跟cad不一致待优化\r\n if (equalv3(p1, this.StartPoint))\r\n {\r\n let v1 = p1.clone().sub(this.Center);\r\n let v2 = p.clone().sub(this.Center);\r\n let an = angleTo(v1, v2);\r\n this.StartAngle = this.StartAngle + an;\r\n }\r\n else if (equalv3(p1, this.EndPoint))\r\n {\r\n let v1 = p1.clone().sub(this.Center);\r\n let v2 = p.clone().sub(this.Center);\r\n let an = angleTo(v2, v1);\r\n this.EndAngle = this.EndAngle + an;\r\n }\r\n else\r\n this.Center = p;\r\n }\r\n }\r\n }\r\n Convert2Polyline(count = 0)\r\n {\r\n const MIN_LEN = 80;\r\n const par = this.TotalAngle / Math.PI * 0.5;\r\n if (!count)\r\n {\r\n count = Math.floor(this.Length / par / MIN_LEN);\r\n count = MathUtils.clamp(count, 15, 80);\r\n }\r\n\r\n count = Math.floor(count * par);\r\n\r\n if ((count & 1) === 0)\r\n count++;\r\n\r\n let pts = this.Shape.getPoints(count);\r\n if (this.IsClose)\r\n pts.pop();\r\n\r\n let pl = Pts2Polyline(pts, this.IsClose);\r\n pl.ApplyMatrix(this.OCS);\r\n if (this.IsClose)\r\n pl.CloseMark = true;\r\n return pl;\r\n }\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n this._radX = file.Read();\r\n this._radY = file.Read();\r\n this._rotate = file.Read();\r\n this._startAngle = file.Read();\r\n this._endAngle = file.Read();\r\n this.Update();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);\r\n file.Write(this.RadX);\r\n file.Write(this.RadY);\r\n file.Write(this.Rotation);\r\n file.Write(this._startAngle);\r\n file.Write(this._endAngle);\r\n }\r\n\r\n}\r\n","import { Box3, BufferGeometry, Line as TLine, Line3, Matrix3, Matrix4, Object3D, Shape, Vector3 } from 'three';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { Status } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { AsVector2, equaln, equalv3, isParallelTo, MoveMatrix } from '../../Geometry/GeUtils';\r\nimport { PlaneExt } from '../../Geometry/Plane';\r\nimport { IntersectEllipseAndLine, IntersectLineAndArc, IntersectLineAndCircle, IntersectLineAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\nimport { Arc } from './Arc';\r\nimport { Circle } from './Circle';\r\nimport { Curve } from './Curve';\r\nimport { Ellipse } from './Ellipse';\r\nimport { Polyline } from './Polyline';\r\n\r\n@Factory\r\nexport class Line extends Curve\r\n{\r\n private _StartPoint: Vector3;\r\n private _EndPoint: Vector3;\r\n constructor(sp?: Vector3, ep?: Vector3)\r\n {\r\n super();\r\n this._StartPoint = sp || new Vector3(0, 0, 0);\r\n this._EndPoint = ep || new Vector3(0, 0, 0);\r\n }\r\n get Is2D()\r\n {\r\n return super.Is2D && equaln(this._StartPoint.z, 0) && equaln(this._EndPoint.z, 0);\r\n }\r\n\r\n get Shape()\r\n {\r\n return new Shape([AsVector2(this._StartPoint), AsVector2(this._EndPoint)]);\r\n }\r\n\r\n Z0()\r\n {\r\n this.WriteAllObjectRecord();\r\n this.StartPoint = this.StartPoint.setZ(0);\r\n this.EndPoint = this.EndPoint.setZ(0);\r\n return this;\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this.StartPoint = this.StartPoint.applyMatrix4(m);\r\n this.EndPoint = this.EndPoint.applyMatrix4(m);\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n let sp = this.StartPoint;\r\n let ep = this.EndPoint;\r\n\r\n reviseMirrorMatrix(this._Matrix);\r\n\r\n this.StartPoint = sp;\r\n this.EndPoint = ep;\r\n return this;\r\n }\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n let geo = BufferGeometryUtils.CreateFromPts([this._StartPoint, this._EndPoint]);\r\n if (renderType === RenderType.Print)\r\n {\r\n var geometry = new LineGeometry();\r\n geometry.setPositions(geo.attributes.position.array as number[]);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n return new TLine(geo, ColorMaterial.GetLineMaterial(this.ColorIndex));\r\n }\r\n\r\n UpdateDrawObject(type: RenderType, lineObj: TLine)\r\n {\r\n BufferGeometryUtils.UpdatePts(lineObj.geometry as BufferGeometry, [this._StartPoint, this._EndPoint]);\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return [this.StartPoint, this.EndPoint];\r\n case ObjectSnapMode.Mid:\r\n return [this.GetPointAtParam(0.5)];\r\n case ObjectSnapMode.Nea:\r\n {\r\n let derv = this.GetFistDeriv(0).normalize();\r\n let viewNormal = new Vector3().fromArray(viewXform.elements, 2 * 3);\r\n\r\n //平行不捕捉\r\n if (isParallelTo(viewNormal, derv))\r\n return [];\r\n\r\n let fNormal = new Vector3().crossVectors(viewNormal, derv);\r\n fNormal.crossVectors(derv, fNormal);\r\n\r\n let plane = new PlaneExt(fNormal, this.StartPoint);\r\n let plocal = plane.intersectLine(new Line3(pickPoint, pickPoint.clone().add(viewNormal)), new Vector3(), true);\r\n let pclosest = this.GetClosestPointTo(plocal, false);\r\n return [pclosest];\r\n }\r\n case ObjectSnapMode.Ext:\r\n return [this.GetClosestPointTo(pickPoint, true)];\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n let { closestPt, param } = this.GetClosestAtPoint(lastPoint, true);\r\n if (this.ParamOnCurve(param))\r\n return [closestPt];\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n return [this.StartPoint, this.GetPointAtParam(0.5), this.EndPoint];\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n for (let index of indexList)\r\n {\r\n if (index === 0)\r\n this.StartPoint = this.StartPoint.add(vec);\r\n else if (index === 2)\r\n this.EndPoint = this.EndPoint.add(vec);\r\n else\r\n {\r\n let m = MoveMatrix(vec);\r\n this.ApplyMatrix(m);\r\n }\r\n }\r\n }\r\n\r\n GetStretchPoints(): Array\r\n {\r\n return [this.StartPoint, this.EndPoint];\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n for (let index of indexList)\r\n {\r\n if (index === 0)\r\n this.StartPoint = this.StartPoint.add(vec);\r\n else\r\n this.EndPoint = this.EndPoint.add(vec);\r\n }\r\n }\r\n\r\n GetFistDeriv(param: number | Vector3): Vector3\r\n {\r\n return this.EndPoint.sub(this.StartPoint);\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-4)\r\n {\r\n if (curve instanceof Line)\r\n {\r\n return IntersectLineAndLine(this, curve, intType, tolerance);\r\n }\r\n if (curve instanceof Arc)\r\n {\r\n return IntersectLineAndArc(this, curve, intType, tolerance);\r\n }\r\n if (curve instanceof Circle)\r\n {\r\n return IntersectLineAndCircle(this, curve, intType, tolerance);\r\n }\r\n if (curve instanceof Polyline)\r\n {\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));\r\n }\r\n\r\n if (curve instanceof Ellipse)\r\n return IntersectEllipseAndLine(this, curve, intType, tolerance);\r\n\r\n //其他的尚未实现.\r\n return [];\r\n }\r\n\r\n //Param\r\n GetPointAtParam(param: number): Vector3\r\n {\r\n return this.StartPoint.add(this.GetFistDeriv(0).multiplyScalar(param));\r\n }\r\n GetParamAtPoint(pt: Vector3): number\r\n {\r\n let { closestPt, param } = this.GetClosestAtPoint(pt, true);\r\n if (!equalv3(closestPt, pt, 1e-5))\r\n return NaN;\r\n return param;\r\n }\r\n GetParamAtDist(d: number): number\r\n {\r\n return d / this.Length;\r\n }\r\n GetPointAtDistance(distance: number): Vector3\r\n {\r\n return this.GetPointAtParam(this.GetParamAtDist(distance));\r\n }\r\n GetDistAtParam(param: number): number\r\n {\r\n return this.Length * param;\r\n }\r\n GetDistAtPoint(pt: Vector3): number\r\n {\r\n return this.GetDistAtParam(this.GetParamAtPoint(pt));\r\n }\r\n GetSplitCurves(param: number[] | number)\r\n {\r\n let params = this.SplitParamSort(param);\r\n let pts = params.map(param => this.GetPointAtParam(param));\r\n let ret = new Array();\r\n if (pts.length >= 2)\r\n {\r\n for (let i = 0; i < pts.length - 1; i++)\r\n {\r\n let newLine = this.Clone() as Line;\r\n newLine.StartPoint = pts[i];\r\n newLine.EndPoint = pts[i + 1];\r\n ret.push(newLine);\r\n }\r\n }\r\n return ret;\r\n }\r\n\r\n GetParamAtPoint2(pt: Vector3): number\r\n {\r\n let { param } = this.GetClosestAtPoint(pt, true);\r\n return param;\r\n }\r\n\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n let { param } = this.GetClosestAtPoint(p, true);\r\n return this.ParamOnCurve(param, fuzz);\r\n }\r\n\r\n GetClosestAtPoint(pt: Vector3, extend: boolean): { closestPt: Vector3, param: number; }\r\n {\r\n let sp = this.StartPoint;\r\n let ep = this.EndPoint;\r\n if (equalv3(pt, sp, 1e-8))\r\n return { closestPt: sp, param: 0 };\r\n else if (equalv3(pt, ep, 1e-8))\r\n return { closestPt: ep, param: 1 };\r\n\r\n let direction = this.GetFistDeriv(0);\r\n let length = direction.length();\r\n\r\n if (length === 0)\r\n {\r\n let param = NaN;\r\n if (equalv3(pt, this.StartPoint, 1e-6))\r\n param = 0;\r\n return { closestPt: sp, param: param };\r\n }\r\n\r\n direction.divideScalar(length);\r\n\r\n let diff = pt.clone().sub(sp);\r\n let param = direction.dot(diff);\r\n\r\n let closestPt: Vector3;\r\n if (extend)\r\n closestPt = sp.add(direction.multiplyScalar(param));\r\n else\r\n if (param < 0)\r\n {\r\n closestPt = sp;\r\n param = 0;\r\n }\r\n else if (param > length)\r\n {\r\n closestPt = this.EndPoint;\r\n param = length;\r\n }\r\n else\r\n closestPt = sp.add(direction.multiplyScalar(param));\r\n return {\r\n closestPt: closestPt,\r\n param: param / length\r\n };\r\n }\r\n\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n return this.GetClosestAtPoint(pt, extend).closestPt;\r\n }\r\n\r\n Extend(newParam: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n if (newParam < this.StartParam)\r\n {\r\n this.StartPoint = this.GetPointAtParam(newParam);\r\n }\r\n else if (newParam > this.EndParam)\r\n {\r\n this.EndPoint = this.GetPointAtParam(newParam);\r\n }\r\n }\r\n\r\n Join(cu: Curve, allowGap = false, tolerance = 1e-5): Status\r\n {\r\n if (cu instanceof Line)\r\n {\r\n //平行\r\n if (!isParallelTo(this.GetFistDeriv(0).normalize(), cu.GetFistDeriv(0).normalize()))\r\n return Status.False;\r\n\r\n let sp = cu.StartPoint;\r\n let { closestPt: cp1, param: param1 } = this.GetClosestAtPoint(sp, true);\r\n if (!equalv3(sp, cp1, tolerance))//点在曲线上,允许较低的精度\r\n return Status.False;\r\n\r\n let ep = cu.EndPoint;\r\n let { closestPt: cp2, param: param2 } = this.GetClosestAtPoint(ep, true);\r\n if (!equalv3(ep, cp2, tolerance))\r\n return Status.False;\r\n\r\n if (param1 > param2)\r\n {\r\n [param1, param2] = [param2, param1];\r\n [sp, ep] = [ep, sp];\r\n }\r\n\r\n if (allowGap || Math.max(0, param1) < Math.min(1, param2) + tolerance)\r\n {\r\n if (param1 < 0)\r\n this.StartPoint = sp;\r\n if (param2 > 1)\r\n this.EndPoint = ep;\r\n return Status.True;\r\n }\r\n }\r\n return Status.False;\r\n }\r\n\r\n Reverse(): this\r\n {\r\n this.WriteAllObjectRecord();\r\n [this._StartPoint, this._EndPoint] = [this._EndPoint, this._StartPoint];\r\n return this;\r\n }\r\n\r\n GetOffsetCurves(offsetDist: number): Array\r\n {\r\n let derv = this.GetFistDeriv(0).normalize().multiplyScalar(offsetDist);\r\n derv.applyMatrix4(new Matrix4().makeRotationAxis(this.Normal, -Math.PI / 2));\r\n let newLine = this.Clone() as Line;\r\n newLine.StartPoint = this.StartPoint.add(derv);\r\n newLine.EndPoint = this.EndPoint.add(derv);\r\n return [newLine];\r\n }\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3().setFromPoints([this.StartPoint, this.EndPoint]);\r\n }\r\n\r\n get StartParam()\r\n {\r\n return 0;\r\n }\r\n get EndParam()\r\n {\r\n return 1;\r\n }\r\n //属性\r\n get Length(): number { return this._StartPoint.distanceTo(this._EndPoint); }\r\n\r\n //#region -----------------------------File-----------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();//1\r\n this._StartPoint.fromArray(file.Read());\r\n this._EndPoint.fromArray(file.Read());\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);//ver\r\n file.Write(this._StartPoint.toArray());\r\n file.Write(this._EndPoint.toArray());\r\n }\r\n //#endregion-----------------------------File End-----------------------------\r\n\r\n //#region 属性\r\n set StartPoint(p: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._StartPoint.copy(p).applyMatrix4(this.OCSInv);\r\n this.Update();\r\n }\r\n get StartPoint(): Vector3\r\n {\r\n return this._StartPoint.clone().applyMatrix4(this.OCS);\r\n }\r\n\r\n get EndPoint(): Vector3\r\n {\r\n return this._EndPoint.clone().applyMatrix4(this.OCS);\r\n }\r\n set EndPoint(p: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._EndPoint.copy(p).applyMatrix4(this.OCSInv);\r\n this.Update();\r\n }\r\n\r\n //#endregion\r\n}\r\n","import { Box3 } from \"three\";\r\nimport { equaln } from \"./GeUtils\";\r\n\r\nexport interface EBox\r\n{\r\n BoundingBox: Box3;\r\n}\r\n\r\n/**\r\n * 根据盒子x排序盒子\r\n * @param {EBox[]} arr\r\n */\r\nexport function SortEntityByBox(arr: T[], sort: boolean = true)\r\n{\r\n let boxMap: Map = new Map();\r\n arr.forEach(e => boxMap.set(e, e.BoundingBox));\r\n\r\n if (sort)\r\n arr.sort((e1, e2) =>\r\n {\r\n let b1 = boxMap.get(e1);\r\n let b2 = boxMap.get(e2);\r\n if (!equaln(b1.min.x, b2.min.x))\r\n return b1.min.x - b2.min.x;\r\n else\r\n {\r\n return b2.min.y - b1.min.y;\r\n }\r\n });\r\n\r\n return boxMap;\r\n}\r\n","import { Box3, Matrix4, Vector3 } from \"three\";\r\nimport { arrayLast } from \"../Common/ArrayExt\";\r\nimport { ConverCircleToPolyline } from \"../Common/CurveUtils\";\r\nimport { Status } from \"../Common/Status\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\nimport { Contour } from \"../DatabaseServices/Contour\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Circle } from \"../DatabaseServices/Entity/Circle\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { Line } from \"../DatabaseServices/Entity/Line\";\r\nimport { Polyline } from \"../DatabaseServices/Entity/Polyline\";\r\nimport { IntersectsBox } from \"../Geometry/Box\";\r\nimport { CurveMap, Route, Vertice } from \"../Geometry/CurveMap\";\r\nimport { angle, equaln, equalv2, equalv3, IdentityMtx4, SelectNearP } from \"../Geometry/GeUtils\";\r\nimport { SortEntityByBox } from \"../Geometry/SortEntityByBox\";\r\nimport { IntersectOption } from \"../GraphicsSystem/IntersectWith\";\r\n\r\ninterface IOffsetResult\r\n{\r\n index: number;\r\n curve: Curve;\r\n sp?: Vector3;\r\n preArc?: Curve;\r\n ep?: Vector3;\r\n nextArc?: Curve;\r\n paddingCurve?: Curve[];\r\n}\r\n\r\nclass CurveTreeNode\r\n{\r\n children: CurveTreeNode[];\r\n box: Box3;\r\n used: boolean;\r\n constructor(public curve: Curve, box?: Box3)\r\n {\r\n this.box = box || curve.BoundingBox;\r\n }\r\n\r\n TrimBy(contour: Contour, box: Box3)\r\n {\r\n if (IntersectsBox(box, this.box))\r\n {\r\n if (this.children !== undefined)\r\n {\r\n for (let c of this.children)\r\n c.TrimBy(contour, box);\r\n }\r\n else\r\n {\r\n if (contour.Curve instanceof Circle && this.curve instanceof Arc)\r\n {\r\n if (equalv3(contour.Curve.Center, this.curve.Center))\r\n {\r\n if (contour.Curve.Radius > this.curve.Radius + 1e-4)\r\n this.children = [];\r\n\r\n return;\r\n }\r\n }\r\n\r\n //交点参数列表\r\n let iParams = this.curve.IntersectWith(contour.Curve, IntersectOption.OnBothOperands)\r\n .map(p => this.curve.GetParamAtPoint2(p));\r\n\r\n let cus = this.curve.GetSplitCurves(iParams);\r\n if (cus.length === 0)\r\n {\r\n let p = this.curve.GetPointAtParam(0.5);\r\n if ((contour.Curve.PtInCurve(p) && !contour.Curve.PtOnCurve(p)))\r\n this.children = [];\r\n }\r\n else\r\n {\r\n this.children = [];\r\n for (let c of cus)\r\n {\r\n let p = c.GetPointAtParam(0.5);\r\n if (c.Length > 1e-5 && (!contour.Curve.PtInCurve(p) || contour.Curve.PtOnCurve(p)))\r\n this.children.push(new CurveTreeNode(c));\r\n }\r\n if (this.children.length === cus.length)\r\n this.children = undefined;\r\n }\r\n }\r\n }\r\n }\r\n\r\n get Nodes()\r\n {\r\n if (!this.children) return [this];\r\n else\r\n {\r\n let cus: CurveTreeNode[] = [];\r\n for (let c of this.children)\r\n cus.push(...c.Nodes);\r\n return cus;\r\n }\r\n }\r\n}\r\n\r\nexport class OffsetPolyline\r\n{\r\n //多段线信息\r\n _CacheOCS: Matrix4;\r\n _Vertexs: Vector3[];\r\n _SubCurves: Curve[];\r\n _Circles: Circle[];\r\n\r\n //偏移子曲线\r\n _SubOffsetedCurves: IOffsetResult[];\r\n //用于裁剪的曲线节点\r\n _CurveTreeNodes: CurveTreeNode[];\r\n //裁剪完的曲线节点\r\n _CurveTrimedTreeNodes: CurveTreeNode[];\r\n\r\n //裁剪轮廓\r\n _TrimPolylineContours: Contour[];\r\n _TrimCircleContours: Circle[];\r\n _TrimArcContours: Contour[];\r\n\r\n //结果曲线\r\n _RetCurves: Polyline[];\r\n\r\n _IsClose: boolean;\r\n _OffsetDistSign: number;\r\n\r\n constructor(public _Polyline: Polyline, public _OffsetDist: number, public _ToolPath = false,\r\n private _OffsetDistSq = (_OffsetDist ** 2) * 2.1//对直角走刀不进行圆弧过度\r\n )\r\n {\r\n }\r\n\r\n Do()\r\n {\r\n this._OffsetDistSign = Math.sign(this._OffsetDist);\r\n this._TrimPolylineContours = [];\r\n this._TrimCircleContours = [];\r\n this._TrimArcContours = [];\r\n\r\n this._RetCurves = [];\r\n this._CurveTreeNodes = [];\r\n\r\n this.InitSubCurves();\r\n if (this._SubCurves.length === 0)\r\n return this._RetCurves;\r\n\r\n this.GeneralCirclesAndVertexs();\r\n this.OffsetSubCurves();\r\n this.LinkSubCurves();\r\n\r\n if (this._SubOffsetedCurves.length === 0)\r\n {\r\n this._SubOffsetedCurves.push({ curve: this._Circles[0], index: 0, paddingCurve: this._Circles.slice(1) });\r\n\r\n this._TrimPolylineContours.push(\r\n ...this._Circles.map(c => Contour.CreateContour(c, false)),\r\n ...this._SubCurves.map(c => Contour.CreateContour([c, new Line(c.StartPoint, c.EndPoint)], false))\r\n );\r\n }\r\n else\r\n this.GeneralTrimContours();\r\n this.TrimByContours();\r\n this.FilterInvalidCurve();\r\n this.JoinCollinear();\r\n this.LinkResultPolyline();\r\n return this._RetCurves;\r\n }\r\n\r\n InitSubCurves()\r\n {\r\n this._CacheOCS = this._Polyline.OCS;\r\n this._IsClose = this._Polyline.IsClose;\r\n this._Polyline.OCS = IdentityMtx4;\r\n this._SubCurves = this._Polyline.Explode().filter(c => c.Length > 1e-4);\r\n this._Polyline.OCS = this._CacheOCS;\r\n return this;\r\n }\r\n\r\n protected GeneralCirclesAndVertexs()\r\n {\r\n this._Vertexs = this._SubCurves.map(c => c.StartPoint);\r\n let lastCu = arrayLast(this._SubCurves);\r\n if (!equalv3(lastCu.EndPoint, this._Vertexs[0], 1e-3))\r\n this._Vertexs.push(lastCu.EndPoint);\r\n\r\n let radius = Math.abs(this._OffsetDist);\r\n this._Circles = this._Vertexs.map(p => new Circle(p, radius));\r\n }\r\n\r\n protected OffsetSubCurves()\r\n {\r\n this._SubOffsetedCurves = [];\r\n for (let index = 0; index < this._SubCurves.length; index++)\r\n {\r\n let curveOld = this._SubCurves[index];\r\n if (curveOld.Length > 1e-6)\r\n {\r\n let curve = curveOld.GetOffsetCurves(this._OffsetDist)[0];\r\n if (curve)\r\n this._SubOffsetedCurves.push({ curve, index });\r\n else\r\n this._TrimArcContours.push(Contour.CreateContour([curveOld, new Line(curveOld.StartPoint, curveOld.EndPoint)], false));\r\n }\r\n }\r\n }\r\n\r\n //连接(延伸)曲线,或者补(圆弧,直线)\r\n protected LinkSubCurves()\r\n {\r\n let count = this._SubOffsetedCurves.length;\r\n if (!this._IsClose) count--;\r\n\r\n for (let i = 0; i < count; i++)\r\n {\r\n let curveResNow = this._SubOffsetedCurves[i];\r\n let iNext = FixIndex(i + 1, this._SubOffsetedCurves);\r\n let curveResNext = this._SubOffsetedCurves[iNext];\r\n let curveNow = curveResNow.curve;\r\n let curveNext = curveResNext.curve;\r\n let isNeighbor = FixIndex(curveResNow.index + 1, this._SubCurves) === curveResNext.index;\r\n\r\n if (isNeighbor)\r\n {\r\n let sp = curveNow.EndPoint;\r\n let ep = curveNext.StartPoint;\r\n //直连\r\n if (equalv3(sp, ep, 1e-3))\r\n continue;\r\n\r\n let iPts = curveNow.IntersectWith(curveNext, IntersectOption.ExtendBoth);\r\n let tPts = iPts.filter(p => curveNow.PtOnCurve3(p) && curveNext.PtOnCurve3(p));\r\n\r\n let code = EntityEncode2(curveNow, curveNext);\r\n\r\n let tp: Vector3;\r\n if (code === 1)\r\n {\r\n if (tPts.length > 0)//不走刀或者有真交点 this._ToolPath === false ||\r\n tp = iPts[0];\r\n else\r\n {\r\n if (iPts.length > 0 && curveNow.GetParamAtPoint(iPts[0]) > 1)\r\n {\r\n let refP = this._Vertexs[curveResNext.index];\r\n let distSq = iPts[0].distanceToSquared(refP);\r\n if (this._ToolPath && distSq > this._OffsetDistSq)\r\n {\r\n curveResNow.paddingCurve = [this.CreateArc(refP, sp, ep)];\r\n this._TrimCircleContours.push(this._Circles[curveResNext.index]);\r\n }\r\n else\r\n tp = iPts[0];\r\n }\r\n // else\r\n // curveResNow.paddingCurve = [new Line(sp, ep)];\r\n }\r\n }\r\n else\r\n {\r\n let refP = this._Vertexs[curveResNext.index];\r\n if (tPts.length > 0) //ipts = 1 or ipts = 2\r\n tp = SelectNearP(iPts, refP);\r\n else //补单圆 或者尝试连接\r\n {\r\n let arc = this.CreateArc(refP, sp, ep);\r\n\r\n if (iPts.length > 0 && !this._ToolPath && this.IsSharpCorner(curveResNow, curveResNext, refP))\r\n {\r\n //设置新的连接点,并且备份旧点\r\n let oldp: Vector3;\r\n if (curveResNow.sp)\r\n {\r\n oldp = curveNow.StartPoint;\r\n curveNow.StartPoint = curveResNow.sp;\r\n }\r\n let oldp2: Vector3;\r\n if (curveResNext.ep)\r\n {\r\n oldp2 = curveNext.EndPoint;\r\n curveNext.EndPoint = curveResNext.ep;\r\n }\r\n\r\n let p: Vector3;\r\n\r\n if (code === 2 && iPts.length === 2)\r\n {\r\n let c = curveNow as Arc;\r\n let minArc = new Arc(c.Center, c.Radius, c.EndAngle, 0, c.IsClockWise);\r\n\r\n let p1 = iPts[0];\r\n let a1 = minArc.GetAngleAtPoint(p1);\r\n let anAll1 = c.ParamOnCurve(c.GetParamAtAngle(a1)) ? Infinity : minArc.ComputeAnlge(a1);\r\n\r\n let p2 = iPts[1];\r\n let a2 = minArc.GetAngleAtPoint(p2);\r\n let anAll2 = c.ParamOnCurve(c.GetParamAtAngle(a2)) ? Infinity : minArc.ComputeAnlge(a2);\r\n\r\n if (anAll2 < anAll1)\r\n p = p2;\r\n else\r\n p = p1;\r\n }\r\n else\r\n p = SelectNearP(iPts, refP);\r\n\r\n let onPre: boolean;\r\n let param = curveNow.GetParamAtPoint2(p);\r\n if (curveNow instanceof Line)\r\n onPre = param > 1;\r\n else\r\n onPre = param < 0 || param > 1;\r\n\r\n let onNext: boolean = false;\r\n if (onPre)\r\n {\r\n let param2 = curveNext.GetParamAtPoint2(p);\r\n if (curveNext instanceof Line)\r\n onNext = param2 < 0;\r\n else\r\n onNext = param2 < 0 || param2 > 1;\r\n }\r\n\r\n if (curveResNow.sp)\r\n curveNow.StartPoint = oldp;\r\n if (curveResNext.ep)\r\n curveNext.EndPoint = oldp2;\r\n\r\n if (onPre && onNext)\r\n tp = p;\r\n else\r\n curveResNow.paddingCurve = [arc];\r\n }\r\n else\r\n curveResNow.paddingCurve = [arc];\r\n\r\n this._TrimCircleContours.push(this._Circles[curveResNext.index]);\r\n }\r\n }\r\n if (tp)\r\n {\r\n curveResNow.ep = tp;\r\n curveResNext.sp = tp;\r\n\r\n curveResNow.nextArc = curveNext;\r\n curveResNext.preArc = curveNow;\r\n }\r\n }\r\n else\r\n {\r\n let padCirs: Circle[] = [];\r\n for (let s = FixIndex(curveResNow.index + 1, this._Circles); ; s = FixIndex(s + 1, this._Circles))\r\n {\r\n let c = this._Circles[s];\r\n this._TrimCircleContours.push(c);\r\n padCirs.push(c);\r\n if (s === curveResNext.index)\r\n break;\r\n }\r\n curveResNow.paddingCurve = padCirs;\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n private IsSharpCorner(curveResNow: IOffsetResult, curveResNext: IOffsetResult, refP: Vector3): boolean\r\n {\r\n let v1 = this._SubCurves[curveResNow.index].GetPointAtParam(0.9);\r\n let v2 = this._SubCurves[curveResNext.index].GetPointAtParam(0.1);\r\n v1.subVectors(refP, v1);\r\n v2.sub(refP);\r\n v1.cross(v2);\r\n return Math.sign(v1.z) === this._OffsetDistSign;\r\n }\r\n\r\n protected GeneralTrimContours()\r\n {\r\n for (let d of this._SubOffsetedCurves)\r\n {\r\n let cu2 = d.curve;\r\n if (d.sp && d.ep)\r\n {\r\n let param1 = cu2.GetParamAtPoint(d.sp);\r\n let param2 = cu2.GetParamAtPoint(d.ep);\r\n\r\n if (cu2.ParamOnCurve(param1) && cu2.ParamOnCurve(param2) && param1 > param2)\r\n [d.sp, d.ep] = [d.ep, d.sp];\r\n }\r\n if (d.sp) cu2.StartPoint = d.sp;\r\n if (d.ep) cu2.EndPoint = d.ep;\r\n\r\n //这是极端情况,圆弧被压缩成0长度圆弧,本质是空圆弧(我们会在下面判断它)(因为精度的问题)\r\n //因为精度的问题,这种0圆心角的圆弧会被当成全圆,但是偏移算法中,应该不可能出现全圆弧的圆弧,所以我们压扁它\r\n if (cu2 instanceof Arc\r\n && equaln(cu2.StartAngle, cu2.EndAngle, 1e-6)\r\n // && !equaln((this._SubCurves[d.index]).AllAngle, Math.PI * 2, 1e-3) 应该不会出现\r\n )\r\n {\r\n if (cu2.IsClockWise)\r\n cu2.StartAngle = cu2.EndAngle + 1e-6;\r\n else\r\n cu2.EndAngle = cu2.StartAngle + 1e-6;\r\n }\r\n }\r\n for (let d of this._SubOffsetedCurves)\r\n {\r\n let cu1 = this._SubCurves[d.index];\r\n let cu2 = d.curve;\r\n\r\n let [p1, p2, p3, p4] = [cu1.StartPoint, cu2.StartPoint, cu1.EndPoint, cu2.EndPoint];\r\n let l1 = new Line(p1, p2);\r\n let l2 = new Line(p3, p4);\r\n\r\n let ipts = l1.IntersectWith(l2, IntersectOption.OnBothOperands, 1e-8);\r\n if (ipts.length > 0)\r\n {\r\n let p = ipts[0];\r\n l1.EndPoint = p;\r\n l2.EndPoint = p;\r\n let cus = [cu1, l1, l2];\r\n let contour = Contour.CreateContour(cus, false);\r\n if (contour)\r\n {\r\n this._TrimPolylineContours.push(contour);\r\n continue;\r\n }\r\n else\r\n {\r\n console.error(\"未预料到的错误,构建轮廓失败\" + this._OffsetDist);\r\n }\r\n }\r\n\r\n //真理1:针脚线不可能同时被两个圆弧所切割\r\n let l1Intact = true;\r\n let l2Intact = true;\r\n if (cu2 instanceof Arc)\r\n {\r\n if (Math.sign(cu2.Bul) !== this._OffsetDistSign)\r\n {\r\n let ipts1 = cu2.IntersectWith(l1, IntersectOption.OnBothOperands);\r\n let ipts2 = cu2.IntersectWith(l2, IntersectOption.OnBothOperands);\r\n\r\n let sp: Vector3;\r\n let ep: Vector3;\r\n if (ipts1.length === 2)\r\n sp = SelectNearP(ipts1, p1);\r\n if (ipts2.length === 2)\r\n ep = SelectNearP(ipts2, p3);\r\n\r\n if (sp || ep) cu2 = cu2.Clone();\r\n if (sp)\r\n {\r\n l1.EndPoint = sp;\r\n cu2.StartPoint = sp;\r\n l1Intact = false;\r\n }\r\n if (ep)\r\n {\r\n l2.EndPoint = ep;\r\n cu2.EndPoint = ep;\r\n l2Intact = false;\r\n }\r\n }\r\n }\r\n\r\n let l1PadArc: Arc;\r\n let l2PadArc: Arc;\r\n //真理2:隔壁的圆弧不可能破坏当前的圆弧,只能破坏当前的针脚\r\n if (l1Intact && d.preArc && d.preArc instanceof Arc)\r\n {\r\n let a = d.preArc;\r\n if (Math.sign(a.Bul) !== this._OffsetDistSign && a.AllAngle > 1e-6)\r\n {\r\n let ipts = a.IntersectWith(l1, IntersectOption.OnBothOperands);\r\n if (ipts.length === 2)\r\n {\r\n let sp = SelectNearP(ipts, p1);\r\n l1.EndPoint = sp;\r\n l1PadArc = a.Clone();\r\n l1PadArc.StartPoint = sp;\r\n }\r\n }\r\n }\r\n if (l2Intact && d.nextArc && d.nextArc instanceof Arc)\r\n {\r\n let a = d.nextArc;\r\n if (Math.sign(a.Bul) !== this._OffsetDistSign && a.AllAngle > 1e-6)\r\n {\r\n let ipts = a.IntersectWith(l2, IntersectOption.OnBothOperands);\r\n if (ipts.length === 2)\r\n {\r\n let ep = SelectNearP(ipts, p3);\r\n l2.EndPoint = ep;\r\n l2PadArc = a.Clone();\r\n l2PadArc.EndPoint = ep;\r\n }\r\n }\r\n }\r\n\r\n let pl = new Polyline();\r\n let cus = [cu1, l1];\r\n if (l1PadArc) cus.push(l1PadArc);\r\n cus.push(cu2, l2);\r\n if (l2PadArc) cus.push(l2PadArc);\r\n\r\n for (let c of cus)\r\n pl.Join(c);\r\n\r\n let contour = Contour.CreateContour(pl, false);\r\n if (contour)\r\n this._TrimPolylineContours.push(contour);\r\n else\r\n console.error(\"未预料到的错误,构建轮廓失败\" + this._OffsetDist);\r\n }\r\n\r\n if (!this._IsClose)\r\n {\r\n if (this._TrimCircleContours[0] !== this._Circles[0])\r\n this._TrimCircleContours.push(this._Circles[0]);\r\n let lastTrimCircle = arrayLast(this._TrimCircleContours);\r\n let lastCircle = arrayLast(this._Circles);\r\n if (lastTrimCircle !== lastCircle)\r\n this._TrimCircleContours.push(lastCircle);\r\n if (this._SubOffsetedCurves[0].index !== 0)\r\n this._TrimCircleContours.push(this._Circles[this._SubOffsetedCurves[0].index]);\r\n\r\n let lastIndex = this._Circles.length - 1;\r\n let lastD = arrayLast(this._SubOffsetedCurves);\r\n if (lastIndex !== lastD.index)\r\n this._TrimCircleContours.push(this._Circles[lastD.index + 1]);\r\n }\r\n\r\n this._TrimPolylineContours.push(\r\n ...this._TrimCircleContours.map(c => Contour.CreateContour(c, false)),\r\n ...this._TrimArcContours\r\n );\r\n }\r\n\r\n // 通过构建的轮廓对偏移曲线进行裁剪\r\n protected TrimByContours()\r\n {\r\n for (let d of this._SubOffsetedCurves)\r\n {\r\n let c = d.curve;\r\n this._CurveTreeNodes.push(new CurveTreeNode(c));\r\n if (d.paddingCurve)\r\n this._CurveTreeNodes.push(...d.paddingCurve.map(c => new CurveTreeNode(c)));\r\n }\r\n let boxContours = SortEntityByBox(this._TrimPolylineContours, false);\r\n\r\n for (let i = 0; i < this._TrimPolylineContours.length; i++)\r\n {\r\n let c = this._TrimPolylineContours[i];\r\n for (let curveNode of this._CurveTreeNodes)\r\n {\r\n curveNode.TrimBy(c, boxContours.get(c));\r\n }\r\n }\r\n }\r\n\r\n //过滤方向相反和0长度线\r\n private FilterInvalidCurve()\r\n {\r\n this._CurveTrimedTreeNodes = [];\r\n for (let n of this._CurveTreeNodes)\r\n {\r\n let ns = n.Nodes;\r\n for (let sn of ns)\r\n {\r\n let p = sn.curve.GetPointAtParam(0.5);\r\n if (sn.curve.Length > 1e-5 && this.CheckPointDir(p))\r\n this._CurveTrimedTreeNodes.push(sn);\r\n }\r\n }\r\n }\r\n\r\n //合并共线\r\n private JoinCollinear()\r\n {\r\n for (let i = 0; i < this._CurveTrimedTreeNodes.length; i++)\r\n {\r\n let n = this._CurveTrimedTreeNodes[i];\r\n if (n.used) continue;\r\n let sp = n.curve.StartPoint;\r\n for (let j = i + 1; j < this._CurveTrimedTreeNodes.length; j++)\r\n {\r\n let n2 = this._CurveTrimedTreeNodes[j];\r\n if (n2.used) continue;\r\n let status = n.curve.Join(n2.curve);\r\n if (status === Status.ConverToCircle)\r\n {\r\n n.used = true;\r\n n2.used = true;\r\n let circle = new Circle((n.curve).Center, (n.curve).Radius);\r\n n.curve = circle;\r\n this._RetCurves.push(ConverCircleToPolyline(circle).ApplyMatrix(this._CacheOCS));\r\n }\r\n else if (status === Status.True)\r\n {\r\n if (equalv3(sp, n.curve.StartPoint))\r\n n2.used = true;\r\n else\r\n {\r\n n.used = true;\r\n n2.curve = n.curve;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n //连接结果曲线,返回最终多段线\r\n private LinkResultPolyline()\r\n {\r\n let used = new Set();\r\n let cuMap = new CurveMap(1);\r\n for (let n of this._CurveTrimedTreeNodes)\r\n {\r\n if (!n.used)\r\n cuMap.AddCurveToMap(n.curve);\r\n }\r\n\r\n let preP: Vector3;\r\n\r\n let searchNext = (s: Vertice, pl: Polyline): Vertice =>\r\n {\r\n let minDist = Infinity;\r\n let minR: Route;\r\n for (let r of s.routes)\r\n {\r\n if (used.has(r.curve)) continue;\r\n\r\n if (preP)\r\n {\r\n let d = r.s.distanceToSquared(preP);\r\n if (d < minDist)\r\n {\r\n minR = r;\r\n minDist = d;\r\n }\r\n }\r\n else\r\n {\r\n minR = r;\r\n break;\r\n }\r\n }\r\n\r\n if (minR)\r\n {\r\n used.add(minR.curve);\r\n preP = minR.e;\r\n let status = pl.Join(minR.curve, false, 5e-2);\r\n if (status !== Status.True)\r\n console.warn(\"连接失败\");\r\n return minR.to;\r\n }\r\n };\r\n\r\n for (let s of cuMap.Stands)\r\n {\r\n preP = undefined;\r\n let pl = new Polyline();\r\n let ss = s;\r\n while (ss && !pl.IsClose)\r\n ss = searchNext(ss, pl);\r\n ss = s;\r\n while (ss && !pl.IsClose)\r\n ss = searchNext(ss, pl);\r\n\r\n if (pl.NumberOfVertices > 0)\r\n {\r\n let d = pl.LineData;\r\n let ld = arrayLast(d);\r\n if (equalv2(d[0].pt, ld.pt, 1e-2))\r\n ld.pt.copy(d[0].pt);\r\n this._RetCurves.push(pl.ApplyMatrix(this._CacheOCS));\r\n }\r\n }\r\n }\r\n\r\n CheckPointDir(pt: Vector3): boolean\r\n {\r\n return this.GetPointAtCurveDir(pt) === this._OffsetDistSign;\r\n }\r\n\r\n GetPointAtCurveDir(pt: Vector3): number\r\n {\r\n let minIndex = Infinity;\r\n let minDist = Infinity;\r\n let minCp: Vector3;\r\n for (let i = 0; i < this._SubCurves.length; i++)\r\n {\r\n let c = this._SubCurves[i];\r\n let cp = c.GetClosestPointTo(pt, false);\r\n if (equalv3(cp, pt, 1e-5)) return 0;\r\n\r\n let dist = cp.distanceToSquared(pt);\r\n if (dist < minDist)\r\n {\r\n minDist = dist;\r\n minIndex = i;\r\n minCp = cp;\r\n }\r\n }\r\n\r\n let c = this._SubCurves[minIndex];\r\n let param = c.GetParamAtPoint(minCp);\r\n\r\n if (equaln(param, 0) && ((minIndex === 0) ? this._IsClose : true))\r\n {\r\n let preIndex = FixIndex(minIndex - 1, this._SubCurves);\r\n let preCurve = this._SubCurves[preIndex];\r\n\r\n if (!equalv3(c.GetFistDeriv(0).normalize(), preCurve.GetFistDeriv(1).normalize()))\r\n {\r\n let p = c.StartPoint;\r\n let l1 = c.Length;\r\n let l2 = preCurve.Length;\r\n let minLength = Math.min(l1, l2) * 0.2;\r\n\r\n let nextP: Vector3;\r\n let preP: Vector3;\r\n if (c instanceof Arc)\r\n nextP = c.GetPointAtDistance(minLength);\r\n else\r\n nextP = c.EndPoint;\r\n\r\n if (preCurve instanceof Arc)\r\n preP = preCurve.GetPointAtDistance(l2 - minLength);\r\n else\r\n preP = preCurve.StartPoint;\r\n\r\n let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p)));\r\n\r\n let dir = arc.PtOnCurve3(pt) ? -1 : 1;\r\n return dir;\r\n }\r\n }\r\n else if (equaln(param, 1) && ((minIndex === this._SubCurves.length - 1) ? this._IsClose : true))\r\n {\r\n let nextIndex = FixIndex(minIndex + 1, this._SubCurves);\r\n let nextCurve = this._SubCurves[nextIndex];\r\n\r\n if (!equalv3(c.GetFistDeriv(1).normalize(), nextCurve.GetFistDeriv(0).normalize()))\r\n {\r\n let p = c.EndPoint;\r\n\r\n let l1 = c.Length;\r\n let l2 = nextCurve.Length;\r\n let minLength = Math.min(l1, l2) * 0.2;\r\n\r\n let nextP: Vector3;\r\n let preP: Vector3;\r\n if (c instanceof Arc)\r\n preP = c.GetPointAtDistance(l1 - minLength);\r\n else\r\n preP = c.StartPoint;\r\n\r\n if (nextCurve instanceof Arc)\r\n nextP = nextCurve.GetPointAtDistance(minLength);\r\n else\r\n nextP = nextCurve.EndPoint;\r\n\r\n let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p)));\r\n\r\n let dir = arc.PtOnCurve3(pt) ? -1 : 1;\r\n return dir;\r\n }\r\n }\r\n\r\n let dri = c.GetFistDeriv(param);\r\n let cross = dri.cross(pt.clone().sub(minCp));\r\n return -Math.sign(cross.z);\r\n }\r\n\r\n protected CreateArc(center: Vector3, startP: Vector3, endP?: Vector3)\r\n {\r\n let sa = angle(startP.clone().sub(center));\r\n let ea = endP ? angle(endP.clone().sub(center)) : sa;\r\n let arc = new Arc(center, Math.abs(this._OffsetDist), sa, ea, this._OffsetDist < 0);\r\n return arc;\r\n }\r\n}\r\n\r\nfunction EntityEncode(c: Curve)\r\n{\r\n if (c instanceof Line) return 1;\r\n else return 2;\r\n}\r\nfunction EntityEncode2(c1: Curve, c2: Curve)\r\n{\r\n return EntityEncode(c1) & EntityEncode(c2);\r\n}\r\n","import { Vector2, Vector3 } from 'three';\r\nimport { angle, equaln, equalv3 } from '../Geometry/GeUtils';\r\nimport { IntersectOption } from '../GraphicsSystem/IntersectWith';\r\nimport { Arc } from './Entity/Arc';\r\nimport { Line } from './Entity/Line';\r\nimport { Polyline } from './Entity/Polyline';\r\n\r\n/**\r\n * 点在扇形内部,提供一个简单实现的版本.\r\n * 优化版本请参照:http://www.cnblogs.com/miloyip/archive/2013/04/19/3029852.html\r\n * \r\n * @param arc 二维圆弧\r\n * @param pt \r\n * @returns 点在扇形内部.\r\n */\r\nfunction IsPointInCircularSector(arc: Arc, pt: Vector3): boolean\r\n{\r\n let center = arc.Center;\r\n let disSq = center.distanceTo(pt);\r\n if (disSq > arc.Radius * arc.Radius) return false;\r\n let an = angle(pt.clone().sub(center));\r\n let param = arc.GetParamAtAngle(an);\r\n return arc.ParamOnCurve(param);\r\n}\r\n\r\n/**\r\n * 点在弓型内部\r\n * \r\n * @param arc 二维圆弧\r\n * @param pt 点\r\n * @param isInChrodIsTrue 当点在弦上也认为在弓形内部\r\n * @returns 点在内部\r\n */\r\nexport function IsPointInBowArc(arc: Arc, pt: Vector3, isInChrodIsTrue = false): boolean\r\n{\r\n let pv = pt.clone().sub(arc.StartPoint);\r\n let av = arc.EndPoint.sub(arc.StartPoint);\r\n\r\n pv.cross(av);\r\n\r\n //未优化的代码\r\n // if (pv.z > 0 && arc.IsClockWise)\r\n // return false;\r\n // else if (pv.z < 0 && !arc.IsClockWise)\r\n // return false;\r\n // else\r\n // return arc.Center.distanceToSquared(pt) < arc.Radius * arc.Radius;\r\n\r\n //简化的代码\r\n if ((pv.z > 0) !== arc.IsClockWise || (isInChrodIsTrue && equaln(pv.z, 0)))\r\n {\r\n return arc.Center.distanceToSquared(pt) < arc.Radius * arc.Radius;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * 判断点在多段线内外\r\n * @param pl 多段线\r\n * @param pt 点\r\n * @returns 点在多段线内部\r\n */\r\nexport function IsPointInPolyLine(pl: Polyline, pt: Vector3): boolean\r\n{\r\n let crossings = 0;\r\n\r\n let insLine = new Line(pt, pt.clone().add(new Vector3(0, 10, 0)));\r\n\r\n for (let i = 0; i < pl.EndParam; i++)\r\n {\r\n if (equaln(pl.GetBuilgeAt(i), 0, 5e-6))//直线\r\n {\r\n let sp = pl.GetPointAtParam(i);\r\n let ep = pl.GetPointAtParam(i + 1);\r\n //点位于线上面\r\n if (pt.y > Math.max(sp.y, ep.y))\r\n continue;\r\n //线垂直Y轴\r\n let derX = ep.x - sp.x;\r\n if (equaln(derX, 0, 5e-6))\r\n continue;\r\n\r\n //起点\r\n if (equaln(sp.x, pt.x, 5e-6))\r\n {\r\n if (sp.y > pt.y && derX < 0) crossings++;\r\n continue;\r\n }\r\n //终点\r\n if (equaln(ep.x, pt.x, 5e-6))\r\n {\r\n if (ep.y > pt.y && derX > 0) crossings++;\r\n continue;\r\n }\r\n\r\n //快速求交,只验证有没有交点\r\n let [x1, x2] = sp.x > ep.x ? [ep.x, sp.x] : [sp.x, ep.x];\r\n if (pt.x > x1 && pt.x < x2)\r\n {\r\n let derY = ep.y - sp.y;\r\n let k = derY / derX;\r\n\r\n if ((pt.x - sp.x) * k + sp.y > pt.y)\r\n crossings++;\r\n }\r\n }\r\n else //圆弧\r\n {\r\n let arc = pl.GetCurveAtIndex(i) as Arc;\r\n let sp = arc.StartPoint;\r\n let ep = arc.EndPoint;\r\n\r\n //如果相切\r\n if (equaln(Math.abs(pt.x - arc.Center.x), arc.Radius))\r\n {\r\n //当点和起点或者终点和点相切时\r\n if (equaln(sp.x, pt.x) && sp.y > pt.y)\r\n {\r\n if (ep.x - sp.x < -1e-5)\r\n crossings++;\r\n }\r\n else if (equaln(ep.x, pt.x) && ep.y > pt.y)\r\n {\r\n if (ep.x - sp.x > 1e-5)\r\n crossings++;\r\n }\r\n continue;\r\n }\r\n if (equaln(sp.x, pt.x) && sp.y > pt.y)\r\n {\r\n let der = arc.GetFistDeriv(0);\r\n if (der.x < -1e-5)\r\n crossings++;\r\n }\r\n if (equaln(ep.x, pt.x) && ep.y > pt.y)\r\n {\r\n let der = arc.GetFistDeriv(1);\r\n if (der.x > 1e-5)\r\n crossings++;\r\n }\r\n\r\n for (let pti of arc.IntersectWith(insLine, IntersectOption.ExtendArg))\r\n {\r\n if (pti.y < pt.y || equalv3(sp, pti, 1e-5) || equalv3(ep, pti, 1e-5))\r\n continue;\r\n\r\n let der = arc.GetFistDeriv(pti);\r\n if (!equaln(der.x, 0)) //相切.\r\n crossings++;\r\n }\r\n }\r\n }\r\n\r\n return (crossings % 2) === 1;\r\n}\r\n\r\n/**\r\n * 点在区域内部\r\n * \r\n * @param pt \r\n * @param pts \r\n * @returns \r\n */\r\nfunction IsPointInPolygon(pt: Vector3, pts: Vector2[])\r\n{\r\n let crossings = 0; //int\r\n let [px, py] = [pt.x, pt.y];\r\n\r\n let ptCout = pts.length;\r\n for (let i = 0; i < ptCout; i++)\r\n {\r\n let pti = pts[i];\r\n let ptn = pts[(i + 1) % ptCout];\r\n\r\n let [x1, x2] = [pti.x, ptn.x];\r\n\r\n /* This is done to ensure that we get the same result when\r\n the line goes from left to right and right to left */\r\n if (x1 > x2) [x1, x2] = [x2, x1];\r\n\r\n /* First check if the ray is possible to cross the line */\r\n if (px > x1 && px <= x2 && (py < pti.y || py <= ptn.y))\r\n {\r\n const eps = 0.000001;\r\n\r\n /* Calculate the equation of the line */\r\n let dx = ptn.x - pti.x;\r\n let dy = ptn.y - pti.y;\r\n let k;\r\n\r\n if (Math.abs(dx) < eps)\r\n k = 1e300;\r\n else\r\n k = dy / dx;\r\n\r\n let m = pti.y - k * pts[i].x;\r\n\r\n /* Find if the ray crosses the line */\r\n let y2 = k * px + m;\r\n if (py <= y2)\r\n crossings++;\r\n }\r\n }\r\n\r\n return crossings % 2 === 1;\r\n}\r\n","export enum DragPointType\r\n{\r\n Grip = 0,\r\n Stretch = 1\r\n}\r\n","import { Box3, BufferGeometry, Line as TLine, Matrix3, Matrix4, Object3D, Vector2, Vector3 } from 'three';\r\nimport { CreateBoardUtil } from '../../ApplicationServices/mesh/createBoard';\r\nimport { arrayLast, arrayRemoveDuplicateBySort, changeArrayStartIndex } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { ComputerCurvesNormalOCS, getDeterminantFor2V } from '../../Common/CurveUtils';\r\nimport { matrixAlignCoordSys, matrixIsCoplane, reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { Status } from '../../Common/Status';\r\nimport { FixIndex } from '../../Common/Utils';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { AsVector2, AsVector3, equaln, equalv2, equalv3, updateGeometry } from '../../Geometry/GeUtils';\r\nimport { IntersectOption, IntersectPolylineAndCurve } from '../../GraphicsSystem/IntersectWith';\r\nimport { OffsetPolyline } from '../../GraphicsSystem/OffsetPolyline';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { IsPointInPolyLine } from '../PointInPolyline';\r\nimport { Arc } from './Arc';\r\nimport { Curve, ExtendType } from './Curve';\r\nimport { DragPointType } from './DragPointType';\r\nimport { Line } from './Line';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\n\r\nexport interface PolylineProps\r\n{\r\n pt: Vector2,\r\n bul: number;\r\n}\r\n@Factory\r\nexport class Polyline extends Curve\r\n{\r\n private _ClosedMark: boolean = false;\r\n constructor(private _LineData: PolylineProps[] = [])\r\n {\r\n super();\r\n }\r\n\r\n UpdateMatrixTo(m: Matrix4)\r\n {\r\n this.WriteAllObjectRecord();\r\n let p = new Vector3().setFromMatrixPosition(m);\r\n p.applyMatrix4(this.OCSInv);\r\n if (equaln(p.z, 0))\r\n {\r\n let dir = Math.sign(this.Area2);\r\n let tm = matrixAlignCoordSys(this.OCS, m);\r\n for (let p of this._LineData)\r\n {\r\n let p3 = AsVector3(p.pt);\r\n p3.applyMatrix4(tm);\r\n p.pt.set(p3.x, p3.y);\r\n }\r\n this.OCS = m;\r\n let newDir = Math.sign(this.Area2);\r\n if (dir !== newDir)\r\n for (let p of this._LineData)\r\n p.bul *= -1;\r\n }\r\n }\r\n\r\n /**\r\n * 原地翻转,仅改变法向量\r\n */\r\n Flip()\r\n {\r\n this.WriteAllObjectRecord();\r\n let x = new Vector3();\r\n let y = new Vector3();\r\n let z = new Vector3();\r\n this._Matrix.extractBasis(x, y, z);\r\n z.negate();\r\n y.crossVectors(z, x);\r\n let p = this.Position;\r\n this._Matrix.makeBasis(x, y, z).setPosition(p);\r\n\r\n for (let d of this._LineData)\r\n {\r\n d.pt.y *= -1;\r\n d.bul *= -1;\r\n }\r\n this.Update();\r\n return this;\r\n }\r\n\r\n //翻转曲线,首尾调换\r\n Reverse(): this\r\n {\r\n if (this._LineData.length === 0)\r\n return this;\r\n this.WriteAllObjectRecord();\r\n\r\n let pts = [];\r\n let buls = [];\r\n for (let data of this._LineData)\r\n {\r\n pts.push(data.pt);\r\n buls.push(-data.bul);\r\n }\r\n\r\n let lastBul = buls.pop();\r\n buls.reverse();\r\n buls.push(lastBul);\r\n\r\n pts.reverse();\r\n\r\n if (this._ClosedMark && !equalv2(pts[0], arrayLast(pts)))\r\n {\r\n pts.unshift(pts.pop());\r\n buls.unshift(buls.pop());\r\n }\r\n\r\n for (let i = 0; i < pts.length; i++)\r\n {\r\n let d = this._LineData[i];\r\n d.pt = pts[i];\r\n d.bul = buls[i];\r\n }\r\n\r\n return this;\r\n }\r\n set LineData(data: PolylineProps[])\r\n {\r\n this.WriteAllObjectRecord();\r\n this._LineData = data;\r\n this.Update();\r\n }\r\n get LineData()\r\n {\r\n return this._LineData;\r\n }\r\n\r\n get NumberOfVertices(): number\r\n {\r\n return this._LineData.length;\r\n }\r\n\r\n /**\r\n * 在指定位置插入点.\r\n * 例如:\r\n * pl.AddVertexAt(pl.NumberOfVerticesk,p);//在末尾插入一个点\r\n *\r\n * @param {number} index 索引位置\r\n * @param {Vector2} pt 点\r\n * @returns {this}\r\n * @memberof Polyline\r\n */\r\n AddVertexAt(index: number, pt: Vector2 | Vector2[]): this\r\n {\r\n this.WriteAllObjectRecord();\r\n let pts: PolylineProps[];\r\n if (Array.isArray(pt))\r\n {\r\n pts = pt.map(p =>\r\n {\r\n return {\r\n pt: p.clone(),\r\n bul: 0\r\n };\r\n });\r\n }\r\n else\r\n pts = [{ pt: pt.clone(), bul: 0 }];\r\n\r\n this._LineData.splice(index, 0, ...pts);\r\n this.Update();\r\n return this;\r\n }\r\n RemoveVertexAt(index: number): this\r\n {\r\n if (index < this._LineData.length)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._LineData.splice(index, 1);\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n RemoveVertexIn(from: number, to: number): this\r\n {\r\n if (from + 1 < this._LineData.length && to > from)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._LineData.splice(from + 1, to - from - 1);\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * 重设闭合多段线的起点\r\n * @param index 起始index,如果index非整数,将用最接近的整数作为起始索引\r\n */\r\n ResetStartPoint(index: number)\r\n {\r\n if (!this.IsClose || index >= this.EndParam) return false;\r\n\r\n if (equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))\r\n this._LineData.pop();\r\n\r\n changeArrayStartIndex(this._LineData, Math.floor(index + 0.5));\r\n this._LineData.push({\r\n pt: this._LineData[0].pt.clone(),\r\n bul: 0\r\n });\r\n return true;\r\n }\r\n GetPoint2dAt(index: number): Vector2 | undefined\r\n {\r\n if (index >= 0 && this._LineData.length > index)\r\n return this._LineData[index].pt.clone();\r\n }\r\n /**\r\n * 设置指定点的位置\r\n *\r\n * @param {number} index\r\n * @param {Vector2} pt\r\n * @memberof Polyline\r\n */\r\n SetPointAt(index: number, pt: Vector2): this\r\n {\r\n let d = this._LineData[index];\r\n if (d)\r\n {\r\n this.WriteAllObjectRecord();\r\n d.pt.copy(pt);\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n for (let i = 0; i <= this.EndParam; i++)\r\n {\r\n let p = this.GetPointAtParam(i);\r\n p.applyMatrix4(m).applyMatrix4(this.OCSInv);\r\n this.SetPointAt(i, AsVector2(p));\r\n }\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n let oldPts = this.GetStretchPoints();\r\n reviseMirrorMatrix(this._Matrix);\r\n for (let i = 0; i < oldPts.length; i++)\r\n {\r\n let newP = oldPts[i].applyMatrix4(this.OCSInv);\r\n let newBul = -this.GetBuilgeAt(i);\r\n this.SetPointAt(i, AsVector2(newP));\r\n this.SetBulgeAt(i, newBul);\r\n }\r\n this.Reverse();\r\n return this;\r\n }\r\n SetBulgeAt(index: number, bul: number): this\r\n {\r\n let d = this._LineData[index];\r\n if (d)\r\n {\r\n this.WriteAllObjectRecord();\r\n d.bul = bul;\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n GetBuilgeAt(index: number): number\r\n {\r\n return this._LineData[index].bul;\r\n }\r\n Rectangle(length: number, height: number): this\r\n {\r\n this.LineData = [\r\n { pt: new Vector2(), bul: 0 },\r\n { pt: new Vector2(length), bul: 0 },\r\n { pt: new Vector2(length, height), bul: 0 },\r\n { pt: new Vector2(0, height), bul: 0 }];\r\n this.CloseMark = true;\r\n return this;\r\n }\r\n RectangleFrom2Pt(p1: Vector3, p2: Vector3): this\r\n {\r\n let box = new Box3();\r\n box.setFromPoints([p2, p1].map((p: Vector3) => p.clone().applyMatrix4(this.OCSInv)));\r\n\r\n let px1 = AsVector2(box.min);\r\n let px3 = AsVector2(box.max);\r\n let px2 = new Vector2(px3.x, px1.y);\r\n let px4 = new Vector2(px1.x, px3.y);\r\n\r\n this.LineData = [\r\n { pt: px1, bul: 0 },\r\n { pt: px2, bul: 0 },\r\n { pt: px3, bul: 0 },\r\n { pt: px4, bul: 0 }];\r\n\r\n this.CloseMark = true;\r\n return this;\r\n }\r\n //多段线起点\r\n get StartPoint()\r\n {\r\n if (this._LineData.length > 0)\r\n return AsVector3(this._LineData[0].pt).applyMatrix4(this.OCS);\r\n return new Vector3();\r\n }\r\n set StartPoint(p: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n p = p.clone().applyMatrix4(this.OCSInv);\r\n\r\n if (this._LineData.length === 0)\r\n this.AddVertexAt(0, AsVector2(p));\r\n else if (this._LineData.length === 1)\r\n this.SetPointAt(0, AsVector2(p));\r\n else\r\n {\r\n let bul = this.GetBuilgeAt(0);\r\n if (bul !== 0)\r\n {\r\n let arc = this.GetCurveAtParam(0) as Arc;\r\n arc.StartPoint = p;\r\n //前面线的凸度调整\r\n this.SetBulgeAt(0, Math.tan(arc.AllAngle / 4) * Math.sign(bul));\r\n }\r\n this.SetPointAt(0, AsVector2(p));\r\n }\r\n }\r\n get EndPoint()\r\n {\r\n if (this._ClosedMark) return this.StartPoint;\r\n if (this._LineData.length > 0)\r\n return AsVector3(this._LineData[this.EndParam].pt).applyMatrix4(this.OCS);\r\n return new Vector3();\r\n }\r\n set EndPoint(p: Vector3)\r\n {\r\n if (this._LineData.length < 2 || this.CloseMark)\r\n return;\r\n\r\n this.WriteAllObjectRecord();\r\n p = p.clone().applyMatrix4(this.OCSInv);\r\n\r\n let bul = this.GetBuilgeAt(this.EndParam - 1);\r\n if (bul !== 0)\r\n {\r\n let arc = this.GetCurveAtParam(this.EndParam - 1) as Arc;\r\n arc.ApplyMatrix(this.OCSInv);\r\n arc.EndPoint = p;\r\n //前面线的凸度调整\r\n this.SetBulgeAt(this.EndParam - 1, Math.tan(arc.AllAngle / 4) * Math.sign(bul));\r\n }\r\n this.SetPointAt(this.EndParam, AsVector2(p));\r\n }\r\n\r\n get CurveCount(): number\r\n {\r\n return this.EndParam;\r\n }\r\n\r\n get StartParam()\r\n {\r\n return 0;\r\n }\r\n\r\n /**\r\n * 表示最后一条曲线的终止参数,使用该参数可以直接遍历到多段线的所有子线段. for(i 1 && (equalv3(this.StartPoint, this.EndPoint, 1e-4)));\r\n }\r\n set CloseMark(v: boolean)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._ClosedMark = v;\r\n this.Update();\r\n }\r\n\r\n DigestionCloseMark()\r\n {\r\n if (this._ClosedMark && this._LineData.length > 1)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._ClosedMark = false;\r\n\r\n if (!equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))\r\n this._LineData.push({ pt: AsVector2(this._LineData[0].pt), bul: 0 });\r\n }\r\n }\r\n\r\n get Length()\r\n {\r\n return this.Explode().reduce((l, cu) => l + cu.Length, 0);\r\n }\r\n\r\n /**\r\n * 获得指定参数所在的点.\r\n * 当曲线存在闭合标志时,参数必须在曲线内部.\r\n * 当曲线不存在闭合标志时,参数允许延伸出曲线.\r\n *\r\n * @param {number} param 参数\r\n * @returns {Vector3} 三维点,可为空\r\n * @memberof Polyline\r\n */\r\n GetPointAtParam(param: number): Vector3\r\n {\r\n if (param === Math.floor(param) && this.ParamOnCurve(param))\r\n return AsVector3(this.GetPoint2dAt(FixIndex(param, this.NumberOfVertices))).applyMatrix4(this.OCS);\r\n let cu: Curve = this.GetCurveAtParam(param);\r\n if (cu)\r\n return cu.GetPointAtParam(this.GetCurveParamAtParam(param));\r\n return undefined;\r\n }\r\n\r\n GetDistAtParam(param: number): number\r\n {\r\n if (this._ClosedMark && !this.ParamOnCurve(param))\r\n return NaN;\r\n\r\n //参数 整数\r\n let paramFloor = Math.floor(param);\r\n //需要计算的曲线个数\r\n let cuCout = paramFloor > this.EndParam ? this.EndParam : paramFloor;\r\n\r\n let dist = 0;\r\n //首先计算完整曲线的长度\r\n for (let i = 0; i < cuCout; i++)\r\n {\r\n dist += this.GetCurveAtIndex(i).Length;\r\n }\r\n\r\n //参数已经大于索引,证明参数在线外.\r\n if (paramFloor !== cuCout)\r\n {\r\n dist += this.GetCurveAtParam(param).GetDistAtParam(param - cuCout);\r\n }\r\n else if (param > paramFloor)\r\n {\r\n let lastParam = param - paramFloor;\r\n dist += this.GetCurveAtParam(param).GetDistAtParam(lastParam);\r\n }\r\n\r\n return dist;\r\n }\r\n GetPointAtDistance(dist: number): Vector3\r\n {\r\n let param = this.GetParamAtDist(dist);\r\n return this.GetPointAtParam(param);\r\n }\r\n\r\n /**\r\n * 返回参数所在的点. 如果曲线不闭合,会试图返回延伸点参数\r\n *\r\n * @param {Vector3} pt\r\n * @returns {number}\r\n * @memberof Polyline\r\n */\r\n GetParamAtPoint(pt: Vector3): number\r\n {\r\n let cus = this.Explode();\r\n if (cus.length === 0) return NaN;\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let cu = cus[i];\r\n let param = cu.GetParamAtPoint(pt);\r\n if (cu.ParamOnCurve(param))\r\n return i + param; //返回点在曲线内部的参数\r\n }\r\n\r\n //当曲线闭合时,不需要延伸首尾去判断参数\r\n if (this._ClosedMark) return NaN;\r\n\r\n //起点终点参数集合\r\n let seParams: number[] = [];\r\n //点在第一条曲线上的参数\r\n let startParam = cus[0].GetParamAtPoint(pt);\r\n if (!isNaN(startParam) && startParam < 0)\r\n seParams.push(startParam);\r\n //点在最后一条线上的参数\r\n let endParam = cus[cus.length - 1].GetParamAtPoint(pt);\r\n if (!isNaN(endParam) && endParam > 0)\r\n seParams.push(endParam + this.EndParam - 1);\r\n\r\n if (seParams.length == 1)\r\n {\r\n return seParams[0];\r\n }\r\n else if (seParams.length == 2)\r\n {\r\n //返回较近的参数\r\n if (pt.distanceToSquared(this.StartPoint)\r\n < pt.distanceToSquared(this.EndPoint))\r\n return seParams[0];\r\n else\r\n return seParams[1];\r\n }\r\n return NaN;\r\n }\r\n GetParamAtDist(dist: number): number\r\n {\r\n let cus = this.Explode();\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let cu = cus[i];\r\n let len = cu.Length;\r\n if (dist <= len)\r\n return i + cu.GetParamAtDist(dist);\r\n else if (equaln(dist, len, 1e-8))\r\n return i + 1;\r\n dist -= len;\r\n }\r\n if (!this._ClosedMark)\r\n return cus.length + cus[cus.length - 1].GetParamAtDist(dist);\r\n\r\n return NaN;\r\n }\r\n GetDistAtPoint(pt: Vector3): number\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n if (!this.ParamOnCurve(param)) return NaN;\r\n return this.GetDistAtParam(param);\r\n }\r\n\r\n /**\r\n * 返回曲线的一阶导数.\r\n * 当曲线闭合(标志)且点不在曲线上.\r\n * 或者曲线不闭合(标志) 且点不在曲线上也不在延伸上\r\n *\r\n * @param {(number | Vector3)} param\r\n * @returns {Vector3}\r\n * @memberof Polyline\r\n */\r\n GetFistDeriv(param: number | Vector3): Vector3\r\n {\r\n if (param instanceof Vector3)\r\n param = this.GetParamAtPoint(param);\r\n\r\n if (isNaN(param))\r\n return undefined;\r\n\r\n let cu = this.GetCurveAtParam(param);\r\n\r\n if (!cu) return undefined;\r\n\r\n return cu.GetFistDeriv(this.GetCurveParamAtParam(param));\r\n }\r\n GetSplitCurves(param: number[] | number): Array\r\n {\r\n //参数需要转化为参数数组\r\n let params: number[];\r\n if (typeof param == \"number\")\r\n params = [param];\r\n else\r\n params = param;\r\n\r\n //校验参数在曲线中,修正参数\r\n let endParam = this.EndParam;\r\n params = params.filter(p => this.ParamOnCurve(p) && p > -1e-6)\r\n .map(a =>\r\n {\r\n if (a < 0) return 0;\r\n if (a > endParam) return endParam;\r\n if (equaln(a, Math.floor(a + 0.5), 1e-8))\r\n return Math.floor(a + 0.5);\r\n return a;\r\n });\r\n //排序\r\n params.sort((a, b) => a - b);\r\n let hasEndParam = arrayLast(params) === this.EndParam;\r\n //必须加入最后一个参数,保证切割后的曲线完整\r\n if (!hasEndParam)\r\n params.push(this.EndParam);\r\n arrayRemoveDuplicateBySort(params, (e1, e2) => equaln(e1, e2, 1e-8));\r\n params = params.filter(p => this.ParamOnCurve(p));\r\n if (params.length === 0)\r\n return [];\r\n\r\n //判断是否存在0参数\r\n let hasZeroParam = params[0] === 0;\r\n if (hasZeroParam)\r\n params.shift();\r\n\r\n let { pts, buls } = this.PtsBuls;\r\n\r\n //返回的多段线集合\r\n let pls: Polyline[] = [];\r\n\r\n let len = 0;//已经走过的参数长度(整数)\r\n\r\n //上一个切割参数的位置 0-1\r\n let prePa = 0;\r\n for (let pa of params)\r\n {\r\n //参数所在点\r\n let pt = AsVector2(this.GetPointAtParam(pa).applyMatrix4(this.OCSInv));\r\n pa -= len;\r\n let pafloor = Math.floor(pa);\r\n len += pafloor;\r\n\r\n let plData: PolylineProps[] = [];\r\n\r\n //添加点\r\n for (let i = 0; i < pafloor; i++)\r\n {\r\n if (i === 0 && !equaln(buls[0], 0, 1e-8))\r\n {\r\n buls[0] = Math.tan((1 - prePa) * Math.atan(buls[0]));\r\n }\r\n plData.push({ pt: pts[0], bul: buls[0] });\r\n pts.shift();\r\n buls.shift();\r\n }\r\n\r\n if (equaln(pa, pafloor, 1e-8))//如果pa在点上\r\n {\r\n plData.push({ pt: pts[0].clone(), bul: buls[0] });\r\n }\r\n else //在曲线上\r\n {\r\n let bul: number = buls[0];\r\n if (!equaln(bul, 0, 1e-6))\r\n bul = Math.tan((pa - pafloor - (0 === pafloor ? prePa : 0)) * Math.atan(buls[0])); //->凸度\r\n\r\n //加入顶点+凸度\r\n plData.push({ pt: pts[0].clone(), bul });\r\n //终点\r\n plData.push({ pt, bul: 0 });\r\n\r\n //修正剩余的点表和凸度表\r\n pts[0].copy(pt);\r\n }\r\n\r\n prePa = pa - pafloor;\r\n if (plData.length > 1)\r\n pls.push(new Polyline(plData).ApplyMatrix(this.OCS));\r\n }\r\n\r\n //当曲线为闭合曲线,并且不存在0切割参数时,首尾连接曲线\r\n if (this._ClosedMark && !hasZeroParam && !hasEndParam)\r\n {\r\n let lastPl = pls[pls.length - 1];\r\n if (equalv2(arrayLast(lastPl._LineData).pt, pls[0]._LineData[0].pt))\r\n lastPl._LineData.pop();\r\n\r\n lastPl._LineData.push(...pls[0]._LineData);\r\n\r\n pls.shift();\r\n }\r\n return pls;\r\n }\r\n\r\n //未完善\r\n GetCurveAtParamRange(startParam: number, endParam: number): Array\r\n {\r\n let sfloor = Math.floor(startParam + 0.5);\r\n if (equaln(sfloor, startParam, 1e-8)) startParam = sfloor;\r\n else sfloor = Math.floor(startParam);\r\n let efloor = Math.floor(endParam + 0.5);\r\n if (equaln(efloor, endParam, 1e-8)) endParam = efloor;\r\n else efloor = Math.floor(efloor);\r\n\r\n const GetCurve = (index: number) =>\r\n {\r\n let d = this._LineData[index];\r\n let next = this._LineData[index + 1];\r\n if (!equaln(d.bul, 0, 1e-8))\r\n return new Arc().ParseFromBul(d.pt, next.pt, d.bul);\r\n else\r\n return new Line(AsVector3(d.pt), AsVector3(next.pt));\r\n };\r\n\r\n let lined: PolylineProps[] = [];\r\n if (startParam === sfloor)\r\n {\r\n let d = this._LineData[sfloor];\r\n lined.push({ pt: d.pt.clone(), bul: d.bul });\r\n }\r\n else\r\n {\r\n let d = this._LineData[sfloor];\r\n let cu = GetCurve(sfloor);\r\n let remParam = startParam - sfloor;\r\n let p = cu.GetPointAtParam(remParam);\r\n let bul = d.bul;\r\n if (!equaln(bul, 0))\r\n bul = Math.tan(Math.atan(bul) * (1 - remParam));\r\n lined.push({ pt: AsVector2(p), bul: bul });\r\n }\r\n\r\n for (let i = sfloor + 1; i < efloor; i++)\r\n {\r\n let d = this._LineData[i];\r\n lined.push({ pt: d.pt.clone(), bul: d.bul });\r\n }\r\n\r\n if (efloor !== endParam)\r\n {\r\n let d = this.LineData[efloor];\r\n let remParam = endParam - efloor;\r\n let cu = GetCurve(efloor);\r\n let p = cu.GetPointAtParam(remParam);\r\n let bul = d.bul;\r\n if (!equaln(bul, 0))\r\n {\r\n arrayLast(lined).bul = Math.tan(Math.atan(bul) * remParam);\r\n bul = Math.tan(Math.atan(bul) * (1 - remParam));\r\n }\r\n lined.push({ pt: AsVector2(p), bul });\r\n }\r\n\r\n let pl = new Polyline(lined);\r\n pl.OCS = this.OCSNoClone;\r\n return;\r\n }\r\n\r\n Extend(newParam: number)\r\n {\r\n if (this.CloseMark || this.ParamOnCurve(newParam)) return;\r\n\r\n this.WriteAllObjectRecord();\r\n\r\n let ptIndex: number;\r\n let bulIndex: number;\r\n\r\n if (newParam < 0)\r\n {\r\n ptIndex = 0;\r\n bulIndex = 0;\r\n }\r\n else if (newParam > this.EndParam)\r\n {\r\n ptIndex = this.EndParam;\r\n bulIndex = ptIndex - 1;\r\n }\r\n\r\n //修改顶点\r\n this._LineData[ptIndex].pt = AsVector2(this.GetPointAtParam(newParam).applyMatrix4(this.OCSInv));\r\n\r\n //修改凸度\r\n let oldBul = this._LineData[bulIndex].bul;\r\n if (oldBul != 0)\r\n this._LineData[bulIndex].bul = Math.tan(Math.atan(oldBul) * (1 + newParam - ptIndex));\r\n\r\n this.Update();\r\n }\r\n\r\n //const this\r\n MatrixAlignTo2(toMatrix: Matrix4)\r\n {\r\n if (!matrixIsCoplane(this._Matrix, toMatrix, 1e-4))\r\n return this.PtsBuls;\r\n\r\n let m = matrixAlignCoordSys(this._Matrix, toMatrix);\r\n\r\n let z1 = this.Normal;\r\n let z2 = new Vector3().setFromMatrixColumn(toMatrix, 2);\r\n let isMirror = equalv3(z1, z2.negate());\r\n\r\n let pts: Vector2[] = [];\r\n let buls: number[] = [];\r\n for (let d of this._LineData)\r\n {\r\n let p = AsVector2(AsVector3(d.pt).applyMatrix4(m));\r\n pts.push(p);\r\n buls.push(isMirror ? -d.bul : d.bul);\r\n }\r\n return { pts, buls };\r\n }\r\n\r\n Join(cu: Curve, allowGap = false, tolerance = 1e-4)\r\n {\r\n this.WriteAllObjectRecord();\r\n if (this._ClosedMark)\r\n return Status.False;\r\n\r\n let [sp, ep, cuSp, cuEp] = [this.StartPoint, this.EndPoint, cu.StartPoint, cu.EndPoint];\r\n\r\n let ocsInv = this.OCSInv;\r\n let [cuSp2, cuEp2] = [cuSp, cuEp].map(p => AsVector2(p.clone().applyMatrix4(ocsInv)));\r\n\r\n if (this._LineData.length === 0)\r\n {\r\n if (cu instanceof Line)\r\n {\r\n this._LineData.push({ pt: cuSp2, bul: 0 });\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (cu instanceof Arc)\r\n {\r\n this._LineData.push({ pt: cuSp2, bul: cu.Bul });\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (cu instanceof Polyline)\r\n {\r\n let f = new CADFiler();\r\n cu.WriteFile(f);\r\n this.ReadFile(f);\r\n }\r\n else\r\n return Status.False;\r\n }\r\n else\r\n {\r\n enum LinkType\r\n {\r\n None = 0,\r\n SpSp = 1,\r\n SpEp = 2,\r\n EpSp = 3,\r\n EpEp = 4,\r\n };\r\n\r\n let spspDisSq = cuSp.distanceToSquared(sp);\r\n let spepDisSq = cuSp.distanceToSquared(ep);\r\n let epspDisSq = cuEp.distanceToSquared(sp);\r\n let epepDisSq = cuEp.distanceToSquared(ep);\r\n let minDis = tolerance * tolerance;\r\n\r\n let linkType = LinkType.None;\r\n\r\n if (spspDisSq < minDis)\r\n {\r\n linkType = LinkType.SpSp;\r\n minDis = spspDisSq;\r\n }\r\n\r\n if (spepDisSq < minDis)\r\n {\r\n linkType = LinkType.SpEp;\r\n minDis = spepDisSq;\r\n }\r\n\r\n if (epspDisSq < minDis)\r\n {\r\n linkType = LinkType.EpSp;\r\n minDis = epspDisSq;\r\n }\r\n\r\n if (epepDisSq < minDis)\r\n linkType = LinkType.EpEp;\r\n\r\n if (linkType === LinkType.None)\r\n return Status.False;\r\n\r\n if (cu instanceof Line)\r\n {\r\n if (linkType === LinkType.SpSp)\r\n {\r\n this._LineData.unshift({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.SpEp)\r\n {\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.EpSp)\r\n {\r\n this._LineData.unshift({ pt: cuSp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.EpEp)\r\n {\r\n this._LineData.push({ pt: cuSp2, bul: 0 });\r\n }\r\n }\r\n else if (cu instanceof Arc)\r\n {\r\n let dir = equalv3(this.Normal, cu.Normal.negate()) ? -1 : 1;\r\n let bul = cu.Bul * dir;\r\n if (linkType === LinkType.SpSp)\r\n {\r\n this._LineData.unshift({ pt: cuEp2, bul: -bul });\r\n }\r\n else if (linkType === LinkType.SpEp)\r\n {\r\n arrayLast(this._LineData).bul = bul;\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.EpSp)\r\n {\r\n this._LineData.unshift({ pt: cuSp2, bul: bul });\r\n }\r\n else if (linkType === LinkType.EpEp)\r\n {\r\n arrayLast(this._LineData).bul = -bul;\r\n this._LineData.push({ pt: cuSp2, bul: 0 });\r\n }\r\n }\r\n else if (cu instanceof Polyline)\r\n {\r\n if (cu.CloseMark) return Status.False;\r\n\r\n let { pts, buls } = this.PtsBuls;\r\n\r\n if (linkType === LinkType.SpSp)\r\n {\r\n cu.Reverse();\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n cuPtsBul.pts.pop();\r\n cuPtsBul.buls.pop();\r\n pts = cuPtsBul.pts.concat(pts);\r\n buls = cuPtsBul.buls.concat(buls);\r\n }\r\n else if (linkType === LinkType.SpEp)\r\n {\r\n pts.pop();\r\n buls.pop();\r\n\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n pts = pts.concat(cuPtsBul.pts);\r\n buls = buls.concat(cuPtsBul.buls);\r\n }\r\n else if (linkType === LinkType.EpSp)\r\n {\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n cuPtsBul.pts.pop();\r\n cuPtsBul.buls.pop();\r\n pts = cuPtsBul.pts.concat(pts);\r\n buls = cuPtsBul.buls.concat(buls);\r\n }\r\n else if (linkType === LinkType.EpEp)\r\n {\r\n pts.pop();\r\n buls.pop();\r\n\r\n cu.Reverse();\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n pts = pts.concat(cuPtsBul.pts);\r\n buls = buls.concat(cuPtsBul.buls);\r\n }\r\n\r\n this._LineData.length = 0;\r\n for (let i = 0; i < pts.length; i++)\r\n {\r\n this._LineData.push({ pt: pts[i], bul: buls[i] });\r\n }\r\n }\r\n else\r\n return Status.False;\r\n }\r\n\r\n //在上面的其他分支已经返回了假 所以这里直接返回真.\r\n this.Update();\r\n return Status.True;\r\n }\r\n\r\n /**\r\n * 将曲线数组组合成多段线\r\n * @param curves 已经使用CurveLinked的数组,总是首尾相连\r\n * @returns\r\n */\r\n static Combine(curves: Curve[], tolerance = 1e-5): Polyline | undefined\r\n {\r\n if (!curves || curves.length === 0) return;\r\n\r\n let pl = new Polyline;\r\n pl.OCS = ComputerCurvesNormalOCS(curves);\r\n\r\n for (let cu of curves)\r\n pl.Join(cu, false, tolerance);\r\n\r\n let d = pl.LineData;\r\n if (d.length > 1)\r\n {\r\n let ld = arrayLast(d).pt;\r\n if (equalv2(d[0].pt, ld, tolerance))\r\n ld.copy(d[0].pt);\r\n }\r\n\r\n return pl;\r\n }\r\n\r\n PtOnCurve(pt: Vector3): boolean\r\n {\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let c = this.GetCurveAtIndex(i);\r\n if (c.PtOnCurve(pt))\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let c = this.GetCurveAtIndex(i);\r\n if (c.PtOnCurve3(p, fuzz))\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n PtInCurve(pt: Vector3)\r\n {\r\n return this.IsClose && IsPointInPolyLine(this, pt);\r\n }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n return this.GetClosestPointTo2(pt, extend ? ExtendType.Both : ExtendType.None);\r\n }\r\n GetClosestPointTo2(pt: Vector3, extType: ExtendType): Vector3\r\n {\r\n //当曲线空时,返回空\r\n if (this.EndParam < 1) return undefined;\r\n //当有闭合标志时,曲线在任何位置都不延伸\r\n if (this._ClosedMark) extType = ExtendType.None;\r\n\r\n //最近点\r\n let ptC = undefined;\r\n //最近点的距离\r\n let ptCDist = Infinity;\r\n\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let cu = this.GetCurveAtIndex(i);\r\n\r\n //前延伸\r\n if (i === 0 && (extType & ExtendType.Front) > 0)\r\n {\r\n let ptCFirst = cu.GetClosestPointTo(pt, true);\r\n if (cu.GetParamAtPoint(ptCFirst) <= 1)\r\n {\r\n ptC = ptCFirst;\r\n ptCDist = ptC.distanceToSquared(pt);\r\n }\r\n if (extType === ExtendType.Front)\r\n continue;\r\n }\r\n\r\n let ptCloseNew: Vector3; //新的最近点\r\n\r\n //后延伸 (此处与前延伸分开if 如果线只有一段,那么前后延伸都能同时触发)\r\n if (i === (this.EndParam - 1) && (extType & ExtendType.Back) > 0)\r\n {\r\n let ptCLast = cu.GetClosestPointTo(pt, true);\r\n if (cu.GetParamAtPoint(ptCLast) >= 0)\r\n ptCloseNew = ptCLast;\r\n else //如果延伸之后并不在曲线或者曲线的后延伸上\r\n ptCloseNew = cu.EndPoint;\r\n }\r\n else\r\n {\r\n ptCloseNew = cu.GetClosestPointTo(pt, false);\r\n }\r\n\r\n let newDist = ptCloseNew.distanceToSquared(pt);\r\n if (newDist < ptCDist)\r\n {\r\n ptC = ptCloseNew;\r\n ptCDist = newDist;\r\n }\r\n }\r\n\r\n return ptC;\r\n }\r\n //偏移\r\n GetOffsetCurves(offsetDist: number): Array\r\n {\r\n if (equaln(offsetDist, 0)) return [];\r\n let polyOffestUtil = new OffsetPolyline(this, offsetDist);\r\n let curves = polyOffestUtil.Do();\r\n for (let cu of curves)\r\n cu.ColorIndex = this.ColorIndex;\r\n return curves;\r\n }\r\n GetFeedingToolPath(offsetDist: number): Array\r\n {\r\n if (equaln(offsetDist, 0)) return [];\r\n let polyOffestUtil = new OffsetPolyline(this, offsetDist, true);\r\n return polyOffestUtil.Do();\r\n }\r\n /**\r\n * 分解\r\n */\r\n Explode(): Curve[]\r\n {\r\n let exportCus: Curve[] = [];\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n exportCus.push(this.GetCurveAtIndex(i));\r\n }\r\n return exportCus;\r\n }\r\n\r\n /**\r\n * 根据参数得到参数所在的子曲线.\r\n *\r\n * 当曲线存在闭合标志时,参数必须在曲线内部,否则返回空.\r\n *\r\n * @param {number} param 参数值\r\n * @returns {Curve} 曲线(直线或者圆弧) 或空\r\n * @memberof Polyline\r\n */\r\n GetCurveAtParam(param: number): Curve\r\n {\r\n if (this._ClosedMark && !this.ParamOnCurve(param))\r\n return undefined;\r\n\r\n if (param < 0)\r\n return this.GetCurveAtIndex(0);\r\n else if (param >= this.EndParam)\r\n return this.GetCurveAtIndex(this.EndParam - 1);\r\n else return this.GetCurveAtIndex(Math.floor(param));\r\n }\r\n\r\n /**\r\n * 得到参数在子曲线中的表示\r\n *\r\n * @param {number} param 参数在多段线中表示\r\n * @returns {number} 参数在子曲线中表示\r\n * @memberof Polyline\r\n */\r\n GetCurveParamAtParam(param: number): number\r\n {\r\n if (param >= this.EndParam) param -= this.EndParam - 1;\r\n else if (param > 0) param -= Math.floor(param);\r\n\r\n return param;\r\n }\r\n\r\n /**\r\n * 获得曲线,来自索引位置.\r\n * @param {number} i 索引位置 整数\r\n */\r\n GetCurveAtIndex(i: number): Curve\r\n {\r\n if (i >= this._LineData.length) return undefined;\r\n\r\n if (!this.ParamOnCurve(i)) return undefined;\r\n\r\n if (!this._ClosedMark && i === this._LineData.length - 1) return undefined;\r\n\r\n let d1 = this._LineData[i];\r\n let d2 = this._LineData[FixIndex(i + 1, this._LineData)];\r\n\r\n let curve: Curve;\r\n if (equaln(d1.bul, 0, 1e-8))\r\n curve = new Line(AsVector3(d1.pt), AsVector3(d2.pt)).ApplyMatrix(this.OCS);\r\n else\r\n curve = new Arc().ParseFromBul(d1.pt, d2.pt, d1.bul).ApplyMatrix(this.OCS);\r\n\r\n curve.ColorIndex = this._Color;\r\n return curve;\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-5)\r\n {\r\n return IntersectPolylineAndCurve(this, curve, intType, tolerance);\r\n }\r\n\r\n //计算自交点.\r\n IntersectSelf(): number[]\r\n {\r\n let cus = this.Explode();\r\n if (cus.length === 0) return [];\r\n\r\n let intParams: number[] = [];\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let c = cus[i];\r\n for (let j = i + 2; j < cus.length; j++)\r\n {\r\n let c2 = cus[j];\r\n let pts = c.IntersectWith(c2, IntersectOption.OnBothOperands);\r\n\r\n for (let p of pts)\r\n {\r\n intParams.push(i + c.GetParamAtPoint(p));\r\n intParams.push(j + c2.GetParamAtPoint(p));\r\n }\r\n }\r\n }\r\n return intParams;\r\n }\r\n\r\n get BoundingBox()\r\n {\r\n let box = new Box3();\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let cu = this.GetCurveAtIndex(i);\r\n box.union(cu.BoundingBox);\r\n }\r\n return box;\r\n }\r\n\r\n /**\r\n * 得到曲线有用的点表和凸度(闭合曲线首尾重复)\r\n */\r\n get PtsBuls(): { pts: Vector2[], buls: number[]; }\r\n {\r\n let pts: Vector2[] = [];\r\n let buls: number[] = [];\r\n\r\n if (this._LineData.length === 0)\r\n return { pts, buls };\r\n\r\n for (let data of this._LineData)\r\n {\r\n pts.push(data.pt.clone());\r\n buls.push(data.bul);\r\n }\r\n //闭合且起点不等于终点\r\n if (this._ClosedMark &&\r\n !this._LineData[0].pt.equals(arrayLast(this._LineData).pt))\r\n {\r\n pts.push(pts[0].clone());\r\n buls.push(buls[0]);\r\n }\r\n\r\n return { pts, buls };\r\n }\r\n get IsBulge()\r\n {\r\n if (!this.IsClose) return false;\r\n\r\n let refDir = Math.sign(this.Area2);\r\n let c1: Curve;\r\n let c2: Curve;\r\n\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n c1 = this.GetCurveAtIndex(i);\r\n c2 = this.GetCurveAtIndex(FixIndex(i + 1, this.EndParam));\r\n\r\n let len1 = c1.Length;\r\n let len2 = c2.Length;\r\n let minLen = Math.min(len1, len2) * 0.2;\r\n\r\n let p = c1.EndPoint;\r\n let p1: Vector3;\r\n let p2: Vector3;\r\n\r\n if (c1 instanceof Arc)\r\n {\r\n let dir = c1.IsClockWise ? -1 : 1;\r\n if (dir !== refDir)\r\n return false;\r\n p1 = c1.GetPointAtDistance(len1 - minLen);\r\n }\r\n else\r\n p1 = c1.StartPoint;\r\n\r\n if (c2 instanceof Arc)\r\n {\r\n let dir = c2.IsClockWise ? -1 : 1;\r\n if (dir !== refDir)\r\n return false;\r\n p2 = c2.GetPointAtDistance(minLen);\r\n }\r\n else\r\n p2 = c2.EndPoint;\r\n\r\n let vec1 = p.clone().sub(p1);\r\n let vec2 = p2.sub(p);\r\n let dir = Math.sign(vec1.cross(vec2).z);\r\n\r\n if (dir !== 0 && dir !== refDir)\r\n return false;\r\n }\r\n return true;\r\n }\r\n get Shape()\r\n {\r\n let { pts, buls } = this.PtsBuls;\r\n let curve = CreateBoardUtil.CreatePath(pts, buls);\r\n return curve;\r\n }\r\n get SVG()\r\n {\r\n let sp = this.StartPoint;\r\n let str = `M${sp.x} ${sp.y} `;\r\n for (let i = 1; i <= this.EndParam; i++)\r\n {\r\n let bul = this.GetBuilgeAt(i - 1);\r\n let p = this.GetPointAtParam(i);\r\n if (bul === 0)\r\n str += `L${p.x} ${p.y} `;\r\n else\r\n {\r\n let arc = this.GetCurveAtIndex(i - 1) as Arc;\r\n str += `A ${arc.Radius} ${arc.Radius} 0 ${Math.abs(bul) >= 1 ? 1 : 0} ${arc.IsClockWise ? 0 : 1} ${p.x} ${p.y}`;\r\n }\r\n }\r\n return str;\r\n }\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe)\r\n {\r\n let shape = this.Shape;\r\n\r\n let geo = BufferGeometryUtils.CreateFromPts(shape.getPoints(50).map(AsVector3));\r\n if (renderType === RenderType.Print)\r\n {\r\n var geometry = new LineGeometry().setPositions(geo.attributes.position.array as number[]);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n let obj = new TLine(geo, ColorMaterial.GetLineMaterial(this._Color));\r\n return obj;\r\n }\r\n UpdateDrawObject(type: RenderType, en: Object3D)\r\n {\r\n let shape = this.Shape;\r\n let pts = shape.getPoints(50).map(AsVector3);\r\n let plObj = en as TLine;\r\n let geo = plObj.geometry as BufferGeometry;\r\n if (!BufferGeometryUtils.UpdatePts(geo, pts))\r\n {\r\n updateGeometry(plObj, BufferGeometryUtils.CreateFromPts(pts));\r\n }\r\n }\r\n\r\n GetDragPointCount(drag: DragPointType): number\r\n {\r\n if (drag === DragPointType.Grip)\r\n {\r\n let count = this.EndParam * 2 + 1;\r\n if (this.CloseMark) count--;\r\n return count;\r\n }\r\n else\r\n {\r\n return this._LineData.length;\r\n }\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return this.GetStretchPoints();\r\n case ObjectSnapMode.Mid:\r\n let midPts = [];\r\n let enParam = this.EndParam;\r\n for (let i = 0.5; i < enParam; i++)\r\n {\r\n let p = this.GetPointAtParam(i);\r\n p && midPts.push(p);\r\n }\r\n return midPts;\r\n case ObjectSnapMode.Nea:\r\n {\r\n let nea: Vector3[] = [];\r\n for (let cu of this.Explode())\r\n {\r\n let neaa = cu.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform);\r\n if (neaa)\r\n nea.push(...neaa);\r\n }\r\n return nea;\r\n }\r\n case ObjectSnapMode.Ext:\r\n {\r\n let cp = this.GetClosestPointTo(pickPoint, true);\r\n if (cp)\r\n return [cp];\r\n break;\r\n }\r\n case ObjectSnapMode.Cen:\r\n let cenPts: Vector3[] = [];\r\n for (let i = 0; i < this._LineData.length; i++)\r\n {\r\n let data = this._LineData[i];\r\n if (!equaln(data.bul, 0))\r\n {\r\n let cu = this.GetCurveAtIndex(i) as Arc;\r\n if (cu)//end bul !== 0 但是并没有圆弧\r\n cenPts.push(cu.Center);\r\n }\r\n }\r\n return cenPts;\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n let cp = this.GetClosestPointTo(pickPoint, false);\r\n if (!cp) return [];\r\n let cparam = this.GetParamAtPoint(cp);\r\n let cu = this.GetCurveAtParam(cparam);\r\n if (cu)\r\n {\r\n let closestPt = cu.GetClosestPointTo(lastPoint, true);\r\n if (closestPt && this.PtOnCurve(closestPt))\r\n return [closestPt];\r\n }\r\n }\r\n case ObjectSnapMode.Tan:\r\n if (lastPoint)\r\n {\r\n let clostPt = this.GetClosestPointTo(pickPoint, false);\r\n if (!clostPt) return [];\r\n let par = this.GetParamAtPoint(clostPt);\r\n let cu = this.GetCurveAtParam(par);\r\n if (cu instanceof Arc)\r\n return cu.GetObjectSnapPoints(snapMode, pickPoint, lastPoint);\r\n return [];\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n GetGripPoints(): Array\r\n {\r\n let ptList: Vector3[] = [];\r\n if (this._LineData.length < 2)\r\n return ptList;\r\n\r\n let enParam = this.EndParam;\r\n if (this.CloseMark) enParam -= 0.5;\r\n for (let i = 0; i < enParam + 0.5; i += 0.5)\r\n {\r\n let p = this.GetPointAtParam(i);\r\n ptList.push(p);\r\n }\r\n return ptList;\r\n }\r\n MoveGripPoints(indexList: number[], moveVec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n let moveVLoc = AsVector2(moveVec.clone().applyMatrix4(new Matrix4().extractRotation(this.OCSInv)));\r\n\r\n let calcIndexList = indexList;\r\n if (indexList.length > 1)\r\n {\r\n let centerIndexes = indexList.filter(i => i % 2 === 0);\r\n if (centerIndexes.length > 0)\r\n calcIndexList = centerIndexes;\r\n }\r\n\r\n for (let index of calcIndexList)\r\n {\r\n if (index % 2 === 0)\r\n {\r\n let cuIndex = index / 2;\r\n\r\n let ptCout = this._LineData.length;\r\n\r\n let frontIndex = cuIndex - 1;\r\n if (this._ClosedMark)\r\n frontIndex = FixIndex(frontIndex, ptCout);\r\n\r\n if (frontIndex >= 0 && this.GetBuilgeAt(frontIndex))\r\n {\r\n let arc = this.GetCurveAtIndex(frontIndex) as Arc;\r\n arc.MoveGripPoints([2], moveVec);\r\n this._LineData[frontIndex].bul = arc.Bul;\r\n }\r\n if ((cuIndex !== ptCout - 1) && this.GetBuilgeAt(cuIndex))\r\n {\r\n let arc = this.GetCurveAtIndex(cuIndex) as Arc;\r\n arc.MoveGripPoints([0], moveVec);\r\n this._LineData[cuIndex].bul = arc.Bul;\r\n }\r\n this._LineData[cuIndex].pt.add(moveVLoc);\r\n }\r\n else\r\n {\r\n let ptIndex = (index - 1) / 2;\r\n let nextIndex = (FixIndex(ptIndex + 1, this._LineData));\r\n let d = this._LineData[ptIndex];\r\n if (d.bul == 0)\r\n {\r\n this._LineData[ptIndex].pt.add(moveVLoc);\r\n this._LineData[nextIndex].pt.add(moveVLoc);\r\n }\r\n else\r\n {\r\n let arc = this.GetCurveAtIndex(ptIndex) as Arc;\r\n arc.MoveGripPoints([1], moveVec);\r\n this._LineData[ptIndex].bul = arc.Bul;\r\n }\r\n }\r\n }\r\n\r\n this.Update();\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n let ocs = this.OCS;\r\n let ptList: Vector3[] = [];\r\n for (let data of this._LineData)\r\n {\r\n ptList.push(AsVector3(data.pt).applyMatrix4(ocs));\r\n }\r\n return ptList;\r\n }\r\n\r\n /**\r\n * 范围拉伸(stretch),对夹点进行拉伸.\r\n * 如果对圆弧的一侧进行拉伸,那么修改bul\r\n *\r\n * @param {Array} indexList\r\n * @param {Vector3} vec\r\n * @memberof Polyline\r\n */\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n //本地坐标系移动向量\r\n let moveVLoc = vec.clone().applyMatrix4(new Matrix4().extractRotation(this.OCSInv));\r\n\r\n let ptCout = this._LineData.length;\r\n\r\n for (let index of indexList)\r\n {\r\n if (index >= ptCout)\r\n throw \"在拉伸多段线顶点时,尝试拉伸不存在的顶点!(通常是因为模块中的板轮廓被破坏,导致的顶点丢失!)\";\r\n\r\n let frontIndex = index - 1;\r\n let nextIndex = index + 1;\r\n if (this._ClosedMark)\r\n {\r\n frontIndex = FixIndex(frontIndex, ptCout);\r\n nextIndex = FixIndex(nextIndex, ptCout);\r\n }\r\n\r\n /**\r\n * 根据新的拉伸点修改凸度.\r\n *\r\n * @param {number} nextIndex 隔壁点索引\r\n * @param {number} bulIndex 需要修改凸度位置的索引\r\n * @returns\r\n */\r\n const ChangeBul = (nextIndex: number, bulIndex: number) =>\r\n {\r\n //需要修改的点的数据\r\n let d = this._LineData[bulIndex];\r\n if (d === undefined || d.bul == 0) return;\r\n\r\n //如果隔壁点不在拉伸列表中\r\n if (indexList.indexOf(nextIndex) === -1)\r\n {\r\n let needChangeP = this.GetPointAtParam(index);\r\n let notChangeP = this.GetPointAtParam(nextIndex);\r\n\r\n //原先的弦长的一半\r\n let oldChordLengthHalf = needChangeP.distanceTo(notChangeP) * 0.5;\r\n\r\n //弓高\r\n let arcHeight = oldChordLengthHalf * d.bul;\r\n\r\n needChangeP.add(vec);\r\n\r\n let newChordLengthHalf = needChangeP.distanceTo(notChangeP) * 0.5;\r\n\r\n d.bul = arcHeight / newChordLengthHalf;\r\n }\r\n };\r\n\r\n ChangeBul(frontIndex, frontIndex);\r\n ChangeBul(nextIndex, index);\r\n\r\n //修改顶点\r\n this._LineData[index].pt.add(AsVector2(moveVLoc));\r\n }\r\n this.Update();\r\n }\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n this._LineData.length = 0;\r\n let cout = file.Read();\r\n for (let i = 0; i < cout; i++)\r\n {\r\n let v = new Vector2().fromArray(file.Read());\r\n let bul = file.Read();\r\n\r\n this._LineData.push({ pt: v, bul: bul });\r\n }\r\n if (ver > 1)\r\n this._ClosedMark = file.Read();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(2);\r\n file.Write(this._LineData.length);\r\n\r\n for (let l of this._LineData)\r\n {\r\n file.Write(l.pt.toArray());\r\n file.Write(l.bul);\r\n }\r\n file.Write(this._ClosedMark);\r\n }\r\n}\r\n\r\nexport const TempPolyline = new Polyline();\r\n","import { Matrix4, Vector3 } from 'three';\r\nimport { arrayRemoveDuplicateBySort } from '../Common/ArrayExt';\r\nimport { Arc } from '../DatabaseServices/Entity/Arc';\r\nimport { Circle } from '../DatabaseServices/Entity/Circle';\r\nimport { Curve } from '../DatabaseServices/Entity/Curve';\r\nimport { Ellipse } from '../DatabaseServices/Entity/Ellipse';\r\nimport { Line } from '../DatabaseServices/Entity/Line';\r\nimport { Polyline } from '../DatabaseServices/Entity/Polyline';\r\nimport { comparePoint, equaln, equalv3 } from '../Geometry/GeUtils';\r\n\r\n/**\r\n * 相交延伸选项.\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum IntersectOption\r\n{\r\n /**\r\n * 两者都不延伸\r\n */\r\n OnBothOperands = 0,\r\n /**\r\n * 延伸自身\r\n */\r\n ExtendThis = 1,\r\n /**\r\n * 延伸参数\r\n */\r\n ExtendArg = 2,\r\n /**\r\n * 延伸两者\r\n */\r\n ExtendBoth = 3,\r\n}\r\n\r\nexport interface IntersectResult\r\n{\r\n pt: Vector3,\r\n thisParam: number,\r\n argParam: number,\r\n}\r\n\r\n//延伸自身还是参数反转\r\nexport function reverseIntersectOption(intType: IntersectOption)\r\n{\r\n if (intType === IntersectOption.ExtendThis)\r\n intType = IntersectOption.ExtendArg;\r\n else if (intType === IntersectOption.ExtendArg)\r\n intType = IntersectOption.ExtendThis;\r\n return intType;\r\n}\r\n/**\r\n * 校验相交点是否满足延伸选项\r\n * 算法会计算无限延伸状态下的曲线交点,调用该方法进行校验返回校验后的点表\r\n *\r\n * @param {Vector3[]} intRes 相交点.曲线当作完全状态下的相交点\r\n * @param {Curve} c1 曲线1 由this参数传入\r\n * @param {Curve} c2 曲线2 由arg 参数传入\r\n * @param {Intersect} extType 延伸选项.\r\n * @returns {Array} 校验完成后的点表\r\n */\r\nfunction CheckPointOnCurve(intRes: IntersectResult[], c1: Curve, c2: Curve, extType: IntersectOption, tolerance = 1e-6): Array\r\n{\r\n return intRes.filter(r =>\r\n {\r\n if (!(extType & IntersectOption.ExtendThis))\r\n if (!c1.ParamOnCurve(r.thisParam, tolerance))\r\n return false;\r\n\r\n if (!(extType & IntersectOption.ExtendArg))\r\n if (!c2.ParamOnCurve(r.argParam, tolerance))\r\n return false;\r\n return true;\r\n });\r\n}\r\nexport function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc): IntersectResult[]\r\n{\r\n if (!cu1.IsCoplaneTo(cu2)) return [];\r\n\r\n let c1OcsInv = cu1.OCSInv;\r\n let c1Ocs = cu1.OCS;\r\n\r\n let center1 = cu1.Center.applyMatrix4(c1OcsInv);\r\n let center2 = cu2.Center.applyMatrix4(c1OcsInv);\r\n let radius1 = cu1.Radius;\r\n let radius2 = cu2.Radius;\r\n\r\n let pts: IntersectResult[] = [];\r\n let dist = center2.distanceTo(center1);\r\n\r\n if (dist < Math.abs(radius1 - radius2) - 1e-3\r\n || dist > (radius1 + radius2 + 1e-3))\r\n return pts;\r\n if (equaln(dist, 0, 1e-6)) return pts;\r\n\r\n let dstsqr = dist * dist;\r\n let r1sqr = radius1 * radius1;\r\n let r2sqr = radius2 * radius2;\r\n\r\n let a = (dstsqr - r2sqr + r1sqr) / (2 * dist);\r\n let h = Math.sqrt(Math.abs(r1sqr - (a * a)));\r\n\r\n let ratio_a = a / dist;\r\n let ratio_h = h / dist;\r\n\r\n let dx = center2.x - center1.x;\r\n let dy = center2.y - center1.y;\r\n\r\n let phix = center1.x + (ratio_a * dx);\r\n let phiy = center1.y + (ratio_a * dy);\r\n\r\n dx *= ratio_h;\r\n dy *= ratio_h;\r\n\r\n let p1 = new Vector3(phix + dy, phiy - dx);\r\n let p2 = new Vector3(phix - dy, phiy + dx);\r\n p1.applyMatrix4(c1Ocs);\r\n p2.applyMatrix4(c1Ocs);\r\n\r\n pts.push({\r\n pt: p1,\r\n thisParam: cu1.GetParamAtPoint(p1),\r\n argParam: cu2.GetParamAtPoint(p1),\r\n });\r\n if (!equalv3(p1, p2))//防止点重复\r\n pts.push({\r\n pt: p2,\r\n thisParam: cu1.GetParamAtPoint(p2),\r\n argParam: cu2.GetParamAtPoint(p2),\r\n });\r\n\r\n return pts;\r\n}\r\n/**\r\n * 计算圆与圆弧的交点.\r\n *\r\n * @export\r\n * @param {Circle} circle 圆\r\n * @param {Arc} arc 圆弧\r\n * @param {IntersectOption} extType 延伸选项\r\n * @returns 交点集合\r\n */\r\nexport function IntersectCircleAndArc(circle: Circle, arc: Arc, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let pts = IntersectCircleAndCircle(circle, arc);\r\n return CheckPointOnCurve(pts, circle, arc, extType | IntersectOption.ExtendThis, tolerance);\r\n}\r\n\r\n/**\r\n * 计算圆弧与圆弧的交点\r\n *\r\n * @export\r\n * @param {Arc} arc1 圆弧\r\n * @param {Arc} arc2 圆弧\r\n * @param {IntersectOption} extType 延伸选项\r\n * @returns 交点集合\r\n */\r\nexport function IntersectArcAndArc(arc1: Arc, arc2: Arc, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let pts = IntersectCircleAndCircle(arc1, arc2);\r\n return CheckPointOnCurve(pts, arc1, arc2, extType, tolerance);\r\n}\r\n\r\nexport function IntersectEllipseAndLine(l: Line, el: Ellipse, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let pts = IntersectLineAndEllipseFor2D(l, el);\r\n return CheckPointOnCurve(pts, l, el, extType, tolerance);\r\n}\r\n\r\n/**\r\n * 通用方法:计算直线与圆的交点,默认延伸全部\r\n *\r\n * @export\r\n * @param {Line} line 直线\r\n * @param {(Circle | Arc)} circle 圆或圆弧\r\n * @returns 交点集合\r\n */\r\nfunction IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc): IntersectResult[]\r\n{\r\n let lineOrg = line.StartPoint;\r\n let lineDirection = line.EndPoint.sub(lineOrg);\r\n let dirLen = lineDirection.length();\r\n if (equaln(dirLen, 0)) return [];\r\n lineDirection.divideScalar(dirLen);\r\n\r\n let diff = lineOrg.clone().sub(circle.Center);\r\n let a0 = diff.dot(diff) - circle.Radius ** 2;\r\n let a1 = lineDirection.dot(diff);\r\n let discr = a1 ** 2 - a0;\r\n\r\n if (equaln(discr, 0, 1e-7))\r\n {\r\n let pt = lineOrg.add(lineDirection.multiplyScalar(-a1));\r\n\r\n return [{\r\n pt,\r\n thisParam: -a1 / dirLen,\r\n argParam: circle.GetParamAtPoint(pt)\r\n }];\r\n }\r\n else if (discr > 0)\r\n {\r\n let root = Math.sqrt(discr);\r\n let p1 = lineOrg.clone().add(lineDirection.clone().multiplyScalar(-a1 + root));\r\n let p2 = lineOrg.add(lineDirection.multiplyScalar(-a1 - root));\r\n\r\n return [\r\n {\r\n pt: p1,\r\n thisParam: (-a1 + root) / dirLen,\r\n argParam: circle.GetParamAtPoint(p1)\r\n }, {\r\n pt: p2,\r\n thisParam: (-a1 - root) / dirLen,\r\n argParam: circle.GetParamAtPoint(p2)\r\n }\r\n ];\r\n }\r\n return [];\r\n}\r\n\r\n//直线和圆\r\nexport function IntersectLineAndCircle(line: Line, circle: Circle, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let ptArr = IntersectLineAndCircleOrArc(line, circle);\r\n return CheckPointOnCurve(ptArr, line, circle, extType | IntersectOption.ExtendArg);\r\n}\r\n//直线和圆弧\r\nexport function IntersectLineAndArc(line: Line, arc: Arc, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let ptArr = IntersectLineAndCircleOrArc(line, arc);\r\n return CheckPointOnCurve(ptArr, line, arc, extType, tolerance);\r\n}\r\n//直线和直线\r\nexport function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3\r\n{\r\n let dx1 = p1.x - p2.x;\r\n let dx2 = p3.x - p4.x;\r\n let dx3 = p4.x - p2.x;\r\n let dy1 = p1.y - p2.y;\r\n let dy2 = p3.y - p4.y;\r\n let dy3 = p4.y - p2.y;\r\n\r\n let det = (dx2 * dy1) - (dy2 * dx1);\r\n\r\n if (equaln(det, 0.0, 1e-5))\r\n {\r\n // if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))\r\n // {\r\n // return midPoint(midPoint(p1, p2), midPoint(p3, p4));\r\n // }\r\n return;\r\n }\r\n\r\n let pt = new Vector3;\r\n let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;\r\n pt.x = (ratio * dx2) + p4.x;\r\n pt.y = (ratio * dy2) + p4.y;\r\n\r\n return pt;\r\n}\r\n\r\nexport function IntersectLAndLFor2D2(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3[]\r\n{\r\n let dx1 = p1.x - p2.x;\r\n let dx2 = p3.x - p4.x;\r\n let dx3 = p4.x - p2.x;\r\n let dy1 = p1.y - p2.y;\r\n let dy2 = p3.y - p4.y;\r\n let dy3 = p4.y - p2.y;\r\n\r\n let det = (dx2 * dy1) - (dy2 * dx1);\r\n\r\n if (equaln(det, 0.0, 1e-5))\r\n {\r\n if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))\r\n return [p1, p2, p3, p4];\r\n return [];\r\n }\r\n\r\n let pt = new Vector3;\r\n let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;\r\n pt.x = (ratio * dx2) + p4.x;\r\n pt.y = (ratio * dy2) + p4.y;\r\n\r\n return [pt];\r\n}\r\n\r\nexport function IntersectLine3AndLine3(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3, epsilon = 1e-6)\r\n{\r\n let pts = ShortestLine3AndLine3(p1, p2, p3, p4);\r\n if (pts) return pts[0];\r\n}\r\n\r\n/**\r\n * 三维中两行之间最短的直线\r\n * ref:https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment\r\n * ref:http://paulbourke.net/geometry/pointlineplane/\r\n * ref:http://paulbourke.net/geometry/pointlineplane/calclineline.cs\r\n *\r\n * @export\r\n * @param {Vector3} p1 l1.start\r\n * @param {Vector3} p2 l1.end\r\n * @param {Vector3} p3 l2.start\r\n * @param {Vector3} p4 l2.end\r\n * @returns 交点集合\r\n */\r\nfunction ShortestLine3AndLine3(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3, epsilon = 1e-6)\r\n{\r\n let p43 = p4.clone().sub(p3);\r\n if (p43.lengthSq() < epsilon)\r\n return;\r\n let p21 = p2.clone().sub(p1);\r\n if (p21.lengthSq() < epsilon)\r\n return;\r\n\r\n let p13 = p1.clone().sub(p3);\r\n\r\n let d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z;\r\n let d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z;\r\n let d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z;\r\n let d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z;\r\n let d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z;\r\n\r\n let denom = d2121 * d4343 - d4321 * d4321;\r\n if (Math.abs(denom) < epsilon)\r\n return;\r\n let numer = d1343 * d4321 - d1321 * d4343;\r\n\r\n let mua = numer / denom;\r\n let mub = (d1343 + d4321 * (mua)) / d4343;\r\n\r\n let resultSegmentPoint1 = new Vector3();\r\n resultSegmentPoint1.x = p1.x + mua * p21.x;\r\n resultSegmentPoint1.y = p1.y + mua * p21.y;\r\n resultSegmentPoint1.z = p1.z + mua * p21.z;\r\n let resultSegmentPoint2 = new Vector3();\r\n resultSegmentPoint2.x = p3.x + mub * p43.x;\r\n resultSegmentPoint2.y = p3.y + mub * p43.y;\r\n resultSegmentPoint2.z = p3.z + mub * p43.z;\r\n\r\n return [resultSegmentPoint1, resultSegmentPoint2];\r\n}\r\n\r\n//直线和直线\r\nexport function IntersectLineAndLine(l1: Line, l2: Line, extType: IntersectOption, fuzz = 1e-4): IntersectResult[]\r\n{\r\n let [pt1, pt2, pt3, pt4] = [l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint];\r\n\r\n let ipts: Vector3[];\r\n if (equaln(pt1.z, 0, fuzz) && equaln(pt2.z, 0, fuzz) && equaln(pt3.z, 0, fuzz) && equaln(pt4.z, 0, fuzz))\r\n {\r\n ipts = IntersectLAndLFor2D2(pt1, pt2, pt3, pt4);\r\n ipts.sort(comparePoint(\"xy\"));\r\n arrayRemoveDuplicateBySort(ipts, (p1, p2) => equalv3(p1, p2, fuzz));\r\n }\r\n else\r\n {\r\n ipts = ShortestLine3AndLine3(pt1, pt2, pt3, pt4);\r\n if (!ipts) return [];\r\n if (ipts.length === 2)\r\n ipts.pop();\r\n }\r\n\r\n let ints: IntersectResult[] = [];\r\n for (let pt of ipts)\r\n {\r\n let { closestPt: p1, param: param1 } = l1.GetClosestAtPoint(pt, true);\r\n if (!equalv3(pt, p1, fuzz)) return [];\r\n if (!(extType & IntersectOption.ExtendThis))\r\n if (!(l1.ParamOnCurve(param1, 0) || equalv3(pt1, pt, fuzz) || equalv3(pt2, pt, fuzz)))\r\n return [];\r\n let { closestPt: p2, param: param2 } = l2.GetClosestAtPoint(pt, true);\r\n if (!equalv3(pt, p2, fuzz)) return [];\r\n if (!(extType & IntersectOption.ExtendArg))\r\n if (!(l2.ParamOnCurve(param2, 0) || equalv3(pt3, pt, fuzz) || equalv3(pt4, pt, fuzz)))\r\n return [];\r\n ints.push({ pt, thisParam: param1, argParam: param2 });\r\n }\r\n return ints;\r\n}\r\n\r\nexport function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: IntersectOption, tolerance = 1e-6): IntersectResult[]\r\n{\r\n let cus: Curve[] = pl.Explode();\r\n let cus2: Curve[];\r\n if (cu instanceof Polyline)\r\n cus2 = cu.Explode();\r\n else\r\n cus2 = [cu];\r\n\r\n let intRes: IntersectResult[] = [];\r\n\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let cu1 = cus[i];\r\n for (let j = 0; j < cus2.length; j++)\r\n {\r\n let cu2 = cus2[j];\r\n let ext = extType;\r\n\r\n let isStart = i === 0;\r\n let isEnd = i === cus.length - 1;\r\n\r\n let isStart2 = j === 0;\r\n let isEnd2 = j === cus2.length - 1;\r\n\r\n //当曲线闭合时,或者当前的子曲线不是起始和不是结束,那么不延伸曲线.\r\n if (pl.CloseMark || !(isStart || isEnd))\r\n ext = ext & ~IntersectOption.ExtendThis;\r\n if ((cu instanceof Polyline && cu.CloseMark) || !(isStart2 || isEnd2))\r\n ext = ext & ~IntersectOption.ExtendArg;\r\n\r\n let ptPars = cu1.IntersectWith2(cu2, ext, tolerance).filter(r1 => intRes.every(r2 => !equalv3(r1.pt, r2.pt)));\r\n\r\n //校验延伸\r\n if (IntersectOption.ExtendThis & ext)\r\n {\r\n //如果曲线是起始又是结束,那么不校验.\r\n if (isStart && isEnd)\r\n {\r\n }\r\n else if (isStart)\r\n {\r\n ptPars = ptPars.filter(res => res.thisParam <= 1);\r\n }\r\n else if (isEnd)\r\n {\r\n ptPars = ptPars.filter(res => res.thisParam >= 0);\r\n }\r\n }\r\n if (IntersectOption.ExtendArg & ext)\r\n {\r\n //如果曲线是起始又是结束,那么不校验.\r\n if (isStart2 && isEnd2)\r\n {\r\n }\r\n else if (isStart2)\r\n {\r\n ptPars = ptPars.filter(res => res.argParam + j <= cu2.EndParam);\r\n }\r\n else if (isEnd2)\r\n {\r\n ptPars = ptPars.filter(res => res.argParam + j >= 0);\r\n }\r\n }\r\n\r\n intRes.push(...ptPars.map(r =>\r\n {\r\n return {\r\n pt: r.pt,\r\n thisParam: i + r.thisParam,\r\n argParam: j + r.argParam,\r\n };\r\n }));\r\n }\r\n }\r\n return intRes;\r\n}\r\n\r\nexport function IntersectLineAndEllipseFor2D(l: Line, el: Ellipse)\r\n{\r\n if (!l.IsCoplaneTo(el)) return [];\r\n\r\n let mat = new Matrix4().makeRotationZ(-el.Rotation).multiply(el.OCSInv);\r\n let a = el.RadX;\r\n let b = el.RadY;\r\n let sp = l.StartPoint.applyMatrix4(mat);\r\n let ep = l.EndPoint.applyMatrix4(mat);\r\n let pts: Vector3[] = [];\r\n if (equaln(sp.x, ep.x))\r\n {\r\n let c = sp.x;\r\n let j = (b ** 2) * (1 - (c ** 2) / (a ** 2));\r\n if (equaln(j, 0))\r\n {\r\n pts = [new Vector3(sp.x, 0)];\r\n }\r\n else if (j < 0)\r\n return [];\r\n else\r\n {\r\n let y1 = Math.sqrt(j);\r\n let y2 = -Math.sqrt(j);\r\n pts = [\r\n new Vector3(c, y1),\r\n new Vector3(c, y2)\r\n ];\r\n }\r\n }\r\n else\r\n {\r\n let k = (sp.y - ep.y) / (sp.x - ep.x);\r\n let c = sp.y - sp.x * k;\r\n let j = (2 * a * a * k * c) * (2 * a * a * k * c) - 4 * (b * b + a * a * k * k) * a * a * (c * c - b * b);\r\n if (equaln(j, 0))\r\n {\r\n let x1 = -2 * k * c * a * a / (2 * (b * b + a * a * k * k));\r\n let y1 = k * x1 + c;\r\n pts = [new Vector3(x1, y1)];\r\n }\r\n else if (j < 0)\r\n return [];\r\n else\r\n {\r\n let x1 = (-2 * k * c * a * a + Math.sqrt(j)) / (2 * (b * b + a * a * k * k));\r\n let y1 = k * x1 + c;\r\n let x2 = (-2 * k * c * a * a - Math.sqrt(j)) / (2 * (b * b + a * a * k * k));\r\n let y2 = k * x2 + c;\r\n pts = [\r\n new Vector3(x1, y1),\r\n new Vector3(x2, y2)\r\n ];\r\n }\r\n }\r\n\r\n let matInv = new Matrix4().getInverse(mat);\r\n return pts.map(p =>\r\n {\r\n let pt = p.applyMatrix4(matInv);\r\n return {\r\n pt,\r\n thisParam: l.GetParamAtPoint(pt),\r\n argParam: el.GetParamAtPoint(pt)\r\n };\r\n });\r\n}\r\nexport function IntersectEllipseAndCircleOrArc(el: Ellipse, cir: Circle | Arc, type: IntersectOption)\r\n{\r\n if (!el.IsCoplaneTo(cir)) return [];\r\n\r\n let a = Math.max(el.RadX, el.RadY);\r\n let dist = el.Center.distanceTo(cir.Center);\r\n\r\n let disVail = dist > (a + cir.Radius);\r\n\r\n if (disVail)\r\n return [];\r\n\r\n if (equalv3(el.Center, cir.Center))\r\n {\r\n let a = el.RadX;\r\n let b = el.RadY;\r\n let r = cir.Radius;\r\n let j = ((a * b) ** 2 - (b * r) ** 2) / (a ** 2 - b ** 2);\r\n let pts: Vector3[] = [];\r\n if (equaln(j, 0) || equaln(j, r ** 2))\r\n {\r\n if (equaln(j, 0))\r\n pts = [\r\n new Vector3(a, 0),\r\n new Vector3(-a, 0)\r\n ];\r\n else\r\n pts = [\r\n new Vector3(0, r),\r\n new Vector3(0, -r)\r\n ];\r\n }\r\n else if (j < 0)\r\n return [];\r\n else\r\n {\r\n let y1 = Math.sqrt(j);\r\n let y2 = - Math.sqrt(j);\r\n let n = r ** 2 - j;\r\n let x1 = Math.sqrt(n);\r\n let x2 = - Math.sqrt(n);\r\n pts = [\r\n new Vector3(x1, y1),\r\n new Vector3(x1, y2),\r\n new Vector3(x2, y1),\r\n new Vector3(x2, y2),\r\n ];\r\n }\r\n let ro = new Matrix4().makeRotationZ(el.Rotation);\r\n let res = pts.map(p =>\r\n {\r\n let pt = p.applyMatrix4(ro).applyMatrix4(el.OCS);\r\n return {\r\n pt,\r\n thisParam: el.GetParamAtPoint(pt),\r\n argParam: cir.GetParamAtPoint(pt)\r\n };\r\n });\r\n return CheckPointOnCurve(res, el, cir, type);\r\n }\r\n else\r\n {\r\n let pts = el.Shape.getPoints(60);\r\n let lineData = pts.map(p =>\r\n {\r\n return { pt: p, bul: 0 };\r\n });\r\n let pl = new Polyline(lineData);\r\n let cirClone = cir.Clone().ApplyMatrix(el.OCSInv);\r\n\r\n if (type === IntersectOption.ExtendBoth)\r\n type = IntersectOption.ExtendArg;\r\n else if (type !== IntersectOption.ExtendArg)\r\n type = IntersectOption.OnBothOperands;\r\n\r\n let intPts = IntersectPolylineAndCurve(pl, cirClone, type);\r\n intPts.forEach(r => r.pt.applyMatrix4(el.OCS));\r\n return intPts;\r\n }\r\n}\r\nexport function IntersectEllipse(el1: Ellipse, el2: Ellipse, type: IntersectOption)\r\n{\r\n if (!el1.IsCoplaneTo(el2)) return [];\r\n\r\n let isEqul = equalv3(el1.Center, el2.Center)\r\n && equaln(el1.RadX, el2.RadX)\r\n && equaln(el1.RadY, el2.RadY)\r\n && equalv3(el1.StartPoint, el2.StartPoint);\r\n\r\n if (isEqul)\r\n return [];\r\n\r\n let a1 = Math.max(el1.RadX, el1.RadY);\r\n let a2 = Math.max(el2.RadX, el2.RadY);\r\n\r\n let dist = el1.Center.distanceToSquared(el2.Center);\r\n if (dist > (a1 + a2) ** 2)\r\n {\r\n return [];\r\n }\r\n\r\n if (!el1.BoundingBox.intersectsBox(el2.BoundingBox))\r\n return [];\r\n\r\n let diffMat = el1.OCSInv.multiply(el2.OCS);\r\n let pts1 = el1.Shape.getPoints(60);\r\n let pts2 = el2.Shape.getPoints(60);\r\n\r\n let lineData1 = pts1.map(p =>\r\n {\r\n return { pt: p, bul: 0 };\r\n });\r\n let lineData2 = pts2.map(p =>\r\n {\r\n return { pt: p, bul: 0 };\r\n });\r\n\r\n let pl1 = new Polyline(lineData1);\r\n let pl2 = new Polyline(lineData2).ApplyMatrix(diffMat);\r\n\r\n let intPts = pl1.IntersectWith2(pl2, 0);\r\n intPts.forEach(r => r.pt.applyMatrix4(el1.OCS));\r\n return intPts;\r\n}\r\n","import { Box3, BufferGeometry, EllipseCurve, Line as TLine, Material, Matrix3, Matrix4, Object3D, Vector3 } from 'three';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { arrayLast, arrayRemoveDuplicateBySort } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { getArcOrCirNearPts, GetTanPtsOnArcOrCircle } from '../../Common/CurveUtils';\r\nimport { reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { clamp } from '../../Common/Utils';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { angle, AsVector3, equaln, MoveMatrix, polar } from '../../Geometry/GeUtils';\r\nimport { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectEllipseAndCircleOrArc, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { Shape2 } from '../Shape2';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\nimport { Arc } from './Arc';\r\nimport { Curve } from './Curve';\r\nimport { DragPointType } from './DragPointType';\r\nimport { Ellipse } from './Ellipse';\r\nimport { Line } from './Line';\r\nimport { Polyline } from './Polyline';\r\n\r\nlet circleGeometry: BufferGeometry;\r\nfunction GetCircleGeometry()\r\n{\r\n if (!circleGeometry)\r\n circleGeometry = BufferGeometryUtils.CreateFromPts(\r\n new EllipseCurve(0, 0, 1, 1, 0, 2 * Math.PI, false, 0).getPoints(360).map(AsVector3)\r\n );\r\n return circleGeometry;\r\n}\r\n\r\n@Factory\r\nexport class Circle extends Curve\r\n{\r\n constructor(center?: Vector3, radius: number = 1e-6)\r\n {\r\n super();\r\n center && this._Matrix.setPosition(center);\r\n this._Radius = radius;\r\n }\r\n private _Radius: number;\r\n\r\n get Shape()\r\n {\r\n let sp = new Shape2();\r\n sp.ellipse(0, 0, this._Radius, this._Radius, 0, 2 * Math.PI, false, 0);\r\n return sp;\r\n }\r\n\r\n get Center()\r\n {\r\n return new Vector3().setFromMatrixPosition(this._Matrix);\r\n }\r\n set Center(v: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Matrix.setPosition(v);\r\n this.Update();\r\n }\r\n get Radius()\r\n {\r\n return this._Radius;\r\n }\r\n set Radius(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Radius = clamp(v, 1e-9, 1e19);\r\n this.Update();\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this.Center = this.Center.applyMatrix4(m);\r\n this.Radius = this.Radius * m.getMaxScaleOnAxis();\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n reviseMirrorMatrix(this._Matrix);\r\n\r\n return this;\r\n }\r\n\r\n //******************** Curve function start*****************//\r\n\r\n get StartPoint(): Vector3\r\n {\r\n return this.GetPointAtParam(0);\r\n }\r\n get StartParam(): number\r\n {\r\n return 0;\r\n }\r\n get EndPoint(): Vector3\r\n {\r\n return this.GetPointAtParam(0);\r\n }\r\n get EndParam(): number\r\n {\r\n return 1;\r\n }\r\n PtInCurve(pt: Vector3)\r\n {\r\n return pt.distanceToSquared(this.Center) < Math.pow(this.Radius, 2);\r\n }\r\n get Area()\r\n {\r\n return Math.PI * this._Radius ** 2;\r\n }\r\n get Area2()\r\n {\r\n return Math.PI * this._Radius ** 2;\r\n }\r\n get Length()\r\n {\r\n return Math.PI * 2 * this._Radius;\r\n }\r\n\r\n get IsClose(): boolean\r\n {\r\n return true;\r\n }\r\n\r\n //曲线为顺时针\r\n get IsClockWise(): boolean { return false; }\r\n\r\n GetPointAtParam(param: number)\r\n {\r\n return (polar(new Vector3(), param * 2 * Math.PI, this._Radius) as Vector3).applyMatrix4(this._Matrix);\r\n }\r\n\r\n GetPointAtDistance(distance: number)\r\n {\r\n let param = distance / (Math.PI * 2 * this._Radius);\r\n return this.GetPointAtParam(param);\r\n }\r\n\r\n GetDistAtParam(param: number)\r\n {\r\n return Math.PI * 2 * this._Radius * param;\r\n }\r\n\r\n GetDistAtPoint(pt: Vector3)\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n return this.GetDistAtParam(param);\r\n }\r\n\r\n GetParamAtDist(d: number)\r\n {\r\n return d / (Math.PI * 2 * this._Radius);\r\n }\r\n\r\n GetSplitCurves(param: number[] | number)\r\n {\r\n let params: number[];\r\n if (param instanceof Array)\r\n {\r\n params = param.filter(p => this.ParamOnCurve(p));\r\n params.sort((a1, a2) => a2 - a1);//从大到小\r\n arrayRemoveDuplicateBySort(params);\r\n if (params.length < 2) return [];\r\n }\r\n else //圆不能被单个参数切割\r\n return [];\r\n\r\n //补上最后一个到第一个的弧\r\n params.unshift(arrayLast(params));\r\n\r\n let anglelist = params.map(param => Math.PI * 2 * param);\r\n\r\n let curvelist = new Array();\r\n for (let i = 0; i < anglelist.length - 1; i++)\r\n {\r\n let sa = anglelist[i];\r\n let ea = anglelist[i + 1];\r\n if (!equaln(sa, ea, 1e-6))\r\n {\r\n let arc = new Arc(new Vector3(), this._Radius, ea, sa, false);\r\n arc.ApplyMatrix(this.OCS);\r\n curvelist.push(arc);\r\n }\r\n }\r\n return curvelist;\r\n }\r\n\r\n GetParamAtPoint(pt?: Vector3)\r\n {\r\n if (!this.PtOnCurve(pt))\r\n return NaN;\r\n return angle(pt.clone().applyMatrix4(this.OCSInv)) / (Math.PI * 2);\r\n }\r\n\r\n PtOnCurve(pt: Vector3)\r\n {\r\n return equaln(pt.distanceToSquared(this.Center), this._Radius * this._Radius, 1e-5);\r\n }\r\n GetOffsetCurves(offsetDist: number): Curve[]\r\n {\r\n if ((offsetDist + this._Radius) > 0)\r\n {\r\n let circle = this.Clone();\r\n circle.Radius = this._Radius + offsetDist;\r\n return [circle];\r\n }\r\n return [];\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption)\r\n {\r\n if (curve instanceof Arc)\r\n {\r\n return IntersectCircleAndArc(this, curve, intType);\r\n }\r\n if (curve instanceof Line)\r\n {\r\n return SwapParam(IntersectLineAndCircle(curve, this, reverseIntersectOption(intType)));\r\n }\r\n if (curve instanceof Circle)\r\n {\r\n return IntersectCircleAndCircle(this, curve);\r\n }\r\n if (curve instanceof Ellipse)\r\n {\r\n return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));\r\n }\r\n if (curve instanceof Polyline)\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType)));\r\n return [];\r\n }\r\n //******************** Curve function end*****************//\r\n\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3().setFromPoints(this.GetGripPoints());\r\n }\r\n\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe)\r\n {\r\n let cirGeo = GetCircleGeometry();\r\n if (renderType === RenderType.Print)\r\n {\r\n var geometry = new LineGeometry().setPositions(cirGeo.attributes.position.array as number[]);\r\n geometry.scale(this._Radius, this._Radius, this._Radius);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n let line = new TLine(cirGeo, ColorMaterial.GetLineMaterial(this._Color));\r\n let obj = new Object3D().add(line);\r\n this.UpdateDrawObject(renderType, obj);\r\n return obj;\r\n }\r\n UpdateDrawObject(type: RenderType, obj: Object3D)\r\n {\r\n obj.children[0].scale.set(this._Radius, this._Radius, this._Radius);\r\n obj.children[0].updateMatrix();\r\n }\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material: Material)\r\n {\r\n let m = obj.children[0] as TLine;\r\n m.material = material ? material : ColorMaterial.GetLineMaterial(this._Color);\r\n }\r\n\r\n GetDragPointCount(drag: DragPointType): number\r\n {\r\n if (drag === DragPointType.Grip)\r\n return 5;\r\n else\r\n return 1;\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n let pts = [\r\n new Vector3(),\r\n new Vector3(0, this._Radius),\r\n new Vector3(0, -this._Radius),\r\n new Vector3(-this._Radius, 0),\r\n new Vector3(this._Radius, 0),\r\n ];\r\n\r\n let ocs = this.OCS;\r\n pts.forEach(p => p.applyMatrix4(ocs));\r\n return pts;\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.Nea:\r\n {\r\n return getArcOrCirNearPts(this, pickPoint, viewXform);\r\n }\r\n case ObjectSnapMode.Cen:\r\n return [this.Center];\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))\r\n return [];\r\n let l = new Line(this.Center, lastPoint);\r\n return l.IntersectWith(this, IntersectOption.ExtendBoth);\r\n }\r\n case ObjectSnapMode.Tan:\r\n let pts = GetTanPtsOnArcOrCircle(this, lastPoint);\r\n if (pts)\r\n return pts;\r\n case ObjectSnapMode.End:\r\n {\r\n let pts = this.GetGripPoints();\r\n pts.shift();\r\n return pts;\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n\r\n let pts = this.GetGripPoints();\r\n if (indexList.length > 0)\r\n {\r\n let index = indexList[0];\r\n let p = pts[index];\r\n if (p)\r\n {\r\n if (index > 0)\r\n {\r\n p.add(vec);\r\n this.Radius = p.distanceTo(this.Center);\r\n }\r\n else\r\n {\r\n this.Center = this.Center.add(vec);\r\n }\r\n }\r\n }\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n let pts = [new Vector3()];\r\n let ocs = this.OCS;\r\n pts.forEach(p => p.applyMatrix4(ocs));\r\n return pts;\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n if (indexList.length > 0)\r\n {\r\n let mat = MoveMatrix(vec);\r\n this.ApplyMatrix(mat);\r\n }\r\n }\r\n GetFistDeriv(pt: number | Vector3)\r\n {\r\n if (typeof pt === \"number\")\r\n pt = this.GetPointAtParam(pt);\r\n else\r\n pt = pt.clone();\r\n\r\n pt.applyMatrix4(this.OCSInv);\r\n\r\n let an = angle(pt) + Math.PI * 0.5;\r\n\r\n return polar(new Vector3(), an, 1).applyMatrix4(new Matrix4().extractRotation(this.OCS));\r\n }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n pt = pt.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(this.OCS);\r\n if (equaln(pt.distanceToSquared(this.Center), 0, 1e-10))\r\n return this.GetPointAtParam(0);\r\n let l = new Line(this.Center, pt);\r\n let pts = l.IntersectWith(this, IntersectOption.ExtendBoth);\r\n pts.sort((p1, p2) =>\r\n {\r\n return p1.distanceToSquared(pt) - p2.distanceToSquared(pt);\r\n });\r\n return pts[0];\r\n }\r\n //#region -------------------------File-------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n this._Radius = file.Read();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);\r\n file.Write(this._Radius);\r\n }\r\n //#endregion\r\n}\r\n","\r\n/**\r\n * 一个简单的计数器实现,本质是使用一个Map来保存元素的个数\r\n * \r\n * 例:\r\n * let count = new Count();\r\n * count.AddCount(\"Test\", 1);\r\n * count.GetCount(\"Test\");//现在 Test 的个数为1\r\n */\r\nexport class Count\r\n{\r\n private m_CountMap = new WeakMap();\r\n GetCount(obj: any): number\r\n {\r\n let count = this.m_CountMap.get(obj);\r\n if (!count)\r\n {\r\n this.m_CountMap.set(obj, 0);\r\n count = 0;\r\n }\r\n return count;\r\n }\r\n AddCount(obj: any, add: number)\r\n {\r\n this.m_CountMap.set(obj, this.GetCount(obj) + add);\r\n }\r\n}\r\n","import { Vector3, MathUtils } from \"three\";\r\nimport { YAxis, ZAxis, equaln } from \"./GeUtils\";\r\n\r\n/**\r\n * 轨道控制的数学类,观察向量和角度的互相转换\r\n * 当x当抬头或者低头到90度时,触发万向锁.\r\n */\r\nexport class Orbit\r\n{\r\n //抬头低头 正数抬头 负数低头\r\n private phi: number = 0;//Φ\r\n\r\n //身体旋转 0为正右边 逆时针旋转\r\n theta: number = 0;//θ\r\n\r\n get RoX()\r\n {\r\n return this.phi;\r\n }\r\n set RoX(v)\r\n {\r\n this.phi = MathUtils.clamp(v, Math.PI * -0.49, Math.PI * 0.49);\r\n }\r\n\r\n /**\r\n * 使用旋转角度 计算观察向量\r\n * @param [outDirection] 引用传入,如果传入,那么就不构造新的向量\r\n * @returns 返回观察向量\r\n */\r\n UpdateDirection(outDirection = new Vector3()): Vector3\r\n {\r\n outDirection.z = Math.sin(this.phi);\r\n //归一化专用.\r\n let d = Math.abs(Math.cos(this.phi));\r\n\r\n outDirection.x = Math.cos(this.theta) * d;\r\n outDirection.y = Math.sin(this.theta) * d;\r\n\r\n return outDirection;\r\n }\r\n\r\n /**\r\n * 使用观察向量,计算旋转角度\r\n * @param dir 这个向量会被修改成单位向量.\r\n */\r\n SetFromDirection(dir: Vector3): void\r\n {\r\n dir.normalize();\r\n this.phi = Math.asin(dir.z);\r\n if (equaln(dir.x, 0) && equaln(dir.y, 0))\r\n if (dir.z > 0)\r\n this.theta = Math.PI * -0.5;\r\n else\r\n this.theta = Math.PI * 0.5;\r\n else\r\n this.theta = Math.atan2(dir.y, dir.x);\r\n }\r\n\r\n /**\r\n * 参考任意轴坐标系算法.\r\n * http://help.autodesk.com/view/ACD/2017/CHS/?guid=GUID-E19E5B42-0CC7-4EBA-B29F-5E1D595149EE\r\n */\r\n static ComputUpDirection(n: Vector3, ay: Vector3 = new Vector3(), ax: Vector3 = new Vector3()): Vector3\r\n {\r\n n.normalize();\r\n if (Math.abs(n.x) < 0.015625 && Math.abs(n.y) < 0.015625)\r\n ax.crossVectors(YAxis, n);\r\n else\r\n ax.crossVectors(ZAxis, n);\r\n ay.crossVectors(n, ax);\r\n ax.normalize();\r\n ay.normalize();\r\n return ay;\r\n }\r\n}\r\n","import { Box3, Line3, Matrix3, Matrix4, Vec2, Vector2, Vector3 } from 'three';\r\nimport { Arc } from '../DatabaseServices/Entity/Arc';\r\nimport { Circle } from '../DatabaseServices/Entity/Circle';\r\nimport { Curve } from '../DatabaseServices/Entity/Curve';\r\nimport { Ellipse } from '../DatabaseServices/Entity/Ellipse';\r\nimport { Line } from '../DatabaseServices/Entity/Line';\r\nimport { Polyline } from '../DatabaseServices/Entity/Polyline';\r\nimport { IsPointInBowArc } from '../DatabaseServices/PointInPolyline';\r\nimport { Count } from '../Geometry/Count';\r\nimport { CurveMap, Vertice } from '../Geometry/CurveMap';\r\nimport { AsVector2, AsVector3, equaln, equalv2, equalv3, isParallelTo, XAxis, ZeroVec, isPerpendicularityTo, YAxis, isIntersect } from '../Geometry/GeUtils';\r\nimport { Vec3 } from '../Geometry/IVec3';\r\nimport { Orbit } from '../Geometry/Orbit';\r\nimport { PlaneExt } from '../Geometry/Plane';\r\nimport { IntersectOption, IntersectResult } from '../GraphicsSystem/IntersectWith';\r\nimport { OffsetPolyline } from '../GraphicsSystem/OffsetPolyline';\r\nimport { arrayLast, changeArrayStartIndex, equalArray } from './ArrayExt';\r\nimport { Status } from './Status';\r\nimport { FixIndex, LINK_FUZZ } from './Utils';\r\n\r\n//3点获取圆心\r\nexport function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3)\r\n{\r\n if (!(pt1 && pt2 && pt3))\r\n return;\r\n let A1 = pt1.x - pt2.x;\r\n let B1 = pt1.y - pt2.y;\r\n let C1 = (Math.pow(pt1.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt1.y, 2) - Math.pow(pt2.y, 2)) / 2;\r\n let A2 = pt3.x - pt2.x;\r\n let B2 = pt3.y - pt2.y;\r\n let C2 = (Math.pow(pt3.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt3.y, 2) - Math.pow(pt2.y, 2)) / 2;\r\n //令temp = A1*B2 - A2*B1\r\n let temp = A1 * B2 - A2 * B1;\r\n let center = new Vector3();\r\n //判断三点是否共线\r\n if (temp === 0)\r\n {\r\n //共线则将第一个点pt1作为圆心\r\n center.x = pt1.x;\r\n center.y = pt1.y;\r\n }\r\n else\r\n {\r\n //不共线则求出圆心:\r\n center.x = (C1 * B2 - C2 * B1) / temp;\r\n center.y = (A1 * C2 - A2 * C1) / temp;\r\n }\r\n\r\n return center;\r\n}\r\n\r\n// 弦长+切线获取圆心角\r\nexport function getCirAngleByChordAndTangent(chord: Vector3, tangentLine: Vector3)\r\n{\r\n let dir = tangentLine.clone().cross(chord).normalize();\r\n\r\n let ctAngle = chord.angleTo(tangentLine);\r\n\r\n // 圆心角\r\n let cirAng = Math.PI - 2 * Math.abs(ctAngle - Math.PI / 2);\r\n\r\n if (ctAngle > Math.PI / 2)\r\n {\r\n cirAng = Math.PI * 2 - cirAng;\r\n }\r\n return cirAng *= dir.z;\r\n}\r\n//行列式\r\nexport function getDeterminantFor2V(v1: Vector2, v2: Vector2): number\r\n{\r\n return v1.x * v2.y - v1.y * v2.x;\r\n}\r\n\r\nexport function getDeterminantFor3V(v1: Vector3, v2: Vector3, v3: Vector3)\r\n{\r\n let mat = new Matrix3();\r\n mat.set(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z);\r\n return mat.determinant();\r\n}\r\n\r\n/**\r\n * 曲线根据连接来分组,每组都是一条首尾相连的曲线表.\r\n *\r\n * @export\r\n * @param {Curve[]} cus 传入的分组的曲线表\r\n * @returns {Array>} 返回如下\r\n * [\r\n * [c1,c2,c3...],//后面的曲线的起点总是等于上一个曲线的终点\r\n * [c1,c2,c3...],\r\n * ]\r\n */\r\nexport function curveLinkGroup(cus: Curve[]): Array>\r\n{\r\n //返回的曲线组\r\n let groupCus = new Array>();\r\n\r\n //将封闭的曲线先提取出来\r\n cus = cus.filter(c =>\r\n {\r\n let isClose = c.IsClose;\r\n if (isClose)\r\n groupCus.push([c]);\r\n return !isClose;\r\n });\r\n if (cus.length === 0) return groupCus;\r\n //曲线节点图\r\n let cuMap = new CurveMap();\r\n cus.forEach(c => cuMap.AddCurveToMap(c));\r\n\r\n //曲线站点表\r\n let stands = cuMap.Stands;\r\n //曲线使用计数\r\n let cuCount = new Count();\r\n\r\n /**\r\n * 从站点的路线中任意取一条,加入到曲线数组中.\r\n *\r\n * @param {Curve[]} cus 已经连接的曲线列表\r\n * @param {boolean} isEndSeach true:从终点搜索,false:从起点搜索\r\n * @returns {Stand} 如果站点中存在可以取得的曲线,返回下个站点,否则返回undefined\r\n */\r\n function linkCurve(stand: Vertice, cus: Curve[], isEndSeach: boolean): Vertice | undefined\r\n {\r\n for (let route of stand.routes)\r\n {\r\n let cu = route.curve;\r\n if (cuCount.GetCount(cu) === 0)\r\n {\r\n if (isEndSeach)\r\n {\r\n //保证曲线总是从起点连接到终点\r\n if (!equalv3(cu.StartPoint, stand.position))\r\n cu.Reverse();\r\n cus.push(cu);\r\n }\r\n else\r\n {\r\n //保证曲线总是从起点连接到终点\r\n if (!equalv3(cu.EndPoint, stand.position))\r\n cu.Reverse();\r\n cus.unshift(cu);\r\n }\r\n\r\n cuCount.AddCount(cu, 1);\r\n return route.to;\r\n }\r\n }\r\n }\r\n\r\n for (let stand of stands)\r\n {\r\n let startStand = stand;\r\n let cus: Curve[] = []; //形成合并轮廓的曲线组\r\n while (startStand)\r\n startStand = linkCurve(startStand, cus, true);\r\n\r\n if (cus.length > 0)\r\n {\r\n startStand = cuMap.GetOnlyVertice(cus[0].StartPoint);\r\n while (startStand)\r\n startStand = linkCurve(startStand, cus, false);\r\n }\r\n\r\n if (cus.length > 0)\r\n groupCus.push(cus);\r\n }\r\n\r\n return groupCus;\r\n}\r\n\r\nexport function equalCurve(cu1: Curve, cu2: Curve, tolerance = 1e-4)\r\n{\r\n if ((cu1 instanceof Polyline) && (cu2 instanceof Polyline))\r\n {\r\n if (cu1.IsClose !== cu2.IsClose || !isParallelTo(cu1.Normal, cu2.Normal))\r\n return false;\r\n\r\n let area1 = cu1.Area2;\r\n let area2 = cu2.Area2;\r\n\r\n if (!equaln(Math.abs(area1), Math.abs(area2), 0.1))\r\n return false;\r\n\r\n let ptsBuls1 = cu1.PtsBuls;\r\n let ptsBuls2 = cu2.PtsBuls;\r\n\r\n let pts1 = ptsBuls1.pts;\r\n let pts2 = ptsBuls2.pts;\r\n let buls1 = ptsBuls1.buls;\r\n let buls2 = ptsBuls2.buls;\r\n\r\n let isEqualArea = equaln(area1, area2, 0.1);\r\n if (!equalv3(cu1.Normal, cu2.Normal))\r\n {\r\n if (isEqualArea)\r\n {\r\n pts2.reverse();\r\n buls2.reverse();\r\n buls2.push(buls2.shift());\r\n }\r\n else\r\n buls2 = buls2.map(bul => -bul);\r\n }\r\n else if (!isEqualArea)\r\n {\r\n pts2.reverse();\r\n buls2.reverse();\r\n buls2 = buls2.map(bul => -bul);\r\n buls2.push(buls2.shift());\r\n }\r\n\r\n if (cu1.IsClose && equalv2(pts1[0], arrayLast(pts1), tolerance))\r\n {\r\n pts1.pop();\r\n buls1.pop();\r\n }\r\n if (cu2.IsClose && equalv2(pts2[0], arrayLast(pts2), tolerance))\r\n {\r\n pts2.pop();\r\n buls2.pop();\r\n }\r\n\r\n let cu1Sp = AsVector2(cu1.StartPoint.applyMatrix4(cu2.OCSInv));\r\n\r\n let index = pts2.findIndex(p => equalv2(cu1Sp, p, tolerance));\r\n changeArrayStartIndex(buls2, index);\r\n changeArrayStartIndex(pts2, index);\r\n\r\n return equalArray(buls1, buls2, equaln) &&\r\n equalArray(pts1, pts2, (p1: Vector2, p2: Vector2) =>\r\n equalv3(\r\n AsVector3(p1).applyMatrix4(cu1.OCS),\r\n AsVector3(p2).applyMatrix4(cu2.OCS),\r\n tolerance\r\n )\r\n );\r\n }\r\n else if (cu1 instanceof Circle && cu2 instanceof Circle)\r\n {\r\n return equalv3(cu1.Center, cu2.Center) && equaln(cu1.Radius, cu2.Radius, 1e-6);\r\n }\r\n else if (cu1 instanceof Arc && cu2 instanceof Arc)\r\n {\r\n if (!equalv3(cu1.StartPoint, cu2.EndPoint)) cu1.Reverse();\r\n return equalv3(cu1.Center, cu2.Center)\r\n && equaln(cu1.Radius, cu2.Radius, 1e-6)\r\n && equaln(cu1.StartAngle, cu2.StartAngle)\r\n && equaln(cu1.EndAngle, cu2.EndAngle);\r\n }\r\n else if (cu1 instanceof Ellipse && cu2 instanceof Ellipse)\r\n {\r\n return equalv3(cu1.Center, cu2.Center)\r\n && equaln(cu1.RadX, cu2.RadX)\r\n && equaln(cu1.RadY, cu2.RadY)\r\n && equalv3(cu1.StartPoint, cu2.StartPoint);\r\n }\r\n else if (cu1 instanceof Line && cu2 instanceof Line)\r\n {\r\n let ps1 = [cu1.StartPoint, cu1.EndPoint];\r\n let ps2 = [cu2.StartPoint, cu2.EndPoint];\r\n return ps1.every(p => ps2.some(p1 => equalv3(p1, p)));\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n* 计算点在曲线前进方向的方位,左边或者右边\r\n*\r\n* @param {Curve} cu\r\n* @param {Vector3} pt\r\n* @returns {boolean} 左边为-1,右边为1\r\n*/\r\nexport function GetPointAtCurveDir(cu: Curve, pt: Vector3): number\r\n{\r\n if (cu instanceof Circle)\r\n return cu.PtInCurve(pt) ? -1 : 1;\r\n else if (cu instanceof Polyline)\r\n {\r\n let u = new OffsetPolyline(cu, 1);\r\n u.InitSubCurves();\r\n return u.GetPointAtCurveDir(pt.clone().applyMatrix4(cu.OCSInv).setZ(0));\r\n }\r\n //最近点\r\n let cp = cu.GetClosestPointTo(pt, false);\r\n if (equalv3(cp, pt, 1e-6)) return 0;\r\n //最近点参数\r\n let cparam = cu.GetParamAtPoint(cp);\r\n let dri = cu.GetFistDeriv(cparam);\r\n let cross = dri.cross(pt.clone().sub(cp)).applyMatrix4(cu.OCSInv);\r\n return -Math.sign(cross.z);\r\n}\r\n\r\n/**\r\n * 点在多段线的某个索引的圆弧(弓形)内\r\n *\r\n * @param {Polyline} pl\r\n * @param {number} index\r\n * @param {Vector3} pt\r\n * @returns {number}\r\n */\r\nfunction PointInPolylineArc(pl: Polyline, index: number, pt: Vector3): number\r\n{\r\n let bul = pl.GetBuilgeAt(index);\r\n if (equaln(bul, 0, 1e-8)) return 0;\r\n\r\n let arc = pl.GetCurveAtIndex(index) as Arc;\r\n\r\n if (IsPointInBowArc(arc, pt, true))\r\n return Math.sign(bul);\r\n\r\n return 0;\r\n}\r\n\r\nexport function ConverCircleToPolyline(cir: Circle): Polyline\r\n{\r\n //该写法不支持三维坐标系\r\n // let pl = new Polyline();\r\n // let bul = Math.tan(Math.PI * 0.125);\r\n // for (let i = 0; i < 4; i++)\r\n // {\r\n // let p = cir.GetPointAtParam(i * 0.25);\r\n // pl.AddVertexAt(i, Vec3DTo2D(p));\r\n // pl.SetBulgeAt(i, bul);\r\n // }\r\n // pl.CloseMark = true;\r\n // return pl;\r\n\r\n let arcs = cir.GetSplitCurves([0, 0.5]);\r\n let pl = new Polyline();\r\n pl.OCS = cir.OCS;\r\n pl.Join(arcs[0]);\r\n pl.Join(arcs[1]);\r\n return pl;\r\n}\r\n\r\nexport function GetTanPtsOnArcOrCircle(cu: Arc | Circle, lastPoint?: Vector3)\r\n{\r\n if (lastPoint)\r\n {\r\n //ref:wykobi\r\n let ocsInv = cu.OCSInv;\r\n let v = lastPoint.clone().applyMatrix4(ocsInv);\r\n\r\n let lengthSq = v.lengthSq();\r\n let radiusSq = cu.Radius ** 2;\r\n\r\n if (lengthSq >= radiusSq)\r\n {\r\n let ratio = 1 / lengthSq;\r\n let deltaDist = Math.sqrt(lengthSq - radiusSq);\r\n\r\n let pts = [\r\n new Vector3(\r\n cu.Radius * (cu.Radius * v.x - v.y * deltaDist) * ratio,\r\n cu.Radius * (cu.Radius * v.y + v.x * deltaDist) * ratio,\r\n ),\r\n new Vector3(\r\n cu.Radius * (cu.Radius * v.x + v.y * deltaDist) * ratio,\r\n cu.Radius * (cu.Radius * v.y - v.x * deltaDist) * ratio,\r\n ),\r\n ];\r\n for (let p of pts)\r\n p.applyMatrix4(cu.OCS);\r\n return pts;\r\n }\r\n }\r\n}\r\n\r\nexport function CircleInternalTangentLines(cir0: Circle, cir1: Circle): Line[]\r\n{\r\n let c0 = new Vector3();\r\n let c1 = cir1.Center.applyMatrix4(cir0.OCSInv);\r\n\r\n let dist = c0.distanceTo(c1);\r\n\r\n if (dist - (cir0.Radius + cir1.Radius) < 0)\r\n return [];\r\n else if (equaln(dist - (cir0.Radius + cir1.Radius), 0))\r\n return [];\r\n else\r\n {\r\n let m = cir0.Radius / cir1.Radius;\r\n let h0 = (m * dist) / (m + 1);\r\n let h1 = dist / (m + 1);\r\n\r\n let i = new Vector3(\r\n (h1 * c0.x + h0 * c1.x) / dist,\r\n (h1 * c0.y + h0 * c1.y) / dist\r\n ).applyMatrix4(cir0.OCS);\r\n\r\n let [c0p0, c0p1] = GetTanPtsOnArcOrCircle(cir0, i);\r\n let [c1p0, c1p1] = GetTanPtsOnArcOrCircle(cir1, i);\r\n\r\n return [\r\n new Line(c0p0, c1p0),\r\n new Line(c0p1, c1p1),\r\n ];\r\n }\r\n}\r\n\r\nexport function CircleOuterTangentLines(circle0: Circle, circle1: Circle): Line[]\r\n{\r\n let c0 = circle0.Center;\r\n let c1 = circle1.Center;\r\n\r\n let dist = c0.distanceTo(c1);\r\n\r\n let rd = Math.abs(circle0.Radius - circle1.Radius);\r\n if (dist < rd)\r\n return [];\r\n else if (equaln(Math.abs(dist - rd), 0))\r\n return [];\r\n else if (equaln(circle0.Radius, circle1.Radius))\r\n {\r\n let cp = circle0.GetClosestPointTo(c1, true);\r\n let derv = circle0.GetFistDeriv(cp).multiplyScalar(circle0.Radius);\r\n let dervn = derv.clone().negate();\r\n\r\n let c0p0 = c0.clone().add(derv);\r\n let c0p1 = c0.clone().add(dervn);\r\n\r\n let c1p0 = c1.clone().add(derv);\r\n let c1p1 = c1.clone().add(dervn);\r\n\r\n return [\r\n new Line(c0p0, c1p0),\r\n new Line(c0p1, c1p1),\r\n ];\r\n }\r\n else\r\n {\r\n let c0 = new Vector3();\r\n let c1 = circle1.Center.applyMatrix4(circle0.OCSInv);\r\n\r\n let p: Vector3;\r\n if (circle0.Radius > circle1.Radius)\r\n p = new Vector3(\r\n c1.x * circle0.Radius - c0.x * circle1.Radius,\r\n c1.y * circle0.Radius - c0.y * circle1.Radius\r\n );\r\n else\r\n p = new Vector3(\r\n c0.x * circle1.Radius - c1.x * circle0.Radius,\r\n c0.y * circle1.Radius - c1.y * circle0.Radius\r\n );\r\n\r\n let diff = Math.abs(circle0.Radius - circle1.Radius);\r\n\r\n p.x /= diff;\r\n p.y /= diff;\r\n\r\n p.applyMatrix4(circle0.OCS);\r\n\r\n let [c0p0, c0p1] = GetTanPtsOnArcOrCircle(circle0, p);\r\n let [c1p0, c1p1] = GetTanPtsOnArcOrCircle(circle1, p);\r\n\r\n return [\r\n new Line(c0p0, c1p0),\r\n new Line(c0p1, c1p1),\r\n ];\r\n }\r\n}\r\n\r\nexport function getArcOrCirNearPts(cu: Circle | Arc | Ellipse, pickPoint: Vector3, viewXform: Matrix3)\r\n{\r\n let viewNormal = new Vector3().fromArray(viewXform.elements, 2 * 3);\r\n\r\n let plane = new PlaneExt(cu.Normal, cu.Center);\r\n\r\n let pickLocal = plane.intersectLine(new Line3(pickPoint, pickPoint.clone().add(viewNormal)), new Vector3(), true);\r\n\r\n if (pickLocal)\r\n {\r\n let x = new Vector3().fromArray(viewXform.elements, 0).add(pickLocal);\r\n let y = new Vector3().fromArray(viewXform.elements, 3).add(pickLocal);\r\n\r\n x = plane.intersectLine(new Line3(x, x.clone().add(viewNormal)), new Vector3(), true);\r\n y = plane.intersectLine(new Line3(y, y.clone().add(viewNormal)), new Vector3(), true);\r\n\r\n let lx = new Line(pickLocal, x);\r\n let ly = new Line(pickLocal, y);\r\n\r\n let ins = cu.IntersectWith(lx, IntersectOption.ExtendBoth);\r\n ins.push(...cu.IntersectWith(ly, IntersectOption.ExtendBoth));\r\n return ins;\r\n }\r\n else\r\n {\r\n let ptLocal = plane.projectPoint(pickPoint, new Vector3());\r\n let lz = new Line(ptLocal, ptLocal.clone().add(viewNormal));\r\n return cu.IntersectWith(lz, IntersectOption.ExtendBoth);\r\n }\r\n}\r\n\r\nexport function getTanPtsOnEllipse(cu: Ellipse, lastPoint: Vector3)\r\n{\r\n return [];\r\n}\r\n\r\nexport function IsRect(cu: Curve): { isRect: boolean, size?: Vector3, box?: Box3, OCS?: Matrix4; }\r\n{\r\n if (cu instanceof Polyline)\r\n {\r\n if (!cu.IsClose) return { isRect: false };\r\n\r\n let pts = cu.GetStretchPoints();\r\n\r\n if (pts.length < 4) return { isRect: false };\r\n\r\n let xVec: Vector3;\r\n let p1 = pts[0];\r\n for (let i = 1; i < pts.length; i++)\r\n {\r\n xVec = pts[i].clone().sub(p1).normalize();\r\n if (!equalv3(xVec, ZeroVec))\r\n break;\r\n }\r\n\r\n if (!xVec) return { isRect: false };\r\n\r\n let zVec = cu.Normal;\r\n let yVec = zVec.clone().cross(xVec).normalize();\r\n\r\n let rectOCS = new Matrix4().makeBasis(xVec, yVec, zVec);\r\n let rectOCSInv = new Matrix4().getInverse(rectOCS);\r\n\r\n for (let p of pts)\r\n p.applyMatrix4(rectOCSInv);\r\n\r\n let box = new Box3().setFromPoints(pts);\r\n\r\n let size = box.getSize(new Vector3);\r\n if (equaln(size.x * size.y, cu.Area, 0.1))\r\n {\r\n return {\r\n isRect: true,\r\n size,\r\n box,\r\n OCS: rectOCS,\r\n };\r\n }\r\n }\r\n return { isRect: false };\r\n}\r\n\r\n/**用4个矩形点构造矩形 */\r\nexport function getRectFrom4Pts(pts: Vector3[])\r\n{\r\n if (pts.length !== 4) return;\r\n let p = pts.shift();\r\n pts.sort((p1, p2) => p.distanceTo(p1) - p.distanceTo(p2));\r\n pts.splice(1, 0, p);\r\n let lineData = pts.map(p =>\r\n {\r\n return {\r\n pt: new Vector2(p.x, p.y),\r\n bul: 0\r\n };\r\n });\r\n let l = new Polyline(lineData);\r\n l.CloseMark = true;\r\n return l;\r\n}\r\n\r\nexport function MergeCurvelist(cus: Curve[])\r\n{\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let c1 = cus[i];\r\n let nextI = FixIndex(i + 1, cus);\r\n let c2 = cus[nextI];\r\n\r\n\r\n let status = equaln(c2.Length, 0, LINK_FUZZ) ? Status.True : c1.Join(c2, false, LINK_FUZZ);\r\n if (status === Status.True)\r\n {\r\n cus.splice(nextI, 1);\r\n i--;\r\n }\r\n else if (status === Status.ConverToCircle)\r\n {\r\n cus.length = 0;\r\n let a = c1 as Arc;\r\n cus.push(new Circle(a.Center, a.Radius));\r\n break;\r\n }\r\n }\r\n return cus;\r\n}\r\n\r\nexport function SwapParam(res: IntersectResult[]): IntersectResult[]\r\n{\r\n for (let r of res)\r\n [r.thisParam, r.argParam] = [r.argParam, r.thisParam];\r\n return res;\r\n}\r\n\r\nexport function ComputerCurvesNormalOCS(curves: Curve[], allowAutoCalc: boolean = true): Matrix4 | undefined\r\n{\r\n if (!curves || curves.length === 0) return;\r\n\r\n //准备计算多段线的法向量\r\n let normal: Vector3;\r\n let firstV: Vector3;\r\n for (let c of curves)\r\n {\r\n if (c instanceof Arc)\r\n {\r\n normal = c.Normal;\r\n break;\r\n }\r\n else if (firstV)\r\n {\r\n let v = c.GetFistDeriv(0);\r\n v.cross(firstV);\r\n if (!equalv3(v, ZeroVec))\r\n {\r\n normal = v.normalize();\r\n break;\r\n }\r\n }\r\n else\r\n {\r\n let cus = c.Explode() as Curve[];\r\n let ocs = ComputerCurvesNormalOCS(cus, false);\r\n if (ocs)\r\n return ocs;\r\n firstV = c.GetFistDeriv(0);\r\n }\r\n }\r\n\r\n if (!normal && !allowAutoCalc) return;\r\n\r\n let x = new Vector3();\r\n let y = new Vector3();\r\n if (!normal)\r\n {\r\n normal = firstV.normalize();\r\n Orbit.ComputUpDirection(normal, y, x);\r\n [x, y, normal] = [normal, x, y];\r\n }\r\n else\r\n {\r\n if (equalv3(normal, curves[0].Normal.negate()))\r\n normal.negate();\r\n Orbit.ComputUpDirection(normal, y, x);\r\n }\r\n return new Matrix4().makeBasis(x, y, normal).setPosition(curves[0].StartPoint);\r\n}\r\n\r\n\r\nexport function Pts2Polyline(pts: (Vec3 | Vec2)[], isClose: boolean): Polyline\r\n{\r\n let pl = new Polyline();\r\n for (let i = 0; i < pts.length; i += 2)\r\n {\r\n let p1 = AsVector3(pts[i]);\r\n let arc: Arc | Line;\r\n let p2: Vector3;\r\n let p3: Vector3;\r\n\r\n if (isClose)\r\n {\r\n p2 = AsVector3(pts[FixIndex(i + 1, pts.length)]);\r\n p3 = AsVector3(pts[FixIndex(i + 2, pts.length)]);\r\n }\r\n else\r\n {\r\n if (i >= pts.length - 2) break;\r\n p2 = AsVector3(pts[i + 1]);\r\n p3 = AsVector3(pts[i + 2]);\r\n }\r\n let v1 = p1.clone().sub(p2);\r\n let v2 = p2.clone().sub(p3);\r\n\r\n if (equaln(v1.angleTo(v2), 0))\r\n arc = new Line(p1, p3);\r\n else\r\n arc = new Arc().FromThreePoint(p1, p2, p3);\r\n pl.Join(arc);\r\n }\r\n return pl;\r\n}\r\n\r\n/**获取矩形信息 */\r\nexport function GetRectData(cu: Curve): { isRect: boolean, size?: Vector3, box?: Box3, OCS?: Matrix4; }\r\n{\r\n if (cu instanceof Polyline)\r\n {\r\n if (!cu.IsClose) return { isRect: false };\r\n\r\n let pts = cu.GetStretchPoints();\r\n if (cu.Area2 < 0)\r\n pts.reverse();\r\n\r\n if (equalv3(pts[0], arrayLast(pts)))\r\n pts.pop();\r\n\r\n if (pts.length < 4) return { isRect: false };\r\n\r\n let xVec: Vector3;\r\n let p1 = pts[0];\r\n\r\n let originIndex = 0;\r\n\r\n for (let i = 1; i < pts.length; i++)\r\n {\r\n if (pts[i].y < p1.y)\r\n {\r\n p1 = pts[i];\r\n originIndex = i;\r\n }\r\n else if (equaln(pts[i].y, p1.y))\r\n {\r\n if (pts[i].x < p1.x)\r\n {\r\n p1 = pts[i];\r\n originIndex = i;\r\n }\r\n }\r\n }\r\n\r\n let tempPts = pts.splice(0, originIndex);\r\n pts.push(...tempPts);\r\n\r\n p1 = pts[0];\r\n\r\n\r\n for (let i = 1; i < pts.length; i++)\r\n {\r\n let v = pts[i].clone().sub(p1);\r\n if (equalv3(v, ZeroVec))\r\n continue;\r\n if (!xVec)\r\n xVec = v;\r\n else\r\n {\r\n if (isParallelTo(v, xVec))\r\n xVec.copy(v);\r\n else\r\n break;\r\n }\r\n }\r\n\r\n let yVec: Vector3;\r\n\r\n for (let i = pts.length - 1; i > 0; i--)\r\n {\r\n let v = pts[i].clone().sub(p1);\r\n if (equalv3(v, ZeroVec))\r\n continue;\r\n if (!yVec)\r\n yVec = v;\r\n else\r\n {\r\n if (isParallelTo(v, yVec))\r\n yVec.copy(v);\r\n else\r\n break;\r\n }\r\n }\r\n\r\n if (!xVec || !yVec) return { isRect: false };\r\n\r\n //2向量必须垂直\r\n if (!isPerpendicularityTo(xVec.clone().normalize(), yVec.clone().normalize()))\r\n return { isRect: false };\r\n\r\n if (yVec.length() > xVec.length())\r\n [xVec, yVec] = [yVec.negate(), xVec];\r\n\r\n if (xVec.angleTo(XAxis) > Math.PI / 4)\r\n [xVec, yVec] = [yVec.negate(), xVec];\r\n\r\n\r\n let rectOCS = new Matrix4().makeBasis(xVec.normalize(), yVec.normalize(), xVec.clone().cross(yVec));\r\n let rectOCSInv = new Matrix4().getInverse(rectOCS);\r\n\r\n for (let p of pts)\r\n p.applyMatrix4(rectOCSInv);\r\n\r\n let box = new Box3().setFromPoints(pts);\r\n\r\n let size = box.getSize(new Vector3);\r\n if (equaln(size.x * size.y, cu.Area, 0.1))\r\n {\r\n return {\r\n isRect: true,\r\n size,\r\n box,\r\n OCS: rectOCS,\r\n };\r\n }\r\n }\r\n return { isRect: false };\r\n}\r\n\r\nconst PolylineSpliteRectFuzz = 1e-3;\r\n/**封闭多段线 分割成矩形 */\r\nexport function PolylineSpliteRect(outline: Polyline): Polyline[]\r\n{\r\n if (!outline.IsClose || IsRect(outline).isRect)\r\n return [outline];\r\n\r\n let firstDerv = outline.GetFistDeriv(0).normalize();\r\n if (!isParallelTo(firstDerv, XAxis, PolylineSpliteRectFuzz) && !isParallelTo(firstDerv, YAxis, PolylineSpliteRectFuzz)) return [outline];\r\n\r\n let cus = outline.Explode();\r\n let yCus: Curve[] = [];\r\n\r\n for (let c of cus)\r\n {\r\n if (c instanceof Arc) return [outline];\r\n let derv = c.GetFistDeriv(0).normalize();\r\n if (isParallelTo(derv, YAxis, PolylineSpliteRectFuzz))\r\n yCus.push(c);\r\n else\r\n if (!isParallelTo(derv, XAxis, PolylineSpliteRectFuzz))\r\n {\r\n return [outline];\r\n }\r\n }\r\n\r\n yCus.sort((c1, c2) => c1.StartPoint.x - c2.StartPoint.x);\r\n\r\n\r\n let rects: Polyline[] = [];\r\n\r\n for (let i = 0; i < yCus.length - 1; i++)\r\n {\r\n let c1 = yCus[i];\r\n let c2 = yCus[i + 1];\r\n\r\n let x1 = c1.StartPoint.x;\r\n let x2 = c2.StartPoint.x;\r\n if (equaln(x1, x2))\r\n continue;\r\n\r\n let y1: number;\r\n let y2: number;\r\n\r\n let res = c1.IntersectWith2(outline, IntersectOption.ExtendThis);\r\n\r\n let res2 = c2.IntersectWith2(outline, IntersectOption.ExtendThis);\r\n let pars = [...res.map(r => Math.floor(r.argParam)), ...res2.map(r => Math.floor(r.argParam))];\r\n pars = [...new Set(pars)];\r\n pars.sort((a, b) => a - b);\r\n\r\n let ys: number[] = [];\r\n for (let par of pars)\r\n {\r\n let c = outline.GetCurveAtParam(par);\r\n let derv = c.GetFistDeriv(0).normalize();\r\n if (isParallelTo(derv, XAxis, PolylineSpliteRectFuzz))\r\n {\r\n let x3 = c.StartPoint.x;\r\n let x4 = c.EndPoint.x;\r\n if (x3 > x4)\r\n [x3, x4] = [x4, x3];\r\n if (isIntersect(x1, x2, x3, x4, -PolylineSpliteRectFuzz))\r\n ys.push(c.StartPoint.y);\r\n }\r\n }\r\n\r\n if (ys.length < 2) return [outline];\r\n\r\n ys.sort((a, b) => a - b);\r\n\r\n y1 = ys[0];\r\n y2 = arrayLast(ys);\r\n\r\n rects.push(new Polyline().RectangleFrom2Pt(new Vector3(x1, y1), new Vector3(x2, y2)));\r\n }\r\n\r\n return rects;\r\n\r\n}\r\n","import { Box3, BufferGeometry, Line as TLine, Matrix3, Matrix4, Object3D, Shape, Vector2, Vector3 } from 'three';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { getArcOrCirNearPts, getCircleCenter, GetTanPtsOnArcOrCircle } from '../../Common/CurveUtils';\r\nimport { matrixSetVector, reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { Status } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { angle, AsVector3, clampRad, equaln, equalv3, midPoint, MoveMatrix, polar } from '../../Geometry/GeUtils';\r\nimport { IntersectArcAndArc, IntersectCircleAndArc, IntersectEllipseAndCircleOrArc, IntersectLineAndArc, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\nimport { Circle } from './Circle';\r\nimport { Curve } from './Curve';\r\nimport { Ellipse } from './Ellipse';\r\nimport { Line } from './Line';\r\nimport { Polyline } from './Polyline';\r\n\r\n/**\r\n * 圆弧实体类\r\n * 与ACAD不同,这个类加入了时针变量,并且默认构造的圆弧为顺时针圆弧.\r\n *\r\n * 关于时针圆弧:\r\n * 起始圆弧到终止圆弧总是在0-2PI之间.(一个完整的圆).\r\n * 圆弧的绘制从起始圆弧绘制到终止圆弧. 按照时针绘制.\r\n * 参考计算圆弧的完整角度方法查看该计算方式.\r\n */\r\n@Factory\r\nexport class Arc extends Curve\r\n{\r\n constructor(center: Vector3 = new Vector3(), radius: number = 0.1, startAngle: number = 0.1, endAngle: number = 0, clockwise = true)\r\n {\r\n super();\r\n this._Matrix.setPosition(center);\r\n this._Radius = radius;\r\n this._StartAngle = clampRad(startAngle);\r\n this._EndAngle = clampRad(endAngle);\r\n this._Clockwise = clockwise;\r\n }\r\n private _Radius: number;\r\n private _StartAngle: number;\r\n private _EndAngle: number;\r\n /**\r\n * 曲线为顺时针\r\n */\r\n private _Clockwise = true;\r\n\r\n get Shape()\r\n {\r\n let sp = new Shape();\r\n sp.absarc(0, 0, this._Radius, this._StartAngle, this._EndAngle, this._Clockwise);\r\n return sp;\r\n }\r\n\r\n get Center()\r\n {\r\n return this.Position;\r\n }\r\n set Center(v: Vector3)\r\n {\r\n this.Position = v;\r\n }\r\n\r\n get Normal()\r\n {\r\n return new Vector3().setFromMatrixColumn(this._Matrix, 2);\r\n }\r\n set Normal(v: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n matrixSetVector(this._Matrix, 2, v);\r\n this.Update();\r\n }\r\n\r\n get Area(): number\r\n {\r\n return 0.5 * this.AllAngle * this.Radius * this.Radius;\r\n }\r\n //获得曲线的面积,逆时针为正,顺时针为负.\r\n get Area2(): number\r\n {\r\n let clockwise = this._Clockwise ? -1 : 1;\r\n return 0.5 * this.AllAngle * this.Radius * this.Radius * clockwise;\r\n }\r\n get IsClose(): boolean\r\n {\r\n return false;\r\n }\r\n\r\n get BoundingBox(): Box3\r\n {\r\n let pts = [this.StartPoint, this.EndPoint];\r\n\r\n //TODO:考虑三维圆弧.\r\n let addPts = [\r\n this.Center.add(new Vector3(this._Radius, 0)),\r\n this.Center.add(new Vector3(0, this._Radius)),\r\n this.Center.add(new Vector3(-this._Radius, 0)),\r\n this.Center.add(new Vector3(0, -this._Radius)),\r\n ];\r\n addPts.forEach(p =>\r\n {\r\n if (this.PtOnCurve(p))\r\n pts.push(p);\r\n });\r\n return new Box3().setFromPoints(pts);\r\n }\r\n\r\n get Radius()\r\n {\r\n return this._Radius;\r\n }\r\n set Radius(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Radius = v <= 0 ? 1e-19 : v;\r\n this.Update();\r\n }\r\n\r\n get IsClockWise()\r\n {\r\n return this._Clockwise;\r\n }\r\n set IsClockWise(v: boolean)\r\n {\r\n if (v !== this._Clockwise)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Clockwise = v;\r\n this.Update();\r\n }\r\n }\r\n\r\n get StartAngle()\r\n {\r\n return this._StartAngle;\r\n }\r\n set StartAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._StartAngle = v;\r\n this.Update();\r\n }\r\n\r\n get EndAngle()\r\n {\r\n return this._EndAngle;\r\n }\r\n set EndAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._EndAngle = v;\r\n this.Update();\r\n }\r\n\r\n //******************** Curve function start*****************//\r\n get StartPoint()\r\n {\r\n return polar(new Vector3(), this._StartAngle, this._Radius).applyMatrix4(this.OCS);\r\n }\r\n set StartPoint(v: Vector3)\r\n {\r\n let vTemp = v.clone().applyMatrix4(this.OCSInv);\r\n this.StartAngle = angle(vTemp);\r\n }\r\n get EndPoint()\r\n {\r\n return polar(new Vector3(), this._EndAngle, this._Radius).applyMatrix4(this.OCS);\r\n }\r\n set EndPoint(v: Vector3)\r\n {\r\n let vTemp = v.clone().applyMatrix4(this.OCSInv);\r\n this.EndAngle = angle(vTemp);\r\n }\r\n get StartParam()\r\n {\r\n return 0;\r\n }\r\n get EndParam()\r\n {\r\n return 1;\r\n }\r\n get Length()\r\n {\r\n return this.AllAngle * this._Radius;\r\n }\r\n\r\n GetParamAtPoint2(pt: Vector3): number\r\n {\r\n return this.GetParamAtAngle(this.GetAngleAtPoint(pt));\r\n }\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n let param = this.GetParamAtPoint2(p);\r\n return this.ParamOnCurve(param, fuzz);\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this.Center = this.Center.applyMatrix4(m);\r\n this.Radius = this.Radius * m.getMaxScaleOnAxis();\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n let sp = this.StartPoint;\r\n let ep = this.EndPoint;\r\n\r\n reviseMirrorMatrix(this._Matrix);\r\n\r\n this._Clockwise = !this._Clockwise;\r\n this.StartPoint = sp;\r\n this.EndPoint = ep;\r\n return this;\r\n }\r\n GetPointAtParam(param: number)\r\n {\r\n let an = this.GetAngleAtParam(param);\r\n return polar(new Vector3(), an, this._Radius).applyMatrix4(this.OCS);\r\n }\r\n GetPointAtDistance(distance: number)\r\n {\r\n let len = this.Length;\r\n if (len == 0) return;\r\n return this.GetPointAtParam(distance / len);\r\n }\r\n\r\n GetDistAtParam(param: number)\r\n {\r\n return Math.abs(param * this.Length);\r\n }\r\n\r\n GetDistAtPoint(pt: Vector3)\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n return this.GetDistAtParam(param);\r\n }\r\n\r\n GetParamAtPoint(pt: Vector3)\r\n {\r\n if (this._Radius == 0 ||\r\n this.AllAngle == 0 ||\r\n !equaln(pt.distanceTo(this.Center), this._Radius, 1e-6))\r\n return NaN;\r\n\r\n return this.GetParamAtAngle(this.GetAngleAtPoint(pt));\r\n }\r\n\r\n /**\r\n * 利用角度计算该角度在圆弧中代表的参数.\r\n * 如果角度在圆弧内,那么返回0-1\r\n * 如果角度不在圆弧内,那么尝试返回离圆弧起始或者结束的较近的参数\r\n *\r\n * @param {number} an\r\n * @returns\r\n * @memberof Arc\r\n */\r\n GetParamAtAngle(an: number)\r\n {\r\n //如果以pt为终点,那么所有的角度为\r\n let ptAllAn = this.ComputeAnlge(an);\r\n let allAn = this.AllAngle;\r\n\r\n //减去圆弧角度,剩余角度的一半\r\n let surplusAngleHalf = Math.PI - allAn / 2;\r\n\r\n if (ptAllAn > allAn + surplusAngleHalf)//返回负数\r\n return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;\r\n else//返回正数\r\n return ptAllAn / allAn;\r\n }\r\n\r\n /**\r\n * 根据角度获得参数,不过在这里我们可以指定我们是要获取前面的参数还是后面的参数(正负)\r\n * @param an\r\n * @param [isStart] true:返回负数,false 返回正数\r\n * @returns\r\n */\r\n GetParamAtAngle2(an: number, isStart = true)\r\n {\r\n //如果以pt为终点,那么所有的角度为\r\n let ptAllAn = this.ComputeAnlge(an);\r\n let allAn = this.AllAngle;\r\n\r\n //减去圆弧角度,剩余角度的一半\r\n let surplusAngleHalf = Math.PI - allAn / 2;\r\n\r\n if (isStart)//返回负数\r\n return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;\r\n else//返回正数\r\n return ptAllAn / allAn;\r\n }\r\n\r\n GetAngleAtPoint(pt: Vector3)\r\n {\r\n let ptTmp = pt.clone().applyMatrix4(this.OCSInv);\r\n return angle(ptTmp);\r\n }\r\n\r\n GetAngleAtParam(param: number)\r\n {\r\n return clampRad(this._StartAngle + param * this.AllAngle * (this._Clockwise ? -1 : 1));\r\n }\r\n\r\n GetSplitCurves(param: number[] | number): Arc[]\r\n {\r\n let params = this.SplitParamSort(param);\r\n //角度列表\r\n let ans = params.map(p => this.GetAngleAtParam(p));\r\n //返回圆弧表\r\n let arcs: Arc[] = [];\r\n for (let i = 0; i < ans.length - 1; i++)\r\n {\r\n let arc = this.Clone() as Arc;\r\n arc.StartAngle = ans[i];\r\n arc.EndAngle = ans[i + 1];\r\n arcs.push(arc);\r\n }\r\n return arcs;\r\n }\r\n GetOffsetCurves(offsetDist: number)\r\n {\r\n if (this._Clockwise) offsetDist *= -1;\r\n if ((offsetDist + this._Radius) > 0)\r\n {\r\n let arc = this.Clone() as Arc;\r\n arc.Radius = offsetDist + this._Radius;\r\n return [arc];\r\n }\r\n return [];\r\n }\r\n Extend(newParam: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n if (newParam < 0)\r\n {\r\n this._StartAngle = this.GetAngleAtParam(newParam);\r\n }\r\n else if (newParam > 1)\r\n {\r\n this._EndAngle = this.GetAngleAtParam(newParam);\r\n }\r\n this.Update();\r\n }\r\n\r\n Join(cu: Curve): Status\r\n {\r\n if (cu instanceof Arc)\r\n {\r\n if (equalv3(cu.Center, this.Center) && equaln(cu._Radius, this._Radius))\r\n {\r\n this.WriteAllObjectRecord();\r\n let [sa, ea] = [cu.StartAngle, cu.EndAngle];\r\n if (cu._Clockwise != this._Clockwise)\r\n [sa, ea] = [ea, sa];\r\n\r\n let allAn = this.AllAngle;\r\n let saAllan = this.ComputeAnlge(sa);\r\n let eaAllan = this.ComputeAnlge(ea);\r\n\r\n if (equaln(sa, this._StartAngle)) //this起点对起点\r\n {\r\n if (eaAllan > allAn)\r\n this.EndAngle = ea;\r\n\r\n return Status.True;\r\n }\r\n else if (equaln(sa, this._EndAngle))//this终点对起点\r\n {\r\n if (eaAllan < allAn || equaln(ea, this._StartAngle))\r\n return Status.ConverToCircle;\r\n else\r\n this.EndAngle = ea;\r\n\r\n return Status.True;\r\n }\r\n else if (equaln(ea, this.StartAngle))//this起点对终点\r\n {\r\n if (saAllan < allAn)\r\n return Status.ConverToCircle;\r\n else\r\n this.StartAngle = sa;\r\n return Status.True;\r\n }\r\n else if (equaln(ea, this._EndAngle))//this终点对终点\r\n {\r\n if (saAllan > allAn)\r\n this.StartAngle = sa;\r\n return Status.True;\r\n }\r\n else if (this.ParamOnCurve(this.GetParamAtAngle(sa)))\r\n {\r\n if (eaAllan < saAllan)\r\n return Status.ConverToCircle;\r\n else if (eaAllan > allAn)\r\n this.EndAngle = ea;\r\n return Status.True;\r\n }\r\n else if (this.ParamOnCurve(this.GetParamAtAngle(ea)))\r\n {\r\n this.StartAngle = sa;\r\n return Status.True;\r\n }\r\n\r\n //使用按负方向去计算它的参数\r\n let saParam: number;\r\n if (saAllan > allAn)\r\n saParam = (saAllan - Math.PI * 2) / allAn;\r\n else\r\n saParam = saAllan / allAn;\r\n\r\n let eaParam: number;\r\n if (eaAllan > saAllan && saAllan > allAn)\r\n eaParam = (eaAllan - Math.PI * 2) / allAn;\r\n else\r\n eaParam = eaAllan / allAn;\r\n\r\n let pMin = Math.max(0, saParam);\r\n let pMax = Math.min(1, eaParam);\r\n\r\n if (pMin <= pMax + 1e-5)\r\n {\r\n if (saParam < 0)\r\n this.StartAngle = sa;\r\n if (eaParam > 1)\r\n this.EndAngle = ea;\r\n return Status.True;\r\n }\r\n }\r\n }\r\n return Status.False;\r\n }\r\n\r\n Reverse(): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Clockwise = !this._Clockwise;\r\n [this._StartAngle, this._EndAngle] = [this._EndAngle, this._StartAngle];\r\n return this;\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-4)\r\n {\r\n if (curve instanceof Arc)\r\n {\r\n return IntersectArcAndArc(this, curve, intType);\r\n }\r\n if (curve instanceof Line)\r\n {\r\n return SwapParam(IntersectLineAndArc(curve, this, reverseIntersectOption(intType), tolerance));\r\n }\r\n if (curve instanceof Circle)\r\n {\r\n return SwapParam(IntersectCircleAndArc(curve, this, reverseIntersectOption(intType), tolerance));\r\n }\r\n if (curve instanceof Polyline)\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));\r\n\r\n if (curve instanceof Ellipse)\r\n return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));\r\n return [];\r\n }\r\n\r\n /**\r\n * 计算出圆弧所包含的角度\r\n *\r\n * @readonly\r\n * @type {number}\r\n * @memberof Arc\r\n */\r\n get AllAngle(): number\r\n {\r\n return this.ComputeAnlge(this._EndAngle);\r\n }\r\n\r\n get Bul(): number\r\n {\r\n if (equaln(this.AllAngle, Math.PI * 2))\r\n return 1;\r\n return Math.tan(this.AllAngle * 0.25) * (this.IsClockWise ? -1 : 1);\r\n }\r\n\r\n /**\r\n * 计算所包含的角度\r\n *\r\n * @private\r\n * @param {number} endAngle 结束的角度\r\n * @returns\r\n * @memberof Arc\r\n */\r\n ComputeAnlge(endAngle: number)\r\n {\r\n //顺时针\r\n if (this._Clockwise)\r\n {\r\n if (this._StartAngle > endAngle)\r\n return this._StartAngle - endAngle;\r\n else //越过0点绘制圆弧\r\n return (Math.PI * 2) - (endAngle - this._StartAngle);\r\n }\r\n else\r\n {\r\n if (endAngle > this._StartAngle)\r\n return endAngle - this._StartAngle;\r\n else\r\n return (Math.PI * 2) - (this._StartAngle - endAngle);\r\n }\r\n }\r\n\r\n /**\r\n * 解析两点和凸度所构成的圆弧\r\n *\r\n * @param {Vector2} p1\r\n * @param {Vector2} p2\r\n * @param {number} bul 凸度,在cad中,凸度为 <(四分之一圆心角)的正切值>\r\n */\r\n ParseFromBul(p1: Vector3 | Vector2, p2: Vector3 | Vector2, bul: number): Arc\r\n {\r\n if (p1 instanceof Vector2)\r\n p1 = AsVector3(p1);\r\n if (p2 instanceof Vector2)\r\n p2 = AsVector3(p2);\r\n\r\n let ocsInv = this.OCSInv;\r\n p1 = p1.clone().applyMatrix4(ocsInv);\r\n p2 = p2.clone().applyMatrix4(ocsInv);\r\n\r\n //弦向量\r\n let chordV = p2.clone().sub(p1);\r\n //弦角度\r\n let chordAn = angle(chordV);\r\n //弦长度/2\r\n let chordLengthHalf = chordV.length() / 2;\r\n\r\n let allAngle = Math.atan(bul) * 4;\r\n let HalfAngle = allAngle * 0.5;\r\n //半径\r\n this._Radius = chordLengthHalf / Math.sin(HalfAngle);\r\n\r\n //指向圆心的角度\r\n let toCenterAn = chordAn + Math.PI * 0.5;//弦角度转90\r\n\r\n //圆心\r\n let center = midPoint(p1, p2);\r\n polar(center, toCenterAn, this._Radius - (bul * chordLengthHalf));\r\n this.Center = center.clone().applyMatrix4(this.OCS);\r\n\r\n this._Radius = Math.abs(this._Radius);\r\n\r\n this._StartAngle = angle(p1.clone().sub(center));\r\n this._EndAngle = angle(p2.clone().sub(center));\r\n\r\n this._Clockwise = bul < 0;\r\n\r\n return this;\r\n }\r\n FromThreePoint(pt1: Vector3, pt2: Vector3, pt3: Vector3)\r\n {\r\n if (!(pt1 && pt2 && pt3))\r\n return;\r\n\r\n let ocsInv = this.OCSInv;\r\n pt1 = pt1.clone().applyMatrix4(ocsInv);\r\n pt2 = pt2.clone().applyMatrix4(ocsInv);\r\n pt3 = pt3.clone().applyMatrix4(ocsInv);\r\n\r\n let center = getCircleCenter(pt1, pt2, pt3);\r\n this.Center = center.clone().applyMatrix4(this.OCS);\r\n //用圆心和其中一个点求距离得到半径:\r\n this._Radius = center.distanceTo(pt1);\r\n //起始角度 端点角度\r\n this._StartAngle = angle(pt1.clone().sub(center));\r\n this._EndAngle = angle(pt3.clone().sub(center));\r\n //求出向量p1->p2,p1->p3\r\n let p1 = pt2.clone().sub(pt1);\r\n let p2 = pt3.clone().sub(pt1);\r\n\r\n this._Clockwise = p1.cross(p2).z < 0;\r\n return this;\r\n }\r\n\r\n /**\r\n * 重载: 初始化绘制实体.\r\n *\r\n * @param {RenderType} [renderType=RenderType.Wireframe]\r\n */\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe)\r\n {\r\n let geo = BufferGeometryUtils.CreateFromPts(this.Shape.getPoints(60).map(AsVector3));\r\n\r\n if (renderType === RenderType.Print)\r\n {\r\n var geometry = new LineGeometry();\r\n geometry.setPositions(geo.attributes.position.array as number[]);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n\r\n return new TLine(geo, ColorMaterial.GetLineMaterial(this._Color));\r\n }\r\n\r\n //更新Geometry\r\n private UpdateGeometry(geo: BufferGeometry)\r\n {\r\n let pts = this.Shape.getPoints(60).map(AsVector3);\r\n BufferGeometryUtils.UpdatePts(geo, pts);\r\n }\r\n\r\n /**\r\n * 重载:更新绘制的实体\r\n *\r\n * @param {RenderType} type\r\n * @param {Object3D} obj\r\n * @memberof Arc\r\n */\r\n UpdateDrawObject(type: RenderType, obj: Object3D)\r\n {\r\n let geo = obj[\"geometry\"] as BufferGeometry;\r\n this.UpdateGeometry(geo);\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return [this.StartPoint, this.EndPoint];\r\n case ObjectSnapMode.Mid:\r\n return [this.GetPointAtParam(0.5)];\r\n case ObjectSnapMode.Nea:\r\n return getArcOrCirNearPts(this, pickPoint, viewXform)\r\n .filter(p => this.PtOnCurve(p));\r\n case ObjectSnapMode.Ext:\r\n return [this.GetClosestPointTo(pickPoint, true)];\r\n case ObjectSnapMode.Cen:\r\n return [this.Center];\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))\r\n return [];\r\n let l = new Line(this.Center, lastPoint);\r\n return l.IntersectWith(this, IntersectOption.ExtendBoth).filter(p => this.PtOnCurve(p));\r\n }\r\n case ObjectSnapMode.Tan:\r\n let pts = GetTanPtsOnArcOrCircle(this, lastPoint);\r\n if (pts)\r\n return pts.filter(p => this.PtOnCurve(p));\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n return [\r\n this.StartPoint,\r\n this.GetPointAtParam(0.5),\r\n this.EndPoint,\r\n this.Center.clone(),\r\n ];\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n if (indexList.length > 0)\r\n {\r\n this.WriteAllObjectRecord();\r\n let ptsArr = this.GetGripPoints();\r\n let index = indexList[0];\r\n let p = ptsArr[index];\r\n if (p)\r\n {\r\n p.add(vec);\r\n if (index > 2)\r\n this.Center = this.Center.add(vec);\r\n else\r\n this.FromThreePoint(ptsArr[0], ptsArr[1], ptsArr[2]);\r\n this.Update();\r\n }\r\n }\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n return [this.StartPoint, this.EndPoint];\r\n }\r\n\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n if (indexList.length === 0)\r\n return;\r\n\r\n this.WriteAllObjectRecord();\r\n\r\n if (indexList.length === 2)\r\n this.ApplyMatrix(MoveMatrix(vec));\r\n else\r\n for (let index of indexList)\r\n {\r\n let pts = [this.StartPoint, this.EndPoint];\r\n let [sp, ep] = pts;\r\n\r\n let oldChordLengthHalf = sp.distanceTo(ep) * 0.5;\r\n\r\n let arcHeight = oldChordLengthHalf * this.Bul;\r\n\r\n pts[index].add(vec);\r\n\r\n let newChordLengthHalf = sp.distanceTo(ep) * 0.5;\r\n\r\n let newBul = arcHeight / newChordLengthHalf;\r\n\r\n //根据凸度构造新的弧\r\n this.ParseFromBul(sp, ep, newBul);\r\n this.Update();\r\n }\r\n }\r\n\r\n GetParamAtDist(d: number)\r\n {\r\n return d / this.Length;\r\n }\r\n GetFistDeriv(pt: number | Vector3)\r\n {\r\n let an: number;\r\n if (typeof pt === \"number\")\r\n an = this.GetAngleAtParam(pt);\r\n else\r\n an = angle(pt.clone().applyMatrix4(this.OCSInv));\r\n\r\n an += Math.PI * 0.5 * (this._Clockwise ? -1 : 1);\r\n\r\n let ocs = new Matrix4().extractRotation(this.OCS);\r\n return polar(new Vector3(), an, this._Radius).applyMatrix4(ocs);\r\n }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n let l = new Line(this.Center, pt);\r\n let inPts: Vector3[] = this.IntersectWith(l, extend ? IntersectOption.ExtendBoth : IntersectOption.ExtendArg);\r\n if (inPts.length < 2)\r\n inPts.push(this.StartPoint, this.EndPoint);\r\n return inPts.reduce((p1, p2) => p1.distanceToSquared(pt) < p2.distanceToSquared(pt) ? p1 : p2);\r\n }\r\n //#region -------------------------File-------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n if (ver === 1)\r\n {\r\n this.Center = new Vector3().fromArray(file.Read());\r\n this.Normal = new Vector3().fromArray(file.Read());\r\n }\r\n this._Radius = file.Read();\r\n this._StartAngle = file.Read();\r\n this._EndAngle = file.Read();\r\n this._Clockwise = file.Read();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(2);\r\n file.Write(this._Radius);\r\n file.Write(this._StartAngle);\r\n file.Write(this._EndAngle);\r\n file.Write(this._Clockwise);\r\n }\r\n //#endregion\r\n}\r\n"],"names":["iaop","Vector3","Matrix4","Vector2","observable","toJS","Box3","Object3D","LineBasicMaterial","MeshBasicMaterial","DoubleSide","ShaderMaterial","Color","LineDashedMaterial","LineMaterial","BufferGeometry","Shape","ShapeGeometry","BufferAttribute","EllipseCurve","ExtrudeGeometry","Mesh","Arc","Polyline","BoolOpeartionType","Circle","Plane","Line3","Line","TLine","MathUtils","LineGeometry","Line2"],"mappings":"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EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAChB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC;IACnB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IAClB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;IAChB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;IACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;IACjB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACpB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CACf,CAAC;AAEK,MAAM,UAAU,GAAG,CAAC,CAAC;AAE5B;MACa,aAAa;IAEtB,iBAAyB;IAGzB,OAAO,eAAe,CAAC,KAAa;QAEhC,IAAI,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;YAChC,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,GAAG,GAAG,IAAIO,uBAAiB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACtC,OAAO,GAAG,CAAC;KACd;IAED,OAAO,gBAAgB,CAAC,KAAa;QAEjC,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC;YACjC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,GAAG,GAAG,IAAIC,uBAAiB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC;KACd;IAGD,OAAO,0BAA0B,CAAC,KAAa;QAE3C,IAAI,IAAI,CAAC,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC;YAC3C,OAAO,IAAI,CAAC,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,GAAG,GAAG,IAAIA,uBAAiB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,EAAEC,gBAAU,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,2BAA2B,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjD,OAAO,GAAG,CAAC;KACd;IAGD,OAAO,qBAAqB,CAAC,KAAa;QAEtC,IAAI,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC;YACnC,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE/C,IAAI,YAAY,GAAG,mBAAmB,CAClC,IAAIT,aAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAC1D,CAAC;QACF,IAAI,GAAG,GAAG,IAAIU,oBAAc,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC;KACd;IAED,OAAO,0BAA0B;QAE7B,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAClC;YACI,IAAI,CAAC,wBAAwB,GAAG,IAAIA,oBAAc,CAAC;gBAC/C,QAAQ,EAAE;oBACN,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE;iBAC7C;gBACD,YAAY,EAAE,OAAO,CAAC,yBAAyB,CAAC;gBAChD,cAAc,EAAE,OAAO,CAAC,0BAA0B,CAAC;gBACnD,aAAa,EAAE,IAAI;gBACnB,mBAAmB,EAAE,CAAC;gBACtB,kBAAkB,EAAE,UAAU;aACjC,CAAC,CAAC;SACN;QACD,OAAO,IAAI,CAAC,wBAAwB,CAAC;KACxC;IAGD,OAAO,2BAA2B,CAAC,KAAa,EAAE,OAAe;QAE7D,IAAI,GAAG,GAAG,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;QAChC,IAAI,GAAG,GAAG,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACpB,GAAG,GAAG,IAAIF,uBAAiB,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAEC,gBAAU,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO,GAAG,CAAC;KACd;IAGD,OAAO,4BAA4B,CAAC,KAAa,EAAE,OAAe;QAE9D,IAAI,GAAG,GAAG,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;QAChC,IAAI,GAAG,GAAG,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACpB,GAAG,GAAG,IAAID,uBAAiB,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,6BAA6B,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjD,OAAO,GAAG,CAAC;KACd;IAED,OAAO,QAAQ,CAAC,KAAa;QAEzB,IAAI,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,GAAG;YACH,OAAO,IAAIG,WAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;;QAG/D,OAAO,IAAIA,WAAK,EAAE,CAAC;KACtB;;AA5Fc,8BAAgB,GAAG,IAAI,GAAG,EAA6B,CAAC;AACxD,+BAAiB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAmBzD,yCAA2B,GAAG,IAAI,GAAG,EAA6B,CAAC;AAUnE,iCAAmB,GAAgC,IAAI,GAAG,EAAE,CAAC;AAgC7D,0CAA4B,GAAmC,IAAI,GAAG,EAAE,CAAC;AAWzE,2CAA6B,GAAmC,IAAI,GAAG,EAAE,CAAC;AAqBzF;AACO,gCAAkB,GAAG,IAAIC,wBAAkB,CAAC;IAC/C,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,CAAC;CACb,CAAC,CAAC;AAEH;AACO,8BAAgB,GAAG,IAAIA,wBAAkB,CAAC;IAC7C,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;CACb,CAAC,CAAC;AACI,8BAAgB,GAAG,IAAIC,yBAAY,CAAC;IAEvC,KAAK,EAAE,QAAQ;IACf,SAAS,EAAE,UAAU,GAAG,IAAI;IAC5B,MAAM,EAAE,KAAK;CAChB,CAAC,CAAC;AACI,yCAA2B,GAAG,IAAIL,uBAAiB,CAAC;IACvD,KAAK,EAAE,QAAQ;IACf,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,GAAG;CACf,CAAC,CAAC;AACI,qCAAuB,GAAG,IAAIA,uBAAiB,CAAC;IACnD,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,CAAC;CACb,CAAC,CAAC;AACI,qCAAuB,GAAG,IAAIA,uBAAiB,CAAC;IACnD,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,CAAC;CACb,CAAC;;AChZN;;;;;SAqBgB,eAAe,CAAI,GAAa,EAAE,EAAK;IAEnD,IAAI,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,IAAI,KAAK,KAAK,CAAC,CAAC;QACZ,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACzB,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;SAIgB,aAAa,CAAI,GAAa,EAAE,YAA+B;IAE3E,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAC1C;QACI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EACzB;YACI,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;SACrB;KACJ;IACD,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,GAAG,CAAC;AACf,CAAC;SAOe,SAAS,CAAI,GAA0C;IAEnE,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;SAKgB,iBAAiB,CAAI,GAAa;IAE9C,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC5B,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;SAKgB,0BAA0B,CAAI,GAAa,EAAE,eAA0C,UAAU;IAE7G,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QACtC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YACjC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1B,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,GAAG,CAAC;AACf,CAAC;AAUD,SAAS,iBAAiB,CAAC,EAAO,EAAE,EAAO;IAEvC,OAAO,EAAE,GAAG,EAAE,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CAAC,EAAO,EAAE,EAAO;IAEhC,OAAO,EAAE,KAAK,EAAE,CAAC;AACrB,CAAC;AAED;;;;;SAKgB,qBAAqB,CAAI,GAAQ,EAAE,KAAa;IAE5D,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC;AACf,CAAC;SAEe,UAAU,CAAI,CAAM,EAAE,CAAM,EAAE,MAAM,GAAG,UAAU;IAE7D,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,IAAI,CAAC;AAChB;;ACxHA;;;AAGA,IAAY,cAmBX;AAnBD,WAAY,cAAc;IAEtB,mDAAQ,CAAA;IACR,iDAAO,CAAA;IACP,iDAAO,CAAA;IACP,iDAAO,CAAA;IACP,mDAAQ,CAAA;IACR,kDAAQ,CAAA;IACR,kDAAQ,CAAA;IACR,kDAAQ,CAAA;IACR,mDAAS,CAAA;IACT,mDAAS,CAAA;IACT,mDAAS,CAAA;IACT,wEAAoB,CAAA;IACpB,oDAAU,CAAA;IACV,oDAAU,CAAA;IACV,oDAAU,CAAA;IACV,uDAAY,CAAA;IACZ,qDAAwB,CAAA;AAC5B,CAAC,EAnBW,cAAc,KAAd,cAAc;;ICFT,mBAAmB,CAgQnC;AAhQD,WAAiB,mBAAmB;IAEhC,SAAgB,aAAa,CAAC,GAAc;QAExC,OAAO,IAAIM,oBAAc,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;KAClD;IAHe,iCAAa,gBAG5B,CAAA;;;;;;;IAQD,SAAgB,SAAS,CAAC,GAAmB,EAAE,GAAc;QAEzD,IAAI,EAAE,GAAG,GAAG,CAAC,YAAY,CAAC,UAAU,CAAoB,CAAC;QACzD,IAAI,EAAE,KAAK,SAAS;YAChB,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;aACtB,IAAI,EAAE,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,EAC/B;YACI,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAC1B,EAAE,CAAC,WAAW,GAAG,IAAI,CAAC;YACtB,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC;SACpC;;YAEG,OAAO,KAAK,CAAC;QAEjB,OAAO,IAAI,CAAC;KACf;IAfe,6BAAS,YAexB,CAAA;IAED,IAAI,aAA4B,CAAC;IACjC,SAAgB,aAAa;QAEzB,IAAI,aAAa;YACb,OAAO,aAAa,CAAC;aAEzB;YACI,IAAI,UAAU,GAAG,IAAIC,WAAK,EAAE,CAAC;YAC7B,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YAC9B,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;YAC7B,aAAa,GAAG,IAAIC,mBAAa,CAAC,UAAU,CAAC,CAAC;YAC9C,aAAa,CAAC,kBAAkB,EAAE,CAAC;YACnC,OAAO,aAAa,CAAC;SACxB;KACJ;IAbe,iCAAa,gBAa5B,CAAA;IAED,SAAgB,qBAAqB,CAAC,UAA4B,EAAE,YAAqB,KAAK;QAE1F,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YACvB,OAAO,IAAIF,oBAAc,EAAE,CAAC;QAChC,IAAI,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC;QAE7C,IAAI,cAAc,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QACpE,IAAI,mBAAmB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;QAE9E,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,eAAe,GAAG,EAAE,CAAC;QAEzB,IAAI,oBAAoB,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC;QAE9D,IAAI,cAAc,GAAG,IAAIA,oBAAc,EAAE,CAAC;QAE1C,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,EAC1C;YAEI,IAAI,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;;YAI7B,IAAI,SAAS,MAAM,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;;YAIzD,KAAK,IAAI,IAAI,IAAI,QAAQ,CAAC,UAAU,EACpC;gBAEI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAExC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,SAAS;oBAAE,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE1D,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;aAEpD;;YAID,IAAI,oBAAoB,KAAK,QAAQ,CAAC,oBAAoB;gBAAE,OAAO,IAAI,CAAC;YAExE,KAAK,IAAI,IAAI,IAAI,QAAQ,CAAC,eAAe,EACzC;gBAEI,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAE7C,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,SAAS;oBAAE,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBAEpE,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;aAE9D;;YAID,cAAc,CAAC,QAAQ,CAAC,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC,cAAc,IAAI,EAAE,CAAC;YACtF,cAAc,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAE/D,IAAI,SAAS,EACb;gBAEI,IAAI,KAAa,CAAC;gBAElB,IAAI,SAAS,EACb;oBAEI,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;iBAEhC;qBAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS,EACrD;oBAEI,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;iBAE9C;qBACD;oBAEI,OAAO,IAAI,CAAC;iBAEf;gBAED,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;gBAE1C,MAAM,IAAI,KAAK,CAAC;aAEnB;SAEJ;;QAID,IAAI,SAAS,EACb;YAEI,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,WAAW,GAAG,EAAE,CAAC;YAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,EAC1C;gBAEI,IAAI,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;gBAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,EACpC;oBAEI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC;iBAEjD;gBAED,WAAW,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;aAE1D;YAED,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;SAExC;;QAID,KAAK,IAAI,IAAI,IAAI,UAAU,EAC3B;YAEI,IAAI,eAAe,GAAG,qBAAqB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAE9D,IAAI,CAAC,eAAe;gBAAE,OAAO,IAAI,CAAC;YAElC,cAAc,CAAC,YAAY,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;SAEtD;;QAID,KAAK,IAAI,IAAI,IAAI,eAAe,EAChC;YAEI,IAAI,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAEtD,IAAI,eAAe,KAAK,CAAC;gBAAE,MAAM;YAEjC,cAAc,CAAC,eAAe,GAAG,cAAc,CAAC,eAAe,IAAI,EAAE,CAAC;YACtE,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAE1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,EAAE,EAAE,CAAC,EACxC;gBAEI,IAAI,sBAAsB,GAAU,EAAE,CAAC;gBAEvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EACrD;oBAEI,sBAAsB,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBAE5D;gBAED,IAAI,oBAAoB,GAAG,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;gBAEzE,IAAI,CAAC,oBAAoB;oBAAE,OAAO,IAAI,CAAC;gBAEvC,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;aAEnE;SAEJ;QAED,OAAO,cAAc,CAAC;KAEzB;IAvKe,yCAAqB,wBAuKpC,CAAA;IAED,SAAgB,qBAAqB,CAAC,UAA6B;QAE/D,IAAI,UAAU,CAAC;QACf,IAAI,QAAgB,CAAC;QACrB,IAAI,UAAmB,CAAC;QACxB,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,EAC1C;YAEI,IAAI,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAE9B,IAAI,UAAU,KAAK,SAAS;gBAAE,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC;YACvE,IAAI,UAAU,KAAK,SAAS,CAAC,KAAK,CAAC,WAAW;gBAAE,OAAO,IAAI,CAAC;YAE5D,IAAI,QAAQ,KAAK,SAAS;gBAAE,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;YAC1D,IAAI,QAAQ,KAAK,SAAS,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAEjD,IAAI,UAAU,KAAK,SAAS;gBAAE,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;YAChE,IAAI,UAAU,KAAK,SAAS,CAAC,UAAU;gBAAE,OAAO,IAAI,CAAC;YAErD,WAAW,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;SAEzC;QAED,IAAI,KAAK,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,EAC1C;YAEI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAEvC,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;SAExC;QAED,OAAO,IAAIG,qBAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;KAE3D;IAvCe,yCAAqB,wBAuCpC,CAAA;AAEL,CAAC,EAhQgB,mBAAmB,KAAnB,mBAAmB;;MCEvB,MAAO,SAAQF,WAAK;IAE7B,SAAS,CAAC,YAAoB,EAAE;QAE5B,SAAS,GAAG,SAAS,IAAI,EAAE,CAAC;QAC5B,IAAI,MAAM,GAAG,EAAE,EAAE,IAAa,CAAC;QAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAC5D;YACI,IAAI,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;;YAEtB,IAAI,UAAU,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC;;kBAE7F,CAAC,KAAK,KAAK,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC;;sBAEpD,CAAC,KAAK,IAAI,KAAK,CAAC,aAAa,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM;0BAC5D,SAAS,CAAC;YAExB,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;gBACI,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnB,IAAI,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC;oBAClC,SAAS;gBAEb,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnB,IAAI,GAAG,KAAK,CAAC;gBAEb,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC;oBACpB,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;aAC9B;SACJ;QACD,IAAI,IAAI,CAAC,SAAS;eACX,MAAM,CAAC,MAAM,GAAG,CAAC;eACjB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EACnD;YACI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;SAC1B;QACD,OAAO,MAAM,CAAC;KACjB;IAGD,UAAU,CAAC,EAAU,EAAE,EAAU,EAAE,OAAe,EAAE,OAAe,EAAE,WAAmB,EAAE,SAAiB,EAAE,UAAmB,EAAE,SAAiB;QAE/I,IAAI,KAAK,GAAG,IAAIG,kBAAY,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;;;;;;;;;;;;QActG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAExB,IAAI,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAElC,OAAO,IAAI,CAAC;KACf;;;MClEQ,OAAO;IAApB;;QAGI,OAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KA8CrB;IA5CG,GAAG,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;QAE9C,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;KACnB;IAED,WAAW,CAAC,GAAsB;QAE9B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;QAChB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC5B,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;KACf;IAED,WAAW,CAAC,IAAa;QAErB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EACvC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CACrC,CAAC;KACL;IAED,SAAS,CAAC,KAAa;QAEnB,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;KACf;;IAGD,MAAM;;QAGF,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;QAC3B,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EACtB,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,CACpB,CAAC;QACF,OAAO,IAAI,CAAC;KACf;;;AChDL,IAAI,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC;SACN,SAAS,CAAC,GAAmB;IAEzC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EACP,CAAC,EAAE,CAAC,CAAC,CAAC;IAEV,KAAK,IAAI,GAAG,IAAI,GAAG,CAAC,aAAa,EACjC;QACI,KAAK,IAAI,EAAE,IAAI,GAAG,EAClB;YACI,KAAK,IAAI,CAAC,IAAI,EAAE;gBACZ,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SACxB;KACJ;IACD,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC;AAC7B;;ICZiB,eAAe,CA2H/B;AA3HD,WAAiB,eAAe;;IAG5B,MAAa,KAAK;QAQd,YAAY,EAAW,EAAE,EAAW,EAAE,GAAW;YAE7C,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;YAE5B,IAAI,GAAG,GAAY,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;YACvB,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YAEtD,IAAI,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YAC3B,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;YAClC,EAAE,IAAI,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;YAEpB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YAEjC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAE/B,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;YACrD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;YACnD,IAAI,GAAG,GAAG,CAAC,EACX;;gBAEI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;aAC1B;SACJ;KACJ;IApCY,qBAAK,QAoCjB,CAAA;;IAID,SAAgB,UAAU,CAAC,GAAc,EAAE,IAAc;QAErD,IAAI,KAAK,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACnC,IAAI,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAErB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EACvC;YACI,IAAI,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAC5B;gBACI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;aACpC;iBAED;gBACI,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;;;;gBAIhB,IAAI,IAAI,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1C,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;gBACvB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;aACrF;SACJ;QACD,OAAO,KAAK,CAAC;KAChB;IA1Be,0BAAU,aA0BzB,CAAA;;IAGD,SAAgB,WAAW,CAAC,SAAiB;QAEzC,IAAI,GAAG,GAAc,IAAI,KAAK,EAAE,CAAC;QACjC,IAAI,IAAI,GAAa,IAAI,KAAK,EAAE,CAAC;QACjC,IAAI,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAElC,IAAI,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAEjC,IAAI,QAAQ,GAAG,IAAIjB,aAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,GAAY,IAAIA,aAAO,EAAE,CAAC;;QAEpC;YAEI,IAAI,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YACtC,IAAI,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YACtC,IAAI,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YACtC,IAAI,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAEpE,QAAQ,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/B,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC5B,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;SAC/B;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EACxC;YACI,IAAI,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YACtD,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,IAAIC,aAAO,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3B;QAED,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,eAAe,GAAG;YAClB,KAAK,EAAE,CAAC;YACR,YAAY,EAAE,KAAK;YACnB,MAAM,EAAE,WAAW,GAAG,KAAK;SAC9B,CAAC;QAEF,IAAI,GAAG,GAAG,IAAIiB,qBAAe,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;QACnD,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC;QAC1C,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE3B,IAAI,SAAS,CAAC,WAAW,CAAC,KAAK,KAAK,EACpC;YACI,SAAS,CAAC,GAAG,CAAC,CAAC;SAClB;QAED,IAAI,IAAI,GAAG,IAAIC,UAAI,CAAC,GAAG,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;KACf;IAlDe,2BAAW,cAkD1B,CAAA;AACL,CAAC,EA3HgB,eAAe,KAAf,eAAe;;ACuBhC;;;;MAIa,QAAQ;IAEjB,YACW,gBAAgB,CAAC,EACjB,kBAAkB,KAAK,EACtB,aAAa,EAAE,IAAI,aAAa;QAFjC,kBAAa,GAAb,aAAa,CAAI;QACjB,oBAAe,GAAf,eAAe,CAAQ;QACtB,eAAU,GAAV,UAAU,CAAsB;;;;;;QAQ5C,gBAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;QAE1C,cAAS,GAAc,EAAE,CAAC;QA0E1B,iBAAY,GAAgC,EAAE,CAAC;KAnF1C;;;;IAcL,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,SAAS,CAAC;KACzB;;;;;;;IAQD,aAAa,CAAC,KAAY,EAAE,QAAiB,KAAK,YAAYC,WAAG,EAAE,kBAA2B,KAAK,EAAE,UAAU,GAAG,KAAK;QAEnH,IAAI,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;QAC1B,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC;QACxB,IAAI,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;;QAGnC,IAAI,IAAI,CAAC,eAAe,IAAI,MAAM,KAAK,IAAI;YACvC,OAAO,KAAK,CAAC;QAEjB,IAAI,eAAe;SACnB;YACI,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAEjC,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,CAAC,IAAI,EACxE;oBACI,IAAI,KAAK;wBACL,OAAO,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;oBAC7E,OAAO,IAAI,CAAC;iBACf;aACJ,CAAC,CAAC;YACH,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;SAClC;QAED,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1B,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;QAEnB,IAAI,QAAQ,GAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;QAChG,IAAI,QAAQ,GAAU,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;QAE/F,IAAI,CAAC,KAAK,IAAI,UAAU,EACxB;YACI,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC3D,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;YACjB,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;SACxC;QACD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE3B,OAAO,IAAI,CAAC;KACf;;;;IAKD,cAAc,CAAC,CAAU;QAErB,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEpC,IAAI,OAAO,GAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,OAAO,CAAC;KAClB;;;;IAOD,SAAS,CAAC,CAAU;QAEhB,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,IAAI,GAAG,EACjB;YACI,IAAI,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;YACrD,GAAG,IAAI,cAAc,GAAG,GAAG,CAAC;SAC/B;QAED,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY;YACxB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE;YAEvB,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1C,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YAChB,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;SACzC,CAAC,CAAC;QAEH,IAAI,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC;QAC7B,IAAI,SAAS,GAAG,CAAC,IAAI,WAAW,CAAC;QACjC,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,EAAE,EAAE,QAAQ,EACvD;YACI,IAAI,eAAe,GAAG,QAAQ,CAAC;YAC/B,GAAG,GAAG,EAAE,CAAC;YACT,SAAS,CAAC,OAAO,CAAC,UAAU,QAAQ;gBAEhC,GAAG,IAAI,QAAQ,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC;gBACrC,eAAe,KAAK,CAAC,CAAC;aACzB,CAAC,CAAC;YACH,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC9B;QACD,OAAO,CAAC,CAAC;KACZ;;;ACpJL;;;;;;;MAOa,WAAW;;;;;;IAiBpB,YAAY,MAAe,EAAS,gBAAgB,CAAC,EAAU,kBAAkB,IAAI;QAAjD,kBAAa,GAAb,aAAa,CAAI;QAAU,oBAAe,GAAf,eAAe,CAAO;;QAdrF,mBAAc,GAAiB,EAAE,CAAC;;QAElC,oBAAe,GAAiB,EAAE,CAAC;;QAGnC,eAAU,GAAwB,IAAI,GAAG,EAAE,CAAC;;QAYxC,IAAI,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;;QAG/C,OAAO,IAAI,EACX;YACI,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC;gBAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;;gBACrC,MAAM;SACd;QACD,IAAI,YAAqB,CAAC;QAC1B,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,EAC1B;YACI,YAAY,GAAG,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,CAAC,MAAM,IAAG,CAAC,GAAG,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAClG,IAAI,OAAO,GAAG,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC3E,IAAI,OAAO,GAAG,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;YAE3E,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACjD,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAE/C,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YAC9B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EACtB;gBACI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAClC,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,KAAK,EAAE,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;iBAC5F;;oBAEI,KAAK,IAAI,CAAC,IAAI,OAAO,EACrB;wBACI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;wBACnB,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;wBACxC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;qBACzC;oBACD,SAAS;iBACZ;;oBAEG,KAAK,IAAI,CAAC,IAAI,OAAO;wBACjB,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;aAChC;YAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;aACtB;gBACI,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACnC,KAAK,IAAI,CAAC,IAAI,OAAO,EACrB;oBACI,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,EAC1B;wBACI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;wBACnB,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;wBACxC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;qBACzC;iBACJ;aACJ;SACJ;KACJ;IAED,gBAAgB,CAAC,CAAU,EAAE,QAAmB;QAE5C,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,OAAO,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAC3C;YACI,QAAQ,GAAG,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9C,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,EACL;gBACI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACnB,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC;aAClB;;gBAEG,OAAO,GAAG,SAAS,CAAC;SAC3B;KACJ;IAED,UAAU,CAAC,CAAQ;QAEf,IAAI,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QAChE,IAAI,KAAK,KAAK,CAAC,CAAC;YACZ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAEnC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1D,IAAI,KAAK,KAAK,CAAC,CAAC;YACZ,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;KACpC;;;;IAKO,kBAAkB,CAAC,QAAmB;QAE1C,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAExB,IAAI,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YACrC,IAAI,EAAE,GAAG,CAAC;gBAAE,OAAO,CAAC,CAAC;YACrB,IAAI,EAAE,GAAG,CAAC;gBAAE,OAAO,CAAC,CAAC;YACrB,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAClD,CAAC,CAAC;KACN;;;;;IAMO,kBAAkB,CAAC,SAAkB;QAEzC,IAAI,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;;QAGtD,IAAI,KAAK,GAAY,EAAE,CAAC;QACxB,aAAa,CAAC,SAAS,EAAE,CAAC;YAEtB,IAAI,CAAC,YAAYC,gBAAQ,EACzB;gBACI,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;;gBAGtB,IAAI,IAAI,GAAU,EAAE,CAAC;gBACrB,aAAa,CAAC,GAAG,EAAE,CAAC;oBAEhB,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI;wBAAE,OAAO,IAAI,CAAC;oBAEjC,IAAI,CAAC,YAAYD,WAAG,EACpB;wBACI,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;wBAC9B,KAAK,IAAI,GAAG,IAAI,MAAM;4BAClB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;qBACtB;oBAED,OAAO,KAAK,CAAC;iBAChB,CAAC,CAAC;;gBAEH,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;gBAElB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC5B,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;gBACnB,OAAO,IAAI,CAAC;aACf;YACD,OAAO,KAAK,CAAC;SAChB,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAEzB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC;QAEpC,KAAK,IAAI,EAAE,IAAI,SAAS,EACxB;;YAEI,IAAI,EAAE,YAAYA,WAAG,EACrB;gBACI,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAC7B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EACnB;oBACI,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,QAAQ,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC/E,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC9B,SAAS;iBACZ;;oBAEG,QAAQ,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;aACpE;;gBAEG,QAAQ,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;SACrE;;QAGD,KAAK,IAAI,CAAC,IAAI,QAAQ,CAAC,SAAS,EAChC;YACI,IAAI,SAAS,GAAG,QAAQ,CAAC;YACzB,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM;gBAClB,IAAI,CAAC,CAAC,MAAM,GAAG,SAAS;oBAAE,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;YACnD,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM;gBAClB,cAAc,CAAC,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC;YACvC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;SAC5C;QACD,OAAO,QAAQ,CAAC,MAAM,CAAC;KAC1B;IAEO,QAAQ,CAAC,GAAQ;QAErB,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAIrB,aAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1D,IAAI,KAAK,GAAG,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI;YAC5B,OAAO,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;;YAEjC,OAAO,CAAC,GAAG,CAAC,CAAC;KACpB;;;;IAKD,YAAY,CAAC,EAAS;QAElB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAC3B;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC,GAAG;gBACJ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/B,OAAO,GAAG,CAAC;SACd;;YAEG,OAAO,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC;KAC9B;CACJ;AAED,SAAS,cAAc,CAAC,CAAQ,EAAE,MAAc;IAE5C,IAAI,CAAC,CAAC,EAAE,KAAK,SAAS;QAAE,OAAO;IAC/B,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC;IACjB,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS;QACf,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;UACtD,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,IAAK,QAIJ;AAJD,WAAK,QAAQ;IAET,qCAAO,CAAA;IACP,sCAAQ,CAAA;AACZ,CAAC,EAJI,QAAQ,KAAR,QAAQ,QAIZ;AAED,SAAS,cAAc,CAAC,YAAqB,EAAE,QAAgB,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG;IAEhF,IAAI,IAAI,GAAY,EAAE,CAAC;IACvB,IAAI,UAAU,GAAY,YAAY,CAAC;IACvC,IAAI,QAAe,CAAC;;IAEpB,GACA;QACI,IAAI,KAAK,GAAG,YAAY,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QACrD,IAAI,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC;YACjD,OAAO,EAAE,CAAC;;QAEd,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,CAAC;YAC1B,MAAM,UAAU,CAAC;KACxB,QACM,UAAU,KAAK,YAAY,EAAE;IAEpC,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;AAGA,SAAS,UAAU,CAAC,CAAU;IAE1B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;;IAE7B,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EACjC;QACI,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,GAC1B;YACI,IAAI,CAAC,KAAK,CAAC;gBAAE,MAAM;YACnB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACd,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EACnB;gBACI,IAAI,CAAC,GAAG,CAAC;oBACL,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3B,MAAM;aACT;SACJ;KACJ;IAED,OAAO,CAAC,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,CAAU,EAAE,IAAY,EAAE,OAAiB,QAAQ,CAAC,GAAG;IAEzE,IAAI,CAAC,IAAI;QACL,OAAO,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;;IAG/B,IAAI,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,QAAQ,GAAG,QAAQ,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACpD,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC9B;;ACtTA,WAAY,iBAAiB;IAEzB,yEAAgB,CAAA;IAChB,2DAAS,CAAA;IACT,iEAAY,CAAA;AAChB,CAAC,EALWuB,yBAAiB,KAAjBA,yBAAiB,QAK5B;AAED,MAAM,IAAI,GAAG,IAAI,CAAC;AAClB,IAAI,MAAM,GAAG,IAAIvB,aAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAE3C;SACgB,0BAA0B,CAAC,SAAsC,EAAE,SAAgB;IAE/F,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,WAAW,CAAC;QAChF,OAAO,KAAK,CAAC;IAEjB,IAAI,GAAG,GAAY,EAAE,CAAC;IACtB,IAAI,SAAS,YAAYsB,gBAAQ;QAC7B,GAAG,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;;QAE1B,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IAEtB,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;QAEd,IAAI,GAAG,GAAG,kBAAkB,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC3C,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;QACvC,OAAO,iBAAiB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;KAC5C,CAAC,CAAC;AACP,CAAC;AAED;AACA,SAAS,kBAAkB,CAAC,SAAgB,EAAE,EAAS,EAAE,MAAiB,EAAE;IAExE,IAAI,QAAQ,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IAC3E,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EACvB;QACI,IAAI,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,KAAK,IAAI,GAAG,IAAI,IAAI,EACpB;YACI,IAAI,GAAG,IAAI,IAAI;gBACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;YAE7C,IAAI,GAAG,KAAK,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAC3B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;SAChD;KACJ;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AACD;AACA,SAAS,iBAAiB,CAAC,SAAsC,EAAE,GAAc;IAE7E,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE;;QAGf,OAAO,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;KAC7D,CAAC,CAAC;AACP,CAAC;AAED;SACgB,kBAAkB,CAAC,SAA4B,EAAE,GAAc;IAE3E,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE;;QAGf,OAAO,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;KAC9D,CAAC,CAAC;AACP;;AC/DA,IAAY,UAkBX;AAlBD,WAAY,UAAU;;;;IAKlB,2CAAQ,CAAA;;;;IAIR,6CAAS,CAAA;;;;IAIT,2CAAQ,CAAA;;;;IAIR,2CAAQ,CAAA;AACZ,CAAC,EAlBW,UAAU,KAAV,UAAU,QAkBrB;AAED;;;AAIA,IAAsB,KAAK,GAA3B,MAAsB,KAAM,SAAQ,MAAM;IAEtC;QAEI,KAAK,EAAE,CAAC;;;QAuJF,mBAAc,GAAG,IAAI,CAAC;KAtJ/B;IAED,IAAI,IAAI;QAEJ,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KAC/C;IAED,IAAI,UAAU,KAAc,OAAO,EAAE;IACrC,IAAI,UAAU,CAAC,CAAU,IAAI,OAAO,EAAE;IACtC,IAAI,UAAU,KAAa,OAAO,EAAE;IACpC,IAAI,QAAQ,KAAc,OAAO,EAAE;IACnC,IAAI,QAAQ,CAAC,CAAU,IAAI,OAAO,EAAE;;IAGpC,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;KAC9C;IAED,IAAI,QAAQ;QAER,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;YACnB,OAAO,GAAG,CAAC;;YAEX,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;KACrD;IAED,IAAI,QAAQ,KAAa,OAAO,EAAE;IAClC,IAAI,IAAI,KAAa,OAAO,CAAC,CAAC,EAAE;;;;IAIhC,IAAI,KAAK,KAAa,OAAO,CAAC,CAAC,EAAE;IACjC,IAAI,MAAM,KAAa,OAAO,CAAC,CAAC,EAAE;IAClC,IAAI,OAAO,KAAc,OAAO,KAAK,CAAC,EAAE;;IAExC,IAAI,WAAW,KAAc,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE;IAIrD,eAAe,CAAC,KAAa,IAAa,OAAO,EAAE;IACnD,kBAAkB,CAAC,QAAgB,IAAa,OAAO,EAAE;IACzD,cAAc,CAAC,KAAa,IAAY,OAAO,EAAE;IACjD,cAAc,CAAC,EAAW,IAAY,OAAO,EAAE;IAC/C,eAAe,CAAC,EAAW,IAAY,OAAO,EAAE;IAChD,gBAAgB,CAAC,EAAW,IAAY,OAAO,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE;IAE1E,cAAc,CAAC,CAAS,IAAY,OAAO,EAAE;;;;;;;;IAS7C,YAAY,CAAC,KAAuB,IAAa,OAAO,EAAE;IAC1D,iBAAiB,CAAC,KAAuB;QAErC,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KAC/B;;;;;;IAOD,cAAc,CAAC,KAAwB,IAAkB,OAAO,EAAE;;IAElE,oBAAoB,CAAC,UAAkB,EAAE,QAAgB,IAAkB,OAAO,EAAE;IACpF,mBAAmB,CAAC,EAAuB;QAEvC,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;KACpC;IACS,cAAc,CAAC,KAAwB;QAE7C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EACxB;YACI,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAClB,OAAO,EAAE,CAAC;YACd,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,iBAAiB,CAAC,KAAK,CAAC,CAAC;YACzB,0BAA0B,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;YACpE,OAAO,KAAK,CAAC;SAChB;aACI,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAC7B,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;;YAEjC,OAAO,EAAE,CAAC;KACjB;IACD,MAAM,CAAC,QAAgB,KAAK;;;;;;;IAO5B,IAAI,CAAC,EAAS,EAAE,QAAQ,GAAG,KAAK,EAAE,SAAS,GAAG,IAAI,IAAY,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE;;IAGpF,OAAO,KAAW,OAAO,IAAI,CAAC,EAAE;;IAGhC,SAAS,CAAC,EAAW,EAAE,IAAI,GAAG,IAAI;QAE9B,OAAO,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;KAChI;;IAGD,UAAU,CAAC,EAAW;QAElB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KACtI;;IAGD,UAAU,CAAC,CAAU,EAAE,IAAI,GAAG,IAAI;QAE9B,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;KAClC;;IAGD,YAAY,CAAC,KAAa,EAAE,IAAI,GAAG,IAAI,IAAa,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE;IAC9H,eAAe,CAAC,UAAkB,IAAkB,OAAO,EAAE;IAC7D,iBAAiB,CAAC,EAAW,EAAE,MAAe,IAAa,OAAO,EAAE;;;;IAKpE,aAAa,CAAC,KAAY,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;QAElE,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;KACxE;;;;IAKD,cAAc,CAAC,KAAY,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI,IAAuB,OAAO,EAAE,CAAC,EAAE;;;;IAM1G,iBAAiB,CAAC,IAAmB,IAAY,OAAO,CAAC,CAAC,EAAE;;;;IAS5D,wBAAwB,CAAC,IAAgB,EAAE,GAAa,EAAE,QAAmB;QAEzE,IAAI,CAAC,GAAG,GAAW,CAAC;QACpB,CAAC,CAAC,QAAQ,GAAG,QAAQ,IAAI,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;KACvE;IAED,iBAAiB,CAAC,KAAK,GAAG,CAAC;QAEvB,KAAK,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAC7C;YACI,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;SAClF;KACJ;CACJ,CAAA;AA7KqB,KAAK;IAD1B,OAAO;GACc,KAAK,CA6K1B;;AChMD,IAAI,KAAK,GAAG,IAAI,OAAO,EAAE,CAAC;AAE1B,MAAM,YAAY,GAAG,IAAI,CAAC;MAEb,OAAO;IAIN,QAAQ,CAAC,EAAqB;QAEpC,IAAI,EAAE,YAAYA,gBAAQ,EAC1B;YACI,IAAI,EAAE,CAAC,KAAK,GAAG,CAAC;gBACZ,EAAE,CAAC,OAAO,EAAE,CAAC;SACpB;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;KACpB;;IAED,OAAO,aAAa,CAAC,GAAgC,EAAE,QAAQ,GAAG,IAAI;QAElE,IAAI,GAAG,YAAY,KAAK,EACxB;YACI,IAAI,GAAG,CAAC,OAAO,EACf;gBACI,IAAI,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC;gBACtB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAChB,OAAO,CAAC,CAAC;aACZ;YACD,OAAO;SACV;QAED,IAAI,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAsB,CAAC;QACnF,IAAI,UAAU,IAAI,UAAU,CAAC,OAAO,EACpC;YACI,IAAI,UAAU,YAAYA,gBAAQ,IAAI,UAAU,CAAC,SAAS,KAAK,KAAK,EACpE;gBACI,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC;gBAC5B,UAAU,CAAC,cAAc,CAAC,UAAU,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC;aAC9D;YAED,IAAI,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC;YACtB,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YACvB,OAAO,CAAC,CAAC;SACZ;KACJ;IACD,IAAI,KAAK;QAEL,OAAO,IAAI,CAAC,MAAM,CAAC;KACtB;IACD,IAAI,IAAI;QAEJ,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;KAC3B;IACD,IAAI,WAAW;QAEX,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;KAClC;;;;;;;IAOD,sBAAsB,CAAC,GAAW,EAAE,IAAY,EAAE,GAAc;QAE5D,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACrB,IAAI,EAAE,YAAYA,gBAAQ,EAC1B;YACI,IAAI,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC;YAC3B,IAAI,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC7B,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAEzB,IAAI,UAAU,GAAa,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAC/B;gBACI,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG;oBAC7B,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aAC1B;YACD,IAAI,OAAO,GAAG,IAAItB,aAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACpB,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC;SACf;QACD,OAAO,KAAK,CAAC;KAChB;IACD,KAAK;QAED,OAAO,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;KACvD;;IAED,yBAAyB,CAAC,MAAe;QAErC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC;YACpD,OAAO,EAAE,CAAC;QACd,IAAI,SAAS,GAAG,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QACrD,OAAO,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;KAC5D;;IAED,kBAAkB,CAAC,MAAe;QAE9B,IAAI,SAAS,GAAG,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;;QAGrD,IAAI,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;YACzC,OAAO;gBACH,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC;gBACpD,KAAK,EAAE,EAAE;aACZ,CAAC;;QAGN,IAAI,GAAG,GAAY,EAAE,CAAC;QACtB,KAAK,IAAI,EAAE,IAAI,SAAS,CAAC,SAAS,EAClC;YACI,IAAI,EAAE,YAAYsB,gBAAQ;gBACtB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;;gBAE1B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACpB;QACD,IAAI,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACnC,KAAK,IAAI,CAAC,IAAI,QAAQ,EACtB;YACI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EACjC;gBACI,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACd,IAAI,KAAK,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC/B,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;gBAElB,IAAI,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACzB,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI,EAC1B;oBACI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;oBACnB,CAAC,EAAE,CAAC;iBACP;qBACI,IAAI,MAAM,KAAK,MAAM,CAAC,cAAc,EACzC;oBACI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;oBACb,IAAI,CAAC,GAAG,EAAS,CAAC;oBAClB,CAAC,CAAC,IAAI,CAAC,IAAIE,cAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;oBACvC,MAAM;iBACT;aACJ;SACJ;QACD,IAAI,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EACzB;YACI,OAAO;gBACH,QAAQ,EAAE,UAAU;gBACpB,KAAK,EAAE,EAAE;aACZ,CAAC;SACL;aAED;YACI,IAAI,KAAK,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,KAAK,IAAI,CAAC,IAAI,UAAU;gBACpB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACzB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACvD,OAAO;gBACH,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACzB,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;aAC7B,CAAC;SACL;KAEJ;;IAED,qBAAqB,CAAC,MAAe;QAEjC,IAAI,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;;QAGhD,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;YAClC,OAAO,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;QAE/C,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAEhD,IAAI,QAAQ,GAAc,EAAE,CAAC;;QAE7B,MAAM,UAAU,GAAG,CAAC,QAAwB;YAExC,KAAK,IAAI,MAAM,IAAI,QAAQ,EAC3B;gBACI,IAAI,EAAE,GAAY,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;gBAC3C,IAAI,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;gBACzC,IAAI,CAAC;uBACE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;uBAChC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;uBAClC,CAAC,CAAC,IAAI,GAAG,IAAI;oBAChB,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACxB;SACJ,CAAC;QACF,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QACpC,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAErC,OAAO,QAAQ,CAAC;KACnB;;;;IAID,uBAAuB,CAAC,MAAe;QAEnC,IAAI,gBAAgB,GAAY,EAAE,CAAC;QACnC,IAAI,SAAS,GAAY,EAAE,CAAC;QAE5B,IAAI,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;QAChC,IAAI,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;QACjC,IAAI,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAE9E,IAAI,QAAQ,GAAG,aAAa,CAAC,cAAc,CAAC,aAAa,EAAE,eAAe,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QAEzG,IAAI,qBAAqB,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;QAC5D,IAAI,qBAAqB,GAAG,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;;QAG9D,IAAI,qBAAqB;SACzB;YACI,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACrC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;SACjC;aACI,IAAI,qBAAqB;SAC9B;YACI,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC9B,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;SACxC;aACI,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;SAC7B;YACI,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;SAChD;;SAED;YACI,IAAI,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;YAE1C,IAAI,SAAS,GAA0B,aAAa,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC3E,IAAI,SAAS,GAA0B,aAAa,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAE3E,KAAK,IAAI,EAAE,IAAI,SAAS,EACxB;gBACI,IAAI,WAAW,GAAG,KAAK,CAAC;gBACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EACzC;oBACI,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;oBACtB,WAAW,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACrC,IAAI,WAAW,EACf;;wBAEI,IACI,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC;gCACzG,aAAa,EAErB;4BACI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACnB,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;yBAC7B;wBACD,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;wBACvB,MAAM;qBACT;iBACJ;gBAED,IAAI,WAAW;oBACX,SAAS;gBAEb,IAAI,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;oBACtB,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;oBAE1B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC1B;YAED,KAAK,IAAI,EAAE,IAAI,SAAS,EACxB;gBACI,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBACpB,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;oBAE1B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC1B;;YAGD,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,MAAM,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,EAC/F;gBACI,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC;aAC1E;SACJ;QACD,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC;KAC1C;IACD,eAAe,CAAC,MAAe;QAE3B,IAAI,aAAa,GAAG,IAAI,CAAC,MAAkB,CAAC;QAC5C,IAAI,aAAa,GAAG,MAAM,CAAC,KAAiB,CAAC;QAE7C,IAAI,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAE9E,IAAI,QAAQ,GAAG,aAAa,CAAC,cAAc,CAAC,aAAa,EAAE,eAAe,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QAEzG,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,EACxB;;YAEI,IAAI,iBAAiB,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,UAAU,CAAC,aAAa,EAAE,aAAa,CAAC;gBAC3F,OAAO,EAAE,CAAC;;YAEd,IAAI,iBAAiB,CAAC,aAAa,EAAE,aAAa,CAAC;gBAC/C,OAAO,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;;gBAEtC,OAAO,CAAC,aAAa,CAAC,CAAC;SAC9B;;QAGD,IAAI,YAAY,GAAe,EAAE,CAAC;QAClC,IAAI,SAAS,GAAG,aAAa,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAe,CAAC;QAC3F,IAAI,SAAS,GAAG,aAAa,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAe,CAAC;QAE1F,KAAK,IAAI,EAAE,IAAI,SAAS,EACxB;YACI,IAAI,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC;YAC7B,IAAI,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;YAEpD,IAAI,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,EAAE,IAAI,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC9D,IAAI,KAAK,KAAK,CAAC,CAAC,EAChB;gBACI,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;gBAC1B,IAAI,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC;gBAC7B,IAAI,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;gBAEpD,IAAI,aAAa,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC;oBAC9C,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAE1B,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAE3B,SAAS;aACZ;YACD,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,EAAE,CAAC;gBACpC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SAC7B;;QAGD,IAAI,cAAc,GAAG,YAAY,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,CAAC;QAE9D,KAAK,IAAI,EAAE,IAAI,SAAS;YACpB,IAAI,gBAAgB,CAAC,aAAa,EAAE,EAAE,CAAC;gBACnC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE9B,IAAI,cAAc,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;YAC1D,OAAO,CAAC,aAAa,CAAC,CAAC;QAE3B,OAAO,YAAY,CAAC;KACvB;IACD,4BAA4B,CAAC,OAAkB;QAE3C,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;;QAG9D,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;YAClC,OAAO;gBACH,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;gBAC/C,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC;aAChD,CAAC;QAEN,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAEhD,IAAI,QAAQ,GAAc,EAAE,CAAC;;QAE7B,MAAM,UAAU,GAAG,CAAC,QAAwB;YAExC,KAAK,IAAI,MAAM,IAAI,QAAQ,EAC3B;gBACI,IAAI,EAAE,GAAY,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;gBAC3C,IAAI,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;gBACzC,IAAI,CAAC;uBACE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;uBAChC,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;uBAC3D,CAAC,CAAC,IAAI,GAAG,IAAI;oBAChB,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACxB;SACJ,CAAC;QACF,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QACpC,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAErC,OAAO;YACH,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YAC/C,QAAQ,EAAE,QAAQ;SACrB,CAAC;KAEL;IACD,iBAAiB,CAAC,OAAkB;QAEhC,IAAI,aAAa,GAAG,IAAI,CAAC,MAAkB,CAAC;QAC5C,IAAI,YAAY,GAAe,EAAE,CAAC;QAClC,IAAI,KAAK,GAAe,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAa,EAAE,CAAC;QAC3B,IAAI,KAAK,GAAG,IAAI,GAAG,EAAmB,CAAC;QAEvC,IAAI,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC;QAEvC,KAAK,IAAI,GAAG,IAAI,OAAO,EACvB;YACI,MAAM,aAAa,GAAG,GAAG,CAAC,KAAiB,CAAC;YAE5C,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC;gBACjD,SAAS;YAEb,IAAI,GAAG,GAAG,aAAa,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YAChG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EACnB;;gBAEI,IAAI,iBAAiB,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,UAAU,CAAC,aAAa,EAAE,aAAa,CAAC;oBAC3F,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;;gBAEnC,IAAI,iBAAiB,CAAC,aAAa,EAAE,aAAa,CAAC;oBAC/C,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAI5B;aACJ;iBAED;gBACI,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC3C,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;aACtD;SACJ;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,0BAA0B,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;QACtE,IAAI,SAAS,GAAG,aAAa,CAAC,cAAc,CAAC,OAAO,CAAe,CAAC;QACpE,IAAI,SAAS,GAAe,EAAE,CAAC;QAE/B,IAAI,SAAS,GAAG,IAAI,OAAO,EAAgB,CAAC;QAE5C,IAAI,aAAsB,CAAC;QAE3B,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,KAAK,EAC3B;YACI,IAAI,GAAG,GAAG,CAAC,CAAC,cAAc,CAAC,IAAI,CAAe,CAAC;YAC/C,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACxC,SAAS,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;SAC1B;QAED,KAAK,IAAI,EAAE,IAAI,SAAS,EACxB;YACI,IAAI,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC;YAC7B,IAAI,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;YAEpD,IAAI,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,EAAE,IAAI,cAAc,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;YACpE,IAAI,KAAK,KAAK,CAAC,CAAC,EAChB;gBACI,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;gBAC1B,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBAC9E,IAAI,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC;gBAC7B,IAAI,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;gBAEpD,IAAI,aAAa,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC;oBAC9C,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAE1B,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAE3B,SAAS;aACZ;YAED,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAiB,EAAE,EAAE,CAAC,CAAC;gBAC9D,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SAC7B;;QAGD,IAAI,cAAc,GAAG,YAAY,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,CAAC;QAE9D,KAAK,IAAI,EAAE,IAAI,SAAS;YACpB,IAAI,gBAAgB,CAAC,aAAa,EAAE,EAAE,CAAC;gBACnC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE9B,IAAI,cAAc,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;YAC1D,OAAO,EAAE,YAAY,EAAE,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC;QAEpD,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;KAElC;;;;;IAKD,OAAO,aAAa,CAAC,GAAwB;QAEzC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAChB,OAAO,EAAE,CAAC;QAEd,IAAI,QAAmB,CAAC;QACxB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACrB,QAAQ,GAAG,GAAgB,CAAC;;YAE5B,QAAQ,GAAG,cAAc,CAAC,GAAc,CAAC,CAAC;QAE9C,IAAI,QAAQ,GAAc,EAAE,CAAC;QAE7B,KAAK,IAAI,CAAC,IAAI,QAAQ;YAClB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACnD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;KAC5E;;;;;;;IAOD,OAAO,OAAO,CAAC,GAAY,EAAE,QAAQ,GAAG,IAAI,EAAE,SAAS,GAAG,IAAI;QAE1D,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAEvC,IAAI,MAAM,GAAG,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpD,KAAK,IAAI,CAAC,IAAI,MAAM,EACpB;YACI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;gBACd,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;iBAExB;gBACI,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;oBACZ,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAExB,IAAI,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gBAEnC,0BAA0B,CAAC,MAAM,EAAE,CAAC,GAAU,EAAE,GAAU,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;gBAEhH,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC;oBACxE,MAAM,CAAC,GAAG,EAAE,CAAC;gBAEjB,IAAI,EAAE,GAAGF,gBAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBAE7C,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAEjB,OAAO,EAAE,CAAC;aACb;SACJ;KACJ;IACD,IAAI,KAAK;QAEL,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;KAC5B;IACD,WAAW,CAAC,SAAgB;QAExB,OAAO,0BAA0B,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;KAC7D;IACD,KAAK,CAAC,GAAY;QAEd,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;KAC9C;CACJ;AAED;;;AAGA,SAAS,cAAc,CAAC,EAAS,EAAE,EAAS,EAAE,SAAS,GAAG,IAAI;IAE1D,IAAI,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC;IACxB,IAAI,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC;IACxB,IAAI,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC;IAEtB,IAAI,EACA,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC;YACzD,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CACpE;QACG,OAAO,KAAK,CAAC;IAEjB,OAAO,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACxD,CAAC;AAGD;AACA,SAAS,gBAAgB,CAAC,QAAkB,EAAE,QAAkB;IAE5D,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAkB,EAAE,QAAkB;IAE7D,OAAO,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC1C,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,QAAQ,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;AAC9E;;MCzkBa,QAAS,SAAQG,WAAK;IAE/B,YAAY,MAAM,GAAG,IAAIzB,aAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAA2B;QAElE,KAAK,CAAC,MAAM,CAAC,CAAC;QACd,IAAI,OAAO,QAAQ,KAAK,QAAQ;YAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;aACxB,IAAI,QAAQ;YACb,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;KAClD;IAED,aAAa,CAAC,IAAW,EAAE,cAAc,GAAG,IAAIA,aAAO,EAAE,EAAE,UAAU,GAAG,KAAK;QAEzE,IAAI,EAAE,GAAG,IAAIA,aAAO,EAAE,CAAC;QAEvB,IAAI,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAE/B,IAAI,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE7C,IAAI,WAAW,KAAK,CAAC,EACrB;;YAEI,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAC1C;gBACI,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aAC1C;;YAED,OAAO,SAAS,CAAC;SACpB;QAED,IAAI,CAAC,GAAG,EAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC;;QAEtE,IAAI,CAAC,UAAU,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EACvC;YACI,OAAO,SAAS,CAAC;SACpB;QAED,OAAO,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KAC3E;IACD,YAAY,CAAC,GAAQ,EAAE,cAAwB,EAAE,UAAoB;;QAGjE,IAAI,IAAI,GAAG,IAAI0B,WAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QAChF,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;KAC/D;;;;AC3BL,IAAa,OAAO,eAApB,MAAa,OAAQ,SAAQ,KAAK;IAO9B,YACI,MAAgB,EAChB,OAAe,IAAI,EACnB,OAAe,IAAI,EACnB,QAAgB,CAAC;QAEjB,KAAK,EAAE,CAAC;QARJ,gBAAW,GAAG,CAAC,CAAC;QAChB,cAAS,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAQ5B,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;KACxB;IACD,IAAI,UAAU;QAEV,OAAO,CAAC,CAAC;KACZ;IACD,IAAI,QAAQ;QAER,OAAO,CAAC,CAAC;KACZ;IACD,IAAI,UAAU;QAEV,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;KAClC;IACD,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;KAClC;IACD,IAAI,KAAK;QAEL,IAAI,EAAE,GAAG,IAAIX,WAAK,EAAE,CAAC;QACrB,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAChG,OAAO,EAAE,CAAC;KACb;IACD,IAAI,OAAO;QAEP,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;KAC/C;IACD,IAAI,MAAM;QAEN,OAAO,IAAIf,aAAO,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC5D;IACD,IAAI,MAAM,CAAC,CAAU;QAEjB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,IAAI;QAEJ,OAAO,IAAI,CAAC,KAAK,CAAC;KACrB;IACD,IAAI,IAAI,CAAC,CAAS;QAEd,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,IAAI;QAEJ,OAAO,IAAI,CAAC,KAAK,CAAC;KACrB;IACD,IAAI,IAAI,CAAC,CAAS;QAEd,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,OAAO,CAAC;KACvB;IACD,IAAI,QAAQ,CAAC,CAAS;QAElB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,UAAU;QAEV,OAAO,IAAI,CAAC,WAAW,CAAC;KAC3B;IACD,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,WAAW,CAAC;KAC3B;IACD,IAAI,UAAU,CAAC,CAAS;QAEpB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,QAAQ,CAAC,CAAS;QAElB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,MAAM;QAEN,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACnB,OAAO,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;KACnH;IACD,IAAI,IAAI;QAEJ,IAAI,IAAI,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAC7C,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC;QAC3C,IAAI,EAAE,GAAG,CAAC;YACN,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;QAC3B,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAChB,mBAAmB,CACf,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAC3C,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CACjD,GAAG,CAAC,CAAC;QACN,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE;YACZ,IAAI,IAAI,KAAK,CAAC;;YAEd,IAAI,IAAI,KAAK,CAAC;QAClB,OAAO,IAAI,CAAC;KACf;IACD,IAAI,UAAU;QAEV,IAAI,UAAU,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC;QACnD,IAAI,UAAU,GAAG,CAAC;YACd,UAAU,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC;QAC1C,OAAO,UAAU,CAAC;KACrB;IACD,IAAI,WAAW;QAEX,OAAO,IAAIK,UAAI,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;KACzD;IACD,SAAS,CAAC,EAAW;QAEjB,IAAI,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;KACpE;IACD,SAAS,CAAC,EAAW;QAEjB,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,EACxB;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;YACvC,OAAO,CAAC,IAAI,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;SACtC;QACD,OAAO,KAAK,CAAC;KAChB;IACD,WAAW,CAAC,EAAW;QAEnB,IAAI,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1E,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;KACjF;IACD,eAAe,CAAC,KAAa;QAEzB,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC;QAEpD,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE;YACZ,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;QAEtB,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAClB,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAClB,IAAI,EAAE,GAAG,IAAIL,aAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAE5D,EAAE,CAAC,YAAY,CAAC,IAAIC,aAAO,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAE3D,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KACpC;IACD,eAAe,CAAC,EAAY;QAExB,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,EACzB;YACI,OAAO,GAAG,CAAC;SACd;QACD,IAAI,EAAE,GAAG,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QAE/B,IAAI,IAAI,CAAC,OAAO,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI;YAC9B,OAAO,GAAG,CAAC;aAEf;YACI,IAAI,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YAChD,IAAI,GAAG,GAAG,CAAC,GAAG,OAAO,GAAG,CAAC;gBACrB,OAAO,GAAG,CAAC;;gBAEX,OAAO,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC;SAChC;KACJ;IACD,kBAAkB,CAAC,QAAgB;QAE/B,IAAI,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QACnC,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;KACtC;IACD,cAAc,CAAC,KAAa;QAExB,OAAO,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;KAC9B;IACD,cAAc,CAAC,EAAW;QAEtB,IAAI,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;KACrC;IACD,cAAc,CAAC,CAAS;QAEpB,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;KAC1B;IACD,eAAe,CAAC,GAAW;QAEvB,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,IAAIA,aAAO,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvH,OAAO,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;KACvC;IACD,qBAAqB,CAAC,EAAW;QAE7B,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QAClC,IAAI,EAAE,GAAG,CAAC;YACN,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;YAChB,EAAE,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QACtB,IAAI,IAAI,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACzC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACf,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE;YACvB,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YAElB,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpC,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;QAEvB,IAAI,EAAE,GAAG,CAAC;YACN,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;KACb;IAED,YAAY,CAAC,EAAoB;QAE7B,IAAI,OAAO,EAAE,KAAK,QAAQ;YACtB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;;YAE9B,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;QAEpB,IAAI,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAElC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,IAAIA,aAAO,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtG,IAAI,GAAG,GAAG,IAAID,aAAO,EAAE,CAAC;QACxB,IAAI,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;YACtB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;aAChB,IAAI,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAC/B;YACI,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SACrB;aACI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAChB;YACI,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SACtB;aAED;YACI,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SACpB;QACD,GAAG,CAAC,YAAY,CAAC,IAAIC,aAAO,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAE5D,OAAO,GAAG,CAAC,YAAY,CAAC,IAAIA,aAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;KACpE;IACD,iBAAiB,CAAC,CAAU,EAAE,MAAe;;QAGzC,IAAI,EAAE,GAAG,IAAIA,aAAO,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,KAAK,GAAG,IAAIA,aAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACd,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACnB,IAAI,CAAS,EAAE,CAAS,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAC1B;YACI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAChB,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAChB,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YACjB,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YAEjB,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;YAErC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACtD,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAEvD,CAAC,IAAI,EAAE,CAAC;SACX;QACD,IAAI,KAAK,GAAG,IAAID,aAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtE,IAAI,IAAI,CAAC,OAAO,IAAI,MAAM,EAC1B;YACI,OAAO,KAAK,CAAC;SAChB;aACI,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAC9B;YACI,OAAO,KAAK,CAAC;SAChB;aAED;YACI,IAAI,EAAE,GAAG,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,EAAE,GAAG,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5C,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC;SACpD;KACJ;IACD,eAAe,CAAC,UAAkB;QAE9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EACvD;YACI,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACtB,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;YAClC,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;YAClC,OAAO,CAAC,EAAE,CAAC,CAAC;SACf;QACD,OAAO,EAAE,CAAC;KACb;IACD,cAAc,CAAC,KAAwB;QAEnC,IAAI,MAAgB,CAAC;QACrB,IAAI,KAAK,YAAY,KAAK,EAC1B;YACI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;SACpC;;YAEG,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;;QAGrB,IAAI,IAAI,CAAC,OAAO;YACZ,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;aAEtC;YACI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAClB;QACD,0BAA0B,CAAC,MAAM,CAAC,CAAC;QAEnC,IAAI,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,GAAG,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;QAChF,IAAI,OAAO,GAAW,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAC7C;YACI,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EACzB;gBACI,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC;gBACnB,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;gBAC/C,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aACpB;SACJ;QACD,OAAO,OAAO,CAAC;KAClB;IACD,IAAI,CAAC,EAAW;QAEZ,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;YACvF,OAAO,MAAM,CAAC,KAAK,CAAC;QAExB,IAAI,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;QAE1B,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,EAC5C;YACI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;YAC/B,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;SACxB;aACI,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,SAAS,CAAC,EAC/C;YACI,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,WAAW,CAAC;YACjC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;SACxB;QACD,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,EACvF;YACI,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACpB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;SAC/B;QACD,OAAO,MAAM,CAAC;KACjB;IACD,mBAAmB,CACf,QAAwB,EACxB,SAAkB,EAClB,SAAkB,EAClB,SAAmB;QAGnB,QAAQ,QAAQ;YAEZ,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC/B,OAAO,GAAG,CAAC;iBACd;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzB,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,OAAO,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;iBACzD;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,SAAS,EACb;oBACI,IAAI,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;wBAC1D,OAAO,EAAE,CAAC;oBACd,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;iBACrD;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB;;oBAEI,IAAI,SAAS,EACb;wBACI,OAAO,kBAAkB,CAAgB,CAAC,CAAC;qBAC9C;iBACJ;YACL;gBACI,OAAO,EAAE,CAAC;SACjB;KACJ;IACD,cAAc,CAAC,KAAY,EAAE,OAAwB;;QAGjD,IAAI,KAAK,YAAY2B,YAAI,EACzB;YACI,OAAO,SAAS,CAAC,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SAC3F;aACI,IAAI,KAAK,YAAYH,cAAM,IAAI,KAAK,YAAYH,WAAG,EACxD;YACI,OAAO,8BAA8B,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;SAC/D;aACI,IAAI,KAAK,YAAYC,gBAAQ,EAClC;YACI,OAAO,SAAS,CAAC,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;SACrE;aACI,IAAI,KAAK,YAAY,SAAO,EACjC;YACI,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAc,CAAC,CAAC;SACjD;;YAEG,OAAO,EAAE,CAAC;KACjB;IACD,cAAc,CAAC,aAAyB,UAAU,CAAC,SAAS;QAExD,IAAI,IAAI,GAAG,IAAIM,UAAK,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACxF,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC;KACf;IACD,gBAAgB,CAAC,IAAgB,EAAE,GAAa;QAE5C,IAAI,GAAG,GAAI,GAAa,CAAC,QAA0B,CAAC;QACpD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;KAC5B;;IAEO,cAAc,CAAC,GAAoB;QAEvC,IAAI,CAAC,GAAG;YACJ,GAAG,GAAG,IAAId,oBAAc,EAAE,CAAC;QAC/B,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACvB,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC;KACd;IACD,gBAAgB;QAEZ,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;KAC/B;IACD,aAAa;QAET,IAAI,OAAO,GAAG,IAAIb,aAAO,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,GAAG,GAAG;YACN,IAAID,aAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1B,IAAIA,aAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC3B,IAAIA,aAAO,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;YAC1B,IAAIA,aAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;SAC9B,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAE3D,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE5B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,OAAO,GAAG,CAAC;KACd;IACD,iBAAiB,CAAC,SAAwB,EAAE,GAAY;QAEpD,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;KACrC;IACD,cAAc,CAAC,SAAwB,EAAE,GAAY;QAEjD,IAAI,GAAG,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAElC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EACxB;YACI,IAAI,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;YAClC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEX,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;gBACjB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;iBACrC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;gBACtB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;iBAE1C;gBACI,IAAI,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;;gBAE3B,IAAI,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,EAChC;oBACI,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACrC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACpC,IAAI,EAAE,GAAG,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;iBAC1C;qBACI,IAAI,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,EACnC;oBACI,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACrC,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACpC,IAAI,EAAE,GAAG,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;iBACtC;;oBAEG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;aACvB;SACJ;KACJ;IACD,gBAAgB,CAAC,KAAK,GAAG,CAAC;QAEtB,MAAM,OAAO,GAAG,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;QAC5C,IAAI,CAAC,KAAK,EACV;YACI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,CAAC;YAChD,KAAK,GAAG6B,eAAS,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;SAC1C;QAED,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;QAEhC,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC;YACjB,KAAK,EAAE,CAAC;QAEZ,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,OAAO;YACZ,GAAG,CAAC,GAAG,EAAE,CAAC;QAEd,IAAI,EAAE,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO;YACZ,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,OAAO,EAAE,CAAC;KACb;IACS,SAAS,CAAC,IAAc;QAE9B,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;;IAED,SAAS,CAAC,IAAc;QAEpB,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KAC9B;CAEJ,CAAA;AAtkBY,OAAO;IADnB,OAAO;GACK,OAAO,CAskBnB;;;ACnkBYF,YAAI,YAAjB,MAAa,IAAK,SAAQ,KAAK;IAI3B,YAAY,EAAY,EAAE,EAAY;QAElC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,EAAE,IAAI,IAAI3B,aAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,EAAE,IAAI,IAAIA,aAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KAC/C;IACD,IAAI,IAAI;QAEJ,OAAO,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KACrF;IAED,IAAI,KAAK;QAEL,OAAO,IAAIe,WAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;KAC9E;IAED,EAAE;QAEE,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;KACf;IAES,gBAAgB,CAAC,CAAU;QAEjC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAClD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;KACf;IACS,iBAAiB,CAAC,CAAU;QAElC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QACzB,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEvB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEjC,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;KACf;IACD,cAAc,CAAC,aAAyB,UAAU,CAAC,SAAS;QAExD,IAAI,GAAG,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QAChF,IAAI,UAAU,KAAK,UAAU,CAAC,KAAK,EACnC;YACI,IAAI,QAAQ,GAAG,IAAIe,yBAAY,EAAE,CAAC;YAClC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAiB,CAAC,CAAC;YACjE,OAAO,IAAIC,WAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;SAC9D;QACD,OAAO,IAAIH,UAAK,CAAC,GAAG,EAAE,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;KACzE;IAED,gBAAgB,CAAC,IAAgB,EAAE,OAAc;QAE7C,mBAAmB,CAAC,SAAS,CAAC,OAAO,CAAC,QAA0B,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;KACzG;IAED,mBAAmB,CACf,QAAwB,EACxB,SAAkB,EAClB,SAAkB,EAClB,SAAkB;QAGlB,QAAQ,QAAQ;YAEZ,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5C,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;YACvC,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,IAAI,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;oBAC5C,IAAI,UAAU,GAAG,IAAI5B,aAAO,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;;oBAGpE,IAAI,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;wBAC9B,OAAO,EAAE,CAAC;oBAEd,IAAI,OAAO,GAAG,IAAIA,aAAO,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;oBAC3D,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;oBAEpC,IAAI,KAAK,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;oBACnD,IAAI,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI0B,WAAK,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI1B,aAAO,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC/G,IAAI,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;oBACrD,OAAO,CAAC,QAAQ,CAAC,CAAC;iBACrB;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACrD,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,SAAS,EACb;oBACI,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;oBACnE,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;wBACxB,OAAO,CAAC,SAAS,CAAC,CAAC;iBAC1B;SAGR;QACD,OAAO,EAAE,CAAC;KACb;IAED,aAAa;QAET,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;KACtE;IACD,cAAc,CAAC,SAAwB,EAAE,GAAY;QAEjD,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,KAAK,IAAI,KAAK,IAAI,SAAS,EAC3B;YACI,IAAI,KAAK,KAAK,CAAC;gBACX,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;iBAC1C,IAAI,KAAK,KAAK,CAAC;gBAChB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;iBAE3C;gBACI,IAAI,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;gBACxB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;aACvB;SACJ;KACJ;IAED,gBAAgB;QAEZ,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;KAC3C;IACD,iBAAiB,CAAC,SAAwB,EAAE,GAAY;QAEpD,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,KAAK,IAAI,KAAK,IAAI,SAAS,EAC3B;YACI,IAAI,KAAK,KAAK,CAAC;gBACX,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;;gBAE3C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC9C;KACJ;IAED,YAAY,CAAC,KAAuB;QAEhC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;KAC7C;IAED,cAAc,CAAC,KAAY,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;QAEnE,IAAI,KAAK,YAAY,MAAI,EACzB;YACI,OAAO,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;SAChE;QACD,IAAI,KAAK,YAAYqB,WAAG,EACxB;YACI,OAAO,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;SAC/D;QACD,IAAI,KAAK,YAAYG,cAAM,EAC3B;YACI,OAAO,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;SAClE;QACD,IAAI,KAAK,YAAYF,gBAAQ,EAC7B;YACI,OAAO,SAAS,CAAC,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;SACxG;QAED,IAAI,KAAK,YAAY,OAAO;YACxB,OAAO,uBAAuB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;;QAGpE,OAAO,EAAE,CAAC;KACb;;IAGD,eAAe,CAAC,KAAa;QAEzB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;KAC1E;IACD,eAAe,CAAC,EAAW;QAEvB,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC5D,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC;YAC7B,OAAO,GAAG,CAAC;QACf,OAAO,KAAK,CAAC;KAChB;IACD,cAAc,CAAC,CAAS;QAEpB,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;KAC1B;IACD,kBAAkB,CAAC,QAAgB;QAE/B,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;KAC9D;IACD,cAAc,CAAC,KAAa;QAExB,OAAO,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;KAC9B;IACD,cAAc,CAAC,EAAW;QAEtB,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;KACxD;IACD,cAAc,CAAC,KAAwB;QAEnC,IAAI,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3D,IAAI,GAAG,GAAG,IAAI,KAAK,EAAS,CAAC;QAC7B,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EACnB;YACI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EACvC;gBACI,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,EAAU,CAAC;gBACnC,OAAO,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC5B,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9B,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aACrB;SACJ;QACD,OAAO,GAAG,CAAC;KACd;IAED,gBAAgB,CAAC,EAAW;QAExB,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC;KAChB;;IAGD,UAAU,CAAC,CAAU,EAAE,IAAI,GAAG,IAAI;QAE9B,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;KACzC;IAED,iBAAiB,CAAC,EAAW,EAAE,MAAe;QAE1C,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QACzB,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QACvB,IAAI,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;YACrB,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;aAClC,IAAI,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;YAC1B,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAEvC,IAAI,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;QAEhC,IAAI,MAAM,KAAK,CAAC,EAChB;YACI,IAAI,KAAK,GAAG,GAAG,CAAC;YAChB,IAAI,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;gBAClC,KAAK,GAAG,CAAC,CAAC;YACd,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;SAC1C;QAED,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAE/B,IAAI,IAAI,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEhC,IAAI,SAAkB,CAAC;QACvB,IAAI,MAAM;YACN,SAAS,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;aAEpD,IAAI,KAAK,GAAG,CAAC,EACb;YACI,SAAS,GAAG,EAAE,CAAC;YACf,KAAK,GAAG,CAAC,CAAC;SACb;aACI,IAAI,KAAK,GAAG,MAAM,EACvB;YACI,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC1B,KAAK,GAAG,MAAM,CAAC;SAClB;;YAEG,SAAS,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5D,OAAO;YACH,SAAS,EAAE,SAAS;YACpB,KAAK,EAAE,KAAK,GAAG,MAAM;SACxB,CAAC;KACL;IAED,iBAAiB,CAAC,EAAW,EAAE,MAAe;QAE1C,OAAO,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,SAAS,CAAC;KACvD;IAED,MAAM,CAAC,QAAgB;QAEnB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,IAAI,CAAC,UAAU,EAC9B;YACI,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;SACpD;aACI,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,EACjC;YACI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;SAClD;KACJ;IAED,IAAI,CAAC,EAAS,EAAE,QAAQ,GAAG,KAAK,EAAE,SAAS,GAAG,IAAI;QAE9C,IAAI,EAAE,YAAY,MAAI,EACtB;;YAEI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;gBAC/E,OAAO,MAAM,CAAC,KAAK,CAAC;YAExB,IAAI,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC;YACvB,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACzE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC;gBAC5B,OAAO,MAAM,CAAC,KAAK,CAAC;YAExB,IAAI,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC;YACrB,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACzE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC;gBAC5B,OAAO,MAAM,CAAC,KAAK,CAAC;YAExB,IAAI,MAAM,GAAG,MAAM,EACnB;gBACI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACpC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aACvB;YAED,IAAI,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,SAAS,EACrE;gBACI,IAAI,MAAM,GAAG,CAAC;oBACV,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;gBACzB,IAAI,MAAM,GAAG,CAAC;oBACV,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;gBACvB,OAAO,MAAM,CAAC,IAAI,CAAC;aACtB;SACJ;QACD,OAAO,MAAM,CAAC,KAAK,CAAC;KACvB;IAED,OAAO;QAEH,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;KACf;IAED,eAAe,CAAC,UAAkB;QAE9B,IAAI,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QACvE,IAAI,CAAC,YAAY,CAAC,IAAIrB,aAAO,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,EAAU,CAAC;QACnC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3C,OAAO,CAAC,OAAO,CAAC,CAAC;KACpB;IACD,IAAI,WAAW;QAEX,OAAO,IAAII,UAAI,EAAE,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;KACrE;IAED,IAAI,UAAU;QAEV,OAAO,CAAC,CAAC;KACZ;IACD,IAAI,QAAQ;QAER,OAAO,CAAC,CAAC;KACZ;;IAED,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE;;;;IAMlE,SAAS,CAAC,IAAc;QAE9B,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;KACzC;;IAED,SAAS,CAAC,IAAc;QAEpB,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;KACxC;;;IAID,IAAI,UAAU,CAAC,CAAU;QAErB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,UAAU;QAEV,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KAC1D;IAED,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KACxD;IACD,IAAI,QAAQ,CAAC,CAAU;QAEnB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;EAGJ;AA/ZYsB,YAAI;IADhB,OAAO;GACKA,YAAI,CA+ZhB;;AC7aD;;;;SAIgB,eAAe,CAAiB,GAAQ,EAAE,OAAgB,IAAI;IAE1E,IAAI,MAAM,GAAiB,IAAI,GAAG,EAAE,CAAC;IACrC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAE/C,IAAI,IAAI;QACJ,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YAEZ,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACxB,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC3B,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;iBAE/B;gBACI,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;aAC9B;SACJ,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAClB;;ACHA,MAAM,aAAa;IAKf,YAAmB,KAAY,EAAE,GAAU;QAAxB,UAAK,GAAL,KAAK,CAAO;QAE3B,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC;KACvC;IAED,MAAM,CAAC,OAAgB,EAAE,GAAS;QAE9B,IAAI,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,EAChC;YACI,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAC/B;gBACI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ;oBACvB,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;aAC9B;iBAED;gBACI,IAAI,OAAO,CAAC,KAAK,YAAYH,cAAM,IAAI,IAAI,CAAC,KAAK,YAAYH,WAAG,EAChE;oBACI,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EACpD;wBACI,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI;4BAC/C,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;wBAEvB,OAAO;qBACV;iBACJ;;gBAGD,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,eAAe,CAAC,cAAc,CAAC;qBAChF,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9C,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAC7C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EACpB;oBACI,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;oBACxC,KAAK,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;wBAC1D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;iBAC1B;qBAED;oBACI,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;oBACnB,KAAK,IAAI,CAAC,IAAI,GAAG,EACjB;wBACI,IAAI,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;wBAC/B,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;4BAC9E,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;qBAChD;oBACD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM;wBACnC,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;iBACjC;aACJ;SACJ;KACJ;IAED,IAAI,KAAK;QAEL,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC;aAElC;YACI,IAAI,GAAG,GAAoB,EAAE,CAAC;YAC9B,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ;gBACvB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YACzB,OAAO,GAAG,CAAC;SACd;KACJ;CACJ;MAEY,cAAc;IA0BvB,YAAmB,SAAmB,EAAS,WAAmB,EAAS,YAAY,KAAK,EAChF,gBAAgB,CAAC,WAAW,IAAI,CAAC,IAAI,GAAG;;QADjC,cAAS,GAAT,SAAS,CAAU;QAAS,gBAAW,GAAX,WAAW,CAAQ;QAAS,cAAS,GAAT,SAAS,CAAQ;QAChF,kBAAa,GAAb,aAAa,CAA2B;KAGnD;IAED,EAAE;QAEE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACnD,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC,mBAAmB,GAAG,EAAE,CAAC;QAC9B,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAE3B,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;QAE1B,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAC5B,OAAO,IAAI,CAAC,UAAU,CAAC;QAE3B,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAChC,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,EACxC;YACI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAE1G,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAC3B,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAC1D,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAIM,YAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CACrG,CAAC;SACL;;YAEG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC/B,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC;KAC1B;IAED,aAAa;QAET,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;QACpC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;QACpC,OAAO,IAAI,CAAC;KACf;IAES,wBAAwB;QAE9B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAExC,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,IAAIH,cAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KACjE;IAES,eAAe;QAErB,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;QAC7B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,EAC3D;YACI,IAAI,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,EAC1B;gBACI,IAAI,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1D,IAAI,KAAK;oBACL,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;;oBAE/C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,IAAIG,YAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;aAC9H;SACJ;KACJ;;IAGS,aAAa;QAEnB,IAAI,KAAK,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,KAAK,EAAE,CAAC;QAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAC9B;YACI,IAAI,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;YAC7C,IAAI,KAAK,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;YACrD,IAAI,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClD,IAAI,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC;YACjC,IAAI,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC;YACnC,IAAI,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC;YAEzF,IAAI,UAAU,EACd;gBACI,IAAI,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC;gBAC3B,IAAI,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC;;gBAE9B,IAAI,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;oBACrB,SAAS;gBAEb,IAAI,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;gBACzE,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE/E,IAAI,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;gBAE9C,IAAI,EAAW,CAAC;gBAChB,IAAI,IAAI,KAAK,CAAC,EACd;oBACI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;wBACf,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;yBAEjB;wBACI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAC5D;4BACI,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;4BAC7C,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;4BAC7C,IAAI,IAAI,CAAC,SAAS,IAAI,MAAM,GAAG,IAAI,CAAC,aAAa,EACjD;gCACI,WAAW,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;gCAC1D,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;6BACpE;;gCAEG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;yBACpB;;;qBAGJ;iBACJ;qBAED;oBACI,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;oBAC7C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;wBACf,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;;qBAEjC;wBACI,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;wBAEvC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,EAC7F;;4BAEI,IAAI,IAAa,CAAC;4BAClB,IAAI,WAAW,CAAC,EAAE,EAClB;gCACI,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC;gCAC3B,QAAQ,CAAC,UAAU,GAAG,WAAW,CAAC,EAAE,CAAC;6BACxC;4BACD,IAAI,KAAc,CAAC;4BACnB,IAAI,YAAY,CAAC,EAAE,EACnB;gCACI,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC;gCAC3B,SAAS,CAAC,QAAQ,GAAG,YAAY,CAAC,EAAE,CAAC;6BACxC;4BAED,IAAI,CAAU,CAAC;4BAEf,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EACnC;gCACI,IAAI,CAAC,GAAG,QAAe,CAAC;gCACxB,IAAI,MAAM,GAAG,IAAIN,WAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;gCAEvE,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gCACjB,IAAI,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;gCACpC,IAAI,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gCAExF,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gCACjB,IAAI,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;gCACpC,IAAI,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gCAExF,IAAI,MAAM,GAAG,MAAM;oCACf,CAAC,GAAG,EAAE,CAAC;;oCAEP,CAAC,GAAG,EAAE,CAAC;6BACd;;gCAEG,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;4BAEhC,IAAI,KAAc,CAAC;4BACnB,IAAI,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;4BACzC,IAAI,QAAQ,YAAYM,YAAI;gCACxB,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC;;gCAElB,KAAK,GAAG,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;4BAEnC,IAAI,MAAM,GAAY,KAAK,CAAC;4BAC5B,IAAI,KAAK,EACT;gCACI,IAAI,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;gCAC3C,IAAI,SAAS,YAAYA,YAAI;oCACzB,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;;oCAEpB,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;6BACzC;4BAED,IAAI,WAAW,CAAC,EAAE;gCACd,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC;4BAC/B,IAAI,YAAY,CAAC,EAAE;gCACf,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC;4BAE/B,IAAI,KAAK,IAAI,MAAM;gCACf,EAAE,GAAG,CAAC,CAAC;;gCAEP,WAAW,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;yBACxC;;4BAEG,WAAW,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;wBAErC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;qBACpE;iBACJ;gBACD,IAAI,EAAE,EACN;oBACI,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;oBACpB,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;oBAErB,WAAW,CAAC,OAAO,GAAG,SAAS,CAAC;oBAChC,YAAY,CAAC,MAAM,GAAG,QAAQ,CAAC;iBAClC;aACJ;iBAED;gBACI,IAAI,OAAO,GAAa,EAAE,CAAC;gBAC3B,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,EACjG;oBACI,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACzB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAChB,IAAI,CAAC,KAAK,YAAY,CAAC,KAAK;wBACxB,MAAM;iBACb;gBACD,WAAW,CAAC,YAAY,GAAG,OAAO,CAAC;aACtC;SAEJ;KAEJ;IAEO,aAAa,CAAC,WAA0B,EAAE,YAA2B,EAAE,IAAa;QAExF,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAClE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACb,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,eAAe,CAAC;KACnD;IAES,mBAAmB;QAEzB,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,kBAAkB,EACrC;YACI,IAAI,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC;YAClB,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAChB;gBACI,IAAI,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvC,IAAI,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAEvC,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,MAAM;oBACvE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;aACnC;YACD,IAAI,CAAC,CAAC,EAAE;gBAAE,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,CAAC,EAAE;gBAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;;;YAI9B,IAAI,GAAG,YAAYN,WAAG;mBACf,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;;cAGjD;gBACI,IAAI,GAAG,CAAC,WAAW;oBACf,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;;oBAErC,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;aAC5C;SACJ;QACD,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,kBAAkB,EACrC;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACnC,IAAI,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC;YAElB,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpF,IAAI,EAAE,GAAG,IAAIM,YAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1B,IAAI,EAAE,GAAG,IAAIA,YAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAE1B,IAAI,IAAI,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;YACtE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EACnB;gBACI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC;gBAChB,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC;gBAChB,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;gBACxB,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBAChD,IAAI,OAAO,EACX;oBACI,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzC,SAAS;iBACZ;qBAED;oBACI,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;iBACtD;aACJ;;YAGD,IAAI,QAAQ,GAAG,IAAI,CAAC;YACpB,IAAI,QAAQ,GAAG,IAAI,CAAC;YACpB,IAAI,GAAG,YAAYN,WAAG,EACtB;gBACI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,eAAe,EAC/C;oBACI,IAAI,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;oBAClE,IAAI,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;oBAElE,IAAI,EAAW,CAAC;oBAChB,IAAI,EAAW,CAAC;oBAChB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;wBAClB,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;wBAClB,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAEhC,IAAI,EAAE,IAAI,EAAE;wBAAE,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;oBAChC,IAAI,EAAE,EACN;wBACI,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC;wBACjB,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;wBACpB,QAAQ,GAAG,KAAK,CAAC;qBACpB;oBACD,IAAI,EAAE,EACN;wBACI,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC;wBACjB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;wBAClB,QAAQ,GAAG,KAAK,CAAC;qBACpB;iBACJ;aACJ;YAED,IAAI,QAAa,CAAC;YAClB,IAAI,QAAa,CAAC;;YAElB,IAAI,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,YAAYA,WAAG,EACnD;gBACI,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;gBACjB,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI,EAClE;oBACI,IAAI,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;oBAC/D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EACrB;wBACI,IAAI,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;wBAC/B,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC;wBACjB,QAAQ,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;wBACrB,QAAQ,CAAC,UAAU,GAAG,EAAE,CAAC;qBAC5B;iBACJ;aACJ;YACD,IAAI,QAAQ,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,YAAYA,WAAG,EACrD;gBACI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;gBAClB,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC,QAAQ,GAAG,IAAI,EAClE;oBACI,IAAI,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;oBAC/D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EACrB;wBACI,IAAI,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;wBAC/B,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC;wBACjB,QAAQ,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;wBACrB,QAAQ,CAAC,QAAQ,GAAG,EAAE,CAAC;qBAC1B;iBACJ;aACJ;YAED,IAAI,EAAE,GAAG,IAAIC,gBAAQ,EAAE,CAAC;YACxB,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACpB,IAAI,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAClB,IAAI,QAAQ;gBAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAEjC,KAAK,IAAI,CAAC,IAAI,GAAG;gBACb,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEf,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC/C,IAAI,OAAO;gBACP,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;;gBAEzC,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;SAC1D;QAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAClB;YACI,IAAI,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAChD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,IAAI,cAAc,GAAG,SAAS,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACzD,IAAI,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAI,cAAc,KAAK,UAAU;gBAC7B,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9C,IAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC;gBACtC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YAEnF,IAAI,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACzC,IAAI,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YAC/C,IAAI,SAAS,KAAK,KAAK,CAAC,KAAK;gBACzB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;SACrE;QAED,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAC3B,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EACrE,GAAG,IAAI,CAAC,gBAAgB,CAC3B,CAAC;KACL;;IAGS,cAAc;QAEpB,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,kBAAkB,EACrC;YACI,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YAChB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;YAChD,IAAI,CAAC,CAAC,YAAY;gBACd,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACnF;QACD,IAAI,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAErE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,CAAC,EAAE,EAC1D;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YACtC,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,eAAe,EAC1C;gBACI,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;aAC3C;SACJ;KACJ;;IAGO,kBAAkB;QAEtB,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAC;QAChC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,eAAe,EAClC;YACI,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC;YACjB,KAAK,IAAI,EAAE,IAAI,EAAE,EACjB;gBACI,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;gBACtC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;oBAC/C,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aAC3C;SACJ;KACJ;;IAGO,aAAa;QAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,CAAC,EAAE,EAC1D;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,CAAC,IAAI;gBAAE,SAAS;YACrB,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,CAAC,EAAE,EAC9D;gBACI,IAAI,EAAE,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;gBACvC,IAAI,EAAE,CAAC,IAAI;oBAAE,SAAS;gBACtB,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;gBACpC,IAAI,MAAM,KAAK,MAAM,CAAC,cAAc,EACpC;oBACI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;oBACd,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;oBACf,IAAI,MAAM,GAAG,IAAIE,cAAM,CAAO,CAAC,CAAC,KAAM,CAAC,MAAM,EAAQ,CAAC,CAAC,KAAM,CAAC,MAAM,CAAC,CAAC;oBACtE,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC;oBACjB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;iBACpF;qBACI,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI,EAC/B;oBACI,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;wBAC/B,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;yBAEnB;wBACI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;wBACd,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;wBACnB,MAAM;qBACT;iBACJ;aACJ;SACJ;KACJ;;IAGO,kBAAkB;QAEtB,IAAI,IAAI,GAAG,IAAI,GAAG,EAAS,CAAC;QAC5B,IAAI,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,qBAAqB,EACxC;YACI,IAAI,CAAC,CAAC,CAAC,IAAI;gBACP,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;SACpC;QAED,IAAI,IAAa,CAAC;QAElB,IAAI,UAAU,GAAG,CAAC,CAAU,EAAE,EAAY;YAEtC,IAAI,OAAO,GAAG,QAAQ,CAAC;YACvB,IAAI,IAAW,CAAC;YAChB,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EACtB;gBACI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAEhC,IAAI,IAAI,EACR;oBACI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;oBACpC,IAAI,CAAC,GAAG,OAAO,EACf;wBACI,IAAI,GAAG,CAAC,CAAC;wBACT,OAAO,GAAG,CAAC,CAAC;qBACf;iBACJ;qBAED;oBACI,IAAI,GAAG,CAAC,CAAC;oBACT,MAAM;iBACT;aACJ;YAED,IAAI,IAAI,EACR;gBACI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrB,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;gBACd,IAAI,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;gBAC9C,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI;oBACtB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACzB,OAAO,IAAI,CAAC,EAAE,CAAC;aAClB;SACJ,CAAC;QAEF,KAAK,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,EAC1B;YACI,IAAI,GAAG,SAAS,CAAC;YACjB,IAAI,EAAE,GAAG,IAAIF,gBAAQ,EAAE,CAAC;YACxB,IAAI,EAAE,GAAG,CAAC,CAAC;YACX,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO;gBACpB,EAAE,GAAG,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5B,EAAE,GAAG,CAAC,CAAC;YACP,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO;gBACpB,EAAE,GAAG,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAE5B,IAAI,EAAE,CAAC,gBAAgB,GAAG,CAAC,EAC3B;gBACI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;gBACpB,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBACtB,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC;oBAC7B,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACxB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;aACxD;SACJ;KACJ;IAED,aAAa,CAAC,EAAW;QAErB,OAAO,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,eAAe,CAAC;KAC/D;IAED,kBAAkB,CAAC,EAAW;QAE1B,IAAI,QAAQ,GAAG,QAAQ,CAAC;QACxB,IAAI,OAAO,GAAG,QAAQ,CAAC;QACvB,IAAI,KAAc,CAAC;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAC/C;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,iBAAiB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACxC,IAAI,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;gBAAE,OAAO,CAAC,CAAC;YAEpC,IAAI,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,IAAI,GAAG,OAAO,EAClB;gBACI,OAAO,GAAG,IAAI,CAAC;gBACf,QAAQ,GAAG,CAAC,CAAC;gBACb,KAAK,GAAG,EAAE,CAAC;aACd;SACJ;QAED,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,KAAK,GAAG,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAErC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EACjE;YACI,IAAI,QAAQ,GAAG,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACvD,IAAI,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAEzC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,EACjF;gBACI,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;gBACrB,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;gBAClB,IAAI,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC;gBACzB,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;gBAEvC,IAAI,KAAc,CAAC;gBACnB,IAAI,IAAa,CAAC;gBAClB,IAAI,CAAC,YAAYD,WAAG;oBAChB,KAAK,GAAG,CAAC,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;;oBAExC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC;gBAEvB,IAAI,QAAQ,YAAYA,WAAG;oBACvB,IAAI,GAAG,QAAQ,CAAC,kBAAkB,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;;oBAEnD,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC;gBAE/B,IAAI,GAAG,GAAG,IAAIA,WAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAEjE,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBACtC,OAAO,GAAG,CAAC;aACd;SACJ;aACI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAC/F;YACI,IAAI,SAAS,GAAG,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACxD,IAAI,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAE3C,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,EAClF;gBACI,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;gBAEnB,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;gBAClB,IAAI,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC;gBAC1B,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;gBAEvC,IAAI,KAAc,CAAC;gBACnB,IAAI,IAAa,CAAC;gBAClB,IAAI,CAAC,YAAYA,WAAG;oBAChB,IAAI,GAAG,CAAC,CAAC,kBAAkB,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;;oBAE5C,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC;gBAExB,IAAI,SAAS,YAAYA,WAAG;oBACxB,KAAK,GAAG,SAAS,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;;oBAEhD,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC;gBAE/B,IAAI,GAAG,GAAG,IAAIA,WAAG,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAEjE,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBACtC,OAAO,GAAG,CAAC;aACd;SACJ;QAED,IAAI,GAAG,GAAG,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KAC9B;IAES,SAAS,CAAC,MAAe,EAAE,MAAe,EAAE,IAAc;QAEhE,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3C,IAAI,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;QACrD,IAAI,GAAG,GAAG,IAAIA,WAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QACpF,OAAO,GAAG,CAAC;KACd;CACJ;AAED,SAAS,YAAY,CAAC,CAAQ;IAE1B,IAAI,CAAC,YAAYM,YAAI;QAAE,OAAO,CAAC,CAAC;;QAC3B,OAAO,CAAC,CAAC;AAClB,CAAC;AACD,SAAS,aAAa,CAAC,EAAS,EAAE,EAAS;IAEvC,OAAO,YAAY,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;AAC/C;;ACluBA;;;;;;SAMgB,iBAAiB,CAAC,EAAY,EAAE,EAAW;IAEvD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,IAAI,OAAO,GAAG,IAAIA,YAAI,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI3B,aAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAElE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,EACpC;QACI,IAAI,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;SACtC;YACI,IAAI,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;YAEnC,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC3B,SAAS;;YAEb,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACvB,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC;gBACrB,SAAS;;YAGb,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAC5B;gBACI,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;oBAAE,SAAS,EAAE,CAAC;gBACzC,SAAS;aACZ;;YAED,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAC5B;gBACI,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;oBAAE,SAAS,EAAE,CAAC;gBACzC,SAAS;aACZ;;YAGD,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACzD,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,EAC1B;gBACI,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBACvB,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;gBAEpB,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;oBAC/B,SAAS,EAAE,CAAC;aACnB;SACJ;;SAED;YACI,IAAI,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,CAAQ,CAAC;YACvC,IAAI,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;YACxB,IAAI,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC;;YAGtB,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EACrD;;gBAEI,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EACrC;oBACI,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI;wBACnB,SAAS,EAAE,CAAC;iBACnB;qBACI,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAC1C;oBACI,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI;wBAClB,SAAS,EAAE,CAAC;iBACnB;gBACD,SAAS;aACZ;YACD,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EACrC;gBACI,IAAI,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI;oBACb,SAAS,EAAE,CAAC;aACnB;YACD,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EACrC;gBACI,IAAI,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI;oBACZ,SAAS,EAAE,CAAC;aACnB;YAED,KAAK,IAAI,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,EACrE;gBACI,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC;oBAChE,SAAS;gBAEb,IAAI,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjB,SAAS,EAAE,CAAC;aACnB;SACJ;KACJ;IAED,OAAO,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC;AACjC;;AC1JA,IAAY,aAIX;AAJD,WAAY,aAAa;IAErB,iDAAQ,CAAA;IACR,uDAAW,CAAA;AACf,CAAC,EAJW,aAAa,KAAb,aAAa;;;AC8BZsB,gBAAQ,gBAArB,MAAa,QAAS,SAAQ,KAAK;IAG/B,YAAoB,YAA6B,EAAE;QAE/C,KAAK,EAAE,CAAC;QAFQ,cAAS,GAAT,SAAS,CAAsB;QAD3C,gBAAW,GAAY,KAAK,CAAC;KAIpC;IAED,cAAc,CAAC,CAAU;QAErB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,IAAItB,aAAO,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAClB;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,EAAE,GAAG,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC1C,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAC5B;gBACI,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACzB,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gBACpB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;aACxB;YACD,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;YACb,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,IAAI,GAAG,KAAK,MAAM;gBACd,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS;oBACxB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;SACvB;KACJ;;;;IAKD,IAAI;QAEA,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,IAAIA,aAAO,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,IAAIA,aAAO,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,IAAIA,aAAO,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAE/C,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAC5B;YACI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACb,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;SACf;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;KACf;;IAGD,OAAO;QAEH,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3B,OAAO,IAAI,CAAC;QAChB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,EAC/B;YACI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACxB;QAED,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEnB,GAAG,CAAC,OAAO,EAAE,CAAC;QAEd,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EACxD;YACI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;SAC5B;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1B,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACd,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;SACnB;QAED,OAAO,IAAI,CAAC;KACf;IACD,IAAI,QAAQ,CAAC,IAAqB;QAE9B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,SAAS,CAAC;KACzB;IAED,IAAI,gBAAgB;QAEhB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;KAChC;;;;;;;;;;;IAYD,WAAW,CAAC,KAAa,EAAE,EAAuB;QAE9C,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,GAAoB,CAAC;QACzB,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EACrB;YACI,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;gBAEV,OAAO;oBACH,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE;oBACb,GAAG,EAAE,CAAC;iBACT,CAAC;aACL,CAAC,CAAC;SACN;;YAEG,GAAG,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAEvC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;KACf;IACD,cAAc,CAAC,KAAa;QAExB,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EACjC;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,MAAM,EAAE,CAAC;SACjB;QACD,OAAO,IAAI,CAAC;KACf;IACD,cAAc,CAAC,IAAY,EAAE,EAAU;QAEnC,IAAI,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,GAAG,IAAI,EACjD;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;SACjB;QACD,OAAO,IAAI,CAAC;KACf;;;;;IAMD,eAAe,CAAC,KAAa;QAEzB,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QAE1D,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;QAEzB,qBAAqB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAChB,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE;YAChC,GAAG,EAAE,CAAC;SACT,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;KACf;IACD,YAAY,CAAC,KAAa;QAEtB,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,KAAK;YAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;KAC/C;;;;;;;;IAQD,UAAU,CAAC,KAAa,EAAE,EAAW;QAEjC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,EACL;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACd,IAAI,CAAC,MAAM,EAAE,CAAC;SACjB;QACD,OAAO,IAAI,CAAC;KACf;IACS,gBAAgB,CAAC,CAAU;QAEjC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACvC;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;SACpC;QACD,OAAO,IAAI,CAAC;KACf;IACS,iBAAiB,CAAC,CAAU;QAElC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACrC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EACtC;YACI,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;SAC9B;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;KACf;IACD,UAAU,CAAC,KAAa,EAAE,GAAW;QAEjC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,EACL;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;YACZ,IAAI,CAAC,MAAM,EAAE,CAAC;SACjB;QACD,OAAO,IAAI,CAAC;KACf;IACD,WAAW,CAAC,KAAa;QAErB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;KACpC;IACD,SAAS,CAAC,MAAc,EAAE,MAAc;QAEpC,IAAI,CAAC,QAAQ,GAAG;YACZ,EAAE,EAAE,EAAE,IAAIE,aAAO,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE;YAC7B,EAAE,EAAE,EAAE,IAAIA,aAAO,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;YACnC,EAAE,EAAE,EAAE,IAAIA,aAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;YAC3C,EAAE,EAAE,EAAE,IAAIA,aAAO,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;SAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC;KACf;IACD,gBAAgB,CAAC,EAAW,EAAE,EAAW;QAErC,IAAI,GAAG,GAAG,IAAIG,UAAI,EAAE,CAAC;QACrB,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAU,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAErF,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,GAAG,IAAIH,aAAO,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,GAAG,GAAG,IAAIA,aAAO,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAEpC,IAAI,CAAC,QAAQ,GAAG;YACZ,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;YACnB,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;YACnB,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;YACnB,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;SAAC,CAAC;QAEzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,IAAI,CAAC;KACf;;IAED,IAAI,UAAU;QAEV,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YACzB,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO,IAAIF,aAAO,EAAE,CAAC;KACxB;IACD,IAAI,UAAU,CAAC,CAAU;QAErB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAExC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3B,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;aACjC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;aAErC;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,GAAG,KAAK,CAAC,EACb;gBACI,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAQ,CAAC;gBACzC,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC;;gBAEnB,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;aACnE;YACD,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;SACpC;KACJ;IACD,IAAI,QAAQ;QAER,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QAC7C,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YACzB,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9E,OAAO,IAAIA,aAAO,EAAE,CAAC;KACxB;IACD,IAAI,QAAQ,CAAC,CAAU;QAEnB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS;YAC3C,OAAO;QAEX,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAExC,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC9C,IAAI,GAAG,KAAK,CAAC,EACb;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAQ,CAAC;YACzD,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7B,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC;;YAEjB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;SACnF;QACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;KAChD;IAED,IAAI,UAAU;QAEV,OAAO,IAAI,CAAC,QAAQ,CAAC;KACxB;IAED,IAAI,UAAU;QAEV,OAAO,CAAC,CAAC;KACZ;;;;IAKD,IAAI,QAAQ;QAER,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;;QAG1C,IAAI,IAAI,CAAC,WAAW;YAChB,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YAE5D,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;KACpC;IACD,IAAI,KAAK;QAEL,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC;YACjB,OAAO,CAAC,CAAC;QAEb,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACjC,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EACvC;YACI,IAAI,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtB,IAAI,GAAG,GAAG,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAE5C,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,GAAG,KAAK,CAAC,EACb;gBACI,IAAI,GAAG,GAAG,IAAIqB,WAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;gBACpD,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;;gBAE1B,IAAI,OAAO,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;;gBAE5E,GAAG,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;aACvC;YACD,IAAI,IAAI,GAAG,CAAC;SACf;QACD,OAAO,IAAI,GAAG,CAAC,CAAC;KACnB;IACD,IAAI,IAAI;QAEJ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KAC/B;;IAED,IAAI,SAAS;QAET,OAAO,IAAI,CAAC,WAAW,CAAC;KAC3B;;IAED,IAAI,OAAO;QAEP,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,QAAQ,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;KACnG;IACD,IAAI,SAAS,CAAC,CAAU;QAEpB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IAED,kBAAkB;QAEd,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EACjD;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YAEzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;gBAC5D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;SAC5E;KACJ;IAED,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;KAC7D;;;;;;;;;;IAWD,eAAe,CAAC,KAAa;QAEzB,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YACvD,OAAO,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvG,IAAI,EAAE,GAAU,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,EAAE;YACF,OAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;QAChE,OAAO,SAAS,CAAC;KACpB;IAED,cAAc,CAAC,KAAa;QAExB,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAC7C,OAAO,GAAG,CAAC;;QAGf,IAAI,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;;QAEnC,IAAI,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC;QAErE,IAAI,IAAI,GAAG,CAAC,CAAC;;QAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAC/B;YACI,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;SAC1C;;QAGD,IAAI,UAAU,KAAK,MAAM,EACzB;YACI,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;SACtE;aACI,IAAI,KAAK,GAAG,UAAU,EAC3B;YACI,IAAI,SAAS,GAAG,KAAK,GAAG,UAAU,CAAC;YACnC,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;SACjE;QAED,OAAO,IAAI,CAAC;KACf;IACD,kBAAkB,CAAC,IAAY;QAE3B,IAAI,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;KACtC;;;;;;;;IASD,eAAe,CAAC,EAAW;QAEvB,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;YACI,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,IAAI,KAAK,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;YACnC,IAAI,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;gBACtB,OAAO,CAAC,GAAG,KAAK,CAAC;SACxB;;QAGD,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,GAAG,CAAC;;QAGjC,IAAI,QAAQ,GAAa,EAAE,CAAC;;QAE5B,IAAI,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;;QAE9B,IAAI,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;YAChC,QAAQ,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAEhD,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,EACxB;YACI,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;SACtB;aACI,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,EAC7B;;YAEI,IAAI,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;kBACnC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACrC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;;gBAEnB,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;SAC1B;QACD,OAAO,GAAG,CAAC;KACd;IACD,cAAc,CAAC,IAAY;QAEvB,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;YACI,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,IAAI,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;YACpB,IAAI,IAAI,IAAI,GAAG;gBACX,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;iBAClC,IAAI,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,CAAC;YACjB,IAAI,IAAI,GAAG,CAAC;SACf;QACD,IAAI,CAAC,IAAI,CAAC,WAAW;YACjB,OAAO,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAEjE,OAAO,GAAG,CAAC;KACd;IACD,cAAc,CAAC,EAAW;QAEtB,IAAI,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;QAC1C,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;KACrC;;;;;;;;;;IAWD,YAAY,CAAC,KAAuB;QAEhC,IAAI,KAAK,YAAYrB,aAAO;YACxB,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAExC,IAAI,KAAK,CAAC,KAAK,CAAC;YACZ,OAAO,SAAS,CAAC;QAErB,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAErC,IAAI,CAAC,EAAE;YAAE,OAAO,SAAS,CAAC;QAE1B,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;KAC5D;IACD,cAAc,CAAC,KAAwB;;QAGnC,IAAI,MAAgB,CAAC;QACrB,IAAI,OAAO,KAAK,IAAI,QAAQ;YACxB,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;;YAEjB,MAAM,GAAG,KAAK,CAAC;;QAGnB,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC7B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;aACzD,GAAG,CAAC,CAAC;YAEF,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,CAAC;YACpB,IAAI,CAAC,GAAG,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YAClC,IAAI,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC;gBACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAC/B,OAAO,CAAC,CAAC;SACZ,CAAC,CAAC;;QAEP,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC;;QAEtD,IAAI,CAAC,WAAW;YACZ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,0BAA0B,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;QACrE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YACnB,OAAO,EAAE,CAAC;;QAGd,IAAI,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,YAAY;YACZ,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnB,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;;QAGjC,IAAI,GAAG,GAAe,EAAE,CAAC;QAEzB,IAAI,GAAG,GAAG,CAAC,CAAC;;QAGZ,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,EAAE,IAAI,MAAM,EACrB;;YAEI,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YACvE,EAAE,IAAI,GAAG,CAAC;YACV,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC7B,GAAG,IAAI,OAAO,CAAC;YAEf,IAAI,MAAM,GAAoB,EAAE,CAAC;;YAGjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAChC;gBACI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EACxC;oBACI,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACxD;gBACD,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC1C,GAAG,CAAC,KAAK,EAAE,CAAC;gBACZ,IAAI,CAAC,KAAK,EAAE,CAAC;aAChB;YAED,IAAI,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC;aAC7B;gBACI,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACrD;;aAED;gBACI,IAAI,GAAG,GAAW,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC;oBACrB,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,IAAI,CAAC,KAAK,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;gBAGtF,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;;gBAEzC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;;gBAG5B,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aACnB;YAED,KAAK,GAAG,EAAE,GAAG,OAAO,CAAC;YACrB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBACjB,GAAG,CAAC,IAAI,CAAC,IAAI,UAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;SAC5D;;QAGD,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,IAAI,CAAC,WAAW,EACrD;YACI,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACjC,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/D,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;YAE3B,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAE3C,GAAG,CAAC,KAAK,EAAE,CAAC;SACf;QACD,OAAO,GAAG,CAAC;KACd;;IAGD,oBAAoB,CAAC,UAAkB,EAAE,QAAgB;QAErD,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC;YAAE,UAAU,GAAG,MAAM,CAAC;;YACrD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC;YAAE,QAAQ,GAAG,MAAM,CAAC;;YACjD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAEjC,MAAM,QAAQ,GAAG,CAAC,KAAa;YAE3B,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC;gBACvB,OAAO,IAAIqB,WAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;;gBAEpD,OAAO,IAAIM,YAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5D,CAAC;QAEF,IAAI,KAAK,GAAoB,EAAE,CAAC;QAChC,IAAI,UAAU,KAAK,MAAM,EACzB;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;SAChD;aAED;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC/B,IAAI,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;YACnC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;gBACf,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;YACpD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;SAC9C;QAED,KAAK,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EACxC;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;SAChD;QAED,IAAI,MAAM,KAAK,QAAQ,EACvB;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC9B,IAAI,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;YACjC,IAAI,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,EACnB;gBACI,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;gBAC3D,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;aACnD;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;SACzC;QAED,IAAI,EAAE,GAAG,IAAI,UAAQ,CAAC,KAAK,CAAC,CAAC;QAC7B,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;QACzB,OAAO;KACV;IAED,MAAM,CAAC,QAAgB;QAEnB,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC;YAAE,OAAO;QAE1D,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,OAAe,CAAC;QACpB,IAAI,QAAgB,CAAC;QAErB,IAAI,QAAQ,GAAG,CAAC,EAChB;YACI,OAAO,GAAG,CAAC,CAAC;YACZ,QAAQ,GAAG,CAAC,CAAC;SAChB;aACI,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,EACjC;YACI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;YACxB,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC;SAC1B;;QAGD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;;QAGjG,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC;QAC1C,IAAI,MAAM,IAAI,CAAC;YACX,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC;QAE1F,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;;IAGD,cAAc,CAAC,QAAiB;QAE5B,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC;YAC9C,OAAO,IAAI,CAAC,OAAO,CAAC;QAExB,IAAI,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEpD,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACrB,IAAI,EAAE,GAAG,IAAI3B,aAAO,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACxD,IAAI,QAAQ,GAAG,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;QAExC,IAAI,GAAG,GAAc,EAAE,CAAC;QACxB,IAAI,IAAI,GAAa,EAAE,CAAC;QACxB,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAC5B;YACI,IAAI,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;SACxC;QACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;KACxB;IAED,IAAI,CAAC,EAAS,EAAE,QAAQ,GAAG,KAAK,EAAE,SAAS,GAAG,IAAI;QAE9C,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,WAAW;YAChB,OAAO,MAAM,CAAC,KAAK,CAAC;QAExB,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;QAExF,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAEtF,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAC/B;YACI,IAAI,EAAE,YAAY2B,YAAI,EACtB;gBACI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC3C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;aAC9C;iBACI,IAAI,EAAE,YAAYN,WAAG,EAC1B;gBACI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;gBAChD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;aAC9C;iBACI,IAAI,EAAE,YAAY,UAAQ,EAC/B;gBACI,IAAI,CAAC,GAAG,IAAI,QAAQ,EAAE,CAAC;gBACvB,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAChB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;aACpB;;gBAEG,OAAO,MAAM,CAAC,KAAK,CAAC;SAC3B;aAED;YACI,IAAK,QAOJ;YAPD,WAAK,QAAQ;gBAET,uCAAQ,CAAA;gBACR,uCAAQ,CAAA;gBACR,uCAAQ,CAAA;gBACR,uCAAQ,CAAA;gBACR,uCAAQ,CAAA;aACX,EAPI,QAAQ,KAAR,QAAQ,QAOZ;YAED,IAAI,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;YAEnC,IAAI,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;YAE7B,IAAI,SAAS,GAAG,MAAM,EACtB;gBACI,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;gBACzB,MAAM,GAAG,SAAS,CAAC;aACtB;YAED,IAAI,SAAS,GAAG,MAAM,EACtB;gBACI,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;gBACzB,MAAM,GAAG,SAAS,CAAC;aACtB;YAED,IAAI,SAAS,GAAG,MAAM,EACtB;gBACI,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;gBACzB,MAAM,GAAG,SAAS,CAAC;aACtB;YAED,IAAI,SAAS,GAAG,MAAM;gBAClB,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;YAE7B,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI;gBAC1B,OAAO,MAAM,CAAC,KAAK,CAAC;YAExB,IAAI,EAAE,YAAYM,YAAI,EACtB;gBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EAC9B;oBACI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBACjD;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBAC9C;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBACjD;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBAC9C;aACJ;iBACI,IAAI,EAAE,YAAYN,WAAG,EAC1B;gBACI,IAAI,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC5D,IAAI,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC;gBACvB,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EAC9B;oBACI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;iBACpD;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;oBACpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBAC9C;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;iBACnD;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;oBACrC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBAC9C;aACJ;iBACI,IAAI,EAAE,YAAY,UAAQ,EAC/B;gBACI,IAAI,EAAE,CAAC,SAAS;oBAAE,OAAO,MAAM,CAAC,KAAK,CAAC;gBAEtC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;gBAEjC,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EAC9B;oBACI,EAAE,CAAC,OAAO,EAAE,CAAC;oBACb,IAAI,QAAQ,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC3C,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;oBACnB,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;oBACpB,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC/B,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;iBACrC;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,IAAI,CAAC,GAAG,EAAE,CAAC;oBAEX,IAAI,QAAQ,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC3C,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;oBAC/B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;iBACrC;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,IAAI,QAAQ,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC3C,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;oBACnB,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;oBACpB,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC/B,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;iBACrC;qBACI,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,EACnC;oBACI,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,IAAI,CAAC,GAAG,EAAE,CAAC;oBAEX,EAAE,CAAC,OAAO,EAAE,CAAC;oBACb,IAAI,QAAQ,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC3C,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;oBAC/B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;iBACrC;gBAED,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;oBACI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;iBACrD;aACJ;;gBAEG,OAAO,MAAM,CAAC,KAAK,CAAC;SAC3B;;QAGD,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,MAAM,CAAC,IAAI,CAAC;KACtB;;;;;;IAOD,OAAO,OAAO,CAAC,MAAe,EAAE,SAAS,GAAG,IAAI;QAE5C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE3C,IAAI,EAAE,GAAG,IAAI,UAAQ,CAAC;QACtB,EAAE,CAAC,GAAG,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEzC,KAAK,IAAI,EAAE,IAAI,MAAM;YACjB,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAElC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;QACpB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAChB;YACI,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzB,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,CAAC;gBAC/B,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACxB;QAED,OAAO,EAAE,CAAC;KACb;IAED,SAAS,CAAC,EAAW;QAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACtC;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC;SACnB;QACD,OAAO,KAAK,CAAC;KAChB;;IAGD,UAAU,CAAC,CAAU,EAAE,IAAI,GAAG,IAAI;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACtC;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC;gBACrB,OAAO,IAAI,CAAC;SACnB;QACD,OAAO,KAAK,CAAC;KAChB;IAED,SAAS,CAAC,EAAW;QAEjB,OAAO,IAAI,CAAC,OAAO,IAAI,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;KACtD;IACD,iBAAiB,CAAC,EAAW,EAAE,MAAe;QAE1C,OAAO,IAAI,CAAC,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;KAClF;IACD,kBAAkB,CAAC,EAAW,EAAE,OAAmB;;QAG/C,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;;QAExC,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC;;QAGhD,IAAI,GAAG,GAAG,SAAS,CAAC;;QAEpB,IAAI,OAAO,GAAG,QAAQ,CAAC;QAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACtC;YACI,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;;YAGjC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,KAAK,IAAI,CAAC,EAC/C;gBACI,IAAI,QAAQ,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gBAC9C,IAAI,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,EACrC;oBACI,GAAG,GAAG,QAAQ,CAAC;oBACf,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;iBACvC;gBACD,IAAI,OAAO,KAAK,UAAU,CAAC,KAAK;oBAC5B,SAAS;aAChB;YAED,IAAI,UAAmB,CAAC;;YAGxB,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,IAAI,CAAC,EAChE;gBACI,IAAI,OAAO,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gBAC7C,IAAI,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC;oBAChC,UAAU,GAAG,OAAO,CAAC;;oBAErB,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC;aAChC;iBAED;gBACI,UAAU,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;aAChD;YAED,IAAI,OAAO,GAAG,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YAC/C,IAAI,OAAO,GAAG,OAAO,EACrB;gBACI,GAAG,GAAG,UAAU,CAAC;gBACjB,OAAO,GAAG,OAAO,CAAC;aACrB;SACJ;QAED,OAAO,GAAG,CAAC;KACd;;IAED,eAAe,CAAC,UAAkB;QAE9B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,IAAI,cAAc,GAAG,IAAI,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC1D,IAAI,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,CAAC;QACjC,KAAK,IAAI,EAAE,IAAI,MAAM;YACjB,EAAE,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACpC,OAAO,MAAM,CAAC;KACjB;IACD,kBAAkB,CAAC,UAAkB;QAEjC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,IAAI,cAAc,GAAG,IAAI,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;QAChE,OAAO,cAAc,CAAC,EAAE,EAAE,CAAC;KAC9B;;;;IAID,OAAO;QAEH,IAAI,SAAS,GAAY,EAAE,CAAC;QAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACtC;YACI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3C;QACD,OAAO,SAAS,CAAC;KACpB;;;;;;;;;;IAWD,eAAe,CAAC,KAAa;QAEzB,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAC7C,OAAO,SAAS,CAAC;QAErB,IAAI,KAAK,GAAG,CAAC;YACT,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;aAC9B,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ;YAC3B,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;;YAC9C,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;KACvD;;;;;;;;IASD,oBAAoB,CAAC,KAAa;QAE9B,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,KAAK,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;aAClD,IAAI,KAAK,GAAG,CAAC;YAAE,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAE/C,OAAO,KAAK,CAAC;KAChB;;;;;IAMD,eAAe,CAAC,CAAS;QAErB,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAEjD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QAE5C,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QAE3E,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QAEzD,IAAI,KAAY,CAAC;QACjB,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC;YACvB,KAAK,GAAG,IAAIM,YAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;YAE3E,KAAK,GAAG,IAAIN,WAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/E,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;QAC/B,OAAO,KAAK,CAAC;KAChB;IAED,cAAc,CAAC,KAAY,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;QAEnE,OAAO,yBAAyB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;KACrE;;IAGD,aAAa;QAET,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEhC,IAAI,SAAS,GAAa,EAAE,CAAC;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;YACI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACf,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACvC;gBACI,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAChB,IAAI,GAAG,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;gBAE9D,KAAK,IAAI,CAAC,IAAI,GAAG,EACjB;oBACI,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;oBACzC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC7C;aACJ;SACJ;QACD,OAAO,SAAS,CAAC;KACpB;IAED,IAAI,WAAW;QAEX,IAAI,GAAG,GAAG,IAAIhB,UAAI,EAAE,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACtC;YACI,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YACjC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;SAC7B;QACD,OAAO,GAAG,CAAC;KACd;;;;IAKD,IAAI,OAAO;QAEP,IAAI,GAAG,GAAc,EAAE,CAAC;QACxB,IAAI,IAAI,GAAa,EAAE,CAAC;QAExB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAC3B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAEzB,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,EAC/B;YACI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACvB;;QAED,IAAI,IAAI,CAAC,WAAW;YAChB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAC9D;YACI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;SACtB;QAED,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;KACxB;IACD,IAAI,OAAO;QAEP,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAEhC,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,EAAS,CAAC;QACd,IAAI,EAAS,CAAC;QAEd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACtC;YACI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC7B,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE1D,IAAI,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC;YACrB,IAAI,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC;YACrB,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;YAExC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAW,CAAC;YAChB,IAAI,EAAW,CAAC;YAEhB,IAAI,EAAE,YAAYgB,WAAG,EACrB;gBACI,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAClC,IAAI,GAAG,KAAK,MAAM;oBACd,OAAO,KAAK,CAAC;gBACjB,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;aAC7C;;gBAEG,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC;YAEvB,IAAI,EAAE,YAAYA,WAAG,EACrB;gBACI,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;gBAClC,IAAI,GAAG,KAAK,MAAM;oBACd,OAAO,KAAK,CAAC;gBACjB,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;aACtC;;gBAEG,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC;YAErB,IAAI,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7B,IAAI,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAExC,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,MAAM;gBAC3B,OAAO,KAAK,CAAC;SACpB;QACD,OAAO,IAAI,CAAC;KACf;IACD,IAAI,KAAK;QAEL,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACjC,IAAI,KAAK,GAAG,eAAe,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC;KAChB;IACD,IAAI,GAAG;QAEH,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QACzB,IAAI,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EACvC;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,GAAG,KAAK,CAAC;gBACT,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;iBAE7B;gBACI,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAQ,CAAC;gBAC7C,GAAG,IAAI,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,WAAW,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;aACnH;SACJ;QACD,OAAO,GAAG,CAAC;KACd;IACD,cAAc,CAAC,aAAyB,UAAU,CAAC,SAAS;QAExD,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAEvB,IAAI,GAAG,GAAG,mBAAmB,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QAChF,IAAI,UAAU,KAAK,UAAU,CAAC,KAAK,EACnC;YACI,IAAI,QAAQ,GAAG,IAAIS,yBAAY,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAiB,CAAC,CAAC;YAC1F,OAAO,IAAIC,WAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;SAC9D;QACD,IAAI,GAAG,GAAG,IAAIH,UAAK,CAAC,GAAG,EAAE,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACrE,OAAO,GAAG,CAAC;KACd;IACD,gBAAgB,CAAC,IAAgB,EAAE,EAAY;QAE3C,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACvB,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,KAAK,GAAG,EAAW,CAAC;QACxB,IAAI,GAAG,GAAG,KAAK,CAAC,QAA0B,CAAC;QAC3C,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,EAC5C;YACI,cAAc,CAAC,KAAK,EAAE,mBAAmB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;SACjE;KACJ;IAED,iBAAiB,CAAC,IAAmB;QAEjC,IAAI,IAAI,KAAK,aAAa,CAAC,IAAI,EAC/B;YACI,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,IAAI,CAAC,SAAS;gBAAE,KAAK,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;SAChB;aAED;YACI,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAChC;KACJ;IAED,mBAAmB,CACf,QAAwB,EACxB,SAAkB,EAClB,SAAkB,EAClB,SAAmB;QAGnB,QAAQ,QAAQ;YAEZ,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACnC,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,MAAM,GAAG,EAAE,CAAC;gBAChB,IAAI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC5B,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAClC;oBACI,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;oBAChC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBACvB;gBACD,OAAO,MAAM,CAAC;YAClB,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,IAAI,GAAG,GAAc,EAAE,CAAC;oBACxB,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAC7B;wBACI,IAAI,IAAI,GAAG,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;wBAC7E,IAAI,IAAI;4BACJ,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;qBACzB;oBACD,OAAO,GAAG,CAAC;iBACd;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,IAAI,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;oBACjD,IAAI,EAAE;wBACF,OAAO,CAAC,EAAE,CAAC,CAAC;oBAChB,MAAM;iBACT;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,MAAM,GAAc,EAAE,CAAC;gBAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAC9C;oBACI,IAAI,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EACxB;wBACI,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAQ,CAAC;wBACxC,IAAI,EAAE;4BACF,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;qBAC9B;iBACJ;gBACD,OAAO,MAAM,CAAC;YAClB,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,SAAS,EACb;oBACI,IAAI,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;oBAClD,IAAI,CAAC,EAAE;wBAAE,OAAO,EAAE,CAAC;oBACnB,IAAI,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;oBACtC,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;oBACtC,IAAI,EAAE,EACN;wBACI,IAAI,SAAS,GAAG,EAAE,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;wBACtD,IAAI,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;4BACtC,OAAO,CAAC,SAAS,CAAC,CAAC;qBAC1B;iBACJ;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,SAAS,EACb;oBACI,IAAI,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;oBACvD,IAAI,CAAC,OAAO;wBAAE,OAAO,EAAE,CAAC;oBACxB,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;oBACxC,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;oBACnC,IAAI,EAAE,YAAYP,WAAG;wBACjB,OAAO,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;oBAClE,OAAO,EAAE,CAAC;iBACb;SAGR;QACD,OAAO,EAAE,CAAC;KACb;IACD,aAAa;QAET,IAAI,MAAM,GAAc,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YACzB,OAAO,MAAM,CAAC;QAElB,IAAI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5B,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,GAAG,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,EAC3C;YACI,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAClB;QACD,OAAO,MAAM,CAAC;KACjB;IACD,cAAc,CAAC,SAAmB,EAAE,OAAgB;QAEhD,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAIpB,aAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAEnG,IAAI,aAAa,GAAG,SAAS,CAAC;QAC9B,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EACxB;YACI,IAAI,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACvD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC;gBACxB,aAAa,GAAG,aAAa,CAAC;SACrC;QAED,KAAK,IAAI,KAAK,IAAI,aAAa,EAC/B;YACI,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,EACnB;gBACI,IAAI,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC;gBAExB,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;gBAEnC,IAAI,UAAU,GAAG,OAAO,GAAG,CAAC,CAAC;gBAC7B,IAAI,IAAI,CAAC,WAAW;oBAChB,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;gBAE9C,IAAI,UAAU,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EACnD;oBACI,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAQ,CAAC;oBAClD,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBACjC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;iBAC5C;gBACD,IAAI,CAAC,OAAO,KAAK,MAAM,GAAG,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EACzD;oBACI,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAQ,CAAC;oBAC/C,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBACjC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;iBACzC;gBACD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;aAC5C;iBAED;gBACI,IAAI,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC9B,IAAI,SAAS,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;gBACxD,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBAChC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EACd;oBACI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACzC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;iBAC9C;qBAED;oBACI,IAAI,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAQ,CAAC;oBAC/C,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBACjC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;iBACzC;aACJ;SACJ;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,gBAAgB;QAEZ,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACnB,IAAI,MAAM,GAAc,EAAE,CAAC;QAC3B,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,EAC/B;YACI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;SACrD;QACD,OAAO,MAAM,CAAC;KACjB;;;;;;;;;IAUD,iBAAiB,CAAC,SAAwB,EAAE,GAAY;QAEpD,IAAI,CAAC,oBAAoB,EAAE,CAAC;;QAG5B,IAAI,QAAQ,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAIA,aAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAEpF,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QAEnC,KAAK,IAAI,KAAK,IAAI,SAAS,EAC3B;YACI,IAAI,KAAK,IAAI,MAAM;gBACf,MAAM,iDAAiD,CAAC;YAE5D,IAAI,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC;YAC3B,IAAI,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;YAC1B,IAAI,IAAI,CAAC,WAAW,EACpB;gBACI,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;gBAC1C,SAAS,GAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;aAC3C;;;;;;;;YASD,MAAM,SAAS,GAAG,CAAC,SAAiB,EAAE,QAAgB;;gBAGlD,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBACjC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;oBAAE,OAAO;;gBAG1C,IAAI,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EACvC;oBACI,IAAI,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;oBAC9C,IAAI,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;;oBAGjD,IAAI,kBAAkB,GAAG,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC;;oBAGlE,IAAI,SAAS,GAAG,kBAAkB,GAAG,CAAC,CAAC,GAAG,CAAC;oBAE3C,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAErB,IAAI,kBAAkB,GAAG,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC;oBAElE,CAAC,CAAC,GAAG,GAAG,SAAS,GAAG,kBAAkB,CAAC;iBAC1C;aACJ,CAAC;YAEF,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAClC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;;YAG5B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;SACrD;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACS,SAAS,CAAC,IAAc;QAE9B,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAC7B;YACI,IAAI,CAAC,GAAG,IAAIC,aAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAEtB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;SAC5C;QACD,IAAI,GAAG,GAAG,CAAC;YACP,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;KACtC;;IAED,SAAS,CAAC,IAAc;QAEpB,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAElC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,EAC5B;YACI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;SACrB;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;KAChC;EACJ;AAhlDYoB,gBAAQ;IADpB,OAAO;GACKA,gBAAQ,CAglDpB;MAEY,YAAY,GAAG,IAAIA,gBAAQ;;ACtmDxC;;;;;;AAMA,IAAY,eAkBX;AAlBD,WAAY,eAAe;;;;IAKvB,yEAAkB,CAAA;;;;IAIlB,iEAAc,CAAA;;;;IAId,+DAAa,CAAA;;;;IAIb,iEAAc,CAAA;AAClB,CAAC,EAlBW,eAAe,KAAf,eAAe,QAkB1B;AASD;SACgB,sBAAsB,CAAC,OAAwB;IAE3D,IAAI,OAAO,KAAK,eAAe,CAAC,UAAU;QACtC,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC;SACnC,IAAI,OAAO,KAAK,eAAe,CAAC,SAAS;QAC1C,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC;IACzC,OAAO,OAAO,CAAC;AACnB,CAAC;AACD;;;;;;;;;;AAUA,SAAS,iBAAiB,CAAC,MAAyB,EAAE,EAAS,EAAE,EAAS,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAElH,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;QAElB,IAAI,EAAE,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC;YACvC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC;gBACxC,OAAO,KAAK,CAAC;QAErB,IAAI,EAAE,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC;YACtC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC;gBACvC,OAAO,KAAK,CAAC;QACrB,OAAO,IAAI,CAAC;KACf,CAAC,CAAC;AACP,CAAC;SACe,wBAAwB,CAAC,GAAiB,EAAE,GAAiB;IAEzE,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,IAAI,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,IAAI,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC;IAEpB,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;IACzB,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;IAEzB,IAAI,GAAG,GAAsB,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAEvC,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,IAAI;WACtC,IAAI,IAAI,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;QACpC,OAAO,GAAG,CAAC;IACf,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAEtC,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACzB,IAAI,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC;IAC9B,IAAI,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC;IAE9B,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,GAAG,KAAK,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7C,IAAI,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC;IACvB,IAAI,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC;IAEvB,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAC/B,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAE/B,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,OAAO,GAAG,EAAE,CAAC,CAAC;IACtC,IAAI,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,OAAO,GAAG,EAAE,CAAC,CAAC;IAEtC,EAAE,IAAI,OAAO,CAAC;IACd,EAAE,IAAI,OAAO,CAAC;IAEd,IAAI,EAAE,GAAG,IAAItB,aAAO,CAAC,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAC3C,IAAI,EAAE,GAAG,IAAIA,aAAO,CAAC,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAC3C,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACvB,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAEvB,GAAG,CAAC,IAAI,CAAC;QACL,EAAE,EAAE,EAAE;QACN,SAAS,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QAClC,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;KACpC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,CAAC;YACL,EAAE,EAAE,EAAE;YACN,SAAS,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YAClC,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;SACpC,CAAC,CAAC;IAEP,OAAO,GAAG,CAAC;AACf,CAAC;AACD;;;;;;;;;SASgB,qBAAqB,CAAC,MAAc,EAAE,GAAQ,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAEtG,IAAI,GAAG,GAAG,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;AAChG,CAAC;AAED;;;;;;;;;SASgB,kBAAkB,CAAC,IAAS,EAAE,IAAS,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAE/F,IAAI,GAAG,GAAG,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,OAAO,iBAAiB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAClE,CAAC;SAEe,uBAAuB,CAAC,CAAO,EAAE,EAAW,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAEpG,IAAI,GAAG,GAAG,4BAA4B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9C,OAAO,iBAAiB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;AAQA,SAAS,2BAA2B,CAAC,IAAU,EAAE,MAAoB;IAEjE,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC;IAC9B,IAAI,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,aAAa,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAEnC,IAAI,IAAI,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7C,IAAI,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAC1B;QACI,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAExD,OAAO,CAAC;gBACJ,EAAE;gBACF,SAAS,EAAE,CAAC,EAAE,GAAG,MAAM;gBACvB,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;aACvC,CAAC,CAAC;KACN;SACI,IAAI,KAAK,GAAG,CAAC,EAClB;QACI,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC/E,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAE/D,OAAO;YACH;gBACI,EAAE,EAAE,EAAE;gBACN,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,IAAI,MAAM;gBAChC,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;aACvC,EAAE;gBACC,EAAE,EAAE,EAAE;gBACN,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,IAAI,MAAM;gBAChC,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;aACvC;SACJ,CAAC;KACL;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED;SACgB,sBAAsB,CAAC,IAAU,EAAE,MAAc,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAEzG,IAAI,KAAK,GAAG,2BAA2B,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtD,OAAO,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;AACvF,CAAC;AACD;SACgB,mBAAmB,CAAC,IAAU,EAAE,GAAQ,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAEhG,IAAI,KAAK,GAAG,2BAA2B,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AACnE,CAAC;SA8Be,oBAAoB,CAAC,EAAW,EAAE,EAAW,EAAE,EAAW,EAAE,EAAW;IAEnF,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACtB,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAEtB,IAAI,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;IAEpC,IAAI,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAC1B;QACI,IAAI,MAAM,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI,CAAC;YAClC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5B,OAAO,EAAE,CAAC;KACb;IAED,IAAI,EAAE,GAAG,IAAIA,aAAO,CAAC;IACrB,IAAI,KAAK,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC;IAC9C,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5B,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;IAE5B,OAAO,CAAC,EAAE,CAAC,CAAC;AAChB,CAAC;AAQD;;;;;;;;;;;;;AAaA,SAAS,qBAAqB,CAAC,EAAW,EAAE,EAAW,EAAE,EAAW,EAAE,EAAW,EAAE,OAAO,GAAG,IAAI;IAE7F,IAAI,GAAG,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,OAAO;QACxB,OAAO;IACX,IAAI,GAAG,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,OAAO;QACxB,OAAO;IAEX,IAAI,GAAG,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAE7B,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAE1D,IAAI,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAC1C,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO;QACzB,OAAO;IACX,IAAI,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAE1C,IAAI,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC;IACxB,IAAI,GAAG,GAAG,CAAC,KAAK,GAAG,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;IAE1C,IAAI,mBAAmB,GAAG,IAAIA,aAAO,EAAE,CAAC;IACxC,mBAAmB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAC3C,mBAAmB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAC3C,mBAAmB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAC3C,IAAI,mBAAmB,GAAG,IAAIA,aAAO,EAAE,CAAC;IACxC,mBAAmB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAC3C,mBAAmB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAC3C,mBAAmB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;IAE3C,OAAO,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;AACtD,CAAC;AAED;SACgB,oBAAoB,CAAC,EAAQ,EAAE,EAAQ,EAAE,OAAwB,EAAE,IAAI,GAAG,IAAI;IAE1F,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEpF,IAAI,IAAe,CAAC;IACpB,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EACxG;QACI,IAAI,GAAG,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9B,0BAA0B,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;KACvE;SAED;QACI,IAAI,GAAG,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YACjB,IAAI,CAAC,GAAG,EAAE,CAAC;KAClB;IAED,IAAI,IAAI,GAAsB,EAAE,CAAC;IACjC,KAAK,IAAI,EAAE,IAAI,IAAI,EACnB;QACI,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,IAAI,EAAE,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC;YACvC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;gBACjF,OAAO,EAAE,CAAC;QAClB,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,IAAI,EAAE,OAAO,GAAG,eAAe,CAAC,SAAS,CAAC;YACtC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;gBACjF,OAAO,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;KAC1D;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;SAEe,yBAAyB,CAAC,EAAY,EAAE,EAAS,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;IAEzG,IAAI,GAAG,GAAY,EAAE,CAAC,OAAO,EAAE,CAAC;IAChC,IAAI,IAAa,CAAC;IAClB,IAAI,EAAE,YAAYsB,gBAAQ;QACtB,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;;QAEpB,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,MAAM,GAAsB,EAAE,CAAC;IAEnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EACnC;QACI,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EACpC;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,GAAG,GAAG,OAAO,CAAC;YAElB,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;YACtB,IAAI,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;YAEjC,IAAI,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC;YACvB,IAAI,MAAM,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;;YAGnC,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE,OAAO,IAAI,KAAK,CAAC;gBACnC,GAAG,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC;YAC5C,IAAI,CAAC,EAAE,YAAYA,gBAAQ,IAAI,EAAE,CAAC,SAAS,KAAK,EAAE,QAAQ,IAAI,MAAM,CAAC;gBACjE,GAAG,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC;YAE3C,IAAI,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;YAG9G,IAAI,eAAe,CAAC,UAAU,GAAG,GAAG,EACpC;;gBAEI,IAAI,OAAO,IAAI,KAAK,EACpB,CACC;qBACI,IAAI,OAAO,EAChB;oBACI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;iBACrD;qBACI,IAAI,KAAK,EACd;oBACI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;iBACrD;aACJ;YACD,IAAI,eAAe,CAAC,SAAS,GAAG,GAAG,EACnC;;gBAEI,IAAI,QAAQ,IAAI,MAAM,EACtB,CACC;qBACI,IAAI,QAAQ,EACjB;oBACI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;iBACnE;qBACI,IAAI,MAAM,EACf;oBACI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;iBACxD;aACJ;YAED,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;gBAEvB,OAAO;oBACH,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS;oBAC1B,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ;iBAC3B,CAAC;aACL,CAAC,CAAC,CAAC;SACP;KACJ;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;SAEe,4BAA4B,CAAC,CAAO,EAAE,EAAW;IAE7D,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,IAAI,GAAG,GAAG,IAAIrB,aAAO,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACxE,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;IAChB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;IAChB,IAAI,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,GAAG,GAAc,EAAE,CAAC;IACxB,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EACtB;QACI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAChB;YACI,GAAG,GAAG,CAAC,IAAID,aAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;SAChC;aACI,IAAI,CAAC,GAAG,CAAC;YACV,OAAO,EAAE,CAAC;aAEd;YACI,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvB,GAAG,GAAG;gBACF,IAAIA,aAAO,CAAC,CAAC,EAAE,EAAE,CAAC;gBAClB,IAAIA,aAAO,CAAC,CAAC,EAAE,EAAE,CAAC;aACrB,CAAC;SACL;KACJ;SAED;QACI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1G,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAChB;YACI,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC5D,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACpB,GAAG,GAAG,CAAC,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;SAC/B;aACI,IAAI,CAAC,GAAG,CAAC;YACV,OAAO,EAAE,CAAC;aAEd;YACI,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC7E,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACpB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC7E,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACpB,GAAG,GAAG;gBACF,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC;gBACnB,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC;aACtB,CAAC;SACL;KACJ;IAED,IAAI,MAAM,GAAG,IAAIC,aAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC3C,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;QAEZ,IAAI,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAChC,OAAO;YACH,EAAE;YACF,SAAS,EAAE,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC;YAChC,QAAQ,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;SACnC,CAAC;KACL,CAAC,CAAC;AACP,CAAC;SACe,8BAA8B,CAAC,EAAW,EAAE,GAAiB,EAAE,IAAqB;IAEhG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE5C,IAAI,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAEtC,IAAI,OAAO;QACP,OAAO,EAAE,CAAC;IAEd,IAAI,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAClC;QACI,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QAChB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QAChB,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC;QACnB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,IAAI,GAAG,GAAc,EAAE,CAAC;QACxB,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EACrC;YACI,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;gBACZ,GAAG,GAAG;oBACF,IAAID,aAAO,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjB,IAAIA,aAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;iBACrB,CAAC;;gBAEF,GAAG,GAAG;oBACF,IAAIA,aAAO,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjB,IAAIA,aAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;iBACrB,CAAC;SACT;aACI,IAAI,CAAC,GAAG,CAAC;YACV,OAAO,EAAE,CAAC;aAEd;YACI,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,GAAG,CAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,GAAG,CAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxB,GAAG,GAAG;gBACF,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC;gBACnB,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC;gBACnB,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC;gBACnB,IAAIA,aAAO,CAAC,EAAE,EAAE,EAAE,CAAC;aACtB,CAAC;SACL;QACD,IAAI,EAAE,GAAG,IAAIC,aAAO,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YAEf,IAAI,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YACjD,OAAO;gBACH,EAAE;gBACF,SAAS,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;gBACjC,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;aACpC,CAAC;SACL,CAAC,CAAC;QACH,OAAO,iBAAiB,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;KAChD;SAED;QACI,IAAI,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YAEpB,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,EAAE,GAAG,IAAIqB,gBAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,QAAQ,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAElD,IAAI,IAAI,KAAK,eAAe,CAAC,UAAU;YACnC,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC;aAChC,IAAI,IAAI,KAAK,eAAe,CAAC,SAAS;YACvC,IAAI,GAAG,eAAe,CAAC,cAAc,CAAC;QAE1C,IAAI,MAAM,GAAG,yBAAyB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3D,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC;KACjB;AACL,CAAC;SACe,gBAAgB,CAAC,GAAY,EAAE,GAAY,EAAE,IAAqB;IAE9E,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;WACrC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;WAC1B,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;WAC1B,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAE/C,IAAI,MAAM;QACN,OAAO,EAAE,CAAC;IAEd,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EACzB;QACI,OAAO,EAAE,CAAC;KACb;IAED,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC;QAC/C,OAAO,EAAE,CAAC;IAEd,IAAI,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAEnC,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAEtB,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAEtB,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;KAC5B,CAAC,CAAC;IAEH,IAAI,GAAG,GAAG,IAAIA,gBAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,GAAG,GAAG,IAAIA,gBAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAEvD,IAAI,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC;AAClB;;;ACnnBA,IAAI,cAA8B,CAAC;AACnC,SAAS,iBAAiB;IAEtB,IAAI,CAAC,cAAc;QACf,cAAc,GAAG,mBAAmB,CAAC,aAAa,CAC9C,IAAIJ,kBAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CACvF,CAAC;IACN,OAAO,cAAc,CAAC;AAC1B,CAAC;AAGYM,cAAM,cAAnB,MAAa,MAAO,SAAQ,KAAK;IAE7B,YAAY,MAAgB,EAAE,SAAiB,IAAI;QAE/C,KAAK,EAAE,CAAC;QACR,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;KACzB;IAGD,IAAI,KAAK;QAEL,IAAI,EAAE,GAAG,IAAI,MAAM,EAAE,CAAC;QACtB,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACvE,OAAO,EAAE,CAAC;KACb;IAED,IAAI,MAAM;QAEN,OAAO,IAAIxB,aAAO,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC5D;IACD,IAAI,MAAM,CAAC,CAAU;QAEjB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IACD,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,OAAO,CAAC;KACvB;IACD,IAAI,MAAM,CAAC,CAAS;QAEhB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IAES,gBAAgB,CAAC,CAAU;QAEjC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,iBAAiB,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;KACf;IACS,iBAAiB,CAAC,CAAU;QAElC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEjC,OAAO,IAAI,CAAC;KACf;;IAID,IAAI,UAAU;QAEV,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;KAClC;IACD,IAAI,UAAU;QAEV,OAAO,CAAC,CAAC;KACZ;IACD,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;KAClC;IACD,IAAI,QAAQ;QAER,OAAO,CAAC,CAAC;KACZ;IACD,SAAS,CAAC,EAAW;QAEjB,OAAO,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;KACvE;IACD,IAAI,IAAI;QAEJ,OAAO,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;KACtC;IACD,IAAI,KAAK;QAEL,OAAO,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;KACtC;IACD,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;KACrC;IAED,IAAI,OAAO;QAEP,OAAO,IAAI,CAAC;KACf;;IAGD,IAAI,WAAW,KAAc,OAAO,KAAK,CAAC,EAAE;IAE5C,eAAe,CAAC,KAAa;QAEzB,OAAQ,KAAK,CAAC,IAAIA,aAAO,EAAE,EAAE,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAa,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC1G;IAED,kBAAkB,CAAC,QAAgB;QAE/B,IAAI,KAAK,GAAG,QAAQ,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;KACtC;IAED,cAAc,CAAC,KAAa;QAExB,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;KAC7C;IAED,cAAc,CAAC,EAAW;QAEtB,IAAI,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;KACrC;IAED,cAAc,CAAC,CAAS;QAEpB,OAAO,CAAC,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;KAC3C;IAED,cAAc,CAAC,KAAwB;QAEnC,IAAI,MAAgB,CAAC;QACrB,IAAI,KAAK,YAAY,KAAK,EAC1B;YACI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YACjC,0BAA0B,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,EAAE,CAAC;SACpC;;YAEG,OAAO,EAAE,CAAC;;QAGd,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAElC,IAAI,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QAEzD,IAAI,SAAS,GAAG,IAAI,KAAK,EAAO,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAC7C;YACI,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EACzB;gBACI,IAAI,GAAG,GAAG,IAAIqB,WAAG,CAAC,IAAIrB,aAAO,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;gBAC9D,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;aACvB;SACJ;QACD,OAAO,SAAS,CAAC;KACpB;IAED,eAAe,CAAC,EAAY;QAExB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACnB,OAAO,GAAG,CAAC;QACf,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;KACtE;IAED,SAAS,CAAC,EAAW;QAEjB,OAAO,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KACvF;IACD,eAAe,CAAC,UAAkB;QAE9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,EACnC;YACI,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;YAC1C,OAAO,CAAC,MAAM,CAAC,CAAC;SACnB;QACD,OAAO,EAAE,CAAC;KACb;IAED,cAAc,CAAC,KAAY,EAAE,OAAwB;QAEjD,IAAI,KAAK,YAAYqB,WAAG,EACxB;YACI,OAAO,qBAAqB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;SACtD;QACD,IAAI,KAAK,YAAYM,YAAI,EACzB;YACI,OAAO,SAAS,CAAC,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SAC1F;QACD,IAAI,KAAK,YAAY,QAAM,EAC3B;YACI,OAAO,wBAAwB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;SAChD;QACD,IAAI,KAAK,YAAY,OAAO,EAC5B;YACI,OAAO,SAAS,CAAC,8BAA8B,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;SAC1E;QACD,IAAI,KAAK,YAAYL,gBAAQ;YACzB,OAAO,SAAS,CAAC,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC9F,OAAO,EAAE,CAAC;KACb;;IAGD,IAAI,WAAW;QAEX,OAAO,IAAIjB,UAAI,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;KACzD;IAED,cAAc,CAAC,aAAyB,UAAU,CAAC,SAAS;QAExD,IAAI,MAAM,GAAG,iBAAiB,EAAE,CAAC;QACjC,IAAI,UAAU,KAAK,UAAU,CAAC,KAAK,EACnC;YACI,IAAI,QAAQ,GAAG,IAAIyB,yBAAY,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAiB,CAAC,CAAC;YAC7F,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACzD,OAAO,IAAIC,WAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;SAC9D;QACD,IAAI,IAAI,GAAG,IAAIH,UAAK,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACzE,IAAI,GAAG,GAAG,IAAItB,cAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC;KACd;IACD,gBAAgB,CAAC,IAAgB,EAAE,GAAa;QAE5C,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACpE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;KAClC;IACD,wBAAwB,CAAC,IAAgB,EAAE,GAAa,EAAE,QAAkB;QAExE,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAU,CAAC;QACjC,CAAC,CAAC,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;KACjF;IAED,iBAAiB,CAAC,IAAmB;QAEjC,IAAI,IAAI,KAAK,aAAa,CAAC,IAAI;YAC3B,OAAO,CAAC,CAAC;;YAET,OAAO,CAAC,CAAC;KAChB;IAED,aAAa;QAET,IAAI,GAAG,GAAG;YACN,IAAIN,aAAO,EAAE;YACb,IAAIA,aAAO,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC;YAC5B,IAAIA,aAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAIA,aAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7B,IAAIA,aAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;SAC/B,CAAC;QAEF,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACnB,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,OAAO,GAAG,CAAC;KACd;IAED,mBAAmB,CACf,QAAwB,EACxB,SAAkB,EAClB,SAAkB,EAClB,SAAmB;QAGnB,QAAQ,QAAQ;YAEZ,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,OAAO,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;iBACzD;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzB,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,SAAS,EACb;oBACI,IAAI,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;wBAC1D,OAAO,EAAE,CAAC;oBACd,IAAI,CAAC,GAAG,IAAI2B,YAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;oBACzC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;iBAC5D;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,GAAG,GAAG,sBAAsB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAClD,IAAI,GAAG;oBACH,OAAO,GAAG,CAAC;YACnB,KAAK,cAAc,CAAC,GAAG;gBACnB;oBACI,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC/B,GAAG,CAAC,KAAK,EAAE,CAAC;oBACZ,OAAO,GAAG,CAAC;iBACd;SAGR;QACD,OAAO,EAAE,CAAC;KACb;IACD,cAAc,CAAC,SAAwB,EAAE,GAAY;QAGjD,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAC/B,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EACxB;YACI,IAAI,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;YACnB,IAAI,CAAC,EACL;gBACI,IAAI,KAAK,GAAG,CAAC,EACb;oBACI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACX,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;iBAC3C;qBAED;oBACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;iBACtC;aACJ;SACJ;KACJ;IACD,gBAAgB;QAEZ,IAAI,GAAG,GAAG,CAAC,IAAI3B,aAAO,EAAE,CAAC,CAAC;QAC1B,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACnB,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,OAAO,GAAG,CAAC;KACd;IACD,iBAAiB,CAAC,SAAwB,EAAE,GAAY;QAEpD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EACxB;YACI,IAAI,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;SACzB;KACJ;IACD,YAAY,CAAC,EAAoB;QAE7B,IAAI,OAAO,EAAE,KAAK,QAAQ;YACtB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;;YAE9B,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;QAEpB,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7B,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;QAEnC,OAAO,KAAK,CAAC,IAAIA,aAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,IAAIC,aAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;KAC5F;IACD,iBAAiB,CAAC,EAAW,EAAE,MAAe;QAE1C,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzE,IAAI,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;YACnD,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,IAAI0B,YAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAClC,IAAI,GAAG,GAAG,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;QAC5D,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YAEZ,OAAO,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;SAC9D,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;KACjB;;;;IAKS,SAAS,CAAC,IAAc;QAE9B,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;KAC9B;;IAED,SAAS,CAAC,IAAc;QAEpB,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC5B;EAEJ;AAvXYH,cAAM;IADlB,OAAO;GACKA,cAAM,CAuXlB;;ACzZD;;;;;;;;MAQa,KAAK;IAAlB;QAEY,eAAU,GAAG,IAAI,OAAO,EAAe,CAAC;KAenD;IAdG,QAAQ,CAAC,GAAQ;QAEb,IAAI,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EACV;YACI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC5B,KAAK,GAAG,CAAC,CAAC;SACb;QACD,OAAO,KAAK,CAAC;KAChB;IACD,QAAQ,CAAC,GAAQ,EAAE,GAAW;QAE1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;KACtD;;;ACtBL;;;;MAIa,KAAK;IAAlB;;QAGY,QAAG,GAAW,CAAC,CAAC;;QAGxB,UAAK,GAAW,CAAC,CAAC;KA6DrB;IA3DG,IAAI,GAAG;QAEH,OAAO,IAAI,CAAC,GAAG,CAAC;KACnB;IACD,IAAI,GAAG,CAAC,CAAC;QAEL,IAAI,CAAC,GAAG,GAAGK,eAAS,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;KAClE;;;;;;IAOD,eAAe,CAAC,YAAY,GAAG,IAAI7B,aAAO,EAAE;QAExC,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;QAEpC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAErC,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1C,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE1C,OAAO,YAAY,CAAC;KACvB;;;;;IAMD,gBAAgB,CAAC,GAAY;QAEzB,GAAG,CAAC,SAAS,EAAE,CAAC;QAChB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC;gBACT,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;;gBAE5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;;YAE/B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;KAC7C;;;;;IAMD,OAAO,iBAAiB,CAAC,CAAU,EAAE,KAAc,IAAIA,aAAO,EAAE,EAAE,KAAc,IAAIA,aAAO,EAAE;QAEzF,CAAC,CAAC,SAAS,EAAE,CAAC;QACd,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ;YACpD,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;;YAE1B,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9B,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,EAAE,CAAC,SAAS,EAAE,CAAC;QACf,EAAE,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,CAAC;KACb;;;ACrDL;SACgB,eAAe,CAAC,GAAY,EAAE,GAAY,EAAE,GAAY;IAEpE,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC;QACpB,OAAO;IACX,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACjG,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;;IAEjG,IAAI,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,IAAIA,aAAO,EAAE,CAAC;;IAE3B,IAAI,IAAI,KAAK,CAAC,EACd;;QAEI,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACjB,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;KACpB;SAED;;QAEI,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC;QACtC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC;KACzC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAkBD;SACgB,mBAAmB,CAAC,EAAW,EAAE,EAAW;IAExD,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC;AASD;;;;;;;;;;;SAWgB,cAAc,CAAC,GAAY;;IAGvC,IAAI,QAAQ,GAAG,IAAI,KAAK,EAAgB,CAAC;;IAGzC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QAEd,IAAI,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QACxB,IAAI,OAAO;YACP,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,CAAC,OAAO,CAAC;KACnB,CAAC,CAAC;IACH,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;;IAEtC,IAAI,KAAK,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC3B,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;;IAGzC,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;;IAE1B,IAAI,OAAO,GAAG,IAAI,KAAK,EAAE,CAAC;;;;;;;;IAS1B,SAAS,SAAS,CAAC,KAAc,EAAE,GAAY,EAAE,UAAmB;QAEhE,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAC9B;YACI,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;YACrB,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAC9B;gBACI,IAAI,UAAU,EACd;;oBAEI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC;wBACvC,EAAE,CAAC,OAAO,EAAE,CAAC;oBACjB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;iBAChB;qBAED;;oBAEI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC;wBACrC,EAAE,CAAC,OAAO,EAAE,CAAC;oBACjB,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;iBACnB;gBAED,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;gBACxB,OAAO,KAAK,CAAC,EAAE,CAAC;aACnB;SACJ;KACJ;IAED,KAAK,IAAI,KAAK,IAAI,MAAM,EACxB;QACI,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,GAAG,GAAY,EAAE,CAAC;QACtB,OAAO,UAAU;YACb,UAAU,GAAG,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAElD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAClB;YACI,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACrD,OAAO,UAAU;gBACb,UAAU,GAAG,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;SACtD;QAED,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YACd,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KAC1B;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC;SAEe,UAAU,CAAC,GAAU,EAAE,GAAU,EAAE,SAAS,GAAG,IAAI;IAE/D,IAAI,CAAC,GAAG,YAAYsB,gBAAQ,MAAM,GAAG,YAAYA,gBAAQ,CAAC,EAC1D;QACI,IAAI,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;YACpE,OAAO,KAAK,CAAC;QAEjB,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;QACtB,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;QAEtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;YAC9C,OAAO,KAAK,CAAC;QAEjB,IAAI,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC;QAE3B,IAAI,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC;QACxB,IAAI,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC;QACxB,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC1B,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC;QAE1B,IAAI,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EACpC;YACI,IAAI,WAAW,EACf;gBACI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,KAAK,CAAC,OAAO,EAAE,CAAC;gBAChB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;aAC7B;;gBAEG,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;SACtC;aACI,IAAI,CAAC,WAAW,EACrB;YACI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,KAAK,CAAC,OAAO,EAAE,CAAC;YAChB,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;SAC7B;QAED,IAAI,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAC/D;YACI,IAAI,CAAC,GAAG,EAAE,CAAC;YACX,KAAK,CAAC,GAAG,EAAE,CAAC;SACf;QACD,IAAI,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAC/D;YACI,IAAI,CAAC,GAAG,EAAE,CAAC;YACX,KAAK,CAAC,GAAG,EAAE,CAAC;SACf;QAED,IAAI,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAE/D,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAC9D,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAEnC,OAAO,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC;YACnC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAW,EAAE,EAAW,KAC5C,OAAO,CACH,SAAS,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EACnC,SAAS,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EACnC,SAAS,CACZ,CACJ,CAAC;KACT;SACI,IAAI,GAAG,YAAYE,cAAM,IAAI,GAAG,YAAYA,cAAM,EACvD;QACI,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;KAClF;SACI,IAAI,GAAG,YAAYH,WAAG,IAAI,GAAG,YAAYA,WAAG,EACjD;QACI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC;YAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAC1D,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;eAC/B,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;eACpC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC;eACtC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;KAC7C;SACI,IAAI,GAAG,YAAY,OAAO,IAAI,GAAG,YAAY,OAAO,EACzD;QACI,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;eAC/B,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;eAC1B,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;eAC1B,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;KAClD;SACI,IAAI,GAAG,YAAYM,YAAI,IAAI,GAAG,YAAYA,YAAI,EACnD;QACI,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACzD;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;SAkDe,sBAAsB,CAAC,GAAW;;;;;;;;;;;;IAc9C,IAAI,IAAI,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACxC,IAAI,EAAE,GAAG,IAAIL,gBAAQ,EAAE,CAAC;IACxB,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACjB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,EAAE,CAAC;AACd,CAAC;SAEe,sBAAsB,CAAC,EAAgB,EAAE,SAAmB;IAExE,IAAI,SAAS,EACb;;QAEI,IAAI,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC;QACvB,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAE/C,IAAI,QAAQ,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC;QAE9B,IAAI,QAAQ,IAAI,QAAQ,EACxB;YACI,IAAI,KAAK,GAAG,CAAC,GAAG,QAAQ,CAAC;YACzB,IAAI,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;YAE/C,IAAI,GAAG,GAAG;gBACN,IAAItB,aAAO,CACP,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,EACvD,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,CAC1D;gBACD,IAAIA,aAAO,CACP,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,EACvD,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,CAC1D;aACJ,CAAC;YACF,KAAK,IAAI,CAAC,IAAI,GAAG;gBACb,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,GAAG,CAAC;SACd;KACJ;AACL,CAAC;SAiGe,kBAAkB,CAAC,EAA0B,EAAE,SAAkB,EAAE,SAAkB;IAEjG,IAAI,UAAU,GAAG,IAAIA,aAAO,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEpE,IAAI,KAAK,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAE/C,IAAI,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI0B,WAAK,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI1B,aAAO,EAAE,EAAE,IAAI,CAAC,CAAC;IAElH,IAAI,SAAS,EACb;QACI,IAAI,CAAC,GAAG,IAAIA,aAAO,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtE,IAAI,CAAC,GAAG,IAAIA,aAAO,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEtE,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI0B,WAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI1B,aAAO,EAAE,EAAE,IAAI,CAAC,CAAC;QACtF,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI0B,WAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI1B,aAAO,EAAE,EAAE,IAAI,CAAC,CAAC;QAEtF,IAAI,EAAE,GAAG,IAAI2B,YAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,EAAE,GAAG,IAAIA,YAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAEhC,IAAI,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;QAC3D,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,OAAO,GAAG,CAAC;KACd;SAED;QACI,IAAI,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI3B,aAAO,EAAE,CAAC,CAAC;QAC3D,IAAI,EAAE,GAAG,IAAI2B,YAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;KAC3D;AACL,CAAC;SAEe,kBAAkB,CAAC,EAAW,EAAE,SAAkB;IAE9D,OAAO,EAAE,CAAC;AACd,CAAC;SA6Fe,SAAS,CAAC,GAAsB;IAE5C,KAAK,IAAI,CAAC,IAAI,GAAG;QACb,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1D,OAAO,GAAG,CAAC;AACf,CAAC;SAEe,uBAAuB,CAAC,MAAe,EAAE,gBAAyB,IAAI;IAElF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;;IAG3C,IAAI,MAAe,CAAC;IACpB,IAAI,MAAe,CAAC;IACpB,KAAK,IAAI,CAAC,IAAI,MAAM,EACpB;QACI,IAAI,CAAC,YAAYN,WAAG,EACpB;YACI,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YAClB,MAAM;SACT;aACI,IAAI,MAAM,EACf;YACI,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC1B,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChB,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,EACxB;gBACI,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC;gBACvB,MAAM;aACT;SACJ;aAED;YACI,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,EAAa,CAAC;YACjC,IAAI,GAAG,GAAG,uBAAuB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC9C,IAAI,GAAG;gBACH,OAAO,GAAG,CAAC;YACf,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;SAC9B;KACJ;IAED,IAAI,CAAC,MAAM,IAAI,CAAC,aAAa;QAAE,OAAO;IAEtC,IAAI,CAAC,GAAG,IAAIrB,aAAO,EAAE,CAAC;IACtB,IAAI,CAAC,GAAG,IAAIA,aAAO,EAAE,CAAC;IACtB,IAAI,CAAC,MAAM,EACX;QACI,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KACnC;SAED;QACI,IAAI,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC1C,MAAM,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;KACzC;IACD,OAAO,IAAIC,aAAO,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACnF,CAAC;SAGe,YAAY,CAAC,GAAoB,EAAE,OAAgB;IAE/D,IAAI,EAAE,GAAG,IAAIqB,gBAAQ,EAAE,CAAC;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EACtC;QACI,IAAI,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAe,CAAC;QACpB,IAAI,EAAW,CAAC;QAChB,IAAI,EAAW,CAAC;QAEhB,IAAI,OAAO,EACX;YACI,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACjD,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;SACpD;aAED;YACI,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM;YAC/B,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3B,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SAC9B;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAE5B,IAAI,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACzB,GAAG,GAAG,IAAIK,YAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;;YAEvB,GAAG,GAAG,IAAIN,WAAG,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/C,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KAChB;IACD,OAAO,EAAE,CAAC;AACd;;;ACrpBA;;;;;;;;;AAUaA,WAAG,WAAhB,MAAa,GAAI,SAAQ,KAAK;IAE1B,YAAY,SAAkB,IAAIrB,aAAO,EAAE,EAAE,SAAiB,GAAG,EAAE,aAAqB,GAAG,EAAE,WAAmB,CAAC,EAAE,SAAS,GAAG,IAAI;QAE/H,KAAK,EAAE,CAAC;;;;QAaJ,eAAU,GAAG,IAAI,CAAC;QAZtB,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;KAC/B;IASD,IAAI,KAAK;QAEL,IAAI,EAAE,GAAG,IAAIe,WAAK,EAAE,CAAC;QACrB,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACjF,OAAO,EAAE,CAAC;KACb;IAED,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,QAAQ,CAAC;KACxB;IACD,IAAI,MAAM,CAAC,CAAU;QAEjB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;KACrB;IAED,IAAI,MAAM;QAEN,OAAO,IAAIf,aAAO,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;KAC7D;IACD,IAAI,MAAM,CAAC,CAAU;QAEjB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IAED,IAAI,IAAI;QAEJ,OAAO,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;KAC1D;;IAED,IAAI,KAAK;QAEL,IAAI,SAAS,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;KACtE;IACD,IAAI,OAAO;QAEP,OAAO,KAAK,CAAC;KAChB;IAED,IAAI,WAAW;QAEX,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;;QAG3C,IAAI,MAAM,GAAG;YACT,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAIA,aAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAIA,aAAO,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAIA,aAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAIA,aAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SACjD,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC;YAEZ,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;gBACjB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACnB,CAAC,CAAC;QACH,OAAO,IAAIK,UAAI,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;KACxC;IAED,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,OAAO,CAAC;KACvB;IACD,IAAI,MAAM,CAAC,CAAS;QAEhB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IAED,IAAI,WAAW;QAEX,OAAO,IAAI,CAAC,UAAU,CAAC;KAC1B;IACD,IAAI,WAAW,CAAC,CAAU;QAEtB,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,EACzB;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACpB,IAAI,CAAC,MAAM,EAAE,CAAC;SACjB;KACJ;IAED,IAAI,UAAU;QAEV,OAAO,IAAI,CAAC,WAAW,CAAC;KAC3B;IACD,IAAI,UAAU,CAAC,CAAS;QAEpB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IAED,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,SAAS,CAAC;KACzB;IACD,IAAI,QAAQ,CAAC,CAAS;QAElB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;;IAGD,IAAI,UAAU;QAEV,OAAO,KAAK,CAAC,IAAIL,aAAO,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KACtF;IACD,IAAI,UAAU,CAAC,CAAU;QAErB,IAAI,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;KAClC;IACD,IAAI,QAAQ;QAER,OAAO,KAAK,CAAC,IAAIA,aAAO,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KACpF;IACD,IAAI,QAAQ,CAAC,CAAU;QAEnB,IAAI,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;KAChC;IACD,IAAI,UAAU;QAEV,OAAO,CAAC,CAAC;KACZ;IACD,IAAI,QAAQ;QAER,OAAO,CAAC,CAAC;KACZ;IACD,IAAI,MAAM;QAEN,OAAO,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;KACvC;IAED,gBAAgB,CAAC,EAAW;QAExB,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;KACzD;;IAED,UAAU,CAAC,CAAU,EAAE,IAAI,GAAG,IAAI;QAE9B,IAAI,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;KACzC;IAES,gBAAgB,CAAC,CAAU;QAEjC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,iBAAiB,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;KACf;IACS,iBAAiB,CAAC,CAAU;QAElC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;QACzB,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEvB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEjC,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;KACf;IACD,eAAe,CAAC,KAAa;QAEzB,IAAI,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC,IAAIA,aAAO,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KACxE;IACD,kBAAkB,CAAC,QAAgB;QAE/B,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACtB,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO;QACrB,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;KAC/C;IAED,cAAc,CAAC,KAAa;QAExB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;KACxC;IAED,cAAc,CAAC,EAAW;QAEtB,IAAI,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;KACrC;IAED,eAAe,CAAC,EAAW;QAEvB,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC;YACjB,IAAI,CAAC,QAAQ,IAAI,CAAC;YAClB,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;YACvD,OAAO,GAAG,CAAC;QAEf,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;KACzD;;;;;;;;;;IAWD,eAAe,CAAC,EAAU;;QAGtB,IAAI,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;;QAG1B,IAAI,gBAAgB,GAAG,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;QAE3C,IAAI,OAAO,GAAG,KAAK,GAAG,gBAAgB;YAClC,OAAO,CAAC,CAAC,OAAO,GAAG,KAAK,KAAK,gBAAgB,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;;YAE5D,OAAO,OAAO,GAAG,KAAK,CAAC;KAC9B;;;;;;;IAQD,gBAAgB,CAAC,EAAU,EAAE,OAAO,GAAG,IAAI;;QAGvC,IAAI,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;;QAG1B,IAAI,gBAAgB,GAAG,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;QAE3C,IAAI,OAAO;YACP,OAAO,CAAC,CAAC,OAAO,GAAG,KAAK,KAAK,gBAAgB,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;;YAE5D,OAAO,OAAO,GAAG,KAAK,CAAC;KAC9B;IAED,eAAe,CAAC,EAAW;QAEvB,IAAI,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC;KACvB;IAED,eAAe,CAAC,KAAa;QAEzB,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAC1F;IAED,cAAc,CAAC,KAAwB;QAEnC,IAAI,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;;QAExC,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;;QAEnD,IAAI,IAAI,GAAU,EAAE,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EACvC;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,EAAS,CAAC;YAC9B,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACxB,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SAClB;QACD,OAAO,IAAI,CAAC;KACf;IACD,eAAe,CAAC,UAAkB;QAE9B,IAAI,IAAI,CAAC,UAAU;YAAE,UAAU,IAAI,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,EACnC;YACI,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,EAAS,CAAC;YAC9B,GAAG,CAAC,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,CAAC;SAChB;QACD,OAAO,EAAE,CAAC;KACb;IACD,MAAM,CAAC,QAAgB;QAEnB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,CAAC,EAChB;YACI,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;SACrD;aACI,IAAI,QAAQ,GAAG,CAAC,EACrB;YACI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;SACnD;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;KACjB;IAED,IAAI,CAAC,EAAS;QAEV,IAAI,EAAE,YAAY,KAAG,EACrB;YACI,IAAI,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,EACvE;gBACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAC5B,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;gBAC5C,IAAI,EAAE,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU;oBAChC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAExB,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC1B,IAAI,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gBACpC,IAAI,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gBAEpC,IAAI,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC;iBAChC;oBACI,IAAI,OAAO,GAAG,KAAK;wBACf,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;oBAEvB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;qBACI,IAAI,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC;iBACnC;oBACI,IAAI,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC;wBAC/C,OAAO,MAAM,CAAC,cAAc,CAAC;;wBAE7B,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;oBAEvB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;qBACI,IAAI,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC;iBACpC;oBACI,IAAI,OAAO,GAAG,KAAK;wBACf,OAAO,MAAM,CAAC,cAAc,CAAC;;wBAE7B,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;oBACzB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;qBACI,IAAI,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC;iBACnC;oBACI,IAAI,OAAO,GAAG,KAAK;wBACf,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;oBACzB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;qBACI,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,EACpD;oBACI,IAAI,OAAO,GAAG,OAAO;wBACjB,OAAO,MAAM,CAAC,cAAc,CAAC;yBAC5B,IAAI,OAAO,GAAG,KAAK;wBACpB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;oBACvB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;qBACI,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,EACpD;oBACI,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;oBACrB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;;gBAGD,IAAI,OAAe,CAAC;gBACpB,IAAI,OAAO,GAAG,KAAK;oBACf,OAAO,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC;;oBAE1C,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;gBAE9B,IAAI,OAAe,CAAC;gBACpB,IAAI,OAAO,GAAG,OAAO,IAAI,OAAO,GAAG,KAAK;oBACpC,OAAO,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC;;oBAE1C,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;gBAE9B,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAChC,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAEhC,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,EACvB;oBACI,IAAI,OAAO,GAAG,CAAC;wBACX,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;oBACzB,IAAI,OAAO,GAAG,CAAC;wBACX,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;oBACvB,OAAO,MAAM,CAAC,IAAI,CAAC;iBACtB;aACJ;SACJ;QACD,OAAO,MAAM,CAAC,KAAK,CAAC;KACvB;IAED,OAAO;QAEH,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;QACnC,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;KACf;IAED,cAAc,CAAC,KAAY,EAAE,OAAwB,EAAE,SAAS,GAAG,IAAI;QAEnE,IAAI,KAAK,YAAY,KAAG,EACxB;YACI,OAAO,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;SACnD;QACD,IAAI,KAAK,YAAY2B,YAAI,EACzB;YACI,OAAO,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;SAClG;QACD,IAAI,KAAK,YAAYH,cAAM,EAC3B;YACI,OAAO,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;SACpG;QACD,IAAI,KAAK,YAAYF,gBAAQ;YACzB,OAAO,SAAS,CAAC,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,sBAAsB,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAEzG,IAAI,KAAK,YAAY,OAAO;YACxB,OAAO,SAAS,CAAC,8BAA8B,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3E,OAAO,EAAE,CAAC;KACb;;;;;;;;IASD,IAAI,QAAQ;QAER,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KAC5C;IAED,IAAI,GAAG;QAEH,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;YAClC,OAAO,CAAC,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;KACvE;;;;;;;;;IAUD,YAAY,CAAC,QAAgB;;QAGzB,IAAI,IAAI,CAAC,UAAU,EACnB;YACI,IAAI,IAAI,CAAC,WAAW,GAAG,QAAQ;gBAC3B,OAAO,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC;;gBAEnC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;SAC5D;aAED;YACI,IAAI,QAAQ,GAAG,IAAI,CAAC,WAAW;gBAC3B,OAAO,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;;gBAEnC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,CAAC;SAC5D;KACJ;;;;;;;;IASD,YAAY,CAAC,EAAqB,EAAE,EAAqB,EAAE,GAAW;QAElE,IAAI,EAAE,YAAYpB,aAAO;YACrB,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,EAAE,YAAYA,aAAO;YACrB,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAEvB,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;;QAGrC,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;;QAEhC,IAAI,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;;QAE5B,IAAI,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAE1C,IAAI,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,SAAS,GAAG,QAAQ,GAAG,GAAG,CAAC;;QAE/B,IAAI,CAAC,OAAO,GAAG,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;;QAGrD,IAAI,UAAU,GAAG,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC;;QAGzC,IAAI,MAAM,GAAG,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9B,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,OAAO,IAAI,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEpD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEtC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAE/C,IAAI,CAAC,UAAU,GAAG,GAAG,GAAG,CAAC,CAAC;QAE1B,OAAO,IAAI,CAAC;KACf;IACD,cAAc,CAAC,GAAY,EAAE,GAAY,EAAE,GAAY;QAEnD,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC;YACpB,OAAO;QAEX,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACvC,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACvC,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAEvC,IAAI,MAAM,GAAG,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;QAEpD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;;QAEtC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;;QAEhD,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE9B,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;KACf;;;;;;IAOD,cAAc,CAAC,aAAyB,UAAU,CAAC,SAAS;QAExD,IAAI,GAAG,GAAG,mBAAmB,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QAErF,IAAI,UAAU,KAAK,UAAU,CAAC,KAAK,EACnC;YACI,IAAI,QAAQ,GAAG,IAAI4B,yBAAY,EAAE,CAAC;YAClC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAiB,CAAC,CAAC;YACjE,OAAO,IAAIC,WAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;SAC9D;QAED,OAAO,IAAIH,UAAK,CAAC,GAAG,EAAE,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;KACrE;;IAGO,cAAc,CAAC,GAAmB;QAEtC,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClD,mBAAmB,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;KAC3C;;;;;;;;IASD,gBAAgB,CAAC,IAAgB,EAAE,GAAa;QAE5C,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,CAAmB,CAAC;QAC5C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;KAC5B;IAED,mBAAmB,CACf,QAAwB,EACxB,SAAkB,EAClB,SAAkB,EAClB,SAAmB;QAGnB,QAAQ,QAAQ;YAEZ,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5C,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;YACvC,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC;qBAChD,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACrD,KAAK,cAAc,CAAC,GAAG;gBACnB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzB,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,SAAS,EACb;oBACI,IAAI,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;wBAC1D,OAAO,EAAE,CAAC;oBACd,IAAI,CAAC,GAAG,IAAID,YAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;oBACzC,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC3F;YACL,KAAK,cAAc,CAAC,GAAG;gBACnB,IAAI,GAAG,GAAG,sBAAsB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAClD,IAAI,GAAG;oBACH,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;SAGrD;QACD,OAAO,EAAE,CAAC;KACb;IAED,aAAa;QAET,OAAO;YACH,IAAI,CAAC,UAAU;YACf,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;YACzB,IAAI,CAAC,QAAQ;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;SACtB,CAAC;KACL;IACD,cAAc,CAAC,SAAwB,EAAE,GAAY;QAEjD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EACxB;YACI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,IAAI,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YAClC,IAAI,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACtB,IAAI,CAAC,EACL;gBACI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACX,IAAI,KAAK,GAAG,CAAC;oBACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;;oBAEnC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACzD,IAAI,CAAC,MAAM,EAAE,CAAC;aACjB;SACJ;KACJ;IACD,gBAAgB;QAEZ,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;KAC3C;IAED,iBAAiB,CAAC,SAAwB,EAAE,GAAY;QAEpD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YACtB,OAAO;QAEX,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YACtB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;;YAElC,KAAK,IAAI,KAAK,IAAI,SAAS,EAC3B;gBACI,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;gBAEnB,IAAI,kBAAkB,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;gBAEjD,IAAI,SAAS,GAAG,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC;gBAE9C,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEpB,IAAI,kBAAkB,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;gBAEjD,IAAI,MAAM,GAAG,SAAS,GAAG,kBAAkB,CAAC;;gBAG5C,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;gBAClC,IAAI,CAAC,MAAM,EAAE,CAAC;aACjB;KACR;IAED,cAAc,CAAC,CAAS;QAEpB,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;KAC1B;IACD,YAAY,CAAC,EAAoB;QAE7B,IAAI,EAAU,CAAC;QACf,IAAI,OAAO,EAAE,KAAK,QAAQ;YACtB,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;;YAE9B,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAErD,EAAE,IAAI,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEjD,IAAI,GAAG,GAAG,IAAI1B,aAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC,IAAID,aAAO,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;KACnE;IACD,iBAAiB,CAAC,EAAW,EAAE,MAAe;QAE1C,IAAI,CAAC,GAAG,IAAI2B,YAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAClC,IAAI,KAAK,GAAc,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,UAAU,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAC9G,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;KAClG;;;;IAKS,SAAS,CAAC,IAAc;QAE9B,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACtB,IAAI,GAAG,KAAK,CAAC,EACb;YACI,IAAI,CAAC,MAAM,GAAG,IAAI3B,aAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,IAAI,CAAC,MAAM,GAAG,IAAIA,aAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;SACtD;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;KACjC;;IAED,SAAS,CAAC,IAAc;QAEpB,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;KAC/B;EAEJ;AAhvBYqB,WAAG;IADf,OAAO;GACKA,WAAG,CAgvBf;;;;;;;"}
\ No newline at end of file
+{"version":3,"file":"api.cjs.js","sources":["../src/DatabaseServices/CADFactory.ts","../src/DatabaseServices/AllObjectData.ts","../src/DatabaseServices/AutoRecord.ts","../src/DatabaseServices/EraseEntityData.ts","../src/DatabaseServices/CADObject.ts","../src/DatabaseServices/ObjectId.ts","../src/ApplicationServices/HostApplicationServices.ts","../src/Common/Dispose.ts","../src/Geometry/CoordinateSystem.ts","../src/Common/eval.ts","../src/Common/StoreageKeys.ts","../src/Common/Utils.ts","../src/Geometry/GeUtils.ts","../src/Common/Matrix4Utils.ts","../src/Common/Status.ts","../src/GraphicsSystem/RenderType.ts","../src/Common/SystemEnum.ts","../src/Editor/UserConfig.ts","../src/Geometry/Box.ts","../src/DatabaseServices/Entity/Entity.ts","../src/DatabaseServices/CADFiler.ts","../src/GLSL/GoochShader.ts","../src/Common/ColorPalette.ts","../src/Common/ArrayExt.ts","../src/Editor/ObjectSnapMode.ts","../src/Geometry/BufferGeometryUtils.ts","../src/DatabaseServices/Shape2.ts","../src/Geometry/Matrix2.ts","../src/Geometry/RotateUV.ts","../src/ApplicationServices/mesh/createBoard.ts","../src/Geometry/CurveMap.ts","../src/Geometry/RegionParse.ts","../src/GraphicsSystem/BoolOperateUtils.ts","../src/DatabaseServices/Entity/Curve.ts","../src/DatabaseServices/Contour.ts","../src/Geometry/Plane.ts","../src/DatabaseServices/Entity/Ellipse.ts","../src/DatabaseServices/Entity/Line.ts","../src/Geometry/SortEntityByBox.ts","../src/GraphicsSystem/OffsetPolyline.ts","../src/DatabaseServices/PointInPolyline.ts","../src/DatabaseServices/Entity/DragPointType.ts","../src/DatabaseServices/Entity/Polyline.ts","../src/GraphicsSystem/IntersectWith.ts","../src/DatabaseServices/Entity/Circle.ts","../src/Geometry/Count.ts","../src/Geometry/Orbit.ts","../src/Common/CurveUtils.ts","../src/DatabaseServices/Entity/Arc.ts","../src/Common/Log.ts","../src/Common/Singleton.ts","../src/Geometry/UVUtils.ts","../src/DatabaseServices/Shape.ts","../src/DatabaseServices/ShapeManager.ts","../src/DatabaseServices/Entity/Region.ts","../src/Add-on/BoardEditor/Board2Regions.ts","../src/Common/BoardKeyList.ts","../src/Add-on/BoardEditor/SerializeBoardData.ts","../src/Geometry/BoardUVGenerator.ts","../src/UI/Store/BoardInterface.ts","../src/Common/AddEntityDrawObject.ts","../src/csg/core/math/IsMirrot.ts","../src/csg/core/constants.ts","../src/csg/core/math/Vector3.ts","../src/csg/core/math/Vector2.ts","../src/csg/core/math/Vertex3.ts","../src/csg/core/math/Plane.ts","../src/csg/core/math/Polygon3.ts","../src/csg/core/trees.ts","../src/csg/core/FuzzyFactory.ts","../src/csg/core/FuzzyFactory3d.ts","../src/csg/core/utils/canonicalize.ts","../src/csg/core/utils/csgMeasurements.ts","../src/csg/core/utils.ts","../src/csg/core/math/Line2.ts","../src/csg/core/math/OrthoNormalBasis.ts","../src/csg/core/math/reTesselateCoplanarPolygons.ts","../src/csg/core/utils/retesellate.ts","../src/csg/core/CSG.ts","../src/csg/core/Geometry2CSG.ts","../src/Geometry/BSPGroupParse.ts","../src/Geometry/ExtrudeEdgeGeometry.ts","../src/Geometry/ExtrudeEdgeGeometry2.ts","../src/Geometry/OBB/obb.ts","../src/DatabaseServices/Spline.ts","../src/DatabaseServices/Entity/Extrude.ts","../src/DatabaseServices/Entity/CompositeEntity.ts","../src/UI/Store/WineRackInterface.ts","../src/UI/Store/BoardFindInterface.ts","../src/UI/Store/LatticeInterface.ts","../src/UI/Store/DoorInterface.ts","../src/UI/Components/RightPanel/RightPanelInterface.ts","../src/Editor/DefaultConfig.ts","../src/DatabaseServices/Hardware/HardwareCompositeEntity.ts","../src/Geometry/PointShapeUtils.ts","../src/DatabaseServices/Entity/Board.ts","../src/Geometry/CreateWireframe.ts","../src/DatabaseServices/3DSolid/Hole.ts","../src/DatabaseServices/3DSolid/ExtrudeHole.ts","../src/Geometry/DrillParse/BoardGetFace.ts","../src/Nest/Common/Util.ts","../src/DatabaseServices/3DSolid/CylinderHole.ts","../src/Geometry/SweepGeometry.ts","../src/DatabaseServices/3DSolid/SweepSolid.ts","../src/DatabaseServices/Hardware/HardwareTopline.ts","../src/Common/Toaster.ts","../src/Add-on/LookOverBoardInfos/LookOverBoardInfosTool.ts","../src/Production/Product.ts","../src/GraphicsSystem/CalcEdgeSealing.ts","../src/GraphicsSystem/ToolPath/OptimizeToolPath.ts","../src/GraphicsSystem/ToolPath/FeedingToolPath.ts","../src/Add-on/testEntity/SimplifyPolyline.ts"],"sourcesContent":["\r\n/**\r\n * CAD对象工厂,通过注册 和暴露的创建方法,动态创建对象\r\n */\r\nexport class CADFactory\r\n{\r\n private constructor() { }\r\n private objectNameMap = new Map();\r\n private static factory = new CADFactory();\r\n static RegisterObject(C: any)\r\n {\r\n this.factory.objectNameMap.set(C.name, C);\r\n }\r\n static RegisterObjectAlias(C: any, name: string)\r\n {\r\n this.factory.objectNameMap.set(name, C);\r\n }\r\n static CreateObject(name: string): any\r\n {\r\n let C = this.factory.objectNameMap.get(name);\r\n if (C) return new C();\r\n }\r\n}\r\n\r\n//可以通过添加装饰器 在类前面(@Factory),自动注册工厂的序列化\r\nexport function Factory(target: Object)\r\n{\r\n CADFactory.RegisterObject(target);\r\n}\r\n","import { Factory } from './CADFactory';\r\nimport { CADFiler } from './CADFiler';\r\nimport { ISerialize } from './ISerialize';\r\nimport { CADObject } from './CADObject';\r\n\r\n/**\r\n * 保存对象创建或者修改时的所有数据记录\r\n */\r\n@Factory\r\nexport class AllObjectData implements ISerialize\r\n{\r\n file: CADFiler;\r\n constructor(obj?: CADObject)\r\n {\r\n this.file = new CADFiler();\r\n if (obj)\r\n obj.WriteFile(this.file);\r\n }\r\n //#region -------------------------File-------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n //对象从文件中读取数据,初始化自身\r\n ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();\r\n let data = file.Read();\r\n this.file.Data = data;\r\n return this;\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(1);\r\n file.Write(this.file.Data);\r\n return this;\r\n }\r\n}\r\n","\r\n\r\nexport const ISPROXYKEY = \"_isProxy\";\r\n\r\n/**\r\n * 自动对CADObject的属性添加属性记录器,自动调用 `WriteAllObjectRecord`\r\n * 如果属性是数组,那么自动添加`Proxy`.\r\n * 可以使用`ISPROXYKEY`覆盖这个函数的代理行为(使用CADObject.CreateProxyArray快速覆盖)\r\n *\r\n * @param target\r\n * @param property\r\n * @param [descriptor]\r\n */\r\nexport function AutoRecord(\r\n target: { WriteAllObjectRecord: () => void; },\r\n property: string,\r\n descriptor?: PropertyDecorator)\r\n{\r\n let privateKey = '__' + property;\r\n Object.defineProperty(target, property,\r\n {\r\n set: function (value)\r\n {\r\n if (value instanceof Array)\r\n {\r\n if (!this[privateKey])\r\n {\r\n if (value[ISPROXYKEY])\r\n this[privateKey] = value;\r\n else\r\n this[privateKey] = new Proxy(value, {\r\n set: (target, key, value, receiver) =>\r\n {\r\n if (Reflect.get(target, key, receiver) !== value)\r\n this.WriteAllObjectRecord();\r\n return Reflect.set(target, key, value, receiver);\r\n },\r\n get: (target, key, receiver) =>\r\n {\r\n if (key === ISPROXYKEY)\r\n return true;\r\n //实体先被删除后在触发length = xxx\r\n if (key === \"splice\" || key === \"pop\" || key === \"shift\")\r\n this.WriteAllObjectRecord();\r\n return Reflect.get(target, key, receiver);\r\n }\r\n });\r\n }\r\n else\r\n {\r\n let arr = this[privateKey] as Array;\r\n arr.length = 0;\r\n arr.push(...value);\r\n }\r\n }\r\n else\r\n {\r\n let oldv = this[privateKey];\r\n if (oldv !== value)\r\n {\r\n this.WriteAllObjectRecord();\r\n this[privateKey] = value;\r\n }\r\n }\r\n },\r\n get: function ()\r\n {\r\n return this[privateKey];\r\n },\r\n enumerable: true,\r\n configurable: true\r\n }\r\n );\r\n}\r\n","import { Factory } from './CADFactory';\r\nimport { CADFiler } from './CADFiler';\r\nimport { ISerialize } from './ISerialize';\r\n@Factory\r\nexport class EraseEntityData implements ISerialize\r\n{\r\n ReadFile(file: CADFiler): this\r\n {\r\n this.isErase = file.Read();\r\n return this;\r\n }\r\n WriteFile(file: CADFiler): this\r\n {\r\n file.Write(this.isErase);\r\n return this;\r\n }\r\n constructor(public isErase = true)\r\n {\r\n }\r\n}\r\n","import { iaop } from 'xaop';\r\nimport { AllObjectData } from './AllObjectData';\r\nimport { ISPROXYKEY } from './AutoRecord';\r\nimport { CADFactory } from './CADFactory';\r\nimport { CADFiler } from './CADFiler';\r\nimport { CommandHistoryRecord } from './CommandHistoryRecord';\r\nimport { Database } from './Database';\r\nimport { EraseEntityData } from './EraseEntityData';\r\nimport { ISerialize } from './ISerialize';\r\nimport { ObjectId } from './ObjectId';\r\n\r\nexport abstract class CADObject\r\n{\r\n protected _Owner: ObjectId;\r\n /**\r\n * 用于储存临时数据\r\n */\r\n public TempData: any;\r\n\r\n //下面的三个数据由Rect2Board使用\r\n __CacheBox__: any;\r\n __CacheBoard__: any;\r\n __CacheSize__: any;\r\n __CachePolyline__: any;\r\n\r\n set Owner(owner: ObjectId)\r\n {\r\n this._Owner = owner;\r\n }\r\n get Owner()\r\n {\r\n return this._Owner;\r\n }\r\n\r\n Destroy()\r\n {\r\n //在效果图同步反应器中,需要知道被删除的实体的id,所以不删除这个属性\r\n // this.objectId = undefined;\r\n this._db = undefined;\r\n }\r\n\r\n //对象被彻底遗弃\r\n GoodBye(): any\r\n {\r\n this.Destroy();\r\n this.Erase(true);\r\n }\r\n\r\n /**\r\n * 当实体异步更新绘制实体完成后触发这个函数.\r\n * Application通过注入的方式得知这个事件,刷新视图显示.\r\n */\r\n @iaop\r\n AsyncUpdated()\r\n {\r\n }\r\n\r\n //-------------------------DB-------------------------\r\n protected _db: Database;\r\n get Db(): Database\r\n {\r\n return this._db;\r\n }\r\n\r\n //对象在加入数据库时,必须指定一个源数据库,否则无法读取引用id.\r\n SetDefaultDb(db: Database)\r\n {\r\n if (!this._db)\r\n this._db = db;\r\n else\r\n console.warn(\"重复设置默认Database!\");\r\n\r\n return this;\r\n }\r\n\r\n //private 私有的方法,暴露给Db的添加对象,方法使用.\r\n //只用对象加入到db中,我们才初始化ObjectId.\r\n //从db池中分配id给自身使用. 除非你创建对象往db里面加,否则不要调用该方法\r\n SetOwnerDatabase(db: Database)\r\n {\r\n if (!this._db)\r\n {\r\n this._db = db;\r\n this.objectId = db.AllocateId();\r\n this.objectId.Object = this;\r\n }\r\n else\r\n console.warn(\"重复设置源Database!\");\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * WblockClone 的时候,id是db分配的,此刻我们只需要设置它的db\r\n */\r\n SetDatabase(db: Database)\r\n {\r\n this._db = db;\r\n }\r\n\r\n //-------------------------DB End-------------------------\r\n\r\n // -------------------------isErase-------------------------\r\n protected _isErase: boolean = false;\r\n get IsErase(): boolean\r\n {\r\n return this._isErase;\r\n }\r\n Erase(isErase: boolean = true)\r\n {\r\n if (isErase === this._isErase)\r\n return;\r\n let undoData = this.UndoRecord();\r\n if (undoData)\r\n undoData.CreateEraseHistory(this, isErase);\r\n this._isErase = isErase;\r\n }\r\n //-------------------------isErase End-------------------------\r\n\r\n // -------------------------id-------------------------\r\n\r\n //操作这个需要谨慎!\r\n objectId: ObjectId;\r\n\r\n get Id(): ObjectId\r\n {\r\n return this.objectId;\r\n }\r\n\r\n // -------------------------id End-------------------------\r\n\r\n // -------------------------File-------------------------\r\n\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n //对象从文件中读取数据,初始化自身\r\n ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();\r\n //write Id;\r\n let id = file.ReadObjectId();\r\n if (!this.objectId && id)//避免CopyFrom时错误的修改自身Id\r\n {\r\n this.objectId = id;\r\n id.Object = this;\r\n }\r\n this._isErase = file.Read();\r\n if (ver > 1)\r\n this.Owner = file.ReadObjectId();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(2);\r\n file.WriteObjectId(this.objectId);\r\n file.Write(this._isErase);\r\n file.WriteObjectId(this.Owner);\r\n }\r\n //局部撤销\r\n ApplyPartialUndo(undoData: ISerialize)\r\n {\r\n if (undoData instanceof AllObjectData)\r\n {\r\n undoData.file.database = this._db;\r\n undoData.file.Reset();\r\n this.ReadFile(undoData.file);\r\n }\r\n else if (undoData instanceof EraseEntityData)\r\n {\r\n this.Erase(undoData.isErase);\r\n }\r\n }\r\n\r\n //撤销所保存的位置\r\n UndoRecord(): CommandHistoryRecord\r\n {\r\n if (this._db && this.objectId)\r\n return this._db.hm.UndoData;\r\n }\r\n //写入所有的对象数据 以便还原对象\r\n WriteAllObjectRecord(): boolean\r\n {\r\n let undoData = this.UndoRecord();\r\n if (undoData)\r\n {\r\n undoData.WriteObjectSnapshoot(this);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n //复制出一个实体,如果存在关联,则指向原关联实体\r\n Clone(): this\r\n {\r\n let newObject = CADFactory.CreateObject(this.constructor.name) as this;\r\n\r\n //备份\r\n let bakId = this.objectId;\r\n this.objectId = undefined;\r\n\r\n let file = new CADFiler();\r\n file.database = this._db;\r\n this.WriteFile(file);\r\n file.Reset();\r\n newObject.ReadFile(file);\r\n\r\n newObject.objectId = undefined;\r\n newObject._db = undefined;\r\n\r\n this.objectId = bakId;\r\n return newObject;\r\n }\r\n\r\n DeepClone(\r\n ownerObject: CADObject,\r\n cloneObejct: CADObject,\r\n idMaping: Map = undefined,\r\n isPrimary = true\r\n ): this\r\n {\r\n return this;\r\n }\r\n\r\n //从一个实体拷贝数据,实体类型必须相同.\r\n CopyFrom(obj: CADObject)\r\n {\r\n let idBak = this.objectId;\r\n let ownerBak = this._Owner;\r\n this.WriteAllObjectRecord();\r\n let f = new CADFiler();\r\n obj.WriteFile(f);\r\n this.ReadFile(f);\r\n this.objectId = idBak;\r\n this._Owner = ownerBak;\r\n }\r\n\r\n //-------------------------File End-------------------------\r\n\r\n //Utils\r\n /**\r\n * 配合 `@AutoRecord` 使用\r\n * 使用这个方法来覆盖AutoRecord的监听行为.\r\n * 这个行为只能用来监听实体添加和实体修改.\r\n * 实体删除行为暂时无法监听\r\n * @param setCallback 设置新的实体到数组时的回调函数\r\n */\r\n protected CreateProxyArray(setCallback: (v: any) => void)\r\n {\r\n return new Proxy([], {\r\n set: (target, key, value, receiver) =>\r\n {\r\n if (Reflect.get(target, key, receiver) !== value)\r\n {\r\n this.WriteAllObjectRecord();\r\n setCallback(value);\r\n }\r\n return Reflect.set(target, key, value, receiver);\r\n },\r\n get: (target, key, receiver) =>\r\n {\r\n if (key === ISPROXYKEY)\r\n return true;\r\n //实体先被删除后在触发length = xxx\r\n if (key === \"splice\" || key === \"pop\" || key === \"shift\")\r\n {\r\n this.WriteAllObjectRecord();\r\n setCallback(undefined);\r\n }\r\n return Reflect.get(target, key, receiver);\r\n }\r\n });\r\n }\r\n}\r\n","import { CADObject } from './CADObject';\r\n\r\nexport enum RelevancyType\r\n{\r\n General = 0,\r\n Soft = 1,\r\n Hard = 2,\r\n}\r\n\r\n/*\r\nCADObject对象拥有Id属性,用来记录引用关系.\r\n通过id可以得到对应的关联实体,或者记录实体的关联关系.\r\n\r\nObjectId必须使用 Database分配(db里面会存id的列表,以便同时更新id指向实体)\r\n\r\n*/\r\nexport class ObjectId\r\n{\r\n _RelevancyType = RelevancyType.General;\r\n constructor(private index = 0, private obj?: CADObject)\r\n {\r\n }\r\n\r\n get IsErase(): boolean\r\n {\r\n return !this.obj || this.obj.IsErase;\r\n }\r\n set Object(obj: CADObject)\r\n {\r\n this.obj = obj;\r\n }\r\n get Object(): CADObject\r\n {\r\n return this.obj;\r\n }\r\n get Index(): number\r\n {\r\n return this.index;\r\n }\r\n set Index(index: number)\r\n {\r\n this.index = index;\r\n }\r\n}\r\n","import { ApplicationService } from './Application';\r\nimport { MeshBasicMaterial, MeshStandardMaterial } from 'three';\r\n\r\ninterface IHostApplicationServices\r\n{\r\n Application?: ApplicationService;\r\n DefaultMeshMaterial?: MeshBasicMaterial | MeshStandardMaterial;\r\n UseShadow?: boolean;\r\n ShowHistoryLog?: boolean;\r\n}\r\n\r\nexport let HostApplicationServices: IHostApplicationServices = { ShowHistoryLog: true };\r\n","import { Object3D } from \"three\";\r\n\r\n/**\r\n * 销毁Object对象的Geometry,并不会销毁材质(新版本销毁材质,好像问题不大?)\r\n */\r\nexport function DisposeThreeObj(obj: Object3D)\r\n{\r\n for (let o of obj.children)\r\n {\r\n let oany = o as any;\r\n //文字的geometry缓存保留下来\r\n if (oany.geometry && oany.geometry.name !== \"Text\")\r\n oany.geometry.dispose();\r\n\r\n if (oany.material)\r\n oany.material.dispose();\r\n\r\n DisposeThreeObj(o);\r\n\r\n // 下面这个代码可能导致Object3d无法复用,删除它应该问题不大\r\n // o.parent = null;\r\n // o.dispatchEvent({ type: \"removed\" });\r\n }\r\n // 下面这个代码可能导致Object3d无法复用,删除它应该问题不大\r\n // obj.children.length = 0;\r\n return obj;\r\n}\r\n\r\nexport function Object3DRemoveAll(obj: Object3D)\r\n{\r\n for (let o of obj.children)\r\n {\r\n o.parent = null;\r\n o.dispatchEvent({ type: \"removed\" });\r\n }\r\n obj.children.length = 0;\r\n return obj;\r\n}\r\n","import { Matrix4, Vector3 } from 'three';\r\n\r\n/**\r\n * 坐标系运算.\r\n */\r\nexport class CoordinateSystem\r\n{\r\n Postion: Vector3;\r\n XAxis: Vector3;\r\n YAxis: Vector3;\r\n ZAxis: Vector3;\r\n\r\n constructor(postion?: Vector3, xAxis?: Vector3, yAxis?: Vector3, zAxis?: Vector3)\r\n {\r\n this.Postion = postion || new Vector3(0, 0, 0);\r\n this.XAxis = xAxis || new Vector3(1, 0, 0);\r\n this.YAxis = yAxis || new Vector3(0, 1, 0);\r\n this.ZAxis = zAxis || new Vector3(0, 0, 1);\r\n }\r\n\r\n applyMatrix4(mat4: Matrix4)\r\n {\r\n this.Postion.applyMatrix4(mat4);\r\n let roMat = mat4.clone().setPosition(new Vector3());\r\n this.XAxis.applyMatrix4(roMat);\r\n this.YAxis.applyMatrix4(roMat);\r\n this.ZAxis.applyMatrix4(roMat);\r\n return this;\r\n }\r\n\r\n getMatrix4(): Matrix4\r\n {\r\n let m = new Matrix4();\r\n m.makeBasis(this.XAxis, this.YAxis, this.ZAxis);\r\n m.setPosition(this.Postion);\r\n return m;\r\n }\r\n CopyForm(mat4: Matrix4)\r\n {\r\n this.Postion.setFromMatrixPosition(mat4);\r\n mat4.extractBasis(this.XAxis, this.YAxis, this.ZAxis);\r\n return this;\r\n }\r\n\r\n extractBasis(xAxisA: Vector3, yAxisA: Vector3, zAxisA: Vector3)\r\n {\r\n xAxisA.copy(this.XAxis);\r\n yAxisA.copy(this.YAxis);\r\n zAxisA.copy(this.ZAxis);\r\n }\r\n copy(cs: CoordinateSystem): CoordinateSystem\r\n {\r\n this.Postion.copy(cs.Postion);\r\n this.XAxis.copy(cs.XAxis);\r\n this.YAxis.copy(cs.YAxis);\r\n this.ZAxis.copy(cs.ZAxis);\r\n return this;\r\n }\r\n clone()\r\n {\r\n let r = new CoordinateSystem();\r\n r.Postion = this.Postion.clone();\r\n r.XAxis = this.XAxis.clone();\r\n r.YAxis = this.YAxis.clone();\r\n r.ZAxis = this.ZAxis.clone();\r\n return r;\r\n }\r\n}\r\n","import { equaln } from \"../Geometry/GeUtils\";\r\nimport { clamp as CLAMP, FixedNotZero } from \"./Utils\";\r\n\r\nlet abs = Math.abs;\r\nlet acos = Math.acos;\r\nlet acosh = Math.acosh;\r\nlet asin = Math.asin;\r\nlet asinh = Math.asinh;\r\nlet atan = Math.atan;\r\nlet atanh = Math.atanh;\r\nlet atan2 = Math.atan2;\r\nlet ceil = Math.ceil;\r\nlet cbrt = Math.cbrt;\r\nlet expm1 = Math.expm1;\r\nlet clz32 = Math.clz32;\r\nlet cos = Math.cos;\r\nlet cosh = Math.cosh;\r\nlet exp = Math.exp;\r\nlet floor = Math.floor;\r\nlet fround = Math.fround;\r\nlet hypot = Math.hypot;\r\nlet imul = Math.imul;\r\nlet log = Math.log;\r\nlet log1p = Math.log1p;\r\nlet log2 = Math.log2;\r\nlet log10 = Math.log10;\r\nlet max = Math.max;\r\nlet min = Math.min;\r\nlet pow = Math.pow;\r\nlet random = Math.random;\r\nlet round = Math.round;\r\nlet sign = Math.sign;\r\nlet sin = Math.sin;\r\nlet sinh = Math.sinh;\r\nlet sqrt = Math.sqrt;\r\nlet tan = Math.tan;\r\nlet tanh = Math.tanh;\r\nlet trunc = Math.trunc;\r\nlet E = Math.E;\r\nlet LN10 = Math.LN10;\r\nlet LN2 = Math.LN2;\r\nlet LOG10E = Math.LOG10E;\r\nlet LOG2E = Math.LOG2E;\r\nlet PI = Math.PI;\r\nlet SQRT1_2 = Math.SQRT1_2;\r\nlet SQRT2 = Math.SQRT2;\r\nlet clamp = CLAMP;\r\nlet eq = equaln;\r\n\r\nlet OPERATORS = new Set([\"+\", \"-\", \"*\", \"/\"]);\r\n\r\n/**\r\n * eval2(\"+10\", { L: 100 }, \"L\")\r\n * @param expr\r\n * @param [params]\r\n * @param [defaultParam] 当输入 +10 这样的表达式时,设置默认的操作变量\r\n * @returns 计算结果\r\n */\r\nexport function eval2(expr: string, params?: {}, defaultParam?: string): number\r\n{\r\n let code = \"\";\r\n if (params)\r\n for (let name in params)\r\n code += `let ${name} = ${params[name]};`;\r\n\r\n if (defaultParam)\r\n {\r\n expr = expr.trimLeft();\r\n if (expr[0] && OPERATORS.has(expr[0]))\r\n expr = defaultParam + expr;\r\n }\r\n\r\n code += expr;\r\n\r\n let result = eval(code);\r\n\r\n if (typeof result === \"function\")\r\n return result();\r\n\r\n return Number(result);//防止bigint乱入\r\n}\r\n\r\nexport function safeEval(expr: string, params?: {}, defaultParam?: string): number\r\n{\r\n try\r\n {\r\n return eval2(expr, params);\r\n }\r\n catch (error)\r\n {\r\n return NaN;\r\n }\r\n}\r\n\r\nexport function CheckExpr(expr: string, params: any)\r\n{\r\n let resultObj = { res: undefined, error: undefined };\r\n try\r\n {\r\n resultObj.res = eval2(expr, params);\r\n }\r\n catch (error)\r\n {\r\n resultObj.error = error;\r\n }\r\n return resultObj;\r\n}\r\n\r\nconst Reg_Expr = /\\{[^\\}]+\\}/g;\r\n/**解析大括号内的 */\r\nexport function ParseExpr(expr: string, params?: {})\r\n{\r\n let strs = expr.match(Reg_Expr);\r\n if (!strs) return expr;\r\n for (let str of strs)\r\n expr = expr.replace(str, FixedNotZero(safeEval(str.slice(1, -1), params), 2));\r\n return expr;\r\n}\r\n","export enum StoreageKeys\r\n{\r\n IsLogin = \"isLogin\",\r\n PlatSession = \"platSession\",\r\n PlatToken = \"platToken\",\r\n UserName = \"userName\",\r\n UserPhone = \"userPhone\",\r\n RenderType = \"renderType\",\r\n ExactDrill = \"openExactDrill\",\r\n ConfigName = \"configName_\",\r\n IsNewErp = \"isNewErp\",\r\n RoomName = \"roomName\",\r\n LastOpenFileId = \"lastfid\",\r\n Uid = \"uid\",\r\n Goods = \"Goods_\",\r\n DrillTemp = \"drilltemp_\",\r\n DrillReactor = \"drillRreactor\",\r\n kjlConfig = \"kjl\",\r\n}\r\n","import { Object3D } from \"three\";\r\nimport { Entity } from \"../DatabaseServices/Entity/Entity\";\r\nimport { equaln } from \"../Geometry/GeUtils\";\r\nimport { safeEval } from \"./eval\";\r\nimport { StoreageKeys } from \"./StoreageKeys\";\r\nimport { ObjectId } from \"../DatabaseServices/ObjectId\";\r\n\r\n//仅数字构成的3位字符串(不以0开头)\r\nexport const digitStrReg = /^[^0\\D]\\d{0,2}$/;\r\nexport const commandReg = /[^A-Za-z0-9]/g;\r\n//仅可输入英文\r\nexport const onlyEnExpReg = /[^A-Za-z]/g;\r\n/**替换收口条柜名后缀 */\r\nexport const ClosingStripReg = /[左|右|上]{1}收口$/;\r\nexport const FileFormatReg = /^\\[(\\d+,){5}[(true)|(false)].+\\]$/;\r\n\r\n/**扣除封边是否相连和连接共用精度 */\r\nexport const LINK_FUZZ = 1e-3;\r\n\r\nexport function IsNumber(keyCode: number)\r\n{\r\n return (keyCode >= 48 && keyCode <= 57) || (keyCode >= 96 && keyCode <= 105);\r\n}\r\nexport function IsChar(keyCode: number)\r\n{\r\n return keyCode >= 65 && keyCode <= 90;\r\n}\r\nexport function isLetter(s: string)\r\n{\r\n let code = s.charCodeAt(0);\r\n return (code >= 97 && code <= 122) || (code >= 65 && code <= 90);\r\n}\r\nexport function isNum(s: string)\r\n{\r\n return !isNaN(safeEval(s));\r\n}\r\n\r\nexport function clamp(value: number, min: number, max: number)\r\n{\r\n return Math.max(min, Math.min(max, value));\r\n}\r\n\r\nexport function FixIndex(index: number, arr: Array | number)\r\n{\r\n let count = (arr instanceof Array) ? arr.length : arr;\r\n if (index < 0)\r\n return count + index;\r\n else if (index >= count)\r\n return index - count;\r\n else\r\n return index;\r\n}\r\n//格式化日期\r\nexport function formateDate(date: Date, fmt: string)\r\n{\r\n let o = {\r\n \"M+\": date.getMonth() + 1, //月份\r\n \"d+\": date.getDate(), //日\r\n \"h+\": date.getHours(), //小时\r\n \"m+\": date.getMinutes(), //分\r\n \"s+\": date.getSeconds(), //秒\r\n \"q+\": Math.floor((date.getMonth() + 3) / 3), //季度\r\n \"S\": date.getMilliseconds() //毫秒\r\n };\r\n //如:yyyy\r\n if (/(y+)/.test(fmt))\r\n {\r\n fmt = fmt.replace(RegExp.$1, (date.getFullYear().toString()).substr(4 - RegExp.$1.length));\r\n }\r\n //yyyy-MM-dd hh:mm:ss\r\n for (let k in o)\r\n {\r\n if (new RegExp(\"(\" + k + \")\").test(fmt))\r\n {\r\n fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((\"00\" + o[k]).substr((\"\" + o[k]).length)));\r\n }\r\n }\r\n return fmt;\r\n}\r\n\r\n//判断v在v1和v2之间.(v1>v2 or v2>v1)\r\nexport function isBetweenNums(v1: number, v2: number, v: number, fuzz = 1e-8)\r\n{\r\n if (v1 > v2) [v1, v2] = [v2, v1];\r\n return equaln(v, clamp(v, v1, v2), fuzz);\r\n}\r\n\r\n//深复制对象数组\r\nexport function sliceDeep(arr: object[], start?: number, end?: number): object[]\r\n{\r\n return arr.slice(start, end).map((obj) => Object.assign({}, obj));\r\n}\r\n\r\nfunction fallbackCopyTextToClipboard(text)\r\n{\r\n let textArea = document.createElement(\"textarea\");\r\n textArea.value = text;\r\n document.body.appendChild(textArea);\r\n textArea.focus();\r\n textArea.select();\r\n\r\n try\r\n {\r\n let successful = document.execCommand('copy');\r\n } catch (err)\r\n {\r\n }\r\n document.body.removeChild(textArea);\r\n}\r\nexport async function copyTextToClipboard(text: string)\r\n{\r\n if (!navigator[\"clipboard\"])\r\n {\r\n fallbackCopyTextToClipboard(text);\r\n return;\r\n }\r\n return await navigator[\"clipboard\"].writeText(text);\r\n}\r\n\r\n//ref: https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript\r\n\r\n/**\r\n * 读取剪切板的字符串\r\n */\r\nexport async function readClipboardText()\r\n{\r\n if (navigator[\"clipboard\"])\r\n return await navigator[\"clipboard\"].readText();\r\n return \"\";\r\n}\r\n\r\n//使用定点表示法来格式化一个数,小数点后面不尾随0. 如 FixedNotZero(1.1 , 3) => 1.1\r\nexport function FixedNotZero(v: number | string, fractionDigits: number = 0)\r\n{\r\n if (typeof v === \"string\")\r\n v = parseFloat(v);\r\n if (isNaN(v)) return \"\";\r\n if (equaln(v, 0)) return \"0\";\r\n let str = v.toFixed(fractionDigits);\r\n let commonIndex = str.indexOf(\".\");\r\n if (commonIndex !== -1)\r\n {\r\n let zeroCount = 0;\r\n let strCount = str.length;\r\n for (let l = strCount; l--;)\r\n {\r\n if (str[l] === \"0\")\r\n zeroCount++;\r\n else\r\n break;\r\n }\r\n if (zeroCount > 0)\r\n {\r\n if (zeroCount === (strCount - commonIndex - 1))\r\n zeroCount++;\r\n return str.slice(0, strCount - zeroCount);\r\n }\r\n }\r\n return str;\r\n}\r\n\r\n/**\r\n * To fixed\r\n * @param v\r\n * @param [fractionDigits]\r\n * @returns\r\n */\r\nexport function ToFixed(v: number, fractionDigits: number = 5)\r\n{\r\n if (equaln(v, 0, Math.pow(0.1, fractionDigits))) return \"0\";\r\n return v.toFixed(fractionDigits);\r\n}\r\n\r\nexport function GetEntity(obj: Object3D): Entity | undefined\r\n{\r\n while (obj)\r\n {\r\n if (obj.userData.Entity)\r\n return obj.userData.Entity;\r\n\r\n obj = obj.parent;\r\n }\r\n}\r\n\r\nexport function IsEntity(obj: Object3D): boolean\r\n{\r\n return GetEntity(obj) instanceof Entity;\r\n}\r\n\r\nexport function IsNoErase(id: ObjectId): boolean\r\n{\r\n return id && !id.IsErase;\r\n}\r\n\r\n/**\r\n * 原图地址转换为对应缩略图地址\r\n */\r\nexport function getThumbsUrl(url: string)\r\n{\r\n return url ? url.replace(/\\/\\w*\\.\\w*$/, mat => \"/thumbs\" + mat.replace(\".\", \"_100.\")) : \"\";\r\n}\r\n\r\n/**\r\n * 快速判断a是不是被修改了\r\n */\r\nexport function equalObject(a: Object, b: Object)\r\n{\r\n for (let key in a)\r\n {\r\n if (a[key] !== b[key])\r\n return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport function cloneObject(a: T): T\r\n{\r\n return Object.assign({}, a);\r\n}\r\n\r\nexport function Uint8ArrayToBase64(bytes: Uint8Array)\r\n{\r\n let binary = \"\";\r\n let len = bytes.byteLength;\r\n for (let i = 0; i < len; i++)\r\n binary += String.fromCharCode(bytes[i]);\r\n return window.btoa(binary);\r\n}\r\n\r\n/**转换服务端获取的文件大小 */\r\nexport function getFileSize(size: number)\r\n{\r\n let units = [\"B\", \"KB\", \"MB\", \"GB\"];\r\n for (let u of units)\r\n {\r\n if (size > 1 && size < 1024)\r\n return FixedNotZero(size, 2) + u;\r\n else\r\n size /= 1024;\r\n }\r\n}\r\n\r\nexport function GetIndexDBID(id: string)\r\n{\r\n return localStorage.getItem(StoreageKeys.Uid) + \":\" + id;\r\n}\r\n\r\nexport function FixDigits(v: number, fractionDigits = 2)\r\n{\r\n return parseFloat(v.toFixed(fractionDigits));\r\n}\r\n","import { Box3, BufferGeometry, Geometry, Line, Matrix4, Mesh, Object3D, Vector, Vector2, Vector3 } from 'three';\r\nimport { ToFixed } from '../Common/Utils';\r\n\r\nexport const IdentityMtx4 = new Matrix4();\r\nexport const ZeroVec = new Vector3();\r\nexport const XAxis = new Vector3(1, 0, 0);\r\nexport const XAxisN = new Vector3(-1, 0, 0);\r\nexport const YAxis = new Vector3(0, 1, 0);\r\nexport const YAxisN = new Vector3(0, -1, 0);\r\nexport const ZAxis = new Vector3(0, 0, 1);\r\n\r\nexport function AsVector2(p: { x: number, y: number; })\r\n{\r\n return new Vector2(p.x, p.y);\r\n}\r\nexport function AsVector3(p: { x: number, y: number, z?: number; })\r\n{\r\n return new Vector3(p.x, p.y, p.z);\r\n}\r\n\r\n/**\r\n * 判断一维线段a和b是否存在交集\r\n */\r\nexport function isIntersect(amin: number, amax: number, bmin: number, bmax: number, eps = 0)\r\n{\r\n return Math.max(amin, bmin) < Math.min(amax, bmax) + eps;\r\n}\r\n\r\nexport function isIntersect2(a1: number, a2: number, b1: number, b2: number, eps = 0)\r\n{\r\n if (a1 > a2) [a1, a2] = [a2, a1];\r\n if (b1 > b2) [b1, b2] = [b2, b1];\r\n return Math.max(a1, b1) < Math.min(a2, b2) + eps;\r\n}\r\n\r\n/**\r\n * 旋转一个点,旋转中心在原点\r\n * @param {Vector3} p 点\r\n * @param {number} a 角度.\r\n * @returns {Vector3} 返回pt不拷贝.\r\n */\r\nexport function rotatePoint(p: Vector3, a: number): Vector3\r\n{\r\n let s = Math.sin(a);\r\n let c = Math.cos(a);\r\n\r\n let x = p.x * c - p.y * s;\r\n let y = p.x * s + p.y * c;\r\n\r\n p.x = x;\r\n p.y = y;\r\n return p;\r\n}\r\n\r\nexport function equaln(v1: number, v2: number, fuzz = 1e-5)\r\n{\r\n return Math.abs(v1 - v2) <= fuzz;\r\n}\r\n\r\nexport function equalnn(dis = 5)\r\n{\r\n let fuzz = 0.1 ** dis;\r\n return function (v1: number, v2: number)\r\n {\r\n return Math.abs(v1 - v2) <= fuzz;\r\n };\r\n}\r\n\r\ninterface P2\r\n{\r\n x: number; y: number;\r\n}\r\n\r\nexport function equalv3(v1: Vector3, v2: Vector3, fuzz = 1e-8)\r\n{\r\n return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz) && equaln(v1.z, v2.z, fuzz);\r\n}\r\nexport function equalv2(v1: P2, v2: P2, fuzz = 1e-8)\r\n{\r\n return equaln(v1.x, v2.x, fuzz) && equaln(v1.y, v2.y, fuzz);\r\n}\r\n\r\n/**\r\n * 按照极坐标的方式移动一个点\r\n *\r\n * @export\r\n * @template\r\n * @param {T} v 向量(2d,3d)\r\n * @param {number} an 角度\r\n * @param {number} dis 距离\r\n * @returns {T}\r\n */\r\nexport function polar(v: T, an: number, dis: number): T\r\n{\r\n v.x += Math.cos(an) * dis;\r\n v.y += Math.sin(an) * dis;\r\n return v;\r\n}\r\n\r\nexport function angle(v: Vector3 | Vector2)\r\n{\r\n let angle = Math.atan2(v.y, v.x);\r\n if (equaln(angle, 0, 1e-8)) return 0;\r\n if (angle < 0) angle += Math.PI * 2;\r\n return angle;\r\n}\r\n\r\n/**\r\n * 求两个向量的夹角,顺时针为负,逆时针为正\r\n *\r\n * @param {Vector3} v1\r\n * @param {Vector3} v2\r\n * @param {Vector3} [ref] 参考向量,如果为世界坐标系则为0,0,1\r\n * @returns\r\n */\r\nexport function angleTo(v1: Vector3, v2: Vector3, ref: Vector3 = new Vector3(0, 0, 1))\r\n{\r\n if (!ref.equals(new Vector3(0, 0, 1)))\r\n {\r\n ref = ref.clone();\r\n v1 = v1.clone();\r\n v2 = v2.clone();\r\n //任意轴坐标系. 使用相机的构造矩阵.\r\n ref.multiplyScalar(-1);\r\n let up = getLoocAtUpVec(ref);\r\n let refOcs = new Matrix4();\r\n refOcs.lookAt(ZeroVec, ref, up);\r\n let refOcsInv = new Matrix4().getInverse(refOcs);\r\n v1.applyMatrix4(refOcsInv);\r\n v2.applyMatrix4(refOcsInv);\r\n v1.z = 0;\r\n v2.z = 0;\r\n }\r\n if (v1.equals(ZeroVec) || v2.equals(ZeroVec))\r\n return 0;\r\n let cv = new Vector3().crossVectors(v1, v2).normalize();\r\n return cv.z === 0 ? v1.angleTo(v2) : v1.angleTo(v2) * cv.z;\r\n}\r\n\r\nexport function getLoocAtUpVec(dir: Vector3): Vector3\r\n{\r\n if (dir.equals(ZeroVec))\r\n {\r\n throw (\"zero vector\");\r\n }\r\n let norm = dir.clone().normalize();\r\n if (norm.equals(ZAxis))\r\n {\r\n return new Vector3(0, 1, 0);\r\n }\r\n else if (norm.equals(ZAxis.clone().negate()))\r\n {\r\n return new Vector3(0, -1, 0);\r\n }\r\n else\r\n {\r\n let xv: Vector3 = new Vector3();\r\n xv.crossVectors(ZAxis, norm);\r\n\r\n let up = new Vector3();\r\n up.crossVectors(norm, xv);\r\n return up;\r\n }\r\n}\r\n\r\nexport function createLookAtMat4(dir: Vector3): Matrix4\r\n{\r\n let up = getLoocAtUpVec(dir);\r\n let mat = new Matrix4();\r\n mat.lookAt(ZeroVec, dir, up);\r\n return mat;\r\n}\r\n\r\n/**\r\n * 判断2个向量是不是平行,尽量传入单位向量,才能保证计算精度\r\n */\r\nexport function isParallelTo(v1: Vector3, v2: Vector3, fuzz = 1e-8): boolean\r\n{\r\n return v1.clone().cross(v2).lengthSq() < fuzz;\r\n}\r\n\r\n/**\r\n * 垂直向量\r\n */\r\nexport function isPerpendicularityTo(v1: Vector3, v2: Vector3, fuzz = 1e-8)\r\n{\r\n return equaln(v1.dot(v2), 0, fuzz);\r\n}\r\n\r\nexport function ptToString(v: Vector3, fractionDigits: number = 3): string\r\n{\r\n return v.toArray().map(o => ToFixed(o, fractionDigits)).join(\",\");\r\n}\r\n\r\nexport function midPoint(v1: Vector3, v2: Vector3): Vector3\r\n{\r\n return v1.clone().add(v2).multiplyScalar(0.5);\r\n}\r\nexport function midPoint2(v1: Vector2, v2: Vector2): Vector2\r\n{\r\n return v1.clone().add(v2).multiplyScalar(0.5);\r\n}\r\n\r\n/**\r\n * 获得Three对象的包围盒.\r\n * @param obj\r\n * @param [updateMatrix] 是否应该更新对象矩阵\r\n * @returns box\r\n */\r\nexport function GetBox(obj: Object3D, updateMatrix?: boolean): Box3\r\n{\r\n let box = new Box3();\r\n if (updateMatrix) obj.updateMatrixWorld(false);\r\n if (!obj.visible) return box;\r\n\r\n obj.traverseVisible(o =>\r\n {\r\n if (!o.visible) return;\r\n //@ts-ignore\r\n let geo = o.geometry as BufferGeometry;\r\n if (geo)\r\n {\r\n if (!geo.boundingBox)\r\n geo.computeBoundingBox();\r\n let geoBox = geo.boundingBox.clone().applyMatrix4(o.matrixWorld);\r\n if (geoBox.max.z > 1e5)\r\n console.log();\r\n box.union(geoBox);\r\n }\r\n });\r\n return box;\r\n}\r\n\r\nexport function GetBoxArr(arr: Array): Box3\r\n{\r\n let box = new Box3();\r\n for (let o of arr)\r\n {\r\n let b = GetBox(o);\r\n if (!b.isEmpty())\r\n box.union(b);\r\n }\r\n return box;\r\n}\r\n\r\nexport function MoveMatrix(v: Vector3): Matrix4\r\n{\r\n return new Matrix4().setPosition(v);\r\n}\r\n\r\n//获得输入点在2线组成的4个区间的位置\r\nexport function getPtPostion(sp: Vector3, ep: Vector3, c: Vector3, inPt: Vector3)\r\n{\r\n let l1 = sp.clone().sub(c);\r\n let l2 = ep.clone().sub(c);\r\n let l3 = l1.clone().negate();\r\n let l4 = l2.clone().negate();\r\n let inputLine = inPt.clone().sub(c);\r\n let ang1 = angleTo(l1, l2);\r\n let ang2 = Math.PI;\r\n let ang3 = ang2 + Math.abs(ang1);\r\n let inputAng = angleTo(l1, inputLine);\r\n if (ang1 * inputAng < 0)\r\n inputAng = (Math.PI * 2 - Math.abs(inputAng));\r\n ang1 = Math.abs(ang1);\r\n inputAng = Math.abs(inputAng);\r\n if (inputAng <= ang1)\r\n return { sp, ep };\r\n else if (inputAng > ang1 && inputAng <= ang2)\r\n return { sp: c.clone().add(l3), ep };\r\n else if (inputAng > ang2 && inputAng <= ang3)\r\n return { sp: c.clone().add(l3), ep: c.clone().add(l4) };\r\n else\r\n return { sp, ep: c.clone().add(l4) };\r\n}\r\nexport function angleAndX(v: Vector3 | Vector2)\r\n{\r\n return v.x ? Math.atan(v.y / v.x) : Math.PI / 2;\r\n}\r\n\r\n/**\r\n * 将角度调整为0-2pi之间\r\n */\r\nexport function clampRad(an: number)\r\n{\r\n an = an % (Math.PI * 2);\r\n if (an < 0) an += Math.PI * 2;\r\n return an;\r\n}\r\n\r\nexport function updateGeometry(l: Line | Mesh, geometry: Geometry | BufferGeometry)\r\n{\r\n let geo = l.geometry as Geometry;\r\n geo.dispose();\r\n l.geometry = geometry;\r\n geometry.computeBoundingSphere();\r\n}\r\n\r\nexport function UpdateBoundingSphere(obj: Object3D)\r\n{\r\n //@ts-ignore\r\n let geo = obj.geometry as Geometry;\r\n if (geo)\r\n geo.computeBoundingSphere();\r\n}\r\n\r\n\r\nexport type compareVectorFn = (v1: Vector, v2: Vector3) => number;\r\n\r\nconst comparePointCache: Map = new Map();\r\n\r\n/**\r\n * 构建返回一个用来排序的函数.根据key创建排序规则.\r\n *\r\n * 当key = \"xyz\" 时,点集按 x从小到大,y从小到大 z从小到大\r\n * key = \"X\" 时,点集按 x从大到小\r\n * 以此类推.\r\n *\r\n * 例子:\r\n * let pts:Vector3[] =...;\r\n * pts.sort(comparePoint(\"x\")); //x从小到大排序\r\n * pts.sort(comparePoint(\"zX\")); //z从小到大 x从大到小\r\n *\r\n * @export\r\n * @param {string} sortKey\r\n * @returns {compareVectorFn}\r\n */\r\nexport function comparePoint(sortKey: string): compareVectorFn\r\n{\r\n if (comparePointCache.has(sortKey))\r\n return comparePointCache.get(sortKey);\r\n\r\n let sortIndex = [];\r\n\r\n const keys = ['x', 'X', 'y', 'Y', 'z', 'Z'];\r\n for (let char of sortKey)\r\n {\r\n let index = keys.indexOf(char);\r\n\r\n let i2 = index / 2;\r\n let ci = Math.floor(i2);\r\n sortIndex.push([ci, i2 > ci ? 1 : -1]);\r\n }\r\n\r\n let compareFunction = (v1: Vector, v2: Vector3): number =>\r\n {\r\n if (!v1) return -1;\r\n if (!v2) return 1;\r\n for (let s of sortIndex)\r\n {\r\n let vv1 = v1.getComponent(s[0]);\r\n let vv2 = v2.getComponent(s[0]);\r\n if (equaln(vv1, vv2)) continue;\r\n if (vv2 > vv1) return s[1];\r\n else return -s[1];\r\n }\r\n return 0;\r\n };\r\n\r\n comparePointCache.set(sortKey, compareFunction);\r\n return compareFunction;\r\n}\r\n\r\n/**\r\n *计算各轴旋转角度\r\n */\r\nexport function GetEulerAngle(x: Vector3, y: Vector3, z: Vector3)\r\n{\r\n let roY = Math.atan2(x.z, Math.sqrt(x.x ** 2 + x.y ** 2)) * -180 / Math.PI;\r\n let roZ = Math.atan2(x.y, x.x);\r\n let vec = YAxis.clone();\r\n let roMat = new Matrix4().makeRotationZ(roZ);\r\n roZ *= 180 / Math.PI;\r\n vec.applyMatrix4(roMat);\r\n let roX = Math.atan2(z.dot(vec), y.dot(vec)) * -180 / Math.PI;\r\n return { roX, roY, roZ };\r\n}\r\n\r\n/**\r\n * 方形框捕捉\r\n * @param sqCenter 正方形点\r\n * @param snapPt 被捕捉的点\r\n * @param size 捕捉框大小\r\n */\r\nexport function SnapPoint(sqCenter: Vector3, snapPt: Vector3, size: number): boolean\r\n{\r\n return Math.abs(sqCenter.x - snapPt.x) < size\r\n && Math.abs(sqCenter.y - snapPt.y) < size;\r\n}\r\n\r\nexport function SelectNearP(pts: Vector3[], refPt: Vector3): Vector3\r\n{\r\n if (pts.length > 1)\r\n {\r\n let dist1 = refPt.distanceToSquared(pts[0]);\r\n let dist2 = refPt.distanceToSquared(pts[1]);\r\n return dist1 <= dist2 ? pts[0] : pts[1];\r\n }\r\n return pts[0];\r\n}\r\n\r\nexport function IsBetweenA2B(n: number, A: number, B: number)\r\n{\r\n return n >= A && n <= B;\r\n}\r\n","import { Matrix4, Vector2, Vector3 } from 'three';\r\nimport { CoordinateSystem } from '../Geometry/CoordinateSystem';\r\nimport { equaln, isParallelTo } from '../Geometry/GeUtils';\r\n\r\n/**\r\n * 设置矩阵的某列的向量\r\n * @param {Matrix4} mat 矩阵\r\n * @param {number} col 列索引,0x 1y 2z 3org\r\n * @param {Vector3} v 向量或点\r\n */\r\nexport function matrixSetVector(mat: Matrix4, col: number, v: Vector3)\r\n{\r\n let index = col * 4;\r\n mat.elements[index] = v.x;\r\n mat.elements[index + 1] = v.y;\r\n mat.elements[index + 2] = v.z;\r\n}\r\n\r\n/**\r\n * 返回矩阵,该坐标系将坐标系与原点的坐标系映射为坐标系,\r\n * 并将坐标系与X轴坐标系,\r\n * Y轴坐标轴以及Z轴坐标系统之间的坐标系统坐标系统的原点坐标系和原点坐标系统坐标轴的坐标系分别设置为XAxis,YAxis和ZAxis\r\n * @returns {Matrix4} 返回新的矩阵\r\n */\r\nexport function matrixAlignCoordSys(matrixFrom: Matrix4, matrixTo: Matrix4): Matrix4\r\n{\r\n return new Matrix4().getInverse(matrixTo).multiply(matrixFrom);\r\n}\r\n\r\n/**\r\n * 判断2个矩形共面\r\n * @param {Matrix4} matrixFrom\r\n * @param {Matrix4} matrixTo\r\n * @returns {boolean} 2个矩阵共面\r\n */\r\nexport function matrixIsCoplane(matrixFrom: Matrix4, matrixTo: Matrix4, fuzz = 1e-5): boolean\r\n{\r\n let nor1 = new Vector3().setFromMatrixColumn(matrixFrom, 2);\r\n let nor2 = new Vector3().setFromMatrixColumn(matrixTo, 2);\r\n\r\n //法线共面\r\n if (!isParallelTo(nor1, nor2))\r\n return false;\r\n\r\n //高共面\r\n let pt = new Vector3().setFromMatrixPosition(matrixTo);\r\n //变换到自身对象坐标系.\r\n pt.applyMatrix4(new Matrix4().getInverse(matrixFrom));\r\n\r\n return equaln(pt.z, 0, fuzz);\r\n}\r\n\r\n//构造缩放矩阵\r\nexport function matrixScale(scale: number, center?: Vector3)\r\n{\r\n let scaleMat = new Matrix4().makeScale(scale, scale, scale);\r\n if (center)\r\n scaleMat.setPosition(center.clone().multiplyScalar(1 - scale));\r\n return scaleMat;\r\n}\r\n\r\n/**\r\n * 设置旋转矩阵,不改变矩阵的基点\r\n */\r\nexport function setRotationOnAxis(mtx: Matrix4, axis: Vector3, ro: number)\r\n{\r\n let pos = new Vector3().setFromMatrixPosition(mtx);\r\n mtx.makeRotationAxis(axis, ro);\r\n mtx.setPosition(pos);\r\n return mtx;\r\n}\r\n\r\n/**\r\n * 修正镜像后矩阵\r\n */\r\nexport function reviseMirrorMatrix(mtx: Matrix4): Matrix4\r\n{\r\n let cs = new CoordinateSystem().applyMatrix4(mtx);\r\n cs.YAxis.negate();\r\n mtx.copy(cs.getMatrix4());\r\n return mtx;\r\n}\r\n\r\nlet cacheVec: Vector3;\r\nexport function Vector2ApplyMatrix4(mtx: Matrix4, vec: Vector2)\r\n{\r\n if (!cacheVec) cacheVec = new Vector3();\r\n\r\n cacheVec.x = vec.x;\r\n cacheVec.y = vec.y;\r\n\r\n cacheVec.applyMatrix4(mtx);\r\n\r\n vec.x = cacheVec.x;\r\n vec.y = cacheVec.y;\r\n}\r\nexport function GetMirrorMat(v: Vector3)\r\n{\r\n let mirrorMat = new Matrix4();\r\n let xAxis = new Vector3(1 - 2 * v.x ** 2, -2 * v.x * v.y, -2 * v.x * v.z);\r\n let yAxis = new Vector3(-2 * v.x * v.y, 1 - 2 * v.y ** 2, -2 * v.y * v.z);\r\n let zAxis = new Vector3(-2 * v.x * v.z, -2 * v.y * v.z, 1 - 2 * v.z ** 2);\r\n mirrorMat.makeBasis(xAxis, yAxis, zAxis);\r\n return mirrorMat;\r\n}\r\n\r\nexport function ApplyMatrix4IgnorePosition(vec: { x: number, y: number, z: number; }, m: Matrix4)\r\n{\r\n let { x, y, z } = vec;\r\n let e = m.elements;\r\n vec.x = e[0] * x + e[4] * y + e[8] * z;\r\n vec.y = e[1] * x + e[5] * y + e[9] * z;\r\n vec.z = e[2] * x + e[6] * y + e[10] * z;\r\n return vec;\r\n}\r\n\r\n/**\r\n * 把变换矩阵展平成2d矩阵,避免出现三维坐标.\r\n */\r\nexport function MatrixPlanarizere(mtx: Matrix4, z0 = true)\r\n{\r\n mtx.elements[2] = 0;\r\n mtx.elements[6] = 0;\r\n mtx.elements[8] = 0;\r\n mtx.elements[9] = 0;\r\n mtx.elements[10] = Math.sign(mtx.elements[10]);\r\n\r\n if (z0)\r\n mtx.elements[14] = 0;\r\n\r\n return mtx;\r\n}\r\n\r\nexport const tempMatrix1 = new Matrix4;\r\n","\r\n\r\n\r\nexport enum Status\r\n{\r\n False = 0,\r\n True = 1,\r\n Canel = -1,\r\n\r\n ConverToCircle = 101,\r\n\r\n DuplicateRecordName = 102,\r\n}\r\n\r\nexport enum UpdateDraw\r\n{\r\n None = 0,\r\n Matrix = 1,\r\n Geometry = 2,\r\n Material = 4,\r\n All = ~(~0 << 6)\r\n}\r\n\r\n/**\r\n * WblockClne时,遇到重复记录的操作方式\r\n */\r\nexport enum DuplicateRecordCloning\r\n{\r\n Ignore = 1,\r\n Replace = 2,\r\n Rename = 3,\r\n}\r\n","\r\n/**\r\n * 场景的渲染类型.\r\n */\r\nexport enum RenderType\r\n{\r\n /**\r\n * 线框模式\r\n */\r\n Wireframe = 1,\r\n\r\n /**\r\n * 概念\r\n */\r\n Conceptual = 2,\r\n\r\n\r\n /**\r\n * 物理着色PBR\r\n */\r\n Physical = 3,\r\n\r\n Jig = 4,\r\n Print = 5,\r\n /**物理带线框 */\r\n Physical2 = 6,\r\n\r\n /******************************************** 在视口时的渲染模式 */\r\n /**\r\n * 线框模式\r\n */\r\n WireframePrint = 101,\r\n\r\n /**\r\n * 概念\r\n */\r\n ConceptualPrint = 102,\r\n\r\n\r\n /**\r\n * 物理着色PBR\r\n */\r\n PhysicalPrint = 103,\r\n\r\n JigPrint = 104,\r\n PrintPrint = 105,\r\n /**物理带线框 */\r\n Physical2Print = 106,\r\n}\r\n","export enum AAType\r\n{\r\n FXAA = 0,//快速近似抗锯齿(性能更好)\r\n SMAA = 1,//多重采样抗锯齿(质量更好)\r\n}\r\n\r\nexport enum ViewDirType\r\n{\r\n FS = 0,\r\n YAS = 1,\r\n ZS = 2,\r\n YS = 3,\r\n QS = 4,\r\n HS = 5,\r\n XN = 6,\r\n}\r\n","import { RenderType } from \"../GraphicsSystem/RenderType\";\r\nimport { DrillingOption } from \"../UI/Store/drillInterface\";\r\nimport { observable, toJS } from \"mobx\";\r\nimport { StoreageKeys } from \"../Common/StoreageKeys\";\r\nimport { IWineRackOption } from \"../UI/Store/WineRackInterface\";\r\nimport { IBaseOption, IGrooveOption } from \"../UI/Store/BoardInterface\";\r\nimport { IConfigStore } from \"../UI/Store/BoardStore\";\r\nimport { IConfigOption } from \"../UI/Components/Board/UserConfig\";\r\nimport { AAType, ViewDirType } from \"../Common/SystemEnum\";\r\n\r\nexport interface IMaxSizeProps extends IBaseOption\r\n{\r\n height: number;\r\n width: number;\r\n isShow: boolean;\r\n}\r\n\r\nexport interface ISystemConfig extends IBaseOption\r\n{\r\n aaType: AAType;\r\n maxHightightCount: number;\r\n snapSize: number;\r\n}\r\n\r\nexport interface ICursorConfig extends IBaseOption\r\n{\r\n D2: number;\r\n D3: number;\r\n}\r\n\r\nexport class UserConfig implements IConfigStore\r\n{\r\n private readonly _version = 10;\r\n _renderType: RenderType = RenderType.Wireframe;\r\n @observable maxSize: IMaxSizeProps = {\r\n isShow: false,\r\n height: 2440,\r\n width: 1220,\r\n };\r\n @observable private _drillConfigs: Map = new Map();\r\n @observable openDrillingReactor = true;\r\n @observable openAutoCuttingReactor = true;\r\n /**打开将检测排钻是否在板件内*/\r\n @observable openExactDrill = true;\r\n winerackConfig: IWineRackOption;\r\n userConfigName: { [key: string]: string; } = {};\r\n private modeling2HoleRad = 20; //圆造型小于等于该值拆成孔数据\r\n @observable isAdmin = false;\r\n @observable kjlConfig: IGrooveOption = {\r\n grooveAddLength: \"0\",\r\n grooveAddWidth: \"0\",\r\n grooveAddDepth: \"1\",\r\n };\r\n @observable SystemConfig: ISystemConfig = {\r\n maxHightightCount: 15000,\r\n snapSize: 15,\r\n aaType: AAType.FXAA\r\n };\r\n @observable viewDirType: ViewDirType = ViewDirType.XN;\r\n @observable useCtrlRotate = true;\r\n @observable cursorSize: ICursorConfig = {\r\n D2: 1000,\r\n D3: 100,\r\n };\r\n @observable autoSaveConfig = {\r\n enable: true,\r\n time: 1,\r\n };\r\n @observable showLines = false;\r\n @observable keepConfig = false;\r\n @observable autoClearHistory = true;\r\n @observable chaidanOption = {\r\n changXiuBian: 6,\r\n duanXiuBian: 6,\r\n useDefaultRad: false,\r\n radius: 2.5,\r\n modeling2HoleRad: 20, //圆造型小于等于该值拆成孔数据\r\n isCheckInterfere: false,\r\n noModeingData: \"\", //非造型遭数据\r\n };\r\n @observable autoLines = false;\r\n dimTextHeight = 60;\r\n constructor()\r\n {\r\n this.Init();\r\n }\r\n Init()\r\n {\r\n let type = localStorage.getItem(StoreageKeys.RenderType);\r\n if (type)\r\n this._renderType = parseFloat(type);\r\n }\r\n set RenderType(t: RenderType)\r\n {\r\n if (t !== this._renderType)\r\n {\r\n this._renderType = t;\r\n this.SetRenderTypeEvent();\r\n\r\n localStorage.setItem(StoreageKeys.RenderType, t.toString());\r\n }\r\n }\r\n\r\n get RenderType() { return this._renderType; }\r\n\r\n SetRenderTypeEvent() { }\r\n get DrillConfigs()\r\n {\r\n return this._drillConfigs || new Map();\r\n }\r\n set DrillConfigs(config: Map)\r\n {\r\n observable(this._drillConfigs).replace(config);\r\n this.SetDrillConfigsEvent();\r\n }\r\n SetDrillConfigsEvent() { }\r\n configName = \"default\";\r\n configsNames: string[] = [];\r\n InitOption()\r\n {\r\n this.openDrillingReactor = true;\r\n this.openAutoCuttingReactor = true;\r\n Object.assign(this.maxSize, {\r\n height: 2440,\r\n width: 1220\r\n });\r\n Object.assign(this.kjlConfig, {\r\n grooveAddLength: \"0\",\r\n grooveAddWidth: \"0\",\r\n grooveAddDepth: \"1\"\r\n });\r\n Object.assign(this.chaidanOption, {\r\n changXiuBian: 6,\r\n duanXiuBian: 6,\r\n useDefaultRad: false,\r\n radius: 2.5,\r\n modeling2HoleRad: 20,\r\n noModeingData: \"\",\r\n });\r\n this.dimTextHeight = 60;\r\n }\r\n SaveConfig()\r\n {\r\n return {\r\n option: {\r\n version: this._version,\r\n openDrillingReactor: this.openDrillingReactor,\r\n openAutoCuttingReactor: this.openAutoCuttingReactor,\r\n maxSize: toJS(this.maxSize),\r\n kjlConfig: toJS(this.kjlConfig),\r\n systemConfig: toJS(this.SystemConfig),\r\n viewDirType: this.viewDirType,\r\n useCtrlRotate: this.useCtrlRotate,\r\n cursorSize: toJS(this.cursorSize),\r\n autoSaveConfig: toJS(this.autoSaveConfig),\r\n showLines: this.showLines,\r\n keepConfig: this.keepConfig,\r\n autoClearHistory: this.autoClearHistory,\r\n chaidanOption: toJS(this.chaidanOption),\r\n autoLines: this.autoLines,\r\n dimTextHeight: this.dimTextHeight,\r\n }\r\n };\r\n }\r\n UpdateOption(config: IConfigOption)\r\n {\r\n this.openDrillingReactor = config.option.openDrillingReactor;\r\n this.openAutoCuttingReactor = config.option.openAutoCuttingReactor;\r\n Object.assign(this.maxSize, config.option.maxSize);\r\n Object.assign(this.kjlConfig, config.option.kjlConfig);\r\n this.modeling2HoleRad = config.option.modeling2HoleRad;\r\n\r\n if (config.option.version > 1)\r\n {\r\n Object.assign(this.SystemConfig, config.option.systemConfig);\r\n }\r\n if (config.option.version > 2)\r\n {\r\n this.viewDirType = config.option.viewDirType;\r\n this.useCtrlRotate = config.option.useCtrlRotate;\r\n }\r\n\r\n if (config.option.version > 3)\r\n {\r\n Object.assign(this.cursorSize, config.option.cursorSize);\r\n }\r\n if (config.option.version > 4)\r\n {\r\n Object.assign(this.autoSaveConfig, config.option.autoSaveConfig);\r\n }\r\n if (config.option.version > 5)\r\n {\r\n this.showLines = config.option.showLines;\r\n }\r\n if (config.option.version > 6)\r\n {\r\n this.keepConfig = config.option.keepConfig;\r\n }\r\n if (config.option.version > 7)\r\n {\r\n this.autoClearHistory = config.option.autoClearHistory;\r\n }\r\n if (config.option.version > 8)\r\n {\r\n Object.assign(this.chaidanOption, config.option.chaidanOption);\r\n this.autoLines = config.option.autoLines;\r\n }\r\n else\r\n this.chaidanOption.modeling2HoleRad = this.modeling2HoleRad;\r\n\r\n if (config.option.version > 9)\r\n this.dimTextHeight = config.option.dimTextHeight;\r\n }\r\n}\r\n\r\nexport const userConfig = new UserConfig();\r\n","import { Vector3, Box3 } from 'three';\r\n\r\n/**\r\n * 盒子的切割类型\r\n */\r\nexport enum SplitType\r\n{\r\n X = 0,\r\n Y = 1,\r\n Z = 2,\r\n}\r\n\r\n/**\r\n * 扩展Box3,添加切割方法,体积等\r\n */\r\nexport class Box3Ext extends Box3\r\n{\r\n TempData: any;\r\n get Volume()\r\n {\r\n let size = this.getSize(new Vector3());\r\n return size.x * size.y * size.z;\r\n }\r\n\r\n //每个轴的大小必须大于最小的size\r\n isSolid(minSize = 1)\r\n {\r\n return this.getSize(new Vector3()).toArray().every(x => x > minSize);\r\n }\r\n substract(b: Box3Ext, spaceType: SplitType)\r\n {\r\n let interBox = this.clone().intersect(b) as this;\r\n if (interBox.isEmpty() || !interBox.isSolid())\r\n return [this];\r\n\r\n let p1 = interBox.min.clone().setComponent(spaceType, this.min.getComponent(spaceType));\r\n let p2 = interBox.max.clone().setComponent(spaceType, interBox.min.getComponent(spaceType));\r\n\r\n let p3 = interBox.min.clone().setComponent(spaceType, interBox.max.getComponent(spaceType));\r\n let p4 = interBox.max.clone().setComponent(spaceType, this.max.getComponent(spaceType));\r\n\r\n return [\r\n new Box3Ext(p1, p2),\r\n new Box3Ext(p3, p4)\r\n ].filter(b => b.isSolid());\r\n }\r\n clampSpace(b2: Box3Ext, splitType: SplitType)\r\n {\r\n let interBox = this.clone();\r\n interBox.min.max(b2.min);\r\n interBox.max.min(b2.max);\r\n interBox.min.setComponent(splitType, Math.min(this.max.getComponent(splitType), b2.max.getComponent(splitType)));\r\n interBox.max.setComponent(splitType, Math.max(this.min.getComponent(splitType), b2.min.getComponent(splitType)));\r\n return interBox;\r\n }\r\n intersectsBox(box: Box3, fuzz = 1e-8): boolean\r\n {\r\n return IntersectsBox(this, box, fuzz);\r\n }\r\n}\r\n\r\nexport function IntersectsBox(box1: Box3, box2: Box3, fuzz = 1e-6): boolean\r\n{\r\n return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz ||\r\n box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz ||\r\n box2.max.z < box1.min.z - fuzz || box2.min.z > box1.max.z + fuzz ? false : true;\r\n}\r\n\r\n/**盒子二维面是否相交 */\r\nexport function IntersectBox2(box1: Box3, box2: Box3, fuzz = 1e-3)\r\n{\r\n return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz ||\r\n box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz ? false : true;\r\n}\r\n","import { Box3, Material, Matrix3, Matrix4, MeshStandardMaterial, Object3D, Vector3 } from 'three';\r\nimport { iaop } from 'xaop';\r\nimport { HostApplicationServices } from '../../ApplicationServices/HostApplicationServices';\r\nimport { DisposeThreeObj, Object3DRemoveAll } from '../../Common/Dispose';\r\nimport { matrixIsCoplane, MatrixPlanarizere } from '../../Common/Matrix4Utils';\r\nimport { UpdateDraw } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { userConfig } from '../../Editor/UserConfig';\r\nimport { Box3Ext } from '../../Geometry/Box';\r\nimport { equaln, equalv3, UpdateBoundingSphere, IdentityMtx4 } from '../../Geometry/GeUtils';\r\nimport { IntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { AutoRecord } from '../AutoRecord';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { CADObject } from '../CADObject';\r\nimport { ObjectId } from '../ObjectId';\r\nimport { PhysicalMaterialRecord } from '../PhysicalMaterialRecord';\r\n\r\n/**\r\n * Entity 是所有图元的基类,绘制的实体都集成该类.\r\n */\r\n@Factory\r\nexport class Entity extends CADObject\r\n{\r\n\r\n IsEmbedEntity = false;\r\n\r\n /**\r\n * 该实体的只有一个渲染类型,任何渲染类型都一个样\r\n */\r\n protected OnlyRenderType = false;\r\n protected _CacheDrawObject = new Map();\r\n //材质id\r\n protected materialId: ObjectId;\r\n protected _Color: number = 7;\r\n\r\n //自身坐标系\r\n protected _Matrix = new Matrix4();\r\n\r\n //模块空间的标系\r\n protected _SpaceOCS: Matrix4 = new Matrix4();\r\n get SpaceOCS()\r\n {\r\n return this._SpaceOCS.clone();\r\n }\r\n get SpaceOCSInv()\r\n {\r\n return new Matrix4().getInverse(this._SpaceOCS);\r\n }\r\n set SpaceOCS(m: Matrix4)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._SpaceOCS.copy(m);\r\n }\r\n\r\n protected _Visible = true;\r\n\r\n @AutoRecord GroupId: ObjectId;\r\n @AutoRecord Template: ObjectId;\r\n //加工组\r\n @AutoRecord ProcessingGroupList: ObjectId[] = [];\r\n\r\n /**\r\n * 当AutoUpdate为false时,记录需要更新的标志.\r\n * 以便延迟更新时找到相应的更新标志.\r\n */\r\n NeedUpdateFlag: UpdateDraw = UpdateDraw.None;\r\n AutoUpdate = true;\r\n\r\n set Material(materialId: ObjectId)\r\n {\r\n this.WriteAllObjectRecord();\r\n this.materialId = materialId;\r\n this.Update();\r\n }\r\n\r\n get Material()\r\n {\r\n return this.materialId;\r\n }\r\n\r\n set ColorIndex(color: number)\r\n {\r\n if (color !== this._Color)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Color = color;\r\n this.Update(UpdateDraw.Material);\r\n }\r\n }\r\n get ColorIndex(): number\r\n {\r\n return this._Color;\r\n }\r\n /**\r\n * 炸开实体\r\n */\r\n Explode(): Entity[] { return []; }\r\n\r\n /**\r\n * 返回对象的包围框.\r\n */\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3();\r\n }\r\n\r\n /**\r\n * 返回对象在自身坐标系下的Box\r\n */\r\n get BoundingBoxInOCS(): Box3Ext\r\n {\r\n let mtxBak = this._Matrix;\r\n this._Matrix = IdentityMtx4;\r\n let box = this.BoundingBox;\r\n this._Matrix = mtxBak;\r\n return new Box3Ext().copy(box);\r\n }\r\n\r\n GetBoundingBoxInMtx(mtx: Matrix4): Box3Ext\r\n {\r\n return this.BoundingBoxInOCS.applyMatrix4(this.OCS.premultiply(mtx));\r\n }\r\n\r\n get BoundingBoxInSpaceCS(): Box3Ext\r\n {\r\n return this.GetBoundingBoxInMtx(this.SpaceOCSInv);\r\n }\r\n\r\n get OCS(): Matrix4\r\n {\r\n return this._Matrix.clone();\r\n }\r\n\r\n get OCSNoClone()\r\n {\r\n return this._Matrix;\r\n }\r\n\r\n //直接设置实体的矩阵,谨慎使用该函数,没有更新实体.\r\n set OCS(mat4: Matrix4)\r\n {\r\n this._Matrix.copy(mat4);\r\n }\r\n get Normal(): Vector3\r\n {\r\n return new Vector3().setFromMatrixColumn(this._Matrix, 2);\r\n }\r\n get Position(): Vector3\r\n {\r\n return new Vector3().setFromMatrixPosition(this._Matrix);\r\n }\r\n\r\n set Position(pt: Vector3)\r\n {\r\n let moveX = pt.x - this._Matrix.elements[12];\r\n let moveY = pt.y - this._Matrix.elements[13];\r\n let moveZ = pt.z - this._Matrix.elements[14];\r\n\r\n if (moveX === 0 && moveY === 0 && moveZ === 0) return;\r\n\r\n this.WriteAllObjectRecord();\r\n this._Matrix.setPosition(pt);\r\n this._SpaceOCS.elements[12] += moveX;\r\n this._SpaceOCS.elements[13] += moveY;\r\n this._SpaceOCS.elements[14] += moveZ;\r\n this.Update(UpdateDraw.Matrix);\r\n }\r\n\r\n //Z轴归0\r\n Z0()\r\n {\r\n if (this._Matrix.elements[14] === 0) return this;\r\n\r\n this.WriteAllObjectRecord();\r\n this._Matrix.elements[14] = 0;\r\n this.Update(UpdateDraw.Matrix);\r\n return this;\r\n }\r\n\r\n //坐标系二维化\r\n MatrixPlanarizere()\r\n {\r\n let z = this._Matrix.elements[10];\r\n if (equaln(Math.abs(z), 1, 1e-4))\r\n {\r\n this.WriteAllObjectRecord();\r\n MatrixPlanarizere(this._Matrix, false);\r\n }\r\n return this;\r\n }\r\n\r\n get OCSInv(): Matrix4\r\n {\r\n return new Matrix4().getInverse(this._Matrix);\r\n }\r\n\r\n /**\r\n * 与指定实体是否共面.\r\n */\r\n IsCoplaneTo(e: Entity): boolean\r\n {\r\n return matrixIsCoplane(this._Matrix, e.OCS, 1e-4);\r\n }\r\n\r\n /**\r\n * 测试两个实体的包围盒是否相交.\r\n */\r\n BoundingBoxIntersectWith(en: Entity): boolean\r\n {\r\n let box = this.BoundingBox;\r\n let box2 = en.BoundingBox;\r\n return box && box2 && box.intersectsBox(box2);\r\n }\r\n\r\n //#region Draw\r\n\r\n ClearDraw()\r\n {\r\n if (this._drawObject)\r\n {\r\n DisposeThreeObj(this._drawObject);\r\n this._drawObject = undefined;\r\n }\r\n\r\n for (let [, obj] of this._CacheDrawObject)\r\n DisposeThreeObj(obj);\r\n this._CacheDrawObject.clear();\r\n return this;\r\n }\r\n ClearDrawOfJig()\r\n {\r\n let jig = this._CacheDrawObject.get(RenderType.Jig);\r\n if (jig)\r\n this._CacheDrawObject.delete(RenderType.Jig);\r\n for (let [type, obj] of this._CacheDrawObject)\r\n DisposeThreeObj(obj);\r\n this._CacheDrawObject.clear();\r\n if (jig)\r\n this._CacheDrawObject.set(RenderType.Jig, jig);\r\n }\r\n\r\n get IsOnlyRender()\r\n {\r\n return this.OnlyRenderType;\r\n }\r\n _drawObject: Object3D;\r\n\r\n get DrawObject()\r\n {\r\n if (this._drawObject)\r\n return this._drawObject;\r\n\r\n this._drawObject = new Object3D();\r\n if (!this.IsEmbedEntity)\r\n this._drawObject.userData.Entity = this;\r\n if (this.IsVisible)\r\n {\r\n this._CurRenderType = userConfig.RenderType;\r\n let obj = this.GetDrawObjectFromRenderType(userConfig.RenderType);\r\n if (obj) this._drawObject.add(obj);\r\n }\r\n else\r\n this._drawObject.visible = false;\r\n return this._drawObject;\r\n }\r\n\r\n get JigObject()\r\n {\r\n let obj = this.GetDrawObjectFromRenderType(RenderType.Jig);\r\n if (obj && !this.IsEmbedEntity)\r\n obj.userData.Entity = this;\r\n return obj;\r\n }\r\n\r\n DestroyJigObject()\r\n {\r\n let obj = this._CacheDrawObject.get(RenderType.Jig);\r\n if (obj)\r\n {\r\n this._CacheDrawObject.delete(RenderType.Jig);\r\n DisposeThreeObj(obj);\r\n if (obj.parent)\r\n obj.parent.remove(obj);\r\n }\r\n }\r\n\r\n //当前绘制类型,在.DrawObject 和 UpdateRenderType中初始化和更新\r\n protected _CurRenderType: RenderType;\r\n UpdateRenderType(type: RenderType)\r\n {\r\n if (this._CurRenderType !== type)\r\n {\r\n this._CurRenderType = type;\r\n if ((this.OnlyRenderType && this.DrawObject.children.length > 0) || !this.Visible) return;\r\n Object3DRemoveAll(this.DrawObject);\r\n let obj = this.GetDrawObjectFromRenderType(type);\r\n if (obj) this.DrawObject.add(obj);\r\n }\r\n }\r\n\r\n GetDrawObjectFromRenderType(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n if (this.OnlyRenderType)\r\n {\r\n if (renderType === RenderType.Jig)\r\n return;\r\n if (renderType < 100)\r\n renderType = RenderType.Wireframe;\r\n else\r\n renderType = RenderType.WireframePrint;\r\n }\r\n\r\n if (this._CacheDrawObject.has(renderType))\r\n {\r\n return this._CacheDrawObject.get(renderType);\r\n }\r\n else\r\n {\r\n let drawObj = this.InitDrawObject(renderType);\r\n if (drawObj === undefined)\r\n {\r\n if (renderType > 100)//如果实体没有实现打印类型,那么就使用原先的实体的渲染类型\r\n return this.GetDrawObjectFromRenderType(renderType - 100);\r\n return;\r\n };\r\n\r\n //矩阵直接使用指针,因为已经关闭自动更新,所以矩阵不会被Object3D修改.\r\n drawObj.matrixAutoUpdate = false;\r\n drawObj.matrix = this._Matrix;\r\n drawObj.updateMatrixWorld(true);\r\n drawObj.traverse(UpdateBoundingSphere);\r\n\r\n if (!this.IsEmbedEntity)\r\n drawObj.userData.Entity = this;\r\n\r\n this._CacheDrawObject.set(renderType, drawObj);\r\n return drawObj;\r\n }\r\n }\r\n\r\n /**\r\n * 初始化绘制的threejs实体,子类型重载该函数初始化绘制实体.\r\n */\r\n protected InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n return undefined;\r\n }\r\n\r\n //实体绘制更新版本号\r\n __UpdateVersion__ = 0;\r\n\r\n /**\r\n * 当实体数据改变时,绘制的实体必须做出改变.供框架调用\r\n */\r\n @iaop\r\n Update(mode = UpdateDraw.All)\r\n {\r\n this.__UpdateVersion__++;\r\n this.NeedUpdateFlag |= mode;\r\n if (this.AutoUpdate)\r\n this.DeferUpdate();\r\n }\r\n\r\n //三维实体总是一起生成线框实体和网格实体,这个通知更新,然后统一更新就好了\r\n //避免重复更新\r\n UpdateDrawGeometry() { }\r\n\r\n DeferUpdate()\r\n {\r\n let mode = this.NeedUpdateFlag;\r\n if (mode === 0) return;\r\n\r\n if (mode & UpdateDraw.Geometry && this._CacheDrawObject.size > 0)\r\n this.UpdateDrawGeometry();\r\n\r\n this.UpdateVisible();\r\n\r\n let isJigIng = this._CacheDrawObject.has(RenderType.Jig);\r\n for (let [type, obj] of this._CacheDrawObject)\r\n {\r\n if (isJigIng && type !== RenderType.Jig)\r\n continue;\r\n\r\n if (mode & UpdateDraw.Geometry)\r\n {\r\n if (obj.userData.IsClone)\r\n {\r\n let parent = obj.parent;\r\n DisposeThreeObj(obj);\r\n this._CacheDrawObject.delete(type);\r\n let newObj = this.GetDrawObjectFromRenderType(type);\r\n if (parent)\r\n {\r\n parent.remove(obj);\r\n parent.add(newObj);\r\n }\r\n obj = newObj;\r\n }\r\n else\r\n this.UpdateDrawObject(type, obj);\r\n }\r\n\r\n if (mode & UpdateDraw.Material)\r\n this.UpdateDrawObjectMaterial(type, obj);\r\n\r\n if (mode & UpdateDraw.Matrix || mode & UpdateDraw.Geometry)\r\n {\r\n obj.updateMatrixWorld(true);\r\n // if (this.Id)//如果这个是Jig实体,那么我们更新这个盒子球似乎也没有意义 (虽然这在某些情况能改进性能,但是在绘制圆弧的时候,因为没有更新圆弧的盒子,导致绘制出来的圆弧无法被选中)\r\n obj.traverse(UpdateBoundingSphere);\r\n }\r\n\r\n }\r\n this.NeedUpdateFlag = UpdateDraw.None;\r\n }\r\n\r\n /**\r\n * 当实体需要更新时,需要重载该方法,实现实体更新\r\n */\r\n UpdateDrawObject(type: RenderType, en: Object3D)\r\n {\r\n\r\n }\r\n\r\n /**\r\n * 当实体需要被更新时,更新实体材质\r\n */\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material?: Material)\r\n {\r\n\r\n }\r\n\r\n protected get MeshMaterial()\r\n {\r\n if (this.materialId && this.materialId.Object)\r\n return (this.materialId.Object).Material as MeshStandardMaterial;\r\n return HostApplicationServices.DefaultMeshMaterial;\r\n }\r\n\r\n /**\r\n * 更新实体Jig状态时的材质\r\n */\r\n UpdateJigMaterial(color = 8)\r\n {\r\n }\r\n RestoreJigMaterial()\r\n {\r\n for (let [type, en] of this._CacheDrawObject)\r\n this.UpdateDrawObjectMaterial(type, en);\r\n }\r\n get Visible()\r\n {\r\n return this._Visible;\r\n }\r\n set Visible(v: boolean)\r\n {\r\n if (v !== this._Visible)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Visible = v;\r\n this.UpdateVisible();\r\n }\r\n }\r\n\r\n private get IsVisible()\r\n {\r\n return !this._isErase && this._Visible;\r\n }\r\n\r\n UpdateVisible()\r\n {\r\n if (this._drawObject)\r\n {\r\n this._drawObject.visible = this.IsVisible;\r\n if (this.IsVisible)\r\n this.UpdateRenderType(userConfig.RenderType);\r\n }\r\n }\r\n\r\n //#endregion\r\n\r\n GoodBye()\r\n {\r\n super.GoodBye();\r\n if (this._drawObject && this._drawObject.parent)\r\n this._drawObject.parent.remove(this._drawObject);\r\n this.ClearDraw();\r\n }\r\n\r\n Erase(isErase: boolean = true)\r\n {\r\n if (isErase === this._isErase)\r\n return;\r\n this.__UpdateVersion__++;\r\n super.Erase(isErase);\r\n this.UpdateVisible();\r\n this.EraseEvent(isErase);\r\n }\r\n\r\n @iaop\r\n EraseEvent(isErase: boolean)\r\n {\r\n\r\n }\r\n /**\r\n * 使用统一的方法设置对象的矩阵.\r\n * 需要对缩放矩形进行重载.避免对象矩阵不是单位矩阵\r\n */\r\n ApplyMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n if (equaln(m.getMaxScaleOnAxis(), 1))\r\n {\r\n let xA = new Vector3();\r\n let yA = new Vector3();\r\n let zA = new Vector3();\r\n m.extractBasis(xA, yA, zA);\r\n this._Matrix.multiplyMatrices(m, this._Matrix);\r\n this._SpaceOCS.multiplyMatrices(m, this._SpaceOCS);\r\n if (!equalv3(xA.clone().cross(yA).normalize(), zA))\r\n this.ApplyMirrorMatrix(m);\r\n else\r\n this.Update(UpdateDraw.Matrix);\r\n }\r\n else\r\n {\r\n this.ApplyScaleMatrix(m);\r\n }\r\n return this;\r\n }\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n return this;\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n return [];\r\n }\r\n\r\n MoveGripPoints(indexList: number[], vec: Vector3)\r\n {\r\n\r\n }\r\n\r\n /**\r\n *\r\n * @param snapMode 捕捉模式(单一)\r\n * @param pickPoint const\r\n * @param lastPoint const\r\n * @param viewXform const 最近点捕捉需要这个变量\r\n * @returns object snap points\r\n */\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n return [];\r\n }\r\n\r\n GetStretchPoints(): Array\r\n {\r\n return [];\r\n }\r\n\r\n /**\r\n * 拉伸夹点,用于Stretch命令\r\n *\r\n * @param {Array} indexList 拉伸点索引列表.\r\n * @param {Vector3} vec 移动向量\r\n * @memberof Entity\r\n */\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n\r\n }\r\n IntersectWith(curve: Entity, intType: IntersectOption): Vector3[] { return; }\r\n\r\n //#region -------------------------File-------------------------\r\n\r\n Clone(): this\r\n {\r\n let ent = super.Clone();\r\n ent._CurRenderType = this._CurRenderType;\r\n ent.Template = undefined;\r\n ent.CloneDrawObject(this);\r\n return ent;\r\n }\r\n\r\n CloneDrawObject(from: this)\r\n {\r\n for (let [type, obj] of from._CacheDrawObject)\r\n {\r\n let oldUserDaata = obj.userData;\r\n obj.traverse(o => o.userData = {});\r\n let newObj = obj.clone();\r\n obj.userData = oldUserDaata;\r\n obj.userData.IsClone = true;\r\n\r\n newObj.matrix = this._Matrix;\r\n newObj.userData = { Entity: this };\r\n newObj.userData.IsClone = true;\r\n this._CacheDrawObject.set(type, newObj);\r\n }\r\n this.NeedUpdateFlag = UpdateDraw.None;\r\n }\r\n\r\n static __ReadFileIng__: boolean;\r\n __ReadFileIng__: boolean;\r\n\r\n get ReadFileIng()\r\n {\r\n return this.__ReadFileIng__ || Entity.__ReadFileIng__;\r\n }\r\n\r\n /**\r\n * 从文件读取,序列化自身,如果需要,重载_ReadFile\r\n */\r\n ReadFile(file: CADFiler)\r\n {\r\n this.__ReadFileIng__ = true;\r\n this._ReadFile(file);\r\n this.Update();\r\n this.__ReadFileIng__ = false;\r\n }\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();\r\n super.ReadFile(file);\r\n this._Color = file.Read();\r\n this.materialId = file.ReadHardObjectId();\r\n this._Matrix.fromArray(file.Read());\r\n\r\n if (ver === 2)\r\n this.Owner = file.ReadObjectId();\r\n\r\n if (ver > 3)\r\n this.Template = file.ReadObjectId();\r\n\r\n if (ver > 4)\r\n this.GroupId = file.ReadHardObjectId();\r\n\r\n if (ver > 5)\r\n this._Visible = file.Read();\r\n if (ver > 6)\r\n this._SpaceOCS.fromArray(file.Read());\r\n if (ver > 7)\r\n {\r\n let count = file.Read();\r\n this.ProcessingGroupList.length = 0;\r\n for (let i = 0; i < count; i++)\r\n this.ProcessingGroupList.push(file.ReadHardObjectId());\r\n }\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(8);\r\n super.WriteFile(file);\r\n file.Write(this._Color);\r\n file.WriteHardObjectId(this.materialId);\r\n file.Write(this._Matrix.toArray());\r\n file.WriteObjectId(this.Template);\r\n file.WriteHardObjectId(this.GroupId);\r\n file.Write(this._Visible);\r\n file.Write(this._SpaceOCS.toArray());\r\n\r\n file.Write(this.ProcessingGroupList.length);\r\n for (let id of this.ProcessingGroupList)\r\n file.WriteHardObjectId(id);\r\n }\r\n //局部撤销\r\n ApplyPartialUndo(undoData: CADObject)\r\n {\r\n super.ApplyPartialUndo(undoData);\r\n }\r\n\r\n CopyFrom(obj: CADObject)\r\n {\r\n let templateIdBak = this.Template;\r\n super.CopyFrom(obj);\r\n this.Update();\r\n this.Template = templateIdBak;\r\n }\r\n\r\n //#endregion\r\n}\r\n","import { CADFactory } from './CADFactory';\r\nimport { CADObject } from './CADObject';\r\nimport { Database } from './Database';\r\nimport { ISerialize } from './ISerialize';\r\nimport { ObjectId } from './ObjectId';\r\nimport { Entity } from './Entity/Entity';\r\n\r\n/**\r\n * CAD文件数据\r\n */\r\nexport class CADFiler\r\n{\r\n database: Database;\r\n private readIndex: number = 0;\r\n constructor(protected _datas: any[] = [])\r\n {\r\n }\r\n\r\n Destroy()\r\n {\r\n delete this._datas;\r\n delete this.readIndex;\r\n }\r\n\r\n get Data(): any[]\r\n {\r\n return this._datas;\r\n }\r\n\r\n set Data(data: any[])\r\n {\r\n this._datas = data;\r\n this.Reset();\r\n }\r\n\r\n Clear()\r\n {\r\n this._datas.length = 0;\r\n return this.Reset();\r\n }\r\n Reset()\r\n {\r\n this.readIndex = 0;\r\n return this;\r\n }\r\n\r\n WriteString(str: string)\r\n {\r\n this._datas.push(str);\r\n return this;\r\n }\r\n\r\n ReadString(): string\r\n {\r\n return this._datas[this.readIndex++] as string;\r\n }\r\n\r\n WriteObject(obj: ISerialize)\r\n {\r\n if (!obj)\r\n {\r\n this.Write(\"\");\r\n return;\r\n }\r\n this.WriteString(obj.constructor.name);\r\n obj.WriteFile(this);\r\n\r\n return this;\r\n }\r\n\r\n ReadObject(obj?: T): T\r\n {\r\n let className = this.ReadString();\r\n if (className)\r\n {\r\n if (obj === undefined)\r\n {\r\n obj = CADFactory.CreateObject(className);\r\n if (this.database !== undefined && obj instanceof CADObject)\r\n obj.SetDefaultDb(this.database);\r\n }\r\n obj.ReadFile(this);\r\n return obj;\r\n }\r\n }\r\n\r\n CloneObjects(objects: CADObject[], clonedObjects: CADObject[] = [])\r\n {\r\n for (let o of objects)\r\n this.WriteObject(o);\r\n let count = objects.length;\r\n for (let i = 0; i < count; i++)\r\n {\r\n let obj = this.ReadObject();\r\n if (obj instanceof Entity)\r\n obj.CloneDrawObject(objects[i] as Entity);\r\n clonedObjects.push(obj);\r\n }\r\n\r\n return clonedObjects;\r\n }\r\n\r\n Write(data: any)\r\n {\r\n if (data instanceof ObjectId)\r\n this._datas.push(data.Index);\r\n else\r\n this._datas.push(data);\r\n\r\n return this;\r\n }\r\n\r\n Read(): any\r\n {\r\n return this._datas[this.readIndex++];\r\n }\r\n\r\n ReadArray(count: number): any[]\r\n {\r\n let arr = this._datas.slice(this.readIndex, this.readIndex + count);\r\n this.readIndex += count;\r\n return arr;\r\n }\r\n\r\n //------------------------ID序列化------------------------\r\n /*\r\n Id关联分为三种情况:\r\n 1.普通关联:关联对象未被拷贝时,关联到空对象.\r\n 2.软关联 :关联对象未被拷贝时,关联到原先的对象.\r\n 3.硬关联 :对象被拷贝时,被关联的对象必须也被拷贝.\r\n */\r\n\r\n //-------1.普通关联\r\n WriteObjectId(id: ObjectId): this\r\n {\r\n if (id)\r\n this.Write(id.Index);\r\n else\r\n this.Write(0);\r\n return this;\r\n }\r\n\r\n ReadObjectId(): ObjectId\r\n {\r\n let index = this.Read();\r\n if (this.database)\r\n return this.database.GetObjectId(index, true);\r\n }\r\n\r\n //-------2.软关联\r\n WriteSoftObjectId(id: ObjectId): this\r\n {\r\n return this.WriteObjectId(id);\r\n }\r\n ReadSoftObjectId(): ObjectId\r\n {\r\n return this.ReadObjectId();\r\n }\r\n\r\n //-------3.硬关联\r\n WriteHardObjectId(id: ObjectId): this\r\n {\r\n return this.WriteObjectId(id);\r\n }\r\n ReadHardObjectId()\r\n {\r\n return this.ReadObjectId();\r\n }\r\n\r\n //序列化\r\n ToString()\r\n {\r\n return JSON.stringify(this._datas);\r\n }\r\n FromString(str: string)\r\n {\r\n this._datas = JSON.parse(str);\r\n }\r\n}\r\n","import { ShaderMaterialParameters, Vector3 } from \"three\";\r\n\r\n//https://github.com/arefin86/arefin86.github.io/blob/master/js/shaders/GoochShader.js\r\nexport function GetGoochShader()\r\n{\r\n return {\r\n uniforms: {\r\n \"LightPosition\": { type: \"v3\", value: new Vector3(-200, 0, 200) },\r\n \"SurfaceColor\": { type: \"v3\", value: new Vector3(1.0, 1.0, 0.) },\r\n \"WarmColor\": { type: \"v3\", value: new Vector3(1.0, 0.5, 0.0) },\r\n \"CoolColor\": { type: \"v3\", value: new Vector3(0, 0, 0.7) },\r\n \"DiffuseWarm\": { type: \"f\", value: 0.45 },\r\n \"DiffuseCool\": { type: \"f\", value: 0.1 }\r\n },\r\n\r\n vertexShader: require(\"./Goodch2.vs\"),\r\n fragmentShader: require(\"./Goodch2.fs\")\r\n };\r\n}\r\n\r\nexport function GetGoodShaderSimple(color: Vector3 = new Vector3): ShaderMaterialParameters\r\n{\r\n return {\r\n uniforms: {\r\n \"SurfaceColor\": { value: color }\r\n },\r\n vertexShader: require(\"./GoodchSimple.vs\"),\r\n fragmentShader: require(\"./GoodchSimple.fs\"),\r\n\r\n polygonOffset: true,\r\n polygonOffsetFactor: 1,\r\n polygonOffsetUnits: 1\r\n };\r\n}\r\n","import { Color, DoubleSide, LineBasicMaterial, LineDashedMaterial, MeshBasicMaterial, ShaderMaterial, Vector3, Vector2 } from 'three';\r\nimport { GetGoodShaderSimple } from '../GLSL/GoochShader';\r\nimport { LineMaterial } from 'three/examples/jsm/lines/LineMaterial';\r\n\r\nconst ColorPalette = [\r\n [0, 0, 0, 0], //----- 0 - lets make it red for an example\r\n //[255, 255, 255, 255],//----- 0 - ByBlock - White\r\n [255, 0, 0, 255], //----- 1 - Red\r\n // [255, 0, 0, 255], //----- 1 - Red\r\n [255, 255, 0, 255], //----- 2 - Yellow\r\n [0, 255, 0, 255], //----- 3 - Green\r\n [0, 255, 255, 255], //----- 4 - Cyan\r\n [0, 0, 255, 255], //----- 5 - Blue\r\n [255, 0, 255, 255], //----- 6 - Magenta\r\n // [255, 0, 0, 255], //----- 7 - More red Red\r\n // [255, 0, 0, 255], //----- 8 - More red Red\r\n // [255, 0, 0, 255], //----- 9 - More red Red\r\n [255, 255, 255, 255],//----- 7 - White\r\n [128, 128, 128, 255],//----- 8\r\n [192, 192, 192, 255],//----- 9\r\n [255, 0, 0, 255], //----- 10\r\n [255, 127, 127, 255],//----- 11\r\n [165, 0, 0, 255], //----- 12\r\n [165, 82, 82, 255], //----- 13\r\n [127, 0, 0, 255], //----- 14\r\n [127, 63, 63, 255], //----- 15\r\n [76, 0, 0, 255], //----- 16\r\n [76, 38, 38, 255], //----- 17\r\n [38, 0, 0, 255], //----- 18\r\n [38, 19, 19, 255], //----- 19\r\n [255, 63, 0, 255], //----- 20\r\n [255, 159, 127, 255],//----- 21\r\n [165, 41, 0, 255], //----- 22\r\n [165, 103, 82, 255], //----- 23\r\n [127, 31, 0, 255], //----- 24\r\n [127, 79, 63, 255], //----- 25\r\n [76, 19, 0, 255], //----- 26\r\n [76, 47, 38, 255], //----- 27\r\n [38, 9, 0, 255], //----- 28\r\n [38, 23, 19, 255], //----- 29\r\n [255, 127, 0, 255], //----- 30\r\n [255, 191, 127, 255],//----- 31\r\n [165, 82, 0, 255], //----- 32\r\n [165, 124, 82, 255], //----- 33\r\n [127, 63, 0, 255], //----- 34\r\n [127, 95, 63, 255], //----- 35\r\n [76, 38, 0, 255], //----- 36\r\n [76, 57, 38, 255], //----- 37\r\n [38, 19, 0, 255], //----- 38\r\n [38, 28, 19, 255], //----- 39\r\n [255, 191, 0, 255], //----- 40\r\n [255, 223, 127, 255],//----- 41\r\n [165, 124, 0, 255], //----- 42\r\n [165, 145, 82, 255], //----- 43\r\n [127, 95, 0, 255], //----- 44\r\n [127, 111, 63, 255], //----- 45\r\n [76, 57, 0, 255], //----- 46\r\n [76, 66, 38, 255], //----- 47\r\n [38, 28, 0, 255], //----- 48\r\n [38, 33, 19, 255], //----- 49\r\n [255, 255, 0, 255], //----- 50\r\n [255, 255, 127, 255],//----- 51\r\n [165, 165, 0, 255], //----- 52\r\n [165, 165, 82, 255], //----- 53\r\n [127, 127, 0, 255], //----- 54\r\n [127, 127, 63, 255], //----- 55\r\n [76, 76, 0, 255], //----- 56\r\n [76, 76, 38, 255], //----- 57\r\n [38, 38, 0, 255], //----- 58\r\n [38, 38, 19, 255], //----- 59\r\n [191, 255, 0, 255], //----- 60\r\n [223, 255, 127, 255],//----- 61\r\n [124, 165, 0, 255], //----- 62\r\n [145, 165, 82, 255], //----- 63\r\n [95, 127, 0, 255], //----- 64\r\n [111, 127, 63, 255], //----- 65\r\n [57, 76, 0, 255], //----- 66\r\n [66, 76, 38, 255], //----- 67\r\n [28, 38, 0, 255], //----- 68\r\n [33, 38, 19, 255], //----- 69\r\n [127, 255, 0, 255], //----- 70\r\n [191, 255, 127, 255],//----- 71\r\n [82, 165, 0, 255], //----- 72\r\n [124, 165, 82, 255], //----- 73\r\n [63, 127, 0, 255], //----- 74\r\n [95, 127, 63, 255], //----- 75\r\n [38, 76, 0, 255], //----- 76\r\n [57, 76, 38, 255], //----- 77\r\n [19, 38, 0, 255], //----- 78\r\n [28, 38, 19, 255], //----- 79\r\n [63, 255, 0, 255], //----- 80\r\n [159, 255, 127, 255],//----- 81\r\n [41, 165, 0, 255], //----- 82\r\n [103, 165, 82, 255], //----- 83\r\n [31, 127, 0, 255], //----- 84\r\n [79, 127, 63, 255], //----- 85\r\n [19, 76, 0, 255], //----- 86\r\n [47, 76, 38, 255], //----- 87\r\n [9, 38, 0, 255], //----- 88\r\n [23, 38, 19, 255], //----- 89\r\n [0, 255, 0, 255], //----- 90\r\n [127, 255, 127, 255],//----- 91\r\n [0, 165, 0, 255], //----- 92\r\n [82, 165, 82, 255], //----- 93\r\n [0, 127, 0, 255], //----- 94\r\n [63, 127, 63, 255], //----- 95\r\n [0, 76, 0, 255], //----- 96\r\n [38, 76, 38, 255], //----- 97\r\n [0, 38, 0, 255], //----- 98\r\n [19, 38, 19, 255], //----- 99\r\n [0, 255, 63, 255], //----- 100\r\n [127, 255, 159, 255],//----- 101\r\n [0, 165, 41, 255], //----- 102\r\n [82, 165, 103, 255], //----- 103\r\n [0, 127, 31, 255], //----- 104\r\n [63, 127, 79, 255], //----- 105\r\n [0, 76, 19, 255], //----- 106\r\n [38, 76, 47, 255], //----- 107\r\n [0, 38, 9, 255], //----- 108\r\n [19, 38, 23, 255], //----- 109\r\n [0, 255, 127, 255], //----- 110\r\n [127, 255, 191, 255],//----- 111\r\n [0, 165, 82, 255], //----- 112\r\n [82, 165, 124, 255], //----- 113\r\n [0, 127, 63, 255], //----- 114\r\n [63, 127, 95, 255], //----- 115\r\n [0, 76, 38, 255], //----- 116\r\n [38, 76, 57, 255], //----- 117\r\n [0, 38, 19, 255], //----- 118\r\n [19, 38, 28, 255], //----- 119\r\n [0, 255, 191, 255], //----- 120\r\n [127, 255, 223, 255],//----- 121\r\n [0, 165, 124, 255], //----- 122\r\n [82, 165, 145, 255], //----- 123\r\n [0, 127, 95, 255], //----- 124\r\n [63, 127, 111, 255], //----- 125\r\n [0, 76, 57, 255], //----- 126\r\n [38, 76, 66, 255], //----- 127\r\n [0, 38, 28, 255], //----- 128\r\n [19, 38, 33, 255], //----- 129\r\n [0, 255, 255, 255], //----- 130\r\n [127, 255, 255, 255],//----- 131\r\n [0, 165, 165, 255], //----- 132\r\n [82, 165, 165, 255], //----- 133\r\n [0, 127, 127, 255], //----- 134\r\n [63, 127, 127, 255], //----- 135\r\n [0, 76, 76, 255], //----- 136\r\n [38, 76, 76, 255], //----- 137\r\n [0, 38, 38, 255], //----- 138\r\n [19, 38, 38, 255], //----- 139\r\n [0, 191, 255, 255], //----- 140\r\n [127, 223, 255, 255],//----- 141\r\n [0, 124, 165, 255], //----- 142\r\n [82, 145, 165, 255], //----- 143\r\n [0, 95, 127, 255], //----- 144\r\n [63, 111, 127, 255], //----- 145\r\n [0, 57, 76, 255], //----- 146\r\n [38, 66, 76, 255], //----- 147\r\n [0, 28, 38, 255], //----- 148\r\n [19, 33, 38, 255], //----- 149\r\n [0, 127, 255, 255], //----- 150\r\n [127, 191, 255, 255],//----- 151\r\n [0, 82, 165, 255], //----- 152\r\n [82, 124, 165, 255], //----- 153\r\n [0, 63, 127, 255], //----- 154\r\n [63, 95, 127, 255], //----- 155\r\n [0, 38, 76, 255], //----- 156\r\n [38, 57, 76, 255], //----- 157\r\n [0, 19, 38, 255], //----- 158\r\n [19, 28, 38, 255], //----- 159\r\n [0, 63, 255, 255], //----- 160\r\n [127, 159, 255, 255],//----- 161\r\n [0, 41, 165, 255], //----- 162\r\n [82, 103, 165, 255], //----- 163\r\n [0, 31, 127, 255], //----- 164\r\n [63, 79, 127, 255], //----- 165\r\n [0, 19, 76, 255], //----- 166\r\n [38, 47, 76, 255], //----- 167\r\n [0, 9, 38, 255], //----- 168\r\n [19, 23, 38, 255], //----- 169\r\n [0, 0, 255, 255], //----- 170\r\n [127, 127, 255, 255],//----- 171\r\n [0, 0, 165, 255], //----- 172\r\n [82, 82, 165, 255], //----- 173\r\n [0, 0, 127, 255], //----- 174\r\n [63, 63, 127, 255], //----- 175\r\n [0, 0, 76, 255], //----- 176\r\n [38, 38, 76, 255], //----- 177\r\n [0, 0, 38, 255], //----- 178\r\n [19, 19, 38, 255], //----- 179\r\n [63, 0, 255, 255], //----- 180\r\n [159, 127, 255, 255],//----- 181\r\n [41, 0, 165, 255], //----- 182\r\n [103, 82, 165, 255], //----- 183\r\n [31, 0, 127, 255], //----- 184\r\n [79, 63, 127, 255], //----- 185\r\n [19, 0, 76, 255], //----- 186\r\n [47, 38, 76, 255], //----- 187\r\n [9, 0, 38, 255], //----- 188\r\n [23, 19, 38, 255], //----- 189\r\n [127, 0, 255, 255], //----- 190\r\n [191, 127, 255, 255],//----- 191\r\n [82, 0, 165, 255], //----- 192\r\n [124, 82, 165, 255], //----- 193\r\n [63, 0, 127, 255], //----- 194\r\n [95, 63, 127, 255], //----- 195\r\n [38, 0, 76, 255], //----- 196\r\n [57, 38, 76, 255], //----- 197\r\n [19, 0, 38, 255], //----- 198\r\n [28, 19, 38, 255], //----- 199\r\n [191, 0, 255, 255], //----- 200\r\n [223, 127, 255, 255],//----- 201\r\n [124, 0, 165, 255], //----- 202\r\n [145, 82, 165, 255], //----- 203\r\n [95, 0, 127, 255], //----- 204\r\n [111, 63, 127, 255], //----- 205\r\n [57, 0, 76, 255], //----- 206\r\n [66, 38, 76, 255], //----- 207\r\n [28, 0, 38, 255], //----- 208\r\n [33, 19, 38, 255], //----- 209\r\n [255, 0, 255, 255], //----- 210\r\n [255, 127, 255, 255],//----- 211\r\n [165, 0, 165, 255], //----- 212\r\n [165, 82, 165, 255], //----- 213\r\n [127, 0, 127, 255], //----- 214\r\n [127, 63, 127, 255], //----- 215\r\n [76, 0, 76, 255], //----- 216\r\n [76, 38, 76, 255], //----- 217\r\n [38, 0, 38, 255], //----- 218\r\n [38, 19, 38, 255], //----- 219\r\n [255, 0, 191, 255], //----- 220\r\n [255, 127, 223, 255],//----- 221\r\n [165, 0, 124, 255], //----- 222\r\n [165, 82, 145, 255], //----- 223\r\n [127, 0, 95, 255], //----- 224\r\n [127, 63, 111, 255], //----- 225\r\n [76, 0, 57, 255], //----- 226\r\n [76, 38, 66, 255], //----- 227\r\n [38, 0, 28, 255], //----- 228\r\n [38, 19, 33, 255], //----- 229\r\n [255, 0, 127, 255], //----- 230\r\n [255, 127, 191, 255],//----- 231\r\n [165, 0, 82, 255], //----- 232\r\n [165, 82, 124, 255], //----- 233\r\n [127, 0, 63, 255], //----- 234\r\n [127, 63, 95, 255], //----- 235\r\n [76, 0, 38, 255], //----- 236\r\n [76, 38, 57, 255], //----- 237\r\n [38, 0, 19, 255], //----- 238\r\n [38, 19, 28, 255], //----- 239\r\n [255, 0, 63, 255], //----- 240\r\n [255, 127, 159, 255],//----- 241\r\n [165, 0, 41, 255], //----- 242\r\n [165, 82, 103, 255], //----- 243\r\n [127, 0, 31, 255], //----- 244\r\n [127, 63, 79, 255], //----- 245\r\n [76, 0, 19, 255], //----- 246\r\n [76, 38, 47, 255], //----- 247\r\n [38, 0, 9, 255], //----- 248\r\n [38, 19, 23, 255], //----- 249\r\n [84, 84, 84, 255], //----- 250\r\n [118, 118, 118, 255],//----- 251\r\n [152, 152, 152, 255],//----- 252\r\n [186, 186, 186, 255],//----- 253\r\n [220, 220, 220, 255],//----- 254\r\n [255, 255, 255, 255],//----- 255\r\n [0, 0, 0, 0] //----- ByLayer - White\r\n];\r\n\r\nexport const LINE_WIDTH = 2;\r\n\r\n//颜色材质,对于二维图像来说可能有用,应该不对三维对象使用该材质\r\nexport class ColorMaterial\r\n{\r\n private constructor() { }\r\n private static _LineMaterialMap = new Map();\r\n private static _BasicMaterialMap = new Map();\r\n static GetLineMaterial(color: number): LineBasicMaterial\r\n {\r\n if (this._LineMaterialMap.has(color))\r\n return this._LineMaterialMap.get(color);\r\n let mat = new LineBasicMaterial({ color: this.GetColor(color) });\r\n this._LineMaterialMap.set(color, mat);\r\n return mat;\r\n }\r\n\r\n static GetBasicMaterial(color: number): MeshBasicMaterial\r\n {\r\n if (this._BasicMaterialMap.has(color))\r\n return this._BasicMaterialMap.get(color);\r\n let mtl = new MeshBasicMaterial({ color: this.GetColor(color) });\r\n this._BasicMaterialMap.set(color, mtl);\r\n return mtl;\r\n }\r\n\r\n private static _BasicDoubleSideMaterialMap = new Map();\r\n static GetBasicMaterialDoubleSide(color: number): MeshBasicMaterial\r\n {\r\n if (this._BasicDoubleSideMaterialMap.has(color))\r\n return this._BasicDoubleSideMaterialMap.get(color);\r\n let mtl = new MeshBasicMaterial({ color: this.GetColor(color), side: DoubleSide });\r\n this._BasicDoubleSideMaterialMap.set(color, mtl);\r\n return mtl;\r\n }\r\n\r\n private static _ConceptualMaterial: Map = new Map();\r\n static GetConceptualMaterial(color: number)\r\n {\r\n if (this._ConceptualMaterial.has(color))\r\n return this._ConceptualMaterial.get(color);\r\n\r\n let shaderParams = GetGoodShaderSimple(\r\n new Vector3().fromArray(this.GetColor(color).toArray())\r\n );\r\n let mtl = new ShaderMaterial(shaderParams);\r\n this._ConceptualMaterial.set(color, mtl);\r\n return mtl;\r\n }\r\n private static _printConceptualMaterial: ShaderMaterial;\r\n static GetPrintConceptualMaterial()\r\n {\r\n if (!this._printConceptualMaterial)\r\n {\r\n this._printConceptualMaterial = new ShaderMaterial({\r\n uniforms: {\r\n \"SurfaceColor\": { value: [1.0, 1.0, 1.0] }\r\n },\r\n vertexShader: require(\"../GLSL/GoodchSimple.vs\"),\r\n fragmentShader: require(\"../GLSL/GoodchSimple2.fs\"),\r\n polygonOffset: true,\r\n polygonOffsetFactor: 1,\r\n polygonOffsetUnits: LINE_WIDTH\r\n });\r\n }\r\n return this._printConceptualMaterial;\r\n }\r\n\r\n private static _BasicTransparentMaterialMap: Map = new Map();\r\n static GetBasicMaterialTransparent(color: number, opacity: number)\r\n {\r\n let key = `${color},${opacity}`;\r\n let mat = this._BasicTransparentMaterialMap.get(key);\r\n if (mat) return mat;\r\n mat = new MeshBasicMaterial({ transparent: true, opacity: opacity, side: DoubleSide });\r\n this._BasicTransparentMaterialMap.set(key, mat);\r\n return mat;\r\n }\r\n\r\n private static _BasicTransparentMaterialMap2: Map = new Map();\r\n static GetBasicMaterialTransparent2(color: number, opacity: number)\r\n {\r\n let key = `${color},${opacity}`;\r\n let mat = this._BasicTransparentMaterialMap2.get(key);\r\n if (mat) return mat;\r\n mat = new MeshBasicMaterial({ transparent: true, opacity: opacity });\r\n this._BasicTransparentMaterialMap2.set(key, mat);\r\n return mat;\r\n }\r\n\r\n static GetColor(color: number)\r\n {\r\n let rgb = ColorPalette[color];\r\n if (rgb)\r\n return new Color(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255);\r\n\r\n //避免无法获得到颜色而产生的错误\r\n return new Color();\r\n }\r\n\r\n //橡皮筋材质: 黄色 点划线\r\n static RubberBandMaterial = new LineDashedMaterial({\r\n color: 0xF0B41E,\r\n dashSize: 20,\r\n gapSize: 8,\r\n });\r\n\r\n //极轴材质: 绿色 点划线\r\n static SnapAxisMaterial = new LineDashedMaterial({\r\n color: 0x008B00,\r\n dashSize: 5,\r\n gapSize: 5\r\n });\r\n static PrintLineMatrial = new LineMaterial({\r\n color: 0x000000,\r\n linewidth: LINE_WIDTH,\r\n dashed: false,\r\n resolution: new Vector2(1000, 1000)\r\n });\r\n static GrayTransparentMeshMaterial = new MeshBasicMaterial({\r\n color: 0xcccccc,\r\n transparent: true,\r\n opacity: 0.3,\r\n });\r\n static TransparentMeshMaterial = new MeshBasicMaterial({\r\n transparent: true,\r\n opacity: 0,\r\n });\r\n static TransparentLineMaterial = new MeshBasicMaterial({\r\n transparent: true,\r\n opacity: 0,\r\n });\r\n}\r\n","/**\r\n * 删除数组中指定的元素,返回数组本身\r\n * @param {Array} arr 需要操作的数组\r\n * @param {*} el 需要移除的元素\r\n */\r\nexport function arrayRemove(arr: Array, el: T): Array\r\n{\r\n let j = 0;\r\n for (let i = 0, l = arr.length; i < l; i++)\r\n {\r\n if (arr[i] !== el)\r\n {\r\n arr[j++] = arr[i];\r\n }\r\n }\r\n arr.length = j;\r\n\r\n return arr;\r\n}\r\n\r\n\r\nexport function arrayRemoveOnce(arr: Array, el: T): Array\r\n{\r\n let index = arr.indexOf(el);\r\n if (index !== -1)\r\n arr.splice(index, 1);\r\n return arr;\r\n}\r\n\r\n/**\r\n * 删除通过函数校验的元素\r\n * @param {(e: T) => boolean} checkFuntion 校验函数\r\n */\r\nexport function arrayRemoveIf(arr: Array, checkFuntion: (e: T) => boolean): Array\r\n{\r\n let j = 0;\r\n for (let i = 0, l = arr.length; i < l; i++)\r\n {\r\n if (!checkFuntion(arr[i]))\r\n {\r\n arr[j++] = arr[i];\r\n }\r\n }\r\n arr.length = j;\r\n\r\n return arr;\r\n}\r\n\r\nexport function arrayFirst(arr: Array): T\r\n{\r\n return arr[0];\r\n}\r\n\r\nexport function arrayLast(arr: { [key: number]: T, length: number; }): T\r\n{\r\n return arr[arr.length - 1];\r\n}\r\n\r\n/**\r\n * 根据数值从小到大排序数组\r\n * @param {Array} arr\r\n * @returns {Array} 返回自身\r\n */\r\nexport function arraySortByNumber(arr: Array): Array\r\n{\r\n arr.sort(sortNumberCompart);\r\n return arr;\r\n}\r\n\r\n/**\r\n * 对排序好的数组进行去重操作\r\n * @param {(e1, e2) => boolean} [checkFuction] 校验对象相等函数\r\n * @returns {Array} 返回自身\r\n */\r\nexport function arrayRemoveDuplicateBySort(arr: Array, checkFuction: (e1: T, e2: T) => boolean = checkEqual): Array\r\n{\r\n if (arr.length < 2) return arr;\r\n let j = 1;\r\n for (let i = 1, l = arr.length; i < l; i++)\r\n if (!checkFuction(arr[j - 1], arr[i]))\r\n arr[j++] = arr[i];\r\n arr.length = j;\r\n return arr;\r\n}\r\n\r\n//原地更新数组,注意这个函数并不会比map快.\r\nexport function arrayMap(arr: Array, mapFunc: (v: T) => T): Array\r\n{\r\n for (let i = 0, count = arr.length; i < count; i++)\r\n arr[i] = mapFunc(arr[i]);\r\n return arr;\r\n}\r\n\r\nfunction sortNumberCompart(e1: any, e2: any)\r\n{\r\n return e1 - e2;\r\n}\r\n\r\nfunction checkEqual(e1: any, e2: any): boolean\r\n{\r\n return e1 === e2;\r\n}\r\n\r\n/**\r\n * 改变数组的值顺序\r\n * @param arr 需要改变初始值位置的数组\r\n * @param index //将index位置以后的值放到起始位置\r\n */\r\nexport function changeArrayStartIndex(arr: T[], index: number): T[]\r\n{\r\n arr.unshift(...arr.splice(index));\r\n return arr;\r\n}\r\n\r\nexport function equalArray(a: T[], b: T[], checkF = checkEqual)\r\n{\r\n if (a === b) return true;\r\n if (a.length !== b.length) return false;\r\n for (var i = 0; i < a.length; ++i)\r\n if (!checkF(a[i], b[i])) return false;\r\n return true;\r\n}\r\n\r\nexport function arrayClone(arr: T[]): T[]\r\n{\r\n return arr.slice();\r\n}\r\n\r\n//https://jsperf.com/merge-array-implementations/30\r\nexport function arrayPushArray(arr1: T[], arr2: T[]): T[]\r\n{\r\n let arr1Length = arr1.length;\r\n let arr2Length = arr2.length;\r\n arr1.length = arr1Length + arr2Length;\r\n for (let i = 0; i < arr2Length; i++)\r\n arr1[arr1Length + i] = arr2[i];\r\n\r\n return arr1;\r\n}\r\n\r\nexport function arraySum(arr: number[])\r\n{\r\n let sum = 0;\r\n for (let n of arr) sum += n;\r\n return sum;\r\n}\r\n\r\nexport function FilterSet(s: Set, fn: (el: T) => boolean): Set\r\n{\r\n let ns = new Set();\r\n for (let el of s)\r\n {\r\n if (fn(el))\r\n ns.add(el);\r\n }\r\n return ns;\r\n}\r\n","\r\n/**\r\n * OSMODE\r\n */\r\nexport enum ObjectSnapMode\r\n{\r\n None = 0, //无\r\n End = 1, //端点\r\n Mid = 2, //中点\r\n Cen = 4, //圆心\r\n Node = 8,//节点\r\n Qua = 16,//象限点\r\n Int = 32,//交点\r\n Ins = 64,//插入点\r\n Per = 128,//垂足\r\n Tan = 256,//切点\r\n Nea = 512,//最近点\r\n NotEntitySnap = 1024,//清除所有对象捕捉\r\n App = 2048,//外观交点\r\n Ext = 4096,//延伸\r\n Par = 8192,//平行\r\n Axis = 16384,//极轴\r\n All = ~(~0 << 15) - 1024,\r\n}\r\n","import { BufferGeometry, Vector3, BufferAttribute, ShapeGeometry, Shape } from \"three\";\r\n\r\nexport namespace BufferGeometryUtils\r\n{\r\n export function CreateFromPts(pts: Vector3[]): BufferGeometry\r\n {\r\n return new BufferGeometry().setFromPoints(pts);\r\n }\r\n\r\n /**\r\n * 更新BufferGeometry的顶点\r\n * @param geo\r\n * @param pts\r\n * @returns 当成功时返回true,更新失败时返回false\r\n */\r\n export function UpdatePts(geo: BufferGeometry, pts: Vector3[]): boolean\r\n {\r\n let bf = geo.getAttribute(\"position\") as BufferAttribute;\r\n if (bf === undefined)\r\n geo.setFromPoints(pts);\r\n else if (bf.count >= pts.length)\r\n {\r\n bf.copyVector3sArray(pts);\r\n bf.needsUpdate = true;\r\n geo.drawRange.count = pts.length;\r\n }\r\n else\r\n return false;\r\n\r\n return true;\r\n }\r\n\r\n let arrowGeometry: ShapeGeometry;\r\n export function ArrowGeometry()\r\n {\r\n if (arrowGeometry)\r\n return arrowGeometry;\r\n else\r\n {\r\n let arrowShape = new Shape();\r\n arrowShape.lineTo(-0.5, -1.8);\r\n arrowShape.lineTo(0.5, -1.8);\r\n arrowGeometry = new ShapeGeometry(arrowShape);\r\n arrowGeometry.computeBoundingBox();\r\n return arrowGeometry;\r\n }\r\n }\r\n\r\n export function MergeBufferGeometries(geometries: BufferGeometry[], useGroups: boolean = false): BufferGeometry\r\n {\r\n if (geometries.length === 0)\r\n return new BufferGeometry();\r\n let isIndexed = geometries[0].index !== null;\r\n\r\n let attributesUsed = new Set(Object.keys(geometries[0].attributes));\r\n let morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));\r\n\r\n let attributes = {};\r\n let morphAttributes = {};\r\n\r\n let morphTargetsRelative = geometries[0].morphTargetsRelative;\r\n\r\n let mergedGeometry = new BufferGeometry();\r\n\r\n let offset = 0;\r\n\r\n for (let i = 0; i < geometries.length; ++i)\r\n {\r\n\r\n let geometry = geometries[i];\r\n\r\n // ensure that all geometries are indexed, or none\r\n\r\n if (isIndexed !== (geometry.index !== null)) return null;\r\n\r\n // gather attributes, exit early if they're different\r\n\r\n for (let name in geometry.attributes)\r\n {\r\n\r\n if (!attributesUsed.has(name)) continue;\r\n\r\n if (attributes[name] === undefined) attributes[name] = [];\r\n\r\n attributes[name].push(geometry.attributes[name]);\r\n\r\n }\r\n\r\n // gather morph attributes, exit early if they're different\r\n\r\n if (morphTargetsRelative !== geometry.morphTargetsRelative) return null;\r\n\r\n for (let name in geometry.morphAttributes)\r\n {\r\n\r\n if (!morphAttributesUsed.has(name)) continue;\r\n\r\n if (morphAttributes[name] === undefined) morphAttributes[name] = [];\r\n\r\n morphAttributes[name].push(geometry.morphAttributes[name]);\r\n\r\n }\r\n\r\n // gather .userData\r\n\r\n mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];\r\n mergedGeometry.userData.mergedUserData.push(geometry.userData);\r\n\r\n if (useGroups)\r\n {\r\n\r\n let count: number;\r\n\r\n if (isIndexed)\r\n {\r\n\r\n count = geometry.index.count;\r\n\r\n } else if (geometry.attributes.position !== undefined)\r\n {\r\n\r\n count = geometry.attributes.position.count;\r\n\r\n } else\r\n {\r\n\r\n return null;\r\n\r\n }\r\n\r\n mergedGeometry.addGroup(offset, count, i);\r\n\r\n offset += count;\r\n\r\n }\r\n\r\n }\r\n\r\n // merge indices\r\n\r\n if (isIndexed)\r\n {\r\n\r\n let indexOffset = 0;\r\n let mergedIndex = [];\r\n\r\n for (let i = 0; i < geometries.length; ++i)\r\n {\r\n\r\n let index = geometries[i].index;\r\n\r\n for (let j = 0; j < index.count; ++j)\r\n {\r\n\r\n mergedIndex.push(index.getX(j) + indexOffset);\r\n\r\n }\r\n\r\n indexOffset += geometries[i].attributes.position.count;\r\n\r\n }\r\n\r\n mergedGeometry.setIndex(mergedIndex);\r\n\r\n }\r\n\r\n // merge attributes\r\n\r\n for (let name in attributes)\r\n {\r\n\r\n let mergedAttribute = MergeBufferAttributes(attributes[name]);\r\n\r\n if (!mergedAttribute) return null;\r\n\r\n mergedGeometry.setAttribute(name, mergedAttribute);\r\n\r\n }\r\n\r\n // merge morph attributes\r\n\r\n for (let name in morphAttributes)\r\n {\r\n\r\n let numMorphTargets = morphAttributes[name][0].length;\r\n\r\n if (numMorphTargets === 0) break;\r\n\r\n mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};\r\n mergedGeometry.morphAttributes[name] = [];\r\n\r\n for (let i = 0; i < numMorphTargets; ++i)\r\n {\r\n\r\n let morphAttributesToMerge: any[] = [];\r\n\r\n for (let j = 0; j < morphAttributes[name].length; ++j)\r\n {\r\n\r\n morphAttributesToMerge.push(morphAttributes[name][j][i]);\r\n\r\n }\r\n\r\n let mergedMorphAttribute = MergeBufferAttributes(morphAttributesToMerge);\r\n\r\n if (!mergedMorphAttribute) return null;\r\n\r\n mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);\r\n\r\n }\r\n\r\n }\r\n\r\n return mergedGeometry;\r\n\r\n }\r\n\r\n export function MergeBufferAttributes(attributes: BufferAttribute[]): BufferAttribute\r\n {\r\n let TypedArray;\r\n let itemSize: number;\r\n let normalized: boolean;\r\n let arrayLength = 0;\r\n\r\n for (let i = 0; i < attributes.length; ++i)\r\n {\r\n\r\n let attribute = attributes[i];\r\n\r\n if (TypedArray === undefined) TypedArray = attribute.array.constructor;\r\n if (TypedArray !== attribute.array.constructor) return null;\r\n\r\n if (itemSize === undefined) itemSize = attribute.itemSize;\r\n if (itemSize !== attribute.itemSize) return null;\r\n\r\n if (normalized === undefined) normalized = attribute.normalized;\r\n if (normalized !== attribute.normalized) return null;\r\n\r\n arrayLength += attribute.array.length;\r\n\r\n }\r\n\r\n let array = new TypedArray(arrayLength);\r\n let offset = 0;\r\n\r\n for (let i = 0; i < attributes.length; ++i)\r\n {\r\n\r\n array.set(attributes[i].array, offset);\r\n\r\n offset += attributes[i].array.length;\r\n\r\n }\r\n\r\n return new BufferAttribute(array, itemSize, normalized);\r\n\r\n }\r\n\r\n}\r\n","import { EllipseCurve, Shape, Vector2 } from \"three\";\r\nimport { clamp } from \"../Common/Utils\";\r\nimport { equalv2 } from \"../Geometry/GeUtils\";\r\n\r\nexport class Shape2 extends Shape\r\n{\r\n getPoints(divisions: number = 12)\r\n {\r\n divisions = divisions || 12;\r\n let points = [], last: Vector2;\r\n for (let i = 0, curves = this.curves; i < curves.length; i++)\r\n {\r\n let curve = curves[i];\r\n //@ts-ignore\r\n let resolution = (curve && curve.isEllipseCurve) ? clamp(curve.getLength() / 20, divisions * 2, 60)\r\n //@ts-ignore\r\n : (curve && (curve.isLineCurve || curve.isLineCurve3)) ? 1\r\n //@ts-ignore\r\n : (curve && curve.isSplineCurve) ? divisions * curve.points.length\r\n : divisions;\r\n\r\n let pts = curve.getPoints(resolution);\r\n\r\n for (let j = 0; j < pts.length; j++)\r\n {\r\n let point = pts[j];\r\n if (last && equalv2(last, point, 1e-4))\r\n continue; // ensures no consecutive points are duplicates\r\n\r\n points.push(point);\r\n last = point;\r\n\r\n if (j === pts.length - 1)\r\n point[\"_mask_\"] = true;\r\n }\r\n }\r\n if (this.autoClose\r\n && points.length > 1\r\n && !points[points.length - 1].equals(points[0]))\r\n {\r\n points.push(points[0]);\r\n }\r\n return points;\r\n }\r\n\r\n\r\n absellipse(aX: number, aY: number, xRadius: number, yRadius: number, aStartAngle: number, aEndAngle: number, aClockwise: boolean, aRotation: number): this\r\n {\r\n let curve = new EllipseCurve(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation);\r\n\r\n /*\r\n if (this.curves.length > 0)\r\n {\r\n // if a previous curve is present, attempt to join\r\n let firstPoint = curve.getPoint(0);\r\n if (!equalv2(firstPoint, this.currentPoint))\r\n {\r\n this.lineTo(firstPoint.x, firstPoint.y);\r\n }\r\n }\r\n */\r\n\r\n this.curves.push(curve);\r\n\r\n let lastPoint = curve.getPoint(1);\r\n this.currentPoint.copy(lastPoint);\r\n\r\n return this;\r\n }\r\n}\r\n","import { Vector2, Vector3, Matrix4 } from \"three\";\r\n\r\nexport class Matrix2\r\n{\r\n //column-major\r\n el = [1, 0, 0, 1]; //ix iy jx jy [a c b d]\r\n\r\n set(ix: number, iy: number, jx: number, jy: number)\r\n {\r\n this.el[0] = ix;\r\n this.el[1] = iy;\r\n this.el[2] = jx;\r\n this.el[3] = jy;\r\n }\r\n\r\n applyVector(vec: Vector2 | Vector3)\r\n {\r\n let x = vec.x;\r\n let y = vec.y;\r\n let e = this.el;\r\n vec.x = e[0] * x + e[2] * y;\r\n vec.y = e[1] * x + e[3] * y;\r\n return this;\r\n }\r\n\r\n fromMatrix4(mtx4: Matrix4)\r\n {\r\n this.set(mtx4.elements[0], mtx4.elements[1],\r\n mtx4.elements[3], mtx4.elements[4]\r\n );\r\n }\r\n\r\n setRotate(theta: number): this\r\n {\r\n let c = Math.cos(theta);\r\n let s = Math.sin(theta);\r\n this.set(c, s, -s, c);\r\n return this;\r\n }\r\n\r\n //自我求逆矩阵,返回自身\r\n invert(): this\r\n {\r\n //ref:https://www.mathsisfun.com/algebra/matrix-inverse.html\r\n let [a, c, b, d] = this.el;\r\n let det = 1 / (a * d - b * c);\r\n this.set(d * det, -c * det,\r\n -b * det, a * det\r\n );\r\n return this;\r\n }\r\n}\r\n","import { Matrix2 } from './Matrix2';\r\n\r\nlet r = new Matrix2();\r\nexport function RotateUVs(geo: THREE.Geometry)\r\n{\r\n r.set(0, -1,\r\n 1, 0);\r\n\r\n for (let uvs of geo.faceVertexUvs)\r\n {\r\n for (let uv of uvs)\r\n {\r\n for (let v of uv)\r\n r.applyVector(v);\r\n }\r\n }\r\n geo.uvsNeedUpdate = true;\r\n}\r\n","import { ExtrudeGeometry, Matrix4, Mesh, Shape, Vector2 } from 'three';\r\nimport { Shape2 } from '../../DatabaseServices/Shape2';\r\nimport { AsVector3, equaln, polar } from '../../Geometry/GeUtils';\r\nimport { RotateUVs } from '../../Geometry/RotateUV';\r\n\r\nexport namespace CreateBoardUtil\r\n{\r\n //解析二维圆弧\r\n export class Arc2d\r\n {\r\n _StartAn: number;\r\n _EndAn: number;\r\n _StartPoint: Vector2;\r\n _EndPoint: Vector2;\r\n _Center: Vector2;\r\n _Radius: number;\r\n constructor(p1: Vector2, p2: Vector2, bul: number)\r\n {\r\n this._StartPoint = p1.clone();\r\n this._EndPoint = p2.clone();\r\n\r\n let vec: Vector2 = p2.clone().sub(p1);\r\n let len = vec.length();\r\n let an = vec.angle();\r\n this._Radius = len / Math.sin(2 * Math.atan(bul)) / 2;\r\n let allAngle = Math.atan(bul) * 4;\r\n let delDis = bul * len / 2;\r\n let toDis = this._Radius - delDis;\r\n an += Math.PI * 0.5;\r\n\r\n this._Center = p1.clone().add(p2);\r\n this._Center.multiplyScalar(0.5);\r\n\r\n polar(this._Center, an, toDis);\r\n\r\n this._StartAn = p1.clone().sub(this._Center).angle();\r\n this._EndAn = p2.clone().sub(this._Center).angle();\r\n if (bul < 0)\r\n {\r\n //一个神奇的特性 它需要这么做\r\n this._StartAn -= Math.PI;\r\n this._EndAn -= Math.PI;\r\n }\r\n }\r\n }\r\n\r\n\r\n //创建轮廓 通过点表和凸度\r\n export function CreatePath(pts: Vector2[], buls: number[]): Shape\r\n {\r\n let shape = new Shape2();\r\n if (pts.length === 0) return shape;\r\n let firstPt = pts[0];\r\n\r\n shape.moveTo(firstPt.x, firstPt.y);\r\n for (let i = 0; i < pts.length - 1; i++)\r\n {\r\n let nextPt = pts[i + 1];\r\n if (equaln(buls[i], 0, 1e-8))\r\n {\r\n shape.lineTo(nextPt.x, nextPt.y);\r\n }\r\n else\r\n {\r\n let pt = pts[i];\r\n //参考\r\n //http://www.dorodnic.com/blog/tag/three-js/ 绘制一个齿轮\r\n //https://www.kirupa.com/html5/drawing_circles_canvas.htm //html5\r\n let arc2 = new Arc2d(pt, nextPt, buls[i]);\r\n let cen = arc2._Center;\r\n shape.absarc(cen.x, cen.y, arc2._Radius, arc2._StartAn, arc2._EndAn, buls[i] < 0);\r\n }\r\n }\r\n return shape;\r\n }\r\n\r\n //创建板件 暂时这么写\r\n export function createBoard(boardData: object)\r\n {\r\n var pts: Vector2[] = new Array();\r\n var buls: number[] = new Array();\r\n var boardPts = boardData[\"Pts\"];\r\n var boardBuls = boardData[\"Buls\"];\r\n\r\n let boardHeight = boardData[\"H\"];\r\n\r\n var boardMat = new Matrix4();\r\n var matInv: Matrix4 = new Matrix4();\r\n //InitBoardMat\r\n {\r\n\r\n var xD = AsVector3(boardData[\"XVec\"]);\r\n var yD = AsVector3(boardData[\"YVec\"]);\r\n var ZD = AsVector3(boardData[\"ZVec\"]);\r\n var pBase = AsVector3(boardData[\"BasePoint\"]).multiplyScalar(0.001);\r\n\r\n boardMat.makeBasis(xD, yD, ZD);\r\n boardMat.setPosition(pBase);\r\n matInv.getInverse(boardMat);\r\n }\r\n\r\n for (let i = 0; i < boardPts.length; i++)\r\n {\r\n var pt = AsVector3(boardPts[i]).multiplyScalar(0.001);\r\n pt.applyMatrix4(matInv);\r\n pts.push(new Vector2(pt.x, pt.y));\r\n buls.push(boardBuls[i]);\r\n }\r\n\r\n var sp = CreatePath(pts, buls);\r\n var extrudeSettings = {\r\n steps: 1,\r\n bevelEnabled: false,\r\n amount: boardHeight * 0.001\r\n };\r\n\r\n var ext = new ExtrudeGeometry(sp, extrudeSettings);\r\n ext.translate(0, 0, -boardHeight * 0.001);\r\n ext.applyMatrix4(boardMat);\r\n\r\n if (boardData[\"BoardName\"] === \"地脚线\")\r\n {\r\n RotateUVs(ext);\r\n }\r\n\r\n var mesh = new Mesh(ext);\r\n return mesh;\r\n }\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { angle, clampRad, equalv3 } from \"./GeUtils\";\r\n\r\n//顶点\r\nexport interface Vertice\r\n{\r\n //位置\r\n position: Vector3;\r\n //路径\r\n routes: Route[];\r\n}\r\n\r\n//路线\r\nexport interface Route\r\n{\r\n curve: Curve; //路线的曲线\r\n from: Vertice;\r\n to: Vertice; //终点的点\r\n length: number;\r\n isReverse: boolean;\r\n an?: number; //角度\r\n\r\n s: Vector3;\r\n e: Vector3;\r\n}\r\n\r\n/**\r\n * 曲线连接图\r\n * 所有的顶点和边的关系\r\n */\r\nexport class CurveMap\r\n{\r\n constructor(\r\n public numdimensions = 4,\r\n public _RemoveSortLine = false,\r\n private multiplier = 10 ** numdimensions,\r\n ) { }\r\n\r\n /*\r\n 节点图.\r\n 每个节点对应下一个路口的路线表.\r\n 路口表使用逆时针排序,起始角度使用正x轴.\r\n */\r\n _VerticeMap = new Map();\r\n\r\n _Vertices: Vertice[] = [];\r\n\r\n /**\r\n * 得到节点图的所有站点列表\r\n */\r\n get Stands(): Vertice[]\r\n {\r\n return this._Vertices;\r\n }\r\n\r\n /**\r\n * @param curve\r\n * @param [isArc=curve instanceof Arc]\r\n * @param [removeDuplicate=false]\r\n * @returns 加入成功?\r\n */\r\n AddCurveToMap(curve: Curve, isArc: boolean = curve instanceof Arc, removeDuplicate: boolean = false, parseAngle = false): boolean\r\n {\r\n let sp = curve.StartPoint;\r\n let ep = curve.EndPoint;\r\n let startS = this.GetOnlyVertice(sp);\r\n let endS = this.GetOnlyVertice(ep);\r\n\r\n //在面域分析中,路线指向同一个顶点已经没有意义了\r\n if (this._RemoveSortLine && startS === endS)\r\n return false;\r\n\r\n if (removeDuplicate)//删除重复\r\n {\r\n let index = startS.routes.findIndex(r =>\r\n {\r\n if (r.to === endS && r.curve.constructor.name === curve.constructor.name)\r\n {\r\n if (isArc)\r\n return equalv3(curve.GetPointAtParam(0.5), r.curve.GetPointAtParam(0.5));\r\n return true;\r\n }\r\n });\r\n if (index !== -1) return false;\r\n }\r\n\r\n let length = curve.Length;\r\n curve.TempData = 0;\r\n\r\n let routeS2E: Route = { curve, isReverse: false, length, from: startS, to: endS, s: sp, e: ep };\r\n let routeE2S: Route = { curve, isReverse: true, length, from: endS, to: startS, e: sp, s: ep };\r\n\r\n if (!isArc && parseAngle)\r\n {\r\n let an = angle(endS.position.clone().sub(startS.position));\r\n routeS2E.an = an;\r\n routeE2S.an = clampRad(an + Math.PI);\r\n }\r\n startS.routes.push(routeS2E);\r\n endS.routes.push(routeE2S);\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * 获得唯一的顶点\r\n */\r\n GetOnlyVertice(p: Vector3): Vertice\r\n {\r\n let gp = this.GenerateP(p);\r\n if (this._VerticeMap.has(gp))\r\n return this._VerticeMap.get(gp);\r\n\r\n let vertice: Vertice = { position: gp, routes: [] };\r\n this._VerticeMap.set(p, vertice);\r\n this._Vertices.push(vertice);\r\n return vertice;\r\n }\r\n\r\n _LookupTable: { [key: string]: Vector3; } = {};\r\n\r\n /**\r\n * 生成一个唯一的向量.\r\n */\r\n GenerateP(p: Vector3): Vector3\r\n {\r\n let key = \"\";\r\n let els = p.toArray();\r\n for (let n of els)\r\n {\r\n let valueQuantized = Math.round(n * this.multiplier);\r\n key += valueQuantized + '/';\r\n }\r\n\r\n if (key in this._LookupTable)\r\n return this._LookupTable[key];\r\n\r\n let hashparts = els.map((el) =>\r\n {\r\n let q0 = Math.floor(el * this.multiplier);\r\n let q1 = q0 + 1;\r\n return ['' + q0 + '/', '' + q1 + '/'];\r\n });\r\n\r\n let numelements = els.length;\r\n let numhashes = 1 << numelements;\r\n for (let hashmask = 0; hashmask < numhashes; ++hashmask)\r\n {\r\n let hashmaskShifted = hashmask;\r\n key = '';\r\n hashparts.forEach(function (hashpart)\r\n {\r\n key += hashpart[hashmaskShifted & 1];\r\n hashmaskShifted >>= 1;\r\n });\r\n this._LookupTable[key] = p;\r\n }\r\n return p;\r\n }\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { arrayLast, arrayRemoveIf, arrayRemoveOnce } from \"../Common/ArrayExt\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { Polyline } from \"../DatabaseServices/Entity/Polyline\";\r\nimport { CurveMap, Route, Vertice } from \"./CurveMap\";\r\nimport { angle } from \"./GeUtils\";\r\n\r\n//区域的路线表 表示了一个区域\r\ntype RegionRouteS = Route[][];\r\n\r\n/**\r\n面域分析,基于最小循环图重新实现的版本,拓展了实现求最大轮廓。\r\n当最大轮廓=最小轮廓时,只绘制最大轮廓(独立轮廓无分裂)。\r\n\r\n算法只实现去重模式,业务场景应该没有非去重模式。\r\n如果需要非去重模式,那么应该获取到多个CurveMap,然后对多个CurveMap进行面域分析,得出多个重叠的面域。\r\n */\r\nexport class RegionParse\r\n{\r\n //区域列表 通常是外轮廓\r\n RegionsOutline: RegionRouteS = [];\r\n //区域列表 通常是内轮廓\r\n RegionsInternal: RegionRouteS = [];\r\n\r\n //碎线 曲线进入到这里会被炸开.\r\n ExpLineMap: Map = new Map();\r\n\r\n private _CurveCount: number;\r\n\r\n /**\r\n * @param cuList 请不要传递圆和椭圆.\r\n * @param [numDimensions=3] 精度:小数点后个数\r\n * @param [removeDuplicate=true] 删除重复(现在必须是true,请不要修改它)\r\n */\r\n constructor(cuList: Curve[], public numDimensions = 3, private removeDuplicate = true)\r\n {\r\n //需要搜索的站\r\n let vertices = this.GenerateVerticeMap(cuList);\r\n\r\n //移除细丝\r\n while (true)\r\n {\r\n let v = vertices.find(v => v.routes.length < 2);\r\n if (v) this.RemoveFilamentAt(v, vertices);\r\n else break;\r\n }\r\n let lowerVertice: Vertice;\r\n while (vertices.length > 0)\r\n {\r\n lowerVertice = lowerVertice?.routes.length > 1 ? lowerVertice : this.FindLowerLeftStand(vertices);\r\n let minWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Min);\r\n let maxWalk = ClosedWalkFrom(lowerVertice, this._CurveCount, WalkType.Max);\r\n\r\n this.RemoveEdge(minWalk[0]);\r\n this.RemoveFilamentAt(minWalk[0].from, vertices);\r\n this.RemoveFilamentAt(minWalk[0].to, vertices);\r\n\r\n minWalk = ReduceWalk(minWalk);\r\n maxWalk = ReduceWalk(maxWalk);\r\n if (maxWalk.length > 1)\r\n {\r\n this.RegionsOutline.push(maxWalk);\r\n if (minWalk.length === maxWalk.length && minWalk.every((w1, index) => w1 === maxWalk[index]))//大小重叠\r\n {\r\n //直接remove,不用计算引用个数\r\n for (let w of minWalk)\r\n {\r\n this.RemoveEdge(w);\r\n this.RemoveFilamentAt(w.from, vertices);\r\n this.RemoveFilamentAt(w.to, vertices);\r\n }\r\n continue;//继续循环\r\n }\r\n else\r\n for (let w of maxWalk)\r\n w.curve.TempData = 1;\r\n }\r\n\r\n if (minWalk.length > 1)// && minWalk.every(w => (w.curve.TempData) < 2) 没有重复线应该不会被用2次\r\n {\r\n this.RegionsInternal.push(minWalk);\r\n for (let w of minWalk)\r\n {\r\n w.curve.TempData++;\r\n if (w.curve.TempData === 2)\r\n {\r\n this.RemoveEdge(w);\r\n this.RemoveFilamentAt(w.from, vertices);\r\n this.RemoveFilamentAt(w.to, vertices);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n RemoveFilamentAt(v: Vertice, vertices: Vertice[])\r\n {\r\n let current = v;\r\n while (current && current.routes.length < 2)\r\n {\r\n vertices = arrayRemoveOnce(vertices, current);\r\n let r = current.routes[0];\r\n if (r)\r\n {\r\n this.RemoveEdge(r);\r\n current = r.to;\r\n }\r\n else\r\n current = undefined;\r\n }\r\n }\r\n\r\n RemoveEdge(r: Route)\r\n {\r\n let index = r.from.routes.findIndex(rr => rr.curve === r.curve);\r\n if (index !== -1)\r\n r.from.routes.splice(index, 1);\r\n\r\n index = r.to.routes.findIndex(rr => rr.curve === r.curve);\r\n if (index !== -1)\r\n r.to.routes.splice(index, 1);\r\n }\r\n\r\n /**\r\n * 找到最下方并且最左边的站 yx\r\n */\r\n private FindLowerLeftStand(vertices: Vertice[]): Vertice\r\n {\r\n return vertices.reduce((m, v) =>\r\n {\r\n let dy = v.position.y - m.position.y;\r\n if (dy < 0) return v;\r\n if (dy > 0) return m;\r\n return v.position.x - m.position.x < 0 ? v : m;\r\n });\r\n }\r\n\r\n /**\r\n * 构造路线图. 每个节点对应下一个路口的路线表. 路口表使用逆时针排序,起始角度使用正x轴.\r\n * @returns 所有的顶点\r\n */\r\n private GenerateVerticeMap(curveList: Curve[]): Array\r\n {\r\n let curveMap = new CurveMap(this.numDimensions, true);\r\n\r\n //将多段线炸开\r\n let plcus: Curve[] = [];\r\n arrayRemoveIf(curveList, c =>\r\n {\r\n if (c instanceof Polyline)\r\n {\r\n let cus = c.Explode();\r\n\r\n //如果为圆弧,提前打断\r\n let arcs: Arc[] = [];\r\n arrayRemoveIf(cus, c =>\r\n {\r\n if (c.Length < 1e-5) return true;\r\n\r\n if (c instanceof Arc)\r\n {\r\n let arcBrs = this.BreakArc(c);\r\n for (let arc of arcBrs)\r\n arcs.push(arc);\r\n }\r\n\r\n return false;\r\n });\r\n //加入到计算\r\n cus.push(...arcs);\r\n\r\n this.ExpLineMap.set(c, cus);\r\n plcus.push(...cus);\r\n return true;\r\n }\r\n return false;\r\n });\r\n curveList.push(...plcus);\r\n\r\n this._CurveCount = curveList.length;\r\n\r\n for (let cu of curveList)\r\n {\r\n //由于圆弧可能导致最低点计算错误的问题.\r\n if (cu instanceof Arc)\r\n {\r\n let arcs = this.BreakArc(cu);\r\n if (arcs.length > 1)\r\n {\r\n arcs.forEach(a => curveMap.AddCurveToMap(a, true, this.removeDuplicate, true));\r\n this.ExpLineMap.set(cu, arcs);\r\n continue;\r\n }\r\n else\r\n curveMap.AddCurveToMap(cu, true, this.removeDuplicate, true);\r\n }\r\n else\r\n curveMap.AddCurveToMap(cu, false, this.removeDuplicate, true);\r\n }\r\n\r\n //排序,根据角度逆时针排序.\r\n for (let v of curveMap._Vertices)\r\n {\r\n let minLength = Infinity;\r\n for (let r of v.routes)\r\n if (r.length < minLength) minLength = r.length;\r\n for (let r of v.routes)\r\n CalcRouteAngle(r, minLength * 0.2);\r\n v.routes.sort((r1, r2) => r1.an - r2.an);\r\n }\r\n return curveMap.Stands;\r\n }\r\n\r\n private BreakArc(arc: Arc): Arc[]\r\n {\r\n let underPt = arc.Center.add(new Vector3(0, -arc.Radius));\r\n let param = arc.GetParamAtPoint(underPt);\r\n if (param > 0.01 && param < 0.99)\r\n return arc.GetSplitCurves(param);\r\n else\r\n return [arc];\r\n }\r\n\r\n /**\r\n * 曲线是否已经被算法使用\r\n */\r\n GetCueveUsed(cu: Curve): boolean\r\n {\r\n if (this.ExpLineMap.has(cu))\r\n {\r\n let use = this.ExpLineMap.get(cu).some(c => c.TempData > 0);\r\n if (!use)\r\n this.ExpLineMap.delete(cu);\r\n return use;\r\n }\r\n else\r\n return cu.TempData > 0;\r\n }\r\n}\r\n\r\nfunction CalcRouteAngle(r: Route, length: number)\r\n{\r\n if (r.an !== undefined) return;\r\n let cu = r.curve;\r\n let p = r.isReverse ?\r\n cu.GetPointAtParam(cu.GetParamAtDist(r.length - length))\r\n : cu.GetPointAtParam(cu.GetParamAtDist(length));\r\n r.an = angle(p.sub(r.from.position));\r\n}\r\n\r\nenum WalkType\r\n{\r\n Min = 1,\r\n Max = -1,\r\n}\r\n\r\nfunction ClosedWalkFrom(startVertice: Vertice, maxRoute: number, type = WalkType.Min): Route[]\r\n{\r\n let walk: Route[] = [];\r\n let curVertice: Vertice = startVertice;\r\n let preRoute: Route;\r\n // console.log(\"start\", type, startVertice.position.toArray());\r\n do\r\n {\r\n let route = GetNextRoute(curVertice, preRoute, type);\r\n if (type === WalkType.Max && route.curve.TempData > 0)\r\n return [];\r\n // console.log(route.to.position.toArray());\r\n walk.push(route);\r\n [curVertice, preRoute] = [route.to, route];\r\n if (walk.length > maxRoute * 2)\r\n throw \"超过计算次数限制\";\r\n }\r\n while (curVertice !== startVertice);\r\n\r\n return walk;\r\n}\r\n\r\n/**\r\n * 删除中途回路\r\n */\r\nfunction ReduceWalk(w: Route[]): Route[]\r\n{\r\n if (w.length === 0) return w;\r\n //未构成回路,直接回家\r\n if (w[0].curve === arrayLast(w).curve) return [];\r\n\r\n for (let i = 0; i < w.length; i++)\r\n {\r\n let r1 = w[i];\r\n for (let j = w.length; j--;)\r\n {\r\n if (i === j) break;\r\n let r2 = w[j];\r\n if (r1.to === r2.to)\r\n {\r\n if (j > i)\r\n w.splice(i + 1, j - i);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return w;\r\n}\r\n\r\nfunction GetNextRoute(v: Vertice, prev?: Route, type: WalkType = WalkType.Min): Route\r\n{\r\n if (!prev)\r\n return arrayLast(v.routes); //顺时针 cw \\|/ 从左往右\r\n\r\n //逆时针 ccw 往左\r\n let index = v.routes.findIndex(r => r.curve === prev.curve);\r\n let newIndex = FixIndex(index + 1 * type, v.routes);\r\n return v.routes[newIndex];\r\n}\r\n","import { Vector3 } from 'three';\r\nimport { Circle } from '../DatabaseServices/Entity/Circle';\r\nimport { Curve } from '../DatabaseServices/Entity/Curve';\r\nimport { Ellipse } from '../DatabaseServices/Entity/Ellipse';\r\nimport { Polyline } from '../DatabaseServices/Entity/Polyline';\r\nimport { IntersectOption } from './IntersectWith';\r\n\r\nexport enum BoolOpeartionType\r\n{\r\n Intersection = 0,\r\n Union = 1,\r\n Subtract = 2\r\n}\r\n\r\nconst fuzz = 1e-3;\r\nlet fuzzV3 = new Vector3(fuzz, fuzz, fuzz);\r\n\r\n//判断曲线是否在源封闭曲线内\r\nexport function isTargetCurInOrOnSourceCur(sourceCur: Polyline | Circle | Ellipse, targetCur: Curve)\r\n{\r\n if (!sourceCur.BoundingBox.expandByVector(fuzzV3).containsBox(targetCur.BoundingBox))\r\n return false;\r\n\r\n let cus: Curve[] = [];\r\n if (targetCur instanceof Polyline)\r\n cus = targetCur.Explode();\r\n else\r\n cus = [targetCur];\r\n\r\n return cus.every(c =>\r\n {\r\n let pts = getIntPtContextPts(sourceCur, c);\r\n if (pts.length <= 1)\r\n pts.push(c.StartPoint, c.EndPoint);\r\n return IsPtsAllInOrOnReg(sourceCur, pts);\r\n });\r\n}\r\n\r\n//获取交点处上下距0.01par的点\r\nfunction getIntPtContextPts(sourceCur: Curve, cu: Curve, pts: Vector3[] = [])\r\n{\r\n let interPts = cu.IntersectWith(sourceCur, IntersectOption.OnBothOperands);\r\n if (interPts.length > 0)\r\n {\r\n let pars = interPts.map(pt => cu.GetParamAtPoint(pt));\r\n for (let par of pars)\r\n {\r\n if (par >= 0.02)\r\n pts.push(cu.GetPointAtParam(par - 0.01));\r\n\r\n if (par <= (cu.EndParam - 0.02))\r\n pts.push(cu.GetPointAtParam(par + 0.01));\r\n }\r\n }\r\n return pts;\r\n}\r\n//判断点点是否全部都在封闭区域内或者在曲线上\r\nfunction IsPtsAllInOrOnReg(sourceReg: Polyline | Circle | Ellipse, pts: Vector3[])\r\n{\r\n return pts.every(pt =>\r\n {\r\n //是否点在封闭曲线内\r\n return sourceReg.PtOnCurve(pt) || sourceReg.PtInCurve(pt);\r\n });\r\n}\r\n\r\n//判断点是否全部都在封闭区域外或者在曲线上\r\nexport function IsPtsAllOutOrOnReg(sourceReg: Polyline | Circle, pts: Vector3[])\r\n{\r\n return pts.every(pt =>\r\n {\r\n //是否点在封闭曲线内\r\n return sourceReg.PtOnCurve(pt) || !sourceReg.PtInCurve(pt);\r\n });\r\n}\r\n","import { Line, Material, Object3D, Shape, Vector3 } from 'three';\r\nimport { arrayRemoveDuplicateBySort, arraySortByNumber } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { Status } from '../../Common/Status';\r\nimport { equaln, equalv3 } from '../../Geometry/GeUtils';\r\nimport { IntersectOption, IntersectResult } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { DragPointType } from './DragPointType';\r\nimport { Entity } from './Entity';\r\n\r\nexport enum ExtendType\r\n{\r\n /**\r\n * 前后都不延伸\r\n */\r\n None = 0,\r\n /**\r\n * 只允许延伸前面\r\n */\r\n Front = 1,\r\n /**\r\n * 只允许延伸后面\r\n */\r\n Back = 2,\r\n /**\r\n * 前后延伸\r\n */\r\n Both = 3,\r\n}\r\n\r\n/**\r\n * 曲线的基类,子类请实现以下方法.\r\n */\r\n@Factory\r\nexport abstract class Curve extends Entity\r\n{\r\n constructor()\r\n {\r\n super();\r\n }\r\n\r\n get Is2D()\r\n {\r\n return equaln(this._Matrix.elements[14], 0);\r\n }\r\n\r\n get StartPoint(): Vector3 { return; }\r\n set StartPoint(v: Vector3) { return; }\r\n get StartParam(): number { return; }\r\n get EndPoint(): Vector3 { return; }\r\n set EndPoint(v: Vector3) { return; }\r\n\r\n /** 曲线中点 */\r\n get Midpoint()\r\n {\r\n return this.GetPointAtParam(this.MidParam);\r\n }\r\n\r\n get MidParam()\r\n {\r\n if (this.EndParam === 1)\r\n return 0.5;\r\n else\r\n return this.GetParamAtDist(this.Length * 0.5);\r\n }\r\n\r\n get EndParam(): number { return; }\r\n get Area(): number { return 0; }\r\n /**\r\n *获得曲线的面积,逆时针为正,顺时针为负.\r\n */\r\n get Area2(): number { return 0; }\r\n get Length(): number { return 0; }\r\n get IsClose(): boolean { return false; }\r\n /** 曲线为顺时针 */\r\n get IsClockWise(): boolean { return this.Area2 < 0; }\r\n\r\n abstract get Shape(): Shape;\r\n\r\n GetPointAtParam(param: number): Vector3 { return; }\r\n GetPointAtDistance(distance: number): Vector3 { return; }\r\n GetDistAtParam(param: number): number { return; }\r\n GetDistAtPoint(pt: Vector3): number { return; }\r\n GetParamAtPoint(pt: Vector3): number { return; }\r\n GetParamAtPoint2(pt: Vector3): number { return this.GetParamAtPoint(pt); }\r\n\r\n GetParamAtDist(d: number): number { return; }\r\n\r\n /**\r\n * 返回曲线在指定位置的一阶导数(在wcs内)\r\n *\r\n * @param {(number | Vector3)} param\r\n * @returns {Vector3}\r\n * @memberof Curve\r\n */\r\n GetFistDeriv(param: number | Vector3): Vector3 { return; }\r\n GetFistDerivAngle(param: number | Vector3): number\r\n {\r\n let d = this.GetFistDeriv(param);\r\n return Math.atan2(d.y, d.x);\r\n }\r\n\r\n /**\r\n * 返回切割曲线后的结果.总是从起点开始切割,并且按顺序返回曲线.\r\n * @param {(number[] | number)} param\r\n * @returns {Array}\r\n */\r\n GetSplitCurves(param: number[] | number): Array { return; }\r\n //未完善\r\n GetCurveAtParamRange(startParam: number, EndParam: number): Array { return; }\r\n GetSplitCurvesByPts(pt: Vector3[] | Vector3): Array\r\n {\r\n let pts = Array.isArray(pt) ? pt : [pt];\r\n let pars = pts.map(p => this.GetParamAtPoint(p));\r\n return this.GetSplitCurves(pars);\r\n }\r\n protected SplitParamSort(param: number[] | number): number[]\r\n {\r\n if (Array.isArray(param))\r\n {\r\n param = param.filter(p => this.ParamOnCurve(p));\r\n if (param.length === 0)\r\n return [];\r\n param.push(0, this.EndParam);\r\n arraySortByNumber(param);\r\n arrayRemoveDuplicateBySort(param, (e1, e2) => equaln(e1, e2, 1e-7));\r\n return param;\r\n }\r\n else if (this.ParamOnCurve(param))\r\n return [0, param, this.EndParam];\r\n else\r\n return [];\r\n }\r\n Extend(newParam: number) { }\r\n /**\r\n * 连接曲线到本曲线,如果成功返回true\r\n * @param {Curve} cu 需要连接的曲线\r\n * @returns {boolean} 连接成功\r\n * @memberof Curve\r\n */\r\n Join(cu: Curve, allowGap = false, tolerance = 1e-4): Status { return Status.False; }\r\n\r\n //翻转曲线.首尾调换.\r\n Reverse(): this { return this; }\r\n\r\n //点在曲线上\r\n PtOnCurve(pt: Vector3, fuzz = 1e-6): boolean\r\n {\r\n return equalv3(this.StartPoint, pt, fuzz) || equalv3(this.EndPoint, pt, fuzz) || this.ParamOnCurve(this.GetParamAtPoint(pt));\r\n }\r\n\r\n //点在曲线中,不在起点或者终点.\r\n PtOnCurve2(pt: Vector3): boolean\r\n {\r\n return !(equalv3(this.StartPoint, pt, 1e-6) || equalv3(this.EndPoint, pt, 1e-6)) && this.ParamOnCurve(this.GetParamAtPoint(pt), 0);\r\n }\r\n\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n return this.PtOnCurve(p, fuzz);\r\n }\r\n\r\n //参数在曲线上 容差,1e-6\r\n ParamOnCurve(param: number, fuzz = 1e-6): boolean { return !isNaN(param) && param >= -fuzz && param <= this.EndParam + fuzz; }\r\n GetOffsetCurves(offsetDist: number): Array { return; }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { return; }\r\n\r\n /**\r\n * 曲线相交点\r\n */\r\n IntersectWith(curve: Curve, intType: IntersectOption, tolerance = 1e-6): Vector3[]\r\n {\r\n return this.IntersectWith2(curve, intType, tolerance).map(r => r.pt);\r\n }\r\n\r\n /**\r\n * 曲线相交点和点的参数\r\n */\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-6): IntersectResult[] { return []; }\r\n\r\n\r\n /**\r\n * 拽托点个数\r\n */\r\n GetDragPointCount(drag: DragPointType): number { return 0; }\r\n\r\n //------------------绘制相关------------------\r\n //重载\r\n protected OnlyRenderType = true;\r\n\r\n /**\r\n * 重载:更新实体材质\r\n */\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material?: Material)\r\n {\r\n if (type === RenderType.WireframePrint)\r\n {\r\n //打印模式暂时不需要改颜色\r\n }\r\n else\r\n {\r\n let m = obj as Line;\r\n m.material = material || ColorMaterial.GetLineMaterial(this._Color);\r\n }\r\n }\r\n\r\n UpdateJigMaterial(color = 8)\r\n {\r\n for (let [type, obj] of this._CacheDrawObject)\r\n {\r\n this.UpdateDrawObjectMaterial(type, obj, ColorMaterial.GetLineMaterial(color));\r\n }\r\n }\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { arrayLast, arrayRemoveDuplicateBySort } from \"../Common/ArrayExt\";\r\nimport { curveLinkGroup, equalCurve } from \"../Common/CurveUtils\";\r\nimport { Status } from \"../Common/Status\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\nimport { IntersectBox2 } from \"../Geometry/Box\";\r\nimport { Route } from \"../Geometry/CurveMap\";\r\nimport { equaln, equalv3 } from \"../Geometry/GeUtils\";\r\nimport { RegionParse } from \"../Geometry/RegionParse\";\r\nimport { isTargetCurInOrOnSourceCur } from \"../GraphicsSystem/BoolOperateUtils\";\r\nimport { IntersectOption } from \"../GraphicsSystem/IntersectWith\";\r\nimport { Arc } from \"./Entity/Arc\";\r\nimport { Circle } from \"./Entity/Circle\";\r\nimport { Curve } from \"./Entity/Curve\";\r\nimport { Polyline } from \"./Entity/Polyline\";\r\n\r\nlet cache = new WeakMap();\r\n\r\nconst COMBINE_FUZZ = 1e-2;\r\n\r\nexport class Contour\r\n{\r\n private _Curve: Polyline | Circle;\r\n\r\n protected SetCurve(cu: Polyline | Circle)\r\n {\r\n if (cu instanceof Polyline)\r\n {\r\n if (cu.Area2 < 0)\r\n cu.Reverse();\r\n }\r\n this._Curve = cu;\r\n }\r\n /**会将传入的闭合轮廓改为逆时针 */\r\n static CreateContour(cus: Curve[] | Polyline | Circle, needLink = true)\r\n {\r\n if (cus instanceof Curve)\r\n {\r\n if (cus.IsClose)\r\n {\r\n let c = new Contour();\r\n c.SetCurve(cus);\r\n return c;\r\n }\r\n return;\r\n }\r\n\r\n let closeCurve = Contour.Combine(cus, needLink, COMBINE_FUZZ) as Polyline | Circle;\r\n if (closeCurve && closeCurve.IsClose)\r\n {\r\n if (closeCurve instanceof Polyline && closeCurve.CloseMark === false)\r\n {\r\n closeCurve.CloseMark = true;\r\n closeCurve.RemoveVertexAt(closeCurve.NumberOfVertices - 1);\r\n }\r\n\r\n let c = new Contour();\r\n c.SetCurve(closeCurve);\r\n return c;\r\n }\r\n }\r\n get Curve(): Polyline | Circle\r\n {\r\n return this._Curve;\r\n }\r\n get Area()\r\n {\r\n return this._Curve.Area;\r\n }\r\n get BoundingBox()\r\n {\r\n return this._Curve.BoundingBox;\r\n }\r\n /**\r\n * 不等比例缩放\r\n * @param {number} ref 缩放参考值,大于该值的点缩放\r\n * @param {number} dist 缩放距离\r\n * @param {string} dir x y z\r\n */\r\n UnEqualProportionScale(ref: number, dist: number, dir: \"x\" | \"y\")\r\n {\r\n let cu = this._Curve;\r\n if (cu instanceof Polyline)\r\n {\r\n let lineData = cu.LineData;\r\n let length = lineData.length;\r\n let p = cu.Position[dir];\r\n\r\n let moveIndexs: number[] = [];\r\n for (let i = 0; i < length; i++)\r\n {\r\n if (lineData[i].pt[dir] + p > ref)\r\n moveIndexs.push(i);\r\n }\r\n let moveVec = new Vector3();\r\n moveVec[dir] = dist;\r\n cu.MoveStretchPoints(moveIndexs, moveVec);\r\n return true;\r\n }\r\n return false;\r\n }\r\n Clone()\r\n {\r\n return Contour.CreateContour([this._Curve.Clone()]);\r\n }\r\n //交集:结果数组为空则失败\r\n IntersectionBoolOperation(target: Contour): Contour[]\r\n {\r\n if (!IntersectBox2(this.BoundingBox, target.BoundingBox))\r\n return [];\r\n let resultCus = this.GetIntersetAndUnionList(target);\r\n return Contour.GetAllContour(resultCus.intersectionList);\r\n }\r\n //并集:结果轮廓数组长度大于2,则失败.等于1则成功.\r\n UnionBoolOperation(target: Contour): { contours: Contour[], holes: Contour[]; }\r\n {\r\n let resultCus = this.GetIntersetAndUnionList(target);\r\n\r\n //快速\r\n if (resultCus.unionList.every(c => c.IsClose))\r\n return {\r\n contours: Contour.GetAllContour(resultCus.unionList),\r\n holes: [],\r\n };\r\n\r\n //并集后的线段表如果有共线的直接合并起来\r\n let cus: Curve[] = [];\r\n for (let pl of resultCus.unionList)\r\n {\r\n if (pl instanceof Polyline)\r\n cus.push(...pl.Explode());\r\n else\r\n cus.push(pl);\r\n }\r\n let cuGroups = curveLinkGroup(cus);\r\n for (let g of cuGroups)\r\n {\r\n for (let i = 0; i < g.length; i++)\r\n {\r\n let c1 = g[i];\r\n let nextI = FixIndex(i + 1, g);\r\n let c2 = g[nextI];\r\n\r\n let status = c1.Join(c2);\r\n if (status === Status.True)\r\n {\r\n g.splice(nextI, 1);\r\n i--;\r\n }\r\n else if (status === Status.ConverToCircle)\r\n {\r\n g.length = 0;\r\n let a = c1 as Arc;\r\n g.push(new Circle(a.Center, a.Radius));\r\n break;\r\n }\r\n }\r\n }\r\n let allContour = Contour.GetAllContour(cuGroups);\r\n if (allContour.length < 2)\r\n {\r\n return {\r\n contours: allContour,\r\n holes: [],\r\n };\r\n }\r\n else\r\n {\r\n let cache = new WeakMap();\r\n for (let c of allContour)\r\n cache.set(c, c.Area);\r\n allContour.sort((a, b) => cache.get(b) - cache.get(a));\r\n return {\r\n contours: [allContour[0]],\r\n holes: allContour.slice(1)\r\n };\r\n }\r\n\r\n }\r\n //差集:等于0完全被减去\r\n SubstactBoolOperation(target: Contour): Contour[]\r\n {\r\n let subtractList = this.GetSubtractList(target);\r\n\r\n //纯网洞\r\n if (subtractList.every(c => c.IsClose))\r\n return Contour.GetAllContour(subtractList);\r\n\r\n let regParse = new RegionParse(subtractList, 2);\r\n\r\n let contours: Contour[] = [];\r\n //分析封闭包围区域\r\n const parseRoute = (routeSet: Array[]) =>\r\n {\r\n for (let routes of routeSet)\r\n {\r\n let cs: Curve[] = routes.map(r => r.curve);\r\n let c = Contour.CreateContour(cs, false);\r\n if (c\r\n && !equalCurve(c.Curve, this.Curve)\r\n && !equalCurve(c.Curve, target.Curve)\r\n && c.Area > 1e-3)\r\n contours.push(c);\r\n }\r\n };\r\n parseRoute(regParse.RegionsOutline);\r\n parseRoute(regParse.RegionsInternal);\r\n\r\n return contours;\r\n }\r\n /**\r\n * 计算与目标轮廓布尔运算后的结果曲线.\r\n */\r\n GetIntersetAndUnionList(target: Contour): { intersectionList: Curve[], unionList: Curve[]; }\r\n {\r\n let intersectionList: Curve[] = [];\r\n let unionList: Curve[] = [];\r\n\r\n let sourceOutline = this._Curve;\r\n let targetOutline = target.Curve;\r\n let isEqualNormal = equalv3(sourceOutline.Normal, targetOutline.Normal, 1e-3);\r\n\r\n let interPts = sourceOutline.IntersectWith2(targetOutline, IntersectOption.OnBothOperands, COMBINE_FUZZ);\r\n\r\n let sourceContainerTarget = this.CuInOutline(targetOutline);\r\n let targetContainerSource = target.CuInOutline(sourceOutline);\r\n\r\n //包含.相交.分离(三种状态)\r\n if (sourceContainerTarget)//源包含目标\r\n {\r\n intersectionList.push(targetOutline);\r\n unionList.push(sourceOutline);\r\n }\r\n else if (targetContainerSource)//目标包含源\r\n {\r\n unionList.push(targetOutline);\r\n intersectionList.push(sourceOutline);\r\n }\r\n else if (interPts.length <= 1)//分离\r\n {\r\n unionList.push(sourceOutline, targetOutline);\r\n }\r\n else//相交 interPts.length > 0\r\n {\r\n let pars1 = interPts.map(r => r.thisParam);\r\n let pars2 = interPts.map(r => r.argParam);\r\n\r\n let sourceCus: Array = sourceOutline.GetSplitCurves(pars1);\r\n let targetCus: Array = targetOutline.GetSplitCurves(pars2);\r\n\r\n for (let pl of sourceCus)\r\n {\r\n let hasEqualCus = false;\r\n for (let i = 0; i < targetCus.length; i++)\r\n {\r\n let cu = targetCus[i];\r\n hasEqualCus = fastEqualCurve(cu, pl);\r\n if (hasEqualCus)\r\n {\r\n //方向相同\r\n if (\r\n equalv3(cu.GetFistDeriv(cu.EndParam * 0.5).normalize(), pl.GetFistDeriv(pl.EndParam * 0.5).normalize(), 1e-3)\r\n === isEqualNormal\r\n )\r\n {\r\n unionList.push(pl);\r\n intersectionList.push(pl);\r\n }\r\n targetCus.splice(i, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (hasEqualCus)\r\n continue;\r\n\r\n if (target.CuInOutline(pl))\r\n intersectionList.push(pl);\r\n else\r\n unionList.push(pl);\r\n }\r\n\r\n for (let pl of targetCus)\r\n {\r\n if (this.CuInOutline(pl))\r\n intersectionList.push(pl);\r\n else\r\n unionList.push(pl);\r\n }\r\n\r\n //特殊的分离\r\n if (intersectionList.length === 0 && unionList.length === (sourceCus.length + targetCus.length))\r\n {\r\n return { intersectionList, unionList: [sourceOutline, targetOutline] };\r\n }\r\n }\r\n return { intersectionList, unionList };\r\n }\r\n GetSubtractList(target: Contour): Polyline[]\r\n {\r\n let sourceOutline = this._Curve as Polyline;\r\n let targetOutline = target.Curve as Polyline;\r\n\r\n let isEqualNormal = equalv3(sourceOutline.Normal, targetOutline.Normal, 1e-3);\r\n\r\n let interPts = sourceOutline.IntersectWith2(targetOutline, IntersectOption.OnBothOperands, COMBINE_FUZZ);\r\n\r\n if (interPts.length <= 1)\r\n {\r\n //反包含\r\n if (fastCurveInCurve2(targetOutline, sourceOutline) || equalCurve(targetOutline, sourceOutline))\r\n return [];\r\n //包含\r\n if (fastCurveInCurve2(sourceOutline, targetOutline))\r\n return [sourceOutline, targetOutline];\r\n else//分离\r\n return [sourceOutline];\r\n }\r\n\r\n //相交\r\n let subtractList: Polyline[] = [];\r\n let sourceCus = sourceOutline.GetSplitCurves(interPts.map(r => r.thisParam)) as Polyline[];\r\n let targetCus = targetOutline.GetSplitCurves(interPts.map(r => r.argParam)) as Polyline[];\r\n\r\n for (let pl of sourceCus)\r\n {\r\n let plMidParam = pl.MidParam;\r\n let plDir = pl.GetFistDeriv(plMidParam).normalize();\r\n\r\n let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl));\r\n if (index !== -1)\r\n {\r\n let cu = targetCus[index];\r\n let cuMidParam = cu.MidParam;\r\n let cuDir = cu.GetFistDeriv(cuMidParam).normalize();\r\n\r\n if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3))//不同向\r\n subtractList.push(pl);\r\n\r\n targetCus.splice(index, 1);\r\n\r\n continue;\r\n }\r\n if (!fastCurveInCurve(targetOutline, pl))\r\n subtractList.push(pl);\r\n }\r\n\r\n //源对象没有被破坏\r\n let sourceNotBreak = subtractList.length === sourceCus.length;\r\n\r\n for (let pl of targetCus)\r\n if (fastCurveInCurve(sourceOutline, pl))\r\n subtractList.push(pl);\r\n\r\n if (sourceNotBreak && subtractList.length === sourceCus.length)\r\n return [sourceOutline];\r\n\r\n return subtractList;\r\n }\r\n GetSubtractListByMoreTargets(targets: Contour[])\r\n {\r\n let { holes, subtractList } = this.GetSubListWithCus(targets);\r\n\r\n //纯网洞\r\n if (subtractList.every(c => c.IsClose))\r\n return {\r\n holes: holes.map(h => Contour.CreateContour(h)),\r\n outlines: Contour.GetAllContour(subtractList)\r\n };\r\n\r\n let regParse = new RegionParse(subtractList, 2);\r\n\r\n let contours: Contour[] = [];\r\n //分析封闭包围区域\r\n const parseRoute = (routeSet: Array[]) =>\r\n {\r\n for (let routes of routeSet)\r\n {\r\n let cs: Curve[] = routes.map(r => r.curve);\r\n let c = Contour.CreateContour(cs, false);\r\n if (c\r\n && !equalCurve(c.Curve, this.Curve)\r\n && targets.every(target => !equalCurve(c.Curve, target.Curve))\r\n && c.Area > 1e-3)\r\n contours.push(c);\r\n }\r\n };\r\n parseRoute(regParse.RegionsOutline);\r\n parseRoute(regParse.RegionsInternal);\r\n\r\n return {\r\n holes: holes.map(h => Contour.CreateContour(h)),\r\n outlines: contours\r\n };\r\n\r\n }\r\n GetSubListWithCus(targets: Contour[])\r\n {\r\n let sourceOutline = this._Curve as Polyline;\r\n let subtractList: Polyline[] = [];\r\n let holes: Polyline[] = [];\r\n let intPars: number[] = [];\r\n let cuMap = new Map();\r\n\r\n let outBox = sourceOutline.BoundingBox;\r\n\r\n for (let con of targets)\r\n {\r\n const targetOutline = con.Curve as Polyline;\r\n\r\n if (!IntersectBox2(outBox, targetOutline.BoundingBox))\r\n continue;\r\n\r\n let pts = sourceOutline.IntersectWith2(con.Curve, IntersectOption.OnBothOperands, COMBINE_FUZZ);\r\n if (pts.length <= 1)\r\n {\r\n //反包含\r\n if (fastCurveInCurve2(targetOutline, sourceOutline) || equalCurve(targetOutline, sourceOutline))\r\n return { holes, subtractList };\r\n //包含\r\n if (fastCurveInCurve2(sourceOutline, targetOutline))\r\n holes.push(targetOutline);\r\n else//分离\r\n {\r\n\r\n }\r\n }\r\n else\r\n {\r\n intPars.push(...pts.map(r => r.thisParam));\r\n cuMap.set(targetOutline, pts.map(r => r.argParam));\r\n }\r\n }\r\n intPars.sort((a, b) => a - b);\r\n arrayRemoveDuplicateBySort(intPars, (e1, e2) => equaln(e1, e2, 1e-8));\r\n let sourceCus = sourceOutline.GetSplitCurves(intPars) as Polyline[];\r\n let targetCus: Polyline[] = [];\r\n\r\n let targetMap = new WeakMap();\r\n\r\n let isEqualNormal: boolean;\r\n\r\n for (let [c, pars] of cuMap)\r\n {\r\n let cus = c.GetSplitCurves(pars) as Polyline[];\r\n cus.forEach(cu => targetMap.set(cu, c));\r\n targetCus.push(...cus);\r\n }\r\n\r\n for (let pl of sourceCus)\r\n {\r\n let plMidParam = pl.MidParam;\r\n let plDir = pl.GetFistDeriv(plMidParam).normalize();\r\n\r\n let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl, 0.05));\r\n if (index !== -1)\r\n {\r\n let cu = targetCus[index];\r\n isEqualNormal = equalv3(sourceOutline.Normal, targetMap.get(cu).Normal, 1e-3);\r\n let cuMidParam = cu.MidParam;\r\n let cuDir = cu.GetFistDeriv(cuMidParam).normalize();\r\n\r\n if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3))//不同向\r\n subtractList.push(pl);\r\n\r\n targetCus.splice(index, 1);\r\n\r\n continue;\r\n }\r\n\r\n if (targets.every(t => !fastCurveInCurve(t.Curve as Polyline, pl)))\r\n subtractList.push(pl);\r\n }\r\n\r\n //源对象没有被破坏\r\n let sourceNotBreak = subtractList.length === sourceCus.length;\r\n\r\n for (let pl of targetCus)\r\n if (fastCurveInCurve(sourceOutline, pl))\r\n subtractList.push(pl);\r\n\r\n if (sourceNotBreak && subtractList.length === sourceCus.length)\r\n return { subtractList: [sourceOutline], holes };\r\n\r\n return { subtractList, holes };\r\n\r\n }\r\n /**\r\n * 获得全部闭合曲线\r\n * @若传入二维曲线数据,将默认子数组为闭合曲线段\r\n */\r\n static GetAllContour(cus: Curve[] | Curve[][]): Contour[]\r\n {\r\n if (cus.length === 0)\r\n return [];\r\n\r\n let cuGroups: Curve[][];\r\n if (Array.isArray(cus[0]))\r\n cuGroups = cus as Curve[][];\r\n else\r\n cuGroups = curveLinkGroup(cus as Curve[]);\r\n\r\n let contours: Contour[] = [];\r\n\r\n for (let g of cuGroups)\r\n contours.push(Contour.CreateContour(g, false));\r\n return contours.filter(c => c !== undefined && !equaln(c.Area, 0, 1e-6));\r\n }\r\n /**\r\n * 合并曲线组成为多段线\r\n * @param cus 曲线组\r\n * @param [needLink=true] 需要解析成首尾连接状态\r\n * @returns 单一曲线,如果返回超过1个,其他的将被遗弃.\r\n */\r\n static Combine(cus: Curve[], needLink = true, tolerance = 1e-3): Curve\r\n {\r\n if (cus.length === 0) return undefined;\r\n\r\n let groups = needLink ? curveLinkGroup(cus) : [cus];\r\n for (let g of groups)\r\n {\r\n if (g.length === 1)\r\n return g[0].Clone();\r\n else\r\n {\r\n if (cache.has(g))\r\n return cache.get(g);\r\n\r\n let gclone = g.map(c => c.Clone());\r\n\r\n arrayRemoveDuplicateBySort(gclone, (cu1: Curve, cu2: Curve) => cu1.Join(cu2, false, tolerance) === Status.True);\r\n\r\n if (gclone.length > 1 && gclone[0].Join(arrayLast(gclone), false, tolerance))\r\n gclone.pop();\r\n\r\n let pl = Polyline.Combine(gclone, tolerance);\r\n\r\n cache.set(g, pl);\r\n\r\n return pl;\r\n }\r\n }\r\n }\r\n get Shape(): THREE.Shape\r\n {\r\n return this._Curve.Shape;\r\n }\r\n CuInOutline(targetCur: Curve)\r\n {\r\n return isTargetCurInOrOnSourceCur(this._Curve, targetCur);\r\n }\r\n Equal(tar: Contour)\r\n {\r\n return equalCurve(this._Curve, tar._Curve);\r\n }\r\n}\r\n\r\n/**\r\n * 对于轮廓切割后的曲线判断相同,使用这个函数进行快速判断\r\n */\r\nfunction fastEqualCurve(c1: Curve, c2: Curve, tolerance = 1e-3)\r\n{\r\n let sp1 = c1.StartPoint;\r\n let ep1 = c1.EndPoint;\r\n let sp2 = c2.StartPoint;\r\n let ep2 = c2.EndPoint;\r\n\r\n if (!(\r\n (equalv3(sp1, sp2, tolerance) && equalv3(ep1, ep2, tolerance))\r\n || (equalv3(sp1, ep2, tolerance) && equalv3(ep1, sp2, tolerance))\r\n ))\r\n return false;\r\n\r\n return equalv3(c1.Midpoint, c2.Midpoint, tolerance);\r\n}\r\n\r\n\r\n//对于双多段线互相切割后的结果,快速判断曲线是否在另一条曲线内部\r\nfunction fastCurveInCurve(sourceCu: Polyline, targetCu: Polyline)\r\n{\r\n return sourceCu.PtInCurve(targetCu.GetPointAtParam(targetCu.EndParam * 0.5));\r\n}\r\n\r\nfunction fastCurveInCurve2(sourceCu: Polyline, targetCu: Polyline)\r\n{\r\n return sourceCu.PtInCurve(targetCu.StartPoint) &&\r\n sourceCu.PtInCurve(targetCu.GetPointAtParam(targetCu.EndParam * 0.5));\r\n}\r\n","import { Line3, Plane, Ray, Vector3 } from \"three\";\r\n\r\nexport class PlaneExt extends Plane\r\n{\r\n constructor(normal = new Vector3(0, 0, 1), constant?: number | Vector3)\r\n {\r\n super(normal);\r\n if (typeof constant === \"number\")\r\n this.constant = constant;\r\n else if (constant)\r\n this.constant = -this.normal.dot(constant);\r\n }\r\n\r\n intersectLine(line: Line3, optionalTarget = new Vector3(), extendLine = false): Vector3\r\n {\r\n let v1 = new Vector3();\r\n\r\n let direction = line.delta(v1);\r\n\r\n let denominator = this.normal.dot(direction);\r\n\r\n if (denominator === 0)\r\n {\r\n // line is coplanar, return origin\r\n if (this.distanceToPoint(line.start) === 0)\r\n {\r\n return optionalTarget.copy(line.start);\r\n }\r\n // Unsure if this is the correct method to handle this case.\r\n return undefined;\r\n }\r\n\r\n let t = - (line.start.dot(this.normal) + this.constant) / denominator;\r\n //If you not extendLine,check intersect point in Line\r\n if (!extendLine && (t < -1e-6 || t > 1))\r\n {\r\n return undefined;\r\n }\r\n\r\n return optionalTarget.copy(direction).multiplyScalar(t).add(line.start);\r\n }\r\n intersectRay(ray: Ray, optionalTarget?: Vector3, extendLine?: boolean): Vector3\r\n {\r\n // 从射线初始位置\r\n let line = new Line3(ray.origin.clone(), ray.origin.clone().add(ray.direction));\r\n return this.intersectLine(line, optionalTarget, extendLine);\r\n }\r\n}\r\n","import { Box3, BufferGeometry, Matrix3, Matrix4, Object3D, Shape, Vector3, Line as TLine, MathUtils } from 'three';\r\nimport { arrayLast, arrayRemoveDuplicateBySort } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { getDeterminantFor2V, getArcOrCirNearPts, getTanPtsOnEllipse, Pts2Polyline } from '../../Common/CurveUtils';\r\nimport { Status } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { angle, equaln, equalv3, MoveMatrix, rotatePoint, angleTo, AsVector2, AsVector3 } from '../../Geometry/GeUtils';\r\nimport { IntersectEllipse, IntersectEllipseAndCircleOrArc, IntersectEllipseAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Arc } from './Arc';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { Circle } from './Circle';\r\nimport { Curve } from './Curve';\r\nimport { Line } from './Line';\r\nimport { Polyline } from './Polyline';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\n\r\n@Factory\r\nexport class Ellipse extends Curve\r\n{\r\n private _radX: number;\r\n private _radY: number;\r\n private _rotate: number;\r\n private _startAngle = 0;\r\n private _endAngle = Math.PI * 2;\r\n constructor(\r\n center?: Vector3,\r\n radX: number = 1e-3,\r\n radY: number = 1e-3,\r\n angle: number = 0)\r\n {\r\n super();\r\n center && this._Matrix.setPosition(center);\r\n this._radX = radX;\r\n this._radY = radY;\r\n this._rotate = angle;\r\n }\r\n get StartParam(): number\r\n {\r\n return 0;\r\n }\r\n get EndParam(): number\r\n {\r\n return 1;\r\n }\r\n get StartPoint()\r\n {\r\n return this.GetPointAtParam(0);\r\n }\r\n get EndPoint()\r\n {\r\n return this.GetPointAtParam(1);\r\n }\r\n get Shape(): Shape\r\n {\r\n let sp = new Shape();\r\n sp.ellipse(0, 0, this._radX, this._radY, this._startAngle, this._endAngle, false, this._rotate);\r\n return sp;\r\n }\r\n get IsClose(): boolean\r\n {\r\n return equaln(this.TotalAngle, Math.PI * 2);\r\n }\r\n get Center()\r\n {\r\n return new Vector3().setFromMatrixPosition(this._Matrix);\r\n }\r\n set Center(v: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Matrix.setPosition(v);\r\n this.Update();\r\n }\r\n get RadX()\r\n {\r\n return this._radX;\r\n }\r\n set RadX(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._radX = v;\r\n this.Update();\r\n }\r\n get RadY()\r\n {\r\n return this._radY;\r\n }\r\n set RadY(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._radY = v;\r\n this.Update();\r\n }\r\n get Rotation()\r\n {\r\n return this._rotate;\r\n }\r\n set Rotation(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._rotate = v;\r\n this.Update();\r\n }\r\n get StartAngle()\r\n {\r\n return this._startAngle;\r\n }\r\n get EndAngle()\r\n {\r\n return this._startAngle;\r\n }\r\n set StartAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._startAngle = v;\r\n this.Update();\r\n }\r\n set EndAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._endAngle = v;\r\n this.Update();\r\n }\r\n get Length()\r\n {\r\n let a = this._radX;\r\n let b = this._radY;\r\n return Math.PI * Math.abs(3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b))) * this.TotalAngle / Math.PI * 0.5;\r\n }\r\n get Area()\r\n {\r\n let area = Math.PI * this._radX * this._radY;\r\n let an = this._endAngle - this._startAngle;\r\n if (an < 0)\r\n an = Math.PI * 2 + an;\r\n area *= an / Math.PI * 0.5;\r\n let area2 = Math.abs(\r\n getDeterminantFor2V(\r\n AsVector2(this.StartPoint.sub(this.Center)),\r\n AsVector2(this.EndPoint.sub(this.Center)))\r\n ) / 2;\r\n if (an < Math.PI)\r\n area -= area2;\r\n else\r\n area += area2;\r\n return area;\r\n }\r\n get TotalAngle()\r\n {\r\n let totolAngle = this._endAngle - this._startAngle;\r\n if (totolAngle < 0)\r\n totolAngle = Math.PI * 2 + totolAngle;\r\n return totolAngle;\r\n }\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3().setFromPoints(this.GetGripPoints());\r\n }\r\n PtInCurve(pt: Vector3)\r\n {\r\n let p = rotatePoint(pt.clone().sub(this.Center), -this.Rotation);\r\n return p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2 < 1;\r\n }\r\n PtOnCurve(pt: Vector3)\r\n {\r\n if (this.PtOnEllipse(pt))\r\n {\r\n let a = this.GetCircleAngleAtPoint(pt);\r\n return a <= this.TotalAngle + 1e-6;\r\n }\r\n return false;\r\n }\r\n PtOnEllipse(pt: Vector3)\r\n {\r\n let p = rotatePoint(pt.clone().applyMatrix4(this.OCSInv), -this.Rotation);\r\n return equaln(p.x ** 2 / this.RadX ** 2 + p.y ** 2 / this.RadY ** 2, 1, 1e-3);\r\n }\r\n GetPointAtParam(param: number)\r\n {\r\n let an = this.TotalAngle * param + this._startAngle;\r\n\r\n if (an > Math.PI)\r\n an -= 2 * Math.PI;\r\n\r\n let a = this.RadX;\r\n let b = this.RadY;\r\n let pt = new Vector3(a * Math.cos(an), b * Math.sin(an), 0);\r\n\r\n pt.applyMatrix4(new Matrix4().makeRotationZ(this._rotate));\r\n\r\n return pt.applyMatrix4(this.OCS);\r\n }\r\n GetParamAtPoint(pt?: Vector3)\r\n {\r\n if (!this.PtOnEllipse(pt))\r\n {\r\n return NaN;\r\n }\r\n let an = this.GetCircleAngleAtPoint(pt);\r\n let par = an / this.TotalAngle;\r\n\r\n if (this.IsClose || par < 1 + 1e-6)\r\n return par;\r\n else\r\n {\r\n let diffPar = Math.PI * 2 / this.TotalAngle - 1;\r\n if (par - 1 < diffPar / 2)\r\n return par;\r\n else\r\n return par - 1 - diffPar;\r\n }\r\n }\r\n GetPointAtDistance(distance: number)\r\n {\r\n let param = distance / this.Length;\r\n return this.GetPointAtParam(param);\r\n }\r\n GetDistAtParam(param: number)\r\n {\r\n return this.Length * param;\r\n }\r\n GetDistAtPoint(pt: Vector3)\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n return this.GetDistAtParam(param);\r\n }\r\n GetParamAtDist(d: number)\r\n {\r\n return d / this.Length;\r\n }\r\n GetAngleAtParam(par: number)\r\n {\r\n let pt = this.GetPointAtParam(par).applyMatrix4(this.OCSInv).applyMatrix4(new Matrix4().makeRotationZ(-this.Rotation));\r\n return angle(pt) + this._startAngle;\r\n }\r\n GetCircleAngleAtPoint(pt: Vector3)\r\n {\r\n pt = pt.clone().applyMatrix4(this.OCSInv);\r\n let an = angle(pt) - this._rotate;\r\n if (an < 0)\r\n an = Math.PI * 2 - an;\r\n if (an > Math.PI * 2)\r\n an -= Math.PI * 2;\r\n let dist = pt.length();\r\n let k = dist * Math.cos(an) / this._radX;\r\n if (Math.abs(k) > 1)\r\n k = Math.floor(Math.abs(k)) * Math.sign(k);\r\n if (Math.abs(an) <= Math.PI)\r\n an = Math.acos(k);\r\n else\r\n an = Math.PI * 2 - Math.acos(k);\r\n\r\n an -= this._startAngle;\r\n\r\n if (an < 0)\r\n an = Math.PI * 2 + an;\r\n return an;\r\n }\r\n\r\n GetFistDeriv(pt: number | Vector3)\r\n {\r\n if (typeof pt === \"number\")\r\n pt = this.GetPointAtParam(pt);\r\n else\r\n pt = pt.clone();\r\n\r\n let refPts = this.GetGripPoints();\r\n\r\n let p = pt.clone().applyMatrix4(this.OCSInv).applyMatrix4(new Matrix4().makeRotationZ(-this._rotate));\r\n let vec = new Vector3();\r\n if (equalv3(pt, refPts[0]))\r\n vec.set(0, 1, 0);\r\n else if (equalv3(pt, refPts[1]))\r\n {\r\n vec.set(0, -1, 0);\r\n }\r\n else if (p.y > 0)\r\n {\r\n let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);\r\n vec.set(-1, -k, 0);\r\n }\r\n else\r\n {\r\n let k = -(this._radY ** 2 * p.x) / (this._radX ** 2 * p.y);\r\n vec.set(1, k, 0);\r\n }\r\n vec.applyMatrix4(new Matrix4().makeRotationZ(this._rotate));\r\n\r\n return vec.applyMatrix4(new Matrix4().extractRotation(this.OCS));\r\n }\r\n GetClosestPointTo(p: Vector3, extend: boolean): Vector3\r\n {\r\n //参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/\r\n let ro = new Matrix4().makeRotationZ(this._rotate);\r\n let roInv = new Matrix4().getInverse(ro);\r\n let pt = p.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(roInv);\r\n let px = pt.x;\r\n let py = pt.y;\r\n let t = angle(pt);\r\n let a = this._radX;\r\n let b = this._radY;\r\n let x: number, y: number;\r\n for (let i = 0; i < 3; i++)\r\n {\r\n x = a * Math.cos(t);\r\n y = b * Math.sin(t);\r\n let ex = (a ** 2 - b ** 2) * Math.cos(t) ** 3 / a;\r\n let ey = (b * b - a * a) * Math.sin(t) ** 3 / b;\r\n let rx = x - ex;\r\n let ry = y - ey;\r\n let qx = px - ex;\r\n let qy = py - ey;\r\n\r\n let r = Math.sqrt(ry ** 2 + rx ** 2);\r\n let q = Math.sqrt(qy ** 2 + qx ** 2);\r\n\r\n let dc = r * Math.asin((rx * qy - ry * qx) / (r * q));\r\n let dt = dc / Math.sqrt(a * a + b * b - x * x - y * y);\r\n\r\n t += dt;\r\n }\r\n let retPt = new Vector3(x, y).applyMatrix4(ro).applyMatrix4(this.OCS);\r\n if (this.IsClose || extend)\r\n {\r\n return retPt;\r\n }\r\n else if (this.PtOnCurve(retPt))\r\n {\r\n return retPt;\r\n }\r\n else\r\n {\r\n let d1 = p.distanceToSquared(this.StartPoint);\r\n let d2 = p.distanceToSquared(this.EndPoint);\r\n return d1 < d2 ? this.StartPoint : this.EndPoint;\r\n }\r\n }\r\n GetOffsetCurves(offsetDist: number)\r\n {\r\n if ((offsetDist + Math.min(this._radX, this._radY)) > 0)\r\n {\r\n let el = this.Clone();\r\n el.RadX = this._radX + offsetDist;\r\n el.RadY = this._radY + offsetDist;\r\n return [el];\r\n }\r\n return [];\r\n }\r\n GetSplitCurves(param: number[] | number)\r\n {\r\n let params: number[];\r\n if (param instanceof Array)\r\n {\r\n params = param.filter(p => this.ParamOnCurve(p));\r\n params.sort((a1, a2) => a2 - a1);//从大到小\r\n }\r\n else\r\n params = [param];\r\n\r\n //补上最后一个到第一个的弧\r\n if (this.IsClose)\r\n params.unshift(arrayLast(params));\r\n else\r\n {\r\n params.unshift(1);\r\n params.push(0);\r\n }\r\n arrayRemoveDuplicateBySort(params);\r\n\r\n let anglelist = params.map(param => this.TotalAngle * param + this._startAngle);\r\n let elllist: this[] = [];\r\n for (let i = 0; i < anglelist.length - 1; i++)\r\n {\r\n let sa = anglelist[i];\r\n let ea = anglelist[i + 1];\r\n let el = this.Clone();\r\n if (!equaln(sa, ea, 1e-6))\r\n {\r\n el.StartAngle = ea;\r\n el.EndAngle = equaln(sa, 0) ? Math.PI * 2 : sa;\r\n elllist.push(el);\r\n }\r\n }\r\n return elllist;\r\n }\r\n Join(el: Ellipse)\r\n {\r\n if (this.IsClose || el.IsClose || !this.IsCoplaneTo(el) || !equalv3(el.Center, this.Center))\r\n return Status.False;\r\n\r\n let status = Status.False;\r\n\r\n if (equaln(this._endAngle, this._startAngle))\r\n {\r\n this.EndAngle = this._endAngle;\r\n status = Status.True;\r\n }\r\n else if (equaln(this._startAngle, el._endAngle))\r\n {\r\n this.StartAngle = el._startAngle;\r\n status = Status.True;\r\n }\r\n if (status === Status.True && !this.IsClose && equaln(this._startAngle, this._endAngle))\r\n {\r\n this.StartAngle = 0;\r\n this.EndAngle = Math.PI * 2;\r\n }\r\n return status;\r\n }\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n {\r\n let pts = this.GetGripPoints();\r\n return pts;\r\n }\r\n case ObjectSnapMode.Cen:\r\n return [this.Center];\r\n case ObjectSnapMode.Nea:\r\n {\r\n return getArcOrCirNearPts(this, pickPoint, viewXform);\r\n }\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))\r\n return [];\r\n return [this.GetClosestPointTo(lastPoint, false)];\r\n }\r\n case ObjectSnapMode.Tan:\r\n {\r\n //TODO:过某点获取椭圆全部切点\r\n if (lastPoint)\r\n {\r\n return getTanPtsOnEllipse(this, lastPoint);\r\n }\r\n }\r\n default:\r\n return [];\r\n }\r\n }\r\n IntersectWith2(curve: Curve, intType: IntersectOption)\r\n {\r\n //TODO:优化椭圆和椭圆,椭圆和圆相交\r\n if (curve instanceof Line)\r\n {\r\n return SwapParam(IntersectEllipseAndLine(curve, this, reverseIntersectOption(intType)));\r\n }\r\n else if (curve instanceof Circle || curve instanceof Arc)\r\n {\r\n return IntersectEllipseAndCircleOrArc(this, curve, intType);\r\n }\r\n else if (curve instanceof Polyline)\r\n {\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, intType));\r\n }\r\n else if (curve instanceof Ellipse)\r\n {\r\n return IntersectEllipse(this, curve, intType);\r\n }\r\n else\r\n return [];\r\n }\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n let line = new TLine(this.UpdateGeometry(), ColorMaterial.GetLineMaterial(this._Color));\r\n this.UpdateDrawObject(renderType, line);\r\n return line;\r\n }\r\n UpdateDrawObject(type: RenderType, obj: Object3D)\r\n {\r\n let geo = (obj as TLine).geometry as BufferGeometry;\r\n this.UpdateGeometry(geo);\r\n }\r\n //更新Geometry\r\n private UpdateGeometry(geo?: BufferGeometry)\r\n {\r\n if (!geo)\r\n geo = new BufferGeometry();\r\n let curve = this.Shape;\r\n geo.setFromPoints(curve.getPoints(60));\r\n return geo;\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n return this.GetGripPoints();\r\n }\r\n GetGripPoints(): Array\r\n {\r\n let tmpMat4 = new Matrix4().makeRotationZ(this.Rotation);\r\n let pts = [\r\n new Vector3(this._radX, 0),\r\n new Vector3(-this._radX, 0),\r\n new Vector3(0, this._radY),\r\n new Vector3(0, -this._radY)\r\n ].map(p => p.applyMatrix4(tmpMat4).applyMatrix4(this.OCS));\r\n\r\n if (!equaln(0, this._startAngle))\r\n pts.push(this.StartPoint);\r\n if (!equaln(0, this._endAngle))\r\n pts.push(this.EndPoint);\r\n\r\n pts.push(this.Center);\r\n return pts;\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.ApplyMatrix(MoveMatrix(vec));\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n let pts = this.GetStretchPoints();\r\n\r\n if (indexList.length > 0)\r\n {\r\n let p = pts[indexList[0]].clone();\r\n p.add(vec);\r\n\r\n if (indexList[0] <= 1)\r\n this.RadX = p.distanceTo(this.Center);\r\n else if (indexList[0] <= 3)\r\n this.RadY = p.distanceTo(this.Center);\r\n else\r\n {\r\n let p1 = pts[indexList[0]];\r\n //TODO:跟cad不一致待优化\r\n if (equalv3(p1, this.StartPoint))\r\n {\r\n let v1 = p1.clone().sub(this.Center);\r\n let v2 = p.clone().sub(this.Center);\r\n let an = angleTo(v1, v2);\r\n this.StartAngle = this.StartAngle + an;\r\n }\r\n else if (equalv3(p1, this.EndPoint))\r\n {\r\n let v1 = p1.clone().sub(this.Center);\r\n let v2 = p.clone().sub(this.Center);\r\n let an = angleTo(v2, v1);\r\n this.EndAngle = this.EndAngle + an;\r\n }\r\n else\r\n this.Center = p;\r\n }\r\n }\r\n }\r\n Convert2Polyline(count = 0)\r\n {\r\n const MIN_LEN = 80;\r\n const par = this.TotalAngle / Math.PI * 0.5;\r\n if (!count)\r\n {\r\n count = Math.floor(this.Length / par / MIN_LEN);\r\n count = MathUtils.clamp(count, 15, 80);\r\n }\r\n\r\n count = Math.floor(count * par);\r\n\r\n if ((count & 1) === 0)\r\n count++;\r\n\r\n let pts = this.Shape.getPoints(count);\r\n if (this.IsClose)\r\n pts.pop();\r\n\r\n let pl = Pts2Polyline(pts, this.IsClose);\r\n pl.ApplyMatrix(this.OCS);\r\n if (this.IsClose)\r\n pl.CloseMark = true;\r\n return pl;\r\n }\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n this._radX = file.Read();\r\n this._radY = file.Read();\r\n this._rotate = file.Read();\r\n this._startAngle = file.Read();\r\n this._endAngle = file.Read();\r\n this.Update();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);\r\n file.Write(this.RadX);\r\n file.Write(this.RadY);\r\n file.Write(this.Rotation);\r\n file.Write(this._startAngle);\r\n file.Write(this._endAngle);\r\n }\r\n\r\n}\r\n","import { Box3, BufferGeometry, Line as TLine, Line3, Matrix3, Matrix4, Object3D, Shape, Vector3 } from 'three';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { Status } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { AsVector2, equaln, equalv3, isParallelTo, MoveMatrix } from '../../Geometry/GeUtils';\r\nimport { PlaneExt } from '../../Geometry/Plane';\r\nimport { IntersectEllipseAndLine, IntersectLineAndArc, IntersectLineAndCircle, IntersectLineAndLine, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\nimport { Arc } from './Arc';\r\nimport { Circle } from './Circle';\r\nimport { Curve } from './Curve';\r\nimport { Ellipse } from './Ellipse';\r\nimport { Polyline } from './Polyline';\r\n\r\n@Factory\r\nexport class Line extends Curve\r\n{\r\n\r\n constructor(private _StartPoint = new Vector3,\r\n private _EndPoint = new Vector3)\r\n {\r\n super();\r\n }\r\n\r\n get Is2D()\r\n {\r\n return super.Is2D && equaln(this._StartPoint.z, 0) && equaln(this._EndPoint.z, 0);\r\n }\r\n\r\n get Shape()\r\n {\r\n return new Shape([AsVector2(this._StartPoint), AsVector2(this._EndPoint)]);\r\n }\r\n\r\n Z0()\r\n {\r\n this.WriteAllObjectRecord();\r\n this.StartPoint = this.StartPoint.setZ(0);\r\n this.EndPoint = this.EndPoint.setZ(0);\r\n return this;\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this.StartPoint = this.StartPoint.applyMatrix4(m);\r\n this.EndPoint = this.EndPoint.applyMatrix4(m);\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n let sp = this.StartPoint;\r\n let ep = this.EndPoint;\r\n\r\n reviseMirrorMatrix(this._Matrix);\r\n\r\n this.StartPoint = sp;\r\n this.EndPoint = ep;\r\n return this;\r\n }\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n let geo = BufferGeometryUtils.CreateFromPts([this._StartPoint, this._EndPoint]);\r\n if (renderType === RenderType.WireframePrint)\r\n {\r\n var geometry = new LineGeometry();\r\n geometry.setPositions(geo.attributes.position.array as number[]);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n return new TLine(geo, ColorMaterial.GetLineMaterial(this.ColorIndex));\r\n }\r\n\r\n UpdateDrawObject(type: RenderType, lineObj: TLine)\r\n {\r\n BufferGeometryUtils.UpdatePts(lineObj.geometry as BufferGeometry, [this._StartPoint, this._EndPoint]);\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return [this.StartPoint, this.EndPoint];\r\n case ObjectSnapMode.Mid:\r\n return [this.GetPointAtParam(0.5)];\r\n case ObjectSnapMode.Nea:\r\n {\r\n let derv = this.GetFistDeriv(0).normalize();\r\n let viewNormal = new Vector3().fromArray(viewXform.elements, 2 * 3);\r\n\r\n //平行不捕捉\r\n if (isParallelTo(viewNormal, derv))\r\n return [];\r\n\r\n let fNormal = new Vector3().crossVectors(viewNormal, derv);\r\n fNormal.crossVectors(derv, fNormal);\r\n\r\n let plane = new PlaneExt(fNormal, this.StartPoint);\r\n let plocal = plane.intersectLine(new Line3(pickPoint, pickPoint.clone().add(viewNormal)), new Vector3(), true);\r\n let pclosest = this.GetClosestPointTo(plocal, false);\r\n return [pclosest];\r\n }\r\n case ObjectSnapMode.Ext:\r\n return [this.GetClosestPointTo(pickPoint, true)];\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n let { closestPt, param } = this.GetClosestAtPoint(lastPoint, true);\r\n if (this.ParamOnCurve(param))\r\n return [closestPt];\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n return [this.StartPoint, this.GetPointAtParam(0.5), this.EndPoint];\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n for (let index of indexList)\r\n {\r\n if (index === 0)\r\n this.StartPoint = this.StartPoint.add(vec);\r\n else if (index === 2)\r\n this.EndPoint = this.EndPoint.add(vec);\r\n else\r\n {\r\n let m = MoveMatrix(vec);\r\n this.ApplyMatrix(m);\r\n }\r\n }\r\n }\r\n\r\n GetStretchPoints(): Array\r\n {\r\n return [this.StartPoint, this.EndPoint];\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n for (let index of indexList)\r\n {\r\n if (index === 0)\r\n this.StartPoint = this.StartPoint.add(vec);\r\n else\r\n this.EndPoint = this.EndPoint.add(vec);\r\n }\r\n }\r\n\r\n GetFistDeriv(param: number | Vector3): Vector3\r\n {\r\n return this.EndPoint.sub(this.StartPoint);\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-4)\r\n {\r\n if (curve instanceof Line)\r\n {\r\n return IntersectLineAndLine(this, curve, intType, tolerance);\r\n }\r\n if (curve instanceof Arc)\r\n {\r\n return IntersectLineAndArc(this, curve, intType, tolerance);\r\n }\r\n if (curve instanceof Circle)\r\n {\r\n return IntersectLineAndCircle(this, curve, intType, tolerance);\r\n }\r\n if (curve instanceof Polyline)\r\n {\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));\r\n }\r\n\r\n if (curve instanceof Ellipse)\r\n return IntersectEllipseAndLine(this, curve, intType, tolerance);\r\n\r\n //其他的尚未实现.\r\n return [];\r\n }\r\n\r\n //Param\r\n GetPointAtParam(param: number): Vector3\r\n {\r\n return this.StartPoint.add(this.GetFistDeriv(0).multiplyScalar(param));\r\n }\r\n GetParamAtPoint(pt: Vector3): number\r\n {\r\n let { closestPt, param } = this.GetClosestAtPoint(pt, true);\r\n if (!equalv3(closestPt, pt, 1e-5))\r\n return NaN;\r\n return param;\r\n }\r\n GetParamAtDist(d: number): number\r\n {\r\n return d / this.Length;\r\n }\r\n GetPointAtDistance(distance: number): Vector3\r\n {\r\n return this.GetPointAtParam(this.GetParamAtDist(distance));\r\n }\r\n GetDistAtParam(param: number): number\r\n {\r\n return this.Length * param;\r\n }\r\n GetDistAtPoint(pt: Vector3): number\r\n {\r\n return this.GetDistAtParam(this.GetParamAtPoint(pt));\r\n }\r\n GetSplitCurves(param: number[] | number)\r\n {\r\n let params = this.SplitParamSort(param);\r\n let pts = params.map(param => this.GetPointAtParam(param));\r\n let ret = new Array();\r\n if (pts.length >= 2)\r\n {\r\n for (let i = 0; i < pts.length - 1; i++)\r\n {\r\n let newLine = this.Clone() as Line;\r\n newLine.StartPoint = pts[i];\r\n newLine.EndPoint = pts[i + 1];\r\n ret.push(newLine);\r\n }\r\n }\r\n return ret;\r\n }\r\n\r\n GetParamAtPoint2(pt: Vector3): number\r\n {\r\n let { param } = this.GetClosestAtPoint(pt, true);\r\n return param;\r\n }\r\n\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n let { param } = this.GetClosestAtPoint(p, true);\r\n return this.ParamOnCurve(param, fuzz);\r\n }\r\n\r\n GetClosestAtPoint(pt: Vector3, extend: boolean): { closestPt: Vector3, param: number; }\r\n {\r\n let sp = this.StartPoint;\r\n let ep = this.EndPoint;\r\n if (equalv3(pt, sp, 1e-8))\r\n return { closestPt: sp, param: 0 };\r\n else if (equalv3(pt, ep, 1e-8))\r\n return { closestPt: ep, param: 1 };\r\n\r\n let direction = this.GetFistDeriv(0);\r\n let length = direction.length();\r\n\r\n if (length === 0)\r\n {\r\n let param = NaN;\r\n if (equalv3(pt, this.StartPoint, 1e-6))\r\n param = 0;\r\n return { closestPt: sp, param: param };\r\n }\r\n\r\n direction.divideScalar(length);\r\n\r\n let diff = pt.clone().sub(sp);\r\n let param = direction.dot(diff);\r\n\r\n let closestPt: Vector3;\r\n if (extend)\r\n closestPt = sp.add(direction.multiplyScalar(param));\r\n else\r\n if (param < 0)\r\n {\r\n closestPt = sp;\r\n param = 0;\r\n }\r\n else if (param > length)\r\n {\r\n closestPt = this.EndPoint;\r\n param = length;\r\n }\r\n else\r\n closestPt = sp.add(direction.multiplyScalar(param));\r\n return {\r\n closestPt: closestPt,\r\n param: param / length\r\n };\r\n }\r\n\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n return this.GetClosestAtPoint(pt, extend).closestPt;\r\n }\r\n\r\n Extend(newParam: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n if (newParam < this.StartParam)\r\n {\r\n this.StartPoint = this.GetPointAtParam(newParam);\r\n }\r\n else if (newParam > this.EndParam)\r\n {\r\n this.EndPoint = this.GetPointAtParam(newParam);\r\n }\r\n }\r\n\r\n Join(cu: Curve, allowGap = false, tolerance = 1e-5): Status\r\n {\r\n if (cu instanceof Line)\r\n {\r\n //平行\r\n if (!isParallelTo(this.GetFistDeriv(0).normalize(), cu.GetFistDeriv(0).normalize()))\r\n return Status.False;\r\n\r\n let sp = cu.StartPoint;\r\n let { closestPt: cp1, param: param1 } = this.GetClosestAtPoint(sp, true);\r\n if (!equalv3(sp, cp1, tolerance))//点在曲线上,允许较低的精度\r\n return Status.False;\r\n\r\n let ep = cu.EndPoint;\r\n let { closestPt: cp2, param: param2 } = this.GetClosestAtPoint(ep, true);\r\n if (!equalv3(ep, cp2, tolerance))\r\n return Status.False;\r\n\r\n if (param1 > param2)\r\n {\r\n [param1, param2] = [param2, param1];\r\n [sp, ep] = [ep, sp];\r\n }\r\n\r\n if (allowGap || Math.max(0, param1) < Math.min(1, param2) + tolerance)\r\n {\r\n if (param1 < 0)\r\n this.StartPoint = sp;\r\n if (param2 > 1)\r\n this.EndPoint = ep;\r\n return Status.True;\r\n }\r\n }\r\n return Status.False;\r\n }\r\n\r\n Reverse(): this\r\n {\r\n this.WriteAllObjectRecord();\r\n [this._StartPoint, this._EndPoint] = [this._EndPoint, this._StartPoint];\r\n return this;\r\n }\r\n\r\n GetOffsetCurves(offsetDist: number): Array\r\n {\r\n let derv = this.GetFistDeriv(0).normalize().multiplyScalar(offsetDist);\r\n derv.applyMatrix4(new Matrix4().makeRotationAxis(this.Normal, -Math.PI / 2));\r\n let newLine = this.Clone() as Line;\r\n newLine.StartPoint = this.StartPoint.add(derv);\r\n newLine.EndPoint = this.EndPoint.add(derv);\r\n return [newLine];\r\n }\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3().setFromPoints([this.StartPoint, this.EndPoint]);\r\n }\r\n\r\n get StartParam()\r\n {\r\n return 0;\r\n }\r\n get EndParam()\r\n {\r\n return 1;\r\n }\r\n //属性\r\n get Length(): number { return this._StartPoint.distanceTo(this._EndPoint); }\r\n\r\n //#region -----------------------------File-----------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();//1\r\n this._StartPoint.fromArray(file.Read());\r\n this._EndPoint.fromArray(file.Read());\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);//ver\r\n file.Write(this._StartPoint.toArray());\r\n file.Write(this._EndPoint.toArray());\r\n }\r\n //#endregion-----------------------------File End-----------------------------\r\n\r\n //#region 属性\r\n set StartPoint(p: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._StartPoint.copy(p).applyMatrix4(this.OCSInv);\r\n this.Update();\r\n }\r\n get StartPoint(): Vector3\r\n {\r\n return this._StartPoint.clone().applyMatrix4(this.OCS);\r\n }\r\n\r\n get EndPoint(): Vector3\r\n {\r\n return this._EndPoint.clone().applyMatrix4(this.OCS);\r\n }\r\n set EndPoint(p: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._EndPoint.copy(p).applyMatrix4(this.OCSInv);\r\n this.Update();\r\n }\r\n\r\n //#endregion\r\n}\r\n","import { Box3 } from \"three\";\r\nimport { equaln } from \"./GeUtils\";\r\n\r\nexport interface EBox\r\n{\r\n BoundingBox: Box3;\r\n}\r\n\r\n/**\r\n * 根据盒子x排序盒子\r\n * @param {EBox[]} arr\r\n */\r\nexport function SortEntityByBox(arr: T[], sort: boolean = true)\r\n{\r\n let boxMap: Map = new Map();\r\n arr.forEach(e => boxMap.set(e, e.BoundingBox));\r\n\r\n if (sort)\r\n arr.sort((e1, e2) =>\r\n {\r\n let b1 = boxMap.get(e1);\r\n let b2 = boxMap.get(e2);\r\n if (!equaln(b1.min.x, b2.min.x))\r\n return b1.min.x - b2.min.x;\r\n else\r\n {\r\n return b2.min.y - b1.min.y;\r\n }\r\n });\r\n\r\n return boxMap;\r\n}\r\n","import { Box3, Matrix4, Vector3 } from \"three\";\r\nimport { arrayLast } from \"../Common/ArrayExt\";\r\nimport { ConverCircleToPolyline } from \"../Common/CurveUtils\";\r\nimport { Status } from \"../Common/Status\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\nimport { Contour } from \"../DatabaseServices/Contour\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Circle } from \"../DatabaseServices/Entity/Circle\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { Line } from \"../DatabaseServices/Entity/Line\";\r\nimport { Polyline } from \"../DatabaseServices/Entity/Polyline\";\r\nimport { IntersectsBox } from \"../Geometry/Box\";\r\nimport { CurveMap, Route, Vertice } from \"../Geometry/CurveMap\";\r\nimport { angle, equaln, equalv2, equalv3, IdentityMtx4, SelectNearP } from \"../Geometry/GeUtils\";\r\nimport { SortEntityByBox } from \"../Geometry/SortEntityByBox\";\r\nimport { IntersectOption } from \"../GraphicsSystem/IntersectWith\";\r\n\r\ninterface IOffsetResult\r\n{\r\n index: number;\r\n curve: Curve;\r\n sp?: Vector3;\r\n preArc?: Curve;\r\n ep?: Vector3;\r\n nextArc?: Curve;\r\n paddingCurve?: Curve[];\r\n}\r\n\r\nclass CurveTreeNode\r\n{\r\n children: CurveTreeNode[];\r\n box: Box3;\r\n used: boolean;\r\n constructor(public curve: Curve, box?: Box3)\r\n {\r\n this.box = box || curve.BoundingBox;\r\n }\r\n\r\n TrimBy(contour: Contour, box: Box3)\r\n {\r\n if (IntersectsBox(box, this.box))\r\n {\r\n if (this.children !== undefined)\r\n {\r\n for (let c of this.children)\r\n c.TrimBy(contour, box);\r\n }\r\n else\r\n {\r\n if (contour.Curve instanceof Circle && this.curve instanceof Arc)\r\n {\r\n if (equalv3(contour.Curve.Center, this.curve.Center))\r\n {\r\n if (contour.Curve.Radius > this.curve.Radius + 1e-4)\r\n this.children = [];\r\n\r\n return;\r\n }\r\n }\r\n\r\n //交点参数列表\r\n let iParams = this.curve.IntersectWith(contour.Curve, IntersectOption.OnBothOperands)\r\n .map(p => this.curve.GetParamAtPoint2(p));\r\n\r\n let cus = this.curve.GetSplitCurves(iParams);\r\n if (cus.length === 0)\r\n {\r\n let p = this.curve.GetPointAtParam(0.5);\r\n if ((contour.Curve.PtInCurve(p) && !contour.Curve.PtOnCurve(p)))\r\n this.children = [];\r\n }\r\n else\r\n {\r\n this.children = [];\r\n for (let c of cus)\r\n {\r\n let p = c.GetPointAtParam(0.5);\r\n if (c.Length > 1e-5 && (!contour.Curve.PtInCurve(p) || contour.Curve.PtOnCurve(p)))\r\n this.children.push(new CurveTreeNode(c));\r\n }\r\n if (this.children.length === cus.length)\r\n this.children = undefined;\r\n }\r\n }\r\n }\r\n }\r\n\r\n get Nodes()\r\n {\r\n if (!this.children) return [this];\r\n else\r\n {\r\n let cus: CurveTreeNode[] = [];\r\n for (let c of this.children)\r\n cus.push(...c.Nodes);\r\n return cus;\r\n }\r\n }\r\n}\r\n\r\nexport class OffsetPolyline\r\n{\r\n //多段线信息\r\n _CacheOCS: Matrix4;\r\n _Vertexs: Vector3[];\r\n _SubCurves: Curve[];\r\n _Circles: Circle[];\r\n\r\n //偏移子曲线\r\n _SubOffsetedCurves: IOffsetResult[];\r\n //用于裁剪的曲线节点\r\n _CurveTreeNodes: CurveTreeNode[];\r\n //裁剪完的曲线节点\r\n _CurveTrimedTreeNodes: CurveTreeNode[];\r\n\r\n //裁剪轮廓\r\n _TrimPolylineContours: Contour[];\r\n _TrimCircleContours: Circle[];\r\n _TrimArcContours: Contour[];\r\n\r\n //结果曲线\r\n _RetCurves: Polyline[];\r\n\r\n _IsClose: boolean;\r\n _OffsetDistSign: number;\r\n\r\n constructor(public _Polyline: Polyline, public _OffsetDist: number, public _ToolPath = false,\r\n private _OffsetDistSq = (_OffsetDist ** 2) * 2.1//对直角走刀不进行圆弧过度\r\n )\r\n {\r\n }\r\n\r\n Do()\r\n {\r\n this._OffsetDistSign = Math.sign(this._OffsetDist);\r\n this._TrimPolylineContours = [];\r\n this._TrimCircleContours = [];\r\n this._TrimArcContours = [];\r\n\r\n this._RetCurves = [];\r\n this._CurveTreeNodes = [];\r\n\r\n this.InitSubCurves();\r\n if (this._SubCurves.length === 0)\r\n return this._RetCurves;\r\n\r\n this.GeneralCirclesAndVertexs();\r\n this.OffsetSubCurves();\r\n this.LinkSubCurves();\r\n\r\n if (this._SubOffsetedCurves.length === 0)\r\n {\r\n this._SubOffsetedCurves.push({ curve: this._Circles[0], index: 0, paddingCurve: this._Circles.slice(1) });\r\n\r\n this._TrimPolylineContours.push(\r\n ...this._Circles.map(c => Contour.CreateContour(c, false)),\r\n ...this._SubCurves.map(c => Contour.CreateContour([c, new Line(c.StartPoint, c.EndPoint)], false))\r\n );\r\n }\r\n else\r\n this.GeneralTrimContours();\r\n this.TrimByContours();\r\n this.FilterInvalidCurve();\r\n this.JoinCollinear();\r\n this.LinkResultPolyline();\r\n return this._RetCurves;\r\n }\r\n\r\n InitSubCurves()\r\n {\r\n this._CacheOCS = this._Polyline.OCS;\r\n this._IsClose = this._Polyline.IsClose;\r\n this._Polyline.OCS = IdentityMtx4;\r\n this._SubCurves = this._Polyline.Explode().filter(c => c.Length > 1e-4);\r\n this._Polyline.OCS = this._CacheOCS;\r\n return this;\r\n }\r\n\r\n protected GeneralCirclesAndVertexs()\r\n {\r\n this._Vertexs = this._SubCurves.map(c => c.StartPoint);\r\n let lastCu = arrayLast(this._SubCurves);\r\n if (!equalv3(lastCu.EndPoint, this._Vertexs[0], 1e-3))\r\n this._Vertexs.push(lastCu.EndPoint);\r\n\r\n let radius = Math.abs(this._OffsetDist);\r\n this._Circles = this._Vertexs.map(p => new Circle(p, radius));\r\n }\r\n\r\n protected OffsetSubCurves()\r\n {\r\n this._SubOffsetedCurves = [];\r\n for (let index = 0; index < this._SubCurves.length; index++)\r\n {\r\n let curveOld = this._SubCurves[index];\r\n if (curveOld.Length > 1e-6)\r\n {\r\n let curve = curveOld.GetOffsetCurves(this._OffsetDist)[0];\r\n if (curve)\r\n this._SubOffsetedCurves.push({ curve, index });\r\n else\r\n this._TrimArcContours.push(Contour.CreateContour([curveOld, new Line(curveOld.StartPoint, curveOld.EndPoint)], false));\r\n }\r\n }\r\n }\r\n\r\n //连接(延伸)曲线,或者补(圆弧,直线)\r\n protected LinkSubCurves()\r\n {\r\n let count = this._SubOffsetedCurves.length;\r\n if (!this._IsClose) count--;\r\n\r\n for (let i = 0; i < count; i++)\r\n {\r\n let curveResNow = this._SubOffsetedCurves[i];\r\n let iNext = FixIndex(i + 1, this._SubOffsetedCurves);\r\n let curveResNext = this._SubOffsetedCurves[iNext];\r\n let curveNow = curveResNow.curve;\r\n let curveNext = curveResNext.curve;\r\n let isNeighbor = FixIndex(curveResNow.index + 1, this._SubCurves) === curveResNext.index;\r\n\r\n if (isNeighbor)\r\n {\r\n let sp = curveNow.EndPoint;\r\n let ep = curveNext.StartPoint;\r\n //直连\r\n if (equalv3(sp, ep, 1e-3))\r\n continue;\r\n\r\n let iPts = curveNow.IntersectWith(curveNext, IntersectOption.ExtendBoth);\r\n let tPts = iPts.filter(p => curveNow.PtOnCurve3(p) && curveNext.PtOnCurve3(p));\r\n\r\n let code = EntityEncode2(curveNow, curveNext);\r\n\r\n let tp: Vector3;\r\n if (code === 1)\r\n {\r\n if (tPts.length > 0)//不走刀或者有真交点 this._ToolPath === false ||\r\n tp = iPts[0];\r\n else\r\n {\r\n if (iPts.length > 0 && curveNow.GetParamAtPoint(iPts[0]) > 1)\r\n {\r\n let refP = this._Vertexs[curveResNext.index];\r\n let distSq = iPts[0].distanceToSquared(refP);\r\n if (this._ToolPath && distSq > this._OffsetDistSq)\r\n {\r\n curveResNow.paddingCurve = [this.CreateArc(refP, sp, ep)];\r\n this._TrimCircleContours.push(this._Circles[curveResNext.index]);\r\n }\r\n else\r\n tp = iPts[0];\r\n }\r\n // else\r\n // curveResNow.paddingCurve = [new Line(sp, ep)];\r\n }\r\n }\r\n else\r\n {\r\n let refP = this._Vertexs[curveResNext.index];\r\n if (tPts.length > 0) //ipts = 1 or ipts = 2\r\n tp = SelectNearP(iPts, refP);\r\n else //补单圆 或者尝试连接\r\n {\r\n let arc = this.CreateArc(refP, sp, ep);\r\n\r\n if (iPts.length > 0 && !this._ToolPath && this.IsSharpCorner(curveResNow, curveResNext, refP))\r\n {\r\n //设置新的连接点,并且备份旧点\r\n let oldp: Vector3;\r\n if (curveResNow.sp)\r\n {\r\n oldp = curveNow.StartPoint;\r\n curveNow.StartPoint = curveResNow.sp;\r\n }\r\n let oldp2: Vector3;\r\n if (curveResNext.ep)\r\n {\r\n oldp2 = curveNext.EndPoint;\r\n curveNext.EndPoint = curveResNext.ep;\r\n }\r\n\r\n let p: Vector3;\r\n\r\n if (code === 2 && iPts.length === 2)\r\n {\r\n let c = curveNow as Arc;\r\n let minArc = new Arc(c.Center, c.Radius, c.EndAngle, 0, c.IsClockWise);\r\n\r\n let p1 = iPts[0];\r\n let a1 = minArc.GetAngleAtPoint(p1);\r\n let anAll1 = c.ParamOnCurve(c.GetParamAtAngle(a1)) ? Infinity : minArc.ComputeAnlge(a1);\r\n\r\n let p2 = iPts[1];\r\n let a2 = minArc.GetAngleAtPoint(p2);\r\n let anAll2 = c.ParamOnCurve(c.GetParamAtAngle(a2)) ? Infinity : minArc.ComputeAnlge(a2);\r\n\r\n if (anAll2 < anAll1)\r\n p = p2;\r\n else\r\n p = p1;\r\n }\r\n else\r\n p = SelectNearP(iPts, refP);\r\n\r\n let onPre: boolean;\r\n let param = curveNow.GetParamAtPoint2(p);\r\n if (curveNow instanceof Line)\r\n onPre = param > 1;\r\n else\r\n onPre = param < 0 || param > 1;\r\n\r\n let onNext: boolean = false;\r\n if (onPre)\r\n {\r\n let param2 = curveNext.GetParamAtPoint2(p);\r\n if (curveNext instanceof Line)\r\n onNext = param2 < 0;\r\n else\r\n onNext = param2 < 0 || param2 > 1;\r\n }\r\n\r\n if (curveResNow.sp)\r\n curveNow.StartPoint = oldp;\r\n if (curveResNext.ep)\r\n curveNext.EndPoint = oldp2;\r\n\r\n if (onPre && onNext)\r\n tp = p;\r\n else\r\n curveResNow.paddingCurve = [arc];\r\n }\r\n else\r\n curveResNow.paddingCurve = [arc];\r\n\r\n this._TrimCircleContours.push(this._Circles[curveResNext.index]);\r\n }\r\n }\r\n if (tp)\r\n {\r\n curveResNow.ep = tp;\r\n curveResNext.sp = tp;\r\n\r\n curveResNow.nextArc = curveNext;\r\n curveResNext.preArc = curveNow;\r\n }\r\n }\r\n else\r\n {\r\n let padCirs: Circle[] = [];\r\n for (let s = FixIndex(curveResNow.index + 1, this._Circles); ; s = FixIndex(s + 1, this._Circles))\r\n {\r\n let c = this._Circles[s];\r\n this._TrimCircleContours.push(c);\r\n padCirs.push(c);\r\n if (s === curveResNext.index)\r\n break;\r\n }\r\n curveResNow.paddingCurve = padCirs;\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n private IsSharpCorner(curveResNow: IOffsetResult, curveResNext: IOffsetResult, refP: Vector3): boolean\r\n {\r\n let v1 = this._SubCurves[curveResNow.index].GetPointAtParam(0.9);\r\n let v2 = this._SubCurves[curveResNext.index].GetPointAtParam(0.1);\r\n v1.subVectors(refP, v1);\r\n v2.sub(refP);\r\n v1.cross(v2);\r\n return Math.sign(v1.z) === this._OffsetDistSign;\r\n }\r\n\r\n protected GeneralTrimContours()\r\n {\r\n for (let d of this._SubOffsetedCurves)\r\n {\r\n let cu2 = d.curve;\r\n if (d.sp && d.ep)\r\n {\r\n let param1 = cu2.GetParamAtPoint(d.sp);\r\n let param2 = cu2.GetParamAtPoint(d.ep);\r\n\r\n if (cu2.ParamOnCurve(param1) && cu2.ParamOnCurve(param2) && param1 > param2)\r\n [d.sp, d.ep] = [d.ep, d.sp];\r\n }\r\n if (d.sp) cu2.StartPoint = d.sp;\r\n if (d.ep) cu2.EndPoint = d.ep;\r\n\r\n //这是极端情况,圆弧被压缩成0长度圆弧,本质是空圆弧(我们会在下面判断它)(因为精度的问题)\r\n //因为精度的问题,这种0圆心角的圆弧会被当成全圆,但是偏移算法中,应该不可能出现全圆弧的圆弧,所以我们压扁它\r\n if (cu2 instanceof Arc\r\n && equaln(cu2.StartAngle, cu2.EndAngle, 1e-6)\r\n // && !equaln((this._SubCurves[d.index]).AllAngle, Math.PI * 2, 1e-3) 应该不会出现\r\n )\r\n {\r\n if (cu2.IsClockWise)\r\n cu2.StartAngle = cu2.EndAngle + 1e-6;\r\n else\r\n cu2.EndAngle = cu2.StartAngle + 1e-6;\r\n }\r\n }\r\n for (let d of this._SubOffsetedCurves)\r\n {\r\n let cu1 = this._SubCurves[d.index];\r\n let cu2 = d.curve;\r\n\r\n let [p1, p2, p3, p4] = [cu1.StartPoint, cu2.StartPoint, cu1.EndPoint, cu2.EndPoint];\r\n let l1 = new Line(p1, p2);\r\n let l2 = new Line(p3, p4);\r\n\r\n let ipts = l1.IntersectWith(l2, IntersectOption.OnBothOperands, 1e-8);\r\n if (ipts.length > 0)\r\n {\r\n let p = ipts[0];\r\n l1.EndPoint = p;\r\n l2.EndPoint = p;\r\n let cus = [cu1, l1, l2];\r\n let contour = Contour.CreateContour(cus, false);\r\n if (contour)\r\n {\r\n this._TrimPolylineContours.push(contour);\r\n continue;\r\n }\r\n else\r\n {\r\n console.error(\"未预料到的错误,构建轮廓失败\" + this._OffsetDist);\r\n }\r\n }\r\n\r\n //真理1:针脚线不可能同时被两个圆弧所切割\r\n let l1Intact = true;\r\n let l2Intact = true;\r\n if (cu2 instanceof Arc)\r\n {\r\n if (Math.sign(cu2.Bul) !== this._OffsetDistSign)\r\n {\r\n let ipts1 = cu2.IntersectWith(l1, IntersectOption.OnBothOperands);\r\n let ipts2 = cu2.IntersectWith(l2, IntersectOption.OnBothOperands);\r\n\r\n let sp: Vector3;\r\n let ep: Vector3;\r\n if (ipts1.length === 2)\r\n sp = SelectNearP(ipts1, p1);\r\n if (ipts2.length === 2)\r\n ep = SelectNearP(ipts2, p3);\r\n\r\n if (sp || ep) cu2 = cu2.Clone();\r\n if (sp)\r\n {\r\n l1.EndPoint = sp;\r\n cu2.StartPoint = sp;\r\n l1Intact = false;\r\n }\r\n if (ep)\r\n {\r\n l2.EndPoint = ep;\r\n cu2.EndPoint = ep;\r\n l2Intact = false;\r\n }\r\n }\r\n }\r\n\r\n let l1PadArc: Arc;\r\n let l2PadArc: Arc;\r\n //真理2:隔壁的圆弧不可能破坏当前的圆弧,只能破坏当前的针脚\r\n if (l1Intact && d.preArc && d.preArc instanceof Arc)\r\n {\r\n let a = d.preArc;\r\n if (Math.sign(a.Bul) !== this._OffsetDistSign && a.AllAngle > 1e-6)\r\n {\r\n let ipts = a.IntersectWith(l1, IntersectOption.OnBothOperands);\r\n if (ipts.length === 2)\r\n {\r\n let sp = SelectNearP(ipts, p1);\r\n l1.EndPoint = sp;\r\n l1PadArc = a.Clone();\r\n l1PadArc.StartPoint = sp;\r\n }\r\n }\r\n }\r\n if (l2Intact && d.nextArc && d.nextArc instanceof Arc)\r\n {\r\n let a = d.nextArc;\r\n if (Math.sign(a.Bul) !== this._OffsetDistSign && a.AllAngle > 1e-6)\r\n {\r\n let ipts = a.IntersectWith(l2, IntersectOption.OnBothOperands);\r\n if (ipts.length === 2)\r\n {\r\n let ep = SelectNearP(ipts, p3);\r\n l2.EndPoint = ep;\r\n l2PadArc = a.Clone();\r\n l2PadArc.EndPoint = ep;\r\n }\r\n }\r\n }\r\n\r\n let pl = new Polyline();\r\n let cus = [cu1, l1];\r\n if (l1PadArc) cus.push(l1PadArc);\r\n cus.push(cu2, l2);\r\n if (l2PadArc) cus.push(l2PadArc);\r\n\r\n for (let c of cus)\r\n pl.Join(c);\r\n\r\n let contour = Contour.CreateContour(pl, false);\r\n if (contour)\r\n this._TrimPolylineContours.push(contour);\r\n else\r\n console.error(\"未预料到的错误,构建轮廓失败\" + this._OffsetDist);\r\n }\r\n\r\n if (!this._IsClose)\r\n {\r\n if (this._TrimCircleContours[0] !== this._Circles[0])\r\n this._TrimCircleContours.push(this._Circles[0]);\r\n let lastTrimCircle = arrayLast(this._TrimCircleContours);\r\n let lastCircle = arrayLast(this._Circles);\r\n if (lastTrimCircle !== lastCircle)\r\n this._TrimCircleContours.push(lastCircle);\r\n if (this._SubOffsetedCurves[0].index !== 0)\r\n this._TrimCircleContours.push(this._Circles[this._SubOffsetedCurves[0].index]);\r\n\r\n let lastIndex = this._Circles.length - 1;\r\n let lastD = arrayLast(this._SubOffsetedCurves);\r\n if (lastIndex !== lastD.index)\r\n this._TrimCircleContours.push(this._Circles[lastD.index + 1]);\r\n }\r\n\r\n this._TrimPolylineContours.push(\r\n ...this._TrimCircleContours.map(c => Contour.CreateContour(c, false)),\r\n ...this._TrimArcContours\r\n );\r\n }\r\n\r\n // 通过构建的轮廓对偏移曲线进行裁剪\r\n protected TrimByContours()\r\n {\r\n for (let d of this._SubOffsetedCurves)\r\n {\r\n let c = d.curve;\r\n this._CurveTreeNodes.push(new CurveTreeNode(c));\r\n if (d.paddingCurve)\r\n this._CurveTreeNodes.push(...d.paddingCurve.map(c => new CurveTreeNode(c)));\r\n }\r\n let boxContours = SortEntityByBox(this._TrimPolylineContours, false);\r\n\r\n for (let i = 0; i < this._TrimPolylineContours.length; i++)\r\n {\r\n let c = this._TrimPolylineContours[i];\r\n for (let curveNode of this._CurveTreeNodes)\r\n {\r\n curveNode.TrimBy(c, boxContours.get(c));\r\n }\r\n }\r\n }\r\n\r\n //过滤方向相反和0长度线\r\n private FilterInvalidCurve()\r\n {\r\n this._CurveTrimedTreeNodes = [];\r\n for (let n of this._CurveTreeNodes)\r\n {\r\n let ns = n.Nodes;\r\n for (let sn of ns)\r\n {\r\n let p = sn.curve.GetPointAtParam(0.5);\r\n if (sn.curve.Length > 1e-5 && this.CheckPointDir(p))\r\n this._CurveTrimedTreeNodes.push(sn);\r\n }\r\n }\r\n }\r\n\r\n //合并共线\r\n private JoinCollinear()\r\n {\r\n for (let i = 0; i < this._CurveTrimedTreeNodes.length; i++)\r\n {\r\n let n = this._CurveTrimedTreeNodes[i];\r\n if (n.used) continue;\r\n let sp = n.curve.StartPoint;\r\n for (let j = i + 1; j < this._CurveTrimedTreeNodes.length; j++)\r\n {\r\n let n2 = this._CurveTrimedTreeNodes[j];\r\n if (n2.used) continue;\r\n let status = n.curve.Join(n2.curve);\r\n if (status === Status.ConverToCircle)\r\n {\r\n n.used = true;\r\n n2.used = true;\r\n let circle = new Circle((n.curve).Center, (n.curve).Radius);\r\n n.curve = circle;\r\n this._RetCurves.push(ConverCircleToPolyline(circle).ApplyMatrix(this._CacheOCS));\r\n }\r\n else if (status === Status.True)\r\n {\r\n if (equalv3(sp, n.curve.StartPoint))\r\n n2.used = true;\r\n else\r\n {\r\n n.used = true;\r\n n2.curve = n.curve;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n //连接结果曲线,返回最终多段线\r\n private LinkResultPolyline()\r\n {\r\n let used = new Set();\r\n let cuMap = new CurveMap(1);\r\n for (let n of this._CurveTrimedTreeNodes)\r\n {\r\n if (!n.used)\r\n cuMap.AddCurveToMap(n.curve);\r\n }\r\n\r\n let preP: Vector3;\r\n\r\n let searchNext = (s: Vertice, pl: Polyline): Vertice =>\r\n {\r\n let minDist = Infinity;\r\n let minR: Route;\r\n for (let r of s.routes)\r\n {\r\n if (used.has(r.curve)) continue;\r\n\r\n if (preP)\r\n {\r\n let d = r.s.distanceToSquared(preP);\r\n if (d < minDist)\r\n {\r\n minR = r;\r\n minDist = d;\r\n }\r\n }\r\n else\r\n {\r\n minR = r;\r\n break;\r\n }\r\n }\r\n\r\n if (minR)\r\n {\r\n used.add(minR.curve);\r\n preP = minR.e;\r\n let status = pl.Join(minR.curve, false, 5e-2);\r\n if (status !== Status.True)\r\n console.warn(\"连接失败\");\r\n return minR.to;\r\n }\r\n };\r\n\r\n for (let s of cuMap.Stands)\r\n {\r\n preP = undefined;\r\n let pl = new Polyline();\r\n let ss = s;\r\n while (ss && !pl.IsClose)\r\n ss = searchNext(ss, pl);\r\n ss = s;\r\n while (ss && !pl.IsClose)\r\n ss = searchNext(ss, pl);\r\n\r\n if (pl.NumberOfVertices > 0)\r\n {\r\n let d = pl.LineData;\r\n let ld = arrayLast(d);\r\n if (equalv2(d[0].pt, ld.pt, 1e-2))\r\n ld.pt.copy(d[0].pt);\r\n this._RetCurves.push(pl.ApplyMatrix(this._CacheOCS));\r\n }\r\n }\r\n }\r\n\r\n CheckPointDir(pt: Vector3): boolean\r\n {\r\n return this.GetPointAtCurveDir(pt) === this._OffsetDistSign;\r\n }\r\n\r\n GetPointAtCurveDir(pt: Vector3): number\r\n {\r\n let minIndex = Infinity;\r\n let minDist = Infinity;\r\n let minCp: Vector3;\r\n for (let i = 0; i < this._SubCurves.length; i++)\r\n {\r\n let c = this._SubCurves[i];\r\n let cp = c.GetClosestPointTo(pt, false);\r\n if (equalv3(cp, pt, 1e-5)) return 0;\r\n\r\n let dist = cp.distanceToSquared(pt);\r\n if (dist < minDist)\r\n {\r\n minDist = dist;\r\n minIndex = i;\r\n minCp = cp;\r\n }\r\n }\r\n\r\n let c = this._SubCurves[minIndex];\r\n let param = c.GetParamAtPoint(minCp);\r\n\r\n if (equaln(param, 0) && ((minIndex === 0) ? this._IsClose : true))\r\n {\r\n let preIndex = FixIndex(minIndex - 1, this._SubCurves);\r\n let preCurve = this._SubCurves[preIndex];\r\n\r\n if (!equalv3(c.GetFistDeriv(0).normalize(), preCurve.GetFistDeriv(1).normalize()))\r\n {\r\n let p = c.StartPoint;\r\n let l1 = c.Length;\r\n let l2 = preCurve.Length;\r\n let minLength = Math.min(l1, l2) * 0.2;\r\n\r\n let nextP: Vector3;\r\n let preP: Vector3;\r\n if (c instanceof Arc)\r\n nextP = c.GetPointAtDistance(minLength);\r\n else\r\n nextP = c.EndPoint;\r\n\r\n if (preCurve instanceof Arc)\r\n preP = preCurve.GetPointAtDistance(l2 - minLength);\r\n else\r\n preP = preCurve.StartPoint;\r\n\r\n let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p)));\r\n\r\n let dir = arc.PtOnCurve3(pt) ? -1 : 1;\r\n return dir;\r\n }\r\n }\r\n else if (equaln(param, 1) && ((minIndex === this._SubCurves.length - 1) ? this._IsClose : true))\r\n {\r\n let nextIndex = FixIndex(minIndex + 1, this._SubCurves);\r\n let nextCurve = this._SubCurves[nextIndex];\r\n\r\n if (!equalv3(c.GetFistDeriv(1).normalize(), nextCurve.GetFistDeriv(0).normalize()))\r\n {\r\n let p = c.EndPoint;\r\n\r\n let l1 = c.Length;\r\n let l2 = nextCurve.Length;\r\n let minLength = Math.min(l1, l2) * 0.2;\r\n\r\n let nextP: Vector3;\r\n let preP: Vector3;\r\n if (c instanceof Arc)\r\n preP = c.GetPointAtDistance(l1 - minLength);\r\n else\r\n preP = c.StartPoint;\r\n\r\n if (nextCurve instanceof Arc)\r\n nextP = nextCurve.GetPointAtDistance(minLength);\r\n else\r\n nextP = nextCurve.EndPoint;\r\n\r\n let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p)));\r\n\r\n let dir = arc.PtOnCurve3(pt) ? -1 : 1;\r\n return dir;\r\n }\r\n }\r\n\r\n let dri = c.GetFistDeriv(param);\r\n let cross = dri.cross(pt.clone().sub(minCp));\r\n return -Math.sign(cross.z);\r\n }\r\n\r\n protected CreateArc(center: Vector3, startP: Vector3, endP?: Vector3)\r\n {\r\n let sa = angle(startP.clone().sub(center));\r\n let ea = endP ? angle(endP.clone().sub(center)) : sa;\r\n let arc = new Arc(center, Math.abs(this._OffsetDist), sa, ea, this._OffsetDist < 0);\r\n return arc;\r\n }\r\n}\r\n\r\nfunction EntityEncode(c: Curve)\r\n{\r\n if (c instanceof Line) return 1;\r\n else return 2;\r\n}\r\nfunction EntityEncode2(c1: Curve, c2: Curve)\r\n{\r\n return EntityEncode(c1) & EntityEncode(c2);\r\n}\r\n","import { Vector2, Vector3 } from 'three';\r\nimport { angle, equaln, equalv3 } from '../Geometry/GeUtils';\r\nimport { IntersectOption } from '../GraphicsSystem/IntersectWith';\r\nimport { Arc } from './Entity/Arc';\r\nimport { Line } from './Entity/Line';\r\nimport { Polyline } from './Entity/Polyline';\r\n\r\n/**\r\n * 点在扇形内部,提供一个简单实现的版本.\r\n * 优化版本请参照:http://www.cnblogs.com/miloyip/archive/2013/04/19/3029852.html\r\n * \r\n * @param arc 二维圆弧\r\n * @param pt \r\n * @returns 点在扇形内部.\r\n */\r\nfunction IsPointInCircularSector(arc: Arc, pt: Vector3): boolean\r\n{\r\n let center = arc.Center;\r\n let disSq = center.distanceTo(pt);\r\n if (disSq > arc.Radius * arc.Radius) return false;\r\n let an = angle(pt.clone().sub(center));\r\n let param = arc.GetParamAtAngle(an);\r\n return arc.ParamOnCurve(param);\r\n}\r\n\r\n/**\r\n * 点在弓型内部\r\n * \r\n * @param arc 二维圆弧\r\n * @param pt 点\r\n * @param isInChrodIsTrue 当点在弦上也认为在弓形内部\r\n * @returns 点在内部\r\n */\r\nexport function IsPointInBowArc(arc: Arc, pt: Vector3, isInChrodIsTrue = false): boolean\r\n{\r\n let pv = pt.clone().sub(arc.StartPoint);\r\n let av = arc.EndPoint.sub(arc.StartPoint);\r\n\r\n pv.cross(av);\r\n\r\n //未优化的代码\r\n // if (pv.z > 0 && arc.IsClockWise)\r\n // return false;\r\n // else if (pv.z < 0 && !arc.IsClockWise)\r\n // return false;\r\n // else\r\n // return arc.Center.distanceToSquared(pt) < arc.Radius * arc.Radius;\r\n\r\n //简化的代码\r\n if ((pv.z > 0) !== arc.IsClockWise || (isInChrodIsTrue && equaln(pv.z, 0)))\r\n {\r\n return arc.Center.distanceToSquared(pt) < arc.Radius * arc.Radius;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * 判断点在多段线内外\r\n * @param pl 多段线\r\n * @param pt 点\r\n * @returns 点在多段线内部\r\n */\r\nexport function IsPointInPolyLine(pl: Polyline, pt: Vector3): boolean\r\n{\r\n let crossings = 0;\r\n\r\n let insLine = new Line(pt, pt.clone().add(new Vector3(0, 10, 0)));\r\n\r\n for (let i = 0; i < pl.EndParam; i++)\r\n {\r\n if (equaln(pl.GetBuilgeAt(i), 0, 5e-6))//直线\r\n {\r\n let sp = pl.GetPointAtParam(i);\r\n let ep = pl.GetPointAtParam(i + 1);\r\n //点位于线上面\r\n if (pt.y > Math.max(sp.y, ep.y))\r\n continue;\r\n //线垂直Y轴\r\n let derX = ep.x - sp.x;\r\n if (equaln(derX, 0, 5e-6))\r\n continue;\r\n\r\n //起点\r\n if (equaln(sp.x, pt.x, 5e-6))\r\n {\r\n if (sp.y > pt.y && derX < 0) crossings++;\r\n continue;\r\n }\r\n //终点\r\n if (equaln(ep.x, pt.x, 5e-6))\r\n {\r\n if (ep.y > pt.y && derX > 0) crossings++;\r\n continue;\r\n }\r\n\r\n //快速求交,只验证有没有交点\r\n let [x1, x2] = sp.x > ep.x ? [ep.x, sp.x] : [sp.x, ep.x];\r\n if (pt.x > x1 && pt.x < x2)\r\n {\r\n let derY = ep.y - sp.y;\r\n let k = derY / derX;\r\n\r\n if ((pt.x - sp.x) * k + sp.y > pt.y)\r\n crossings++;\r\n }\r\n }\r\n else //圆弧\r\n {\r\n let arc = pl.GetCurveAtIndex(i) as Arc;\r\n let sp = arc.StartPoint;\r\n let ep = arc.EndPoint;\r\n\r\n //如果相切\r\n if (equaln(Math.abs(pt.x - arc.Center.x), arc.Radius))\r\n {\r\n //当点和起点或者终点和点相切时\r\n if (equaln(sp.x, pt.x) && sp.y > pt.y)\r\n {\r\n if (ep.x - sp.x < -1e-5)\r\n crossings++;\r\n }\r\n else if (equaln(ep.x, pt.x) && ep.y > pt.y)\r\n {\r\n if (ep.x - sp.x > 1e-5)\r\n crossings++;\r\n }\r\n continue;\r\n }\r\n if (equaln(sp.x, pt.x) && sp.y > pt.y)\r\n {\r\n let der = arc.GetFistDeriv(0);\r\n if (der.x < -1e-5)\r\n crossings++;\r\n }\r\n if (equaln(ep.x, pt.x) && ep.y > pt.y)\r\n {\r\n let der = arc.GetFistDeriv(1);\r\n if (der.x > 1e-5)\r\n crossings++;\r\n }\r\n\r\n for (let pti of arc.IntersectWith(insLine, IntersectOption.ExtendArg))\r\n {\r\n if (pti.y < pt.y || equalv3(sp, pti, 1e-5) || equalv3(ep, pti, 1e-5))\r\n continue;\r\n\r\n let der = arc.GetFistDeriv(pti);\r\n if (!equaln(der.x, 0)) //相切.\r\n crossings++;\r\n }\r\n }\r\n }\r\n\r\n return (crossings % 2) === 1;\r\n}\r\n\r\n/**\r\n * 点在区域内部\r\n * \r\n * @param pt \r\n * @param pts \r\n * @returns \r\n */\r\nfunction IsPointInPolygon(pt: Vector3, pts: Vector2[])\r\n{\r\n let crossings = 0; //int\r\n let [px, py] = [pt.x, pt.y];\r\n\r\n let ptCout = pts.length;\r\n for (let i = 0; i < ptCout; i++)\r\n {\r\n let pti = pts[i];\r\n let ptn = pts[(i + 1) % ptCout];\r\n\r\n let [x1, x2] = [pti.x, ptn.x];\r\n\r\n /* This is done to ensure that we get the same result when\r\n the line goes from left to right and right to left */\r\n if (x1 > x2) [x1, x2] = [x2, x1];\r\n\r\n /* First check if the ray is possible to cross the line */\r\n if (px > x1 && px <= x2 && (py < pti.y || py <= ptn.y))\r\n {\r\n const eps = 0.000001;\r\n\r\n /* Calculate the equation of the line */\r\n let dx = ptn.x - pti.x;\r\n let dy = ptn.y - pti.y;\r\n let k;\r\n\r\n if (Math.abs(dx) < eps)\r\n k = 1e300;\r\n else\r\n k = dy / dx;\r\n\r\n let m = pti.y - k * pts[i].x;\r\n\r\n /* Find if the ray crosses the line */\r\n let y2 = k * px + m;\r\n if (py <= y2)\r\n crossings++;\r\n }\r\n }\r\n\r\n return crossings % 2 === 1;\r\n}\r\n","export enum DragPointType\r\n{\r\n Grip = 0,\r\n Stretch = 1\r\n}\r\n","import { Box3, BufferGeometry, Line as TLine, Matrix3, Matrix4, Object3D, Vector2, Vector3 } from 'three';\r\nimport { CreateBoardUtil } from '../../ApplicationServices/mesh/createBoard';\r\nimport { arrayLast, arrayRemoveDuplicateBySort, changeArrayStartIndex } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { ComputerCurvesNormalOCS, getDeterminantFor2V } from '../../Common/CurveUtils';\r\nimport { matrixAlignCoordSys, matrixIsCoplane, reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { Status } from '../../Common/Status';\r\nimport { FixIndex } from '../../Common/Utils';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { AsVector2, AsVector3, equaln, equalv2, equalv3, updateGeometry } from '../../Geometry/GeUtils';\r\nimport { IntersectOption, IntersectPolylineAndCurve } from '../../GraphicsSystem/IntersectWith';\r\nimport { OffsetPolyline } from '../../GraphicsSystem/OffsetPolyline';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { IsPointInPolyLine } from '../PointInPolyline';\r\nimport { Arc } from './Arc';\r\nimport { Curve, ExtendType } from './Curve';\r\nimport { DragPointType } from './DragPointType';\r\nimport { Line } from './Line';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\n\r\nexport interface PolylineProps\r\n{\r\n pt: Vector2,\r\n bul: number;\r\n}\r\n@Factory\r\nexport class Polyline extends Curve\r\n{\r\n private _ClosedMark: boolean = false;\r\n constructor(private _LineData: PolylineProps[] = [])\r\n {\r\n super();\r\n }\r\n\r\n UpdateMatrixTo(m: Matrix4)\r\n {\r\n this.WriteAllObjectRecord();\r\n let p = new Vector3().setFromMatrixPosition(m);\r\n p.applyMatrix4(this.OCSInv);\r\n if (equaln(p.z, 0))\r\n {\r\n let dir = Math.sign(this.Area2);\r\n let tm = matrixAlignCoordSys(this.OCS, m);\r\n for (let p of this._LineData)\r\n {\r\n let p3 = AsVector3(p.pt);\r\n p3.applyMatrix4(tm);\r\n p.pt.set(p3.x, p3.y);\r\n }\r\n this.OCS = m;\r\n let newDir = Math.sign(this.Area2);\r\n if (dir !== newDir)\r\n for (let p of this._LineData)\r\n p.bul *= -1;\r\n }\r\n }\r\n\r\n /**\r\n * 原地翻转,仅改变法向量\r\n */\r\n Flip()\r\n {\r\n this.WriteAllObjectRecord();\r\n let x = new Vector3();\r\n let y = new Vector3();\r\n let z = new Vector3();\r\n this._Matrix.extractBasis(x, y, z);\r\n z.negate();\r\n y.crossVectors(z, x);\r\n let p = this.Position;\r\n this._Matrix.makeBasis(x, y, z).setPosition(p);\r\n\r\n for (let d of this._LineData)\r\n {\r\n d.pt.y *= -1;\r\n d.bul *= -1;\r\n }\r\n this.Update();\r\n return this;\r\n }\r\n\r\n //翻转曲线,首尾调换\r\n Reverse(): this\r\n {\r\n if (this._LineData.length === 0)\r\n return this;\r\n this.WriteAllObjectRecord();\r\n\r\n let pts = [];\r\n let buls = [];\r\n for (let data of this._LineData)\r\n {\r\n pts.push(data.pt);\r\n buls.push(-data.bul);\r\n }\r\n\r\n let lastBul = buls.pop();\r\n buls.reverse();\r\n buls.push(lastBul);\r\n\r\n pts.reverse();\r\n\r\n if (this._ClosedMark && !equalv2(pts[0], arrayLast(pts)))\r\n {\r\n pts.unshift(pts.pop());\r\n buls.unshift(buls.pop());\r\n }\r\n\r\n for (let i = 0; i < pts.length; i++)\r\n {\r\n let d = this._LineData[i];\r\n d.pt = pts[i];\r\n d.bul = buls[i];\r\n }\r\n\r\n return this;\r\n }\r\n set LineData(data: PolylineProps[])\r\n {\r\n this.WriteAllObjectRecord();\r\n this._LineData = data;\r\n this.Update();\r\n }\r\n get LineData()\r\n {\r\n return this._LineData;\r\n }\r\n\r\n get NumberOfVertices(): number\r\n {\r\n return this._LineData.length;\r\n }\r\n\r\n /**\r\n * 在指定位置插入点.\r\n * 例如:\r\n * pl.AddVertexAt(pl.NumberOfVerticesk,p);//在末尾插入一个点\r\n *\r\n * @param {number} index 索引位置\r\n * @param {Vector2} pt 点\r\n * @returns {this}\r\n * @memberof Polyline\r\n */\r\n AddVertexAt(index: number, pt: Vector2 | Vector2[]): this\r\n {\r\n this.WriteAllObjectRecord();\r\n let pts: PolylineProps[];\r\n if (Array.isArray(pt))\r\n {\r\n pts = pt.map(p =>\r\n {\r\n return {\r\n pt: p.clone(),\r\n bul: 0\r\n };\r\n });\r\n }\r\n else\r\n pts = [{ pt: pt.clone(), bul: 0 }];\r\n\r\n this._LineData.splice(index, 0, ...pts);\r\n this.Update();\r\n return this;\r\n }\r\n RemoveVertexAt(index: number): this\r\n {\r\n if (index < this._LineData.length)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._LineData.splice(index, 1);\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n RemoveVertexIn(from: number, to: number): this\r\n {\r\n if (from + 1 < this._LineData.length && to > from)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._LineData.splice(from + 1, to - from - 1);\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * 重设闭合多段线的起点\r\n * @param index 起始index,如果index非整数,将用最接近的整数作为起始索引\r\n */\r\n ResetStartPoint(index: number)\r\n {\r\n if (!this.IsClose || index >= this.EndParam) return false;\r\n\r\n if (equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))\r\n this._LineData.pop();\r\n\r\n changeArrayStartIndex(this._LineData, Math.floor(index + 0.5));\r\n this._LineData.push({\r\n pt: this._LineData[0].pt.clone(),\r\n bul: 0\r\n });\r\n return true;\r\n }\r\n GetPoint2dAt(index: number): Vector2 | undefined\r\n {\r\n if (index >= 0 && this._LineData.length > index)\r\n return this._LineData[index].pt.clone();\r\n }\r\n /**\r\n * 设置指定点的位置\r\n *\r\n * @param {number} index\r\n * @param {Vector2} pt\r\n * @memberof Polyline\r\n */\r\n SetPointAt(index: number, pt: Vector2): this\r\n {\r\n let d = this._LineData[index];\r\n if (d)\r\n {\r\n this.WriteAllObjectRecord();\r\n d.pt.copy(pt);\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n for (let i = 0; i <= this.EndParam; i++)\r\n {\r\n let p = this.GetPointAtParam(i);\r\n p.applyMatrix4(m).applyMatrix4(this.OCSInv);\r\n this.SetPointAt(i, AsVector2(p));\r\n }\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n let oldPts = this.GetStretchPoints();\r\n reviseMirrorMatrix(this._Matrix);\r\n for (let i = 0; i < oldPts.length; i++)\r\n {\r\n let newP = oldPts[i].applyMatrix4(this.OCSInv);\r\n let newBul = -this.GetBuilgeAt(i);\r\n this.SetPointAt(i, AsVector2(newP));\r\n this.SetBulgeAt(i, newBul);\r\n }\r\n this.Reverse();\r\n return this;\r\n }\r\n SetBulgeAt(index: number, bul: number): this\r\n {\r\n let d = this._LineData[index];\r\n if (d)\r\n {\r\n this.WriteAllObjectRecord();\r\n d.bul = bul;\r\n this.Update();\r\n }\r\n return this;\r\n }\r\n GetBuilgeAt(index: number): number\r\n {\r\n return this._LineData[index].bul;\r\n }\r\n Rectangle(length: number, height: number): this\r\n {\r\n this.LineData = [\r\n { pt: new Vector2(), bul: 0 },\r\n { pt: new Vector2(length), bul: 0 },\r\n { pt: new Vector2(length, height), bul: 0 },\r\n { pt: new Vector2(0, height), bul: 0 }];\r\n this.CloseMark = true;\r\n return this;\r\n }\r\n RectangleFrom2Pt(p1: Vector3, p2: Vector3): this\r\n {\r\n let box = new Box3();\r\n box.setFromPoints([p2, p1].map((p: Vector3) => p.clone().applyMatrix4(this.OCSInv)));\r\n\r\n let px1 = AsVector2(box.min);\r\n let px3 = AsVector2(box.max);\r\n let px2 = new Vector2(px3.x, px1.y);\r\n let px4 = new Vector2(px1.x, px3.y);\r\n\r\n this.LineData = [\r\n { pt: px1, bul: 0 },\r\n { pt: px2, bul: 0 },\r\n { pt: px3, bul: 0 },\r\n { pt: px4, bul: 0 }];\r\n\r\n this.CloseMark = true;\r\n return this;\r\n }\r\n //多段线起点\r\n get StartPoint()\r\n {\r\n if (this._LineData.length > 0)\r\n return AsVector3(this._LineData[0].pt).applyMatrix4(this.OCS);\r\n return new Vector3();\r\n }\r\n set StartPoint(p: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n p = p.clone().applyMatrix4(this.OCSInv);\r\n\r\n if (this._LineData.length === 0)\r\n this.AddVertexAt(0, AsVector2(p));\r\n else if (this._LineData.length === 1)\r\n this.SetPointAt(0, AsVector2(p));\r\n else\r\n {\r\n let bul = this.GetBuilgeAt(0);\r\n if (bul !== 0)\r\n {\r\n let arc = this.GetCurveAtParam(0) as Arc;\r\n arc.StartPoint = p;\r\n //前面线的凸度调整\r\n this.SetBulgeAt(0, Math.tan(arc.AllAngle / 4) * Math.sign(bul));\r\n }\r\n this.SetPointAt(0, AsVector2(p));\r\n }\r\n }\r\n get EndPoint()\r\n {\r\n if (this._ClosedMark) return this.StartPoint;\r\n if (this._LineData.length > 0)\r\n return AsVector3(this._LineData[this.EndParam].pt).applyMatrix4(this.OCS);\r\n return new Vector3();\r\n }\r\n set EndPoint(p: Vector3)\r\n {\r\n if (this._LineData.length < 2 || this.CloseMark)\r\n return;\r\n\r\n this.WriteAllObjectRecord();\r\n p = p.clone().applyMatrix4(this.OCSInv);\r\n\r\n let bul = this.GetBuilgeAt(this.EndParam - 1);\r\n if (bul !== 0)\r\n {\r\n let arc = this.GetCurveAtParam(this.EndParam - 1) as Arc;\r\n arc.ApplyMatrix(this.OCSInv);\r\n arc.EndPoint = p;\r\n //前面线的凸度调整\r\n this.SetBulgeAt(this.EndParam - 1, Math.tan(arc.AllAngle / 4) * Math.sign(bul));\r\n }\r\n this.SetPointAt(this.EndParam, AsVector2(p));\r\n }\r\n\r\n get CurveCount(): number\r\n {\r\n return this.EndParam;\r\n }\r\n\r\n get StartParam()\r\n {\r\n return 0;\r\n }\r\n\r\n /**\r\n * 表示最后一条曲线的终止参数,使用该参数可以直接遍历到多段线的所有子线段. for(i 1 && (equalv3(this.StartPoint, this.EndPoint, 1e-4)));\r\n }\r\n set CloseMark(v: boolean)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._ClosedMark = v;\r\n this.Update();\r\n }\r\n\r\n DigestionCloseMark()\r\n {\r\n if (this._ClosedMark && this._LineData.length > 1)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._ClosedMark = false;\r\n\r\n if (!equalv2(this._LineData[0].pt, arrayLast(this._LineData).pt))\r\n this._LineData.push({ pt: AsVector2(this._LineData[0].pt), bul: 0 });\r\n }\r\n }\r\n\r\n get Length()\r\n {\r\n return this.Explode().reduce((l, cu) => l + cu.Length, 0);\r\n }\r\n\r\n /**\r\n * 获得指定参数所在的点.\r\n * 当曲线存在闭合标志时,参数必须在曲线内部.\r\n * 当曲线不存在闭合标志时,参数允许延伸出曲线.\r\n *\r\n * @param {number} param 参数\r\n * @returns {Vector3} 三维点,可为空\r\n * @memberof Polyline\r\n */\r\n GetPointAtParam(param: number): Vector3\r\n {\r\n if (param === Math.floor(param) && this.ParamOnCurve(param))\r\n return AsVector3(this.GetPoint2dAt(FixIndex(param, this.NumberOfVertices))).applyMatrix4(this.OCS);\r\n let cu: Curve = this.GetCurveAtParam(param);\r\n if (cu)\r\n return cu.GetPointAtParam(this.GetCurveParamAtParam(param));\r\n return undefined;\r\n }\r\n\r\n GetDistAtParam(param: number): number\r\n {\r\n if (this._ClosedMark && !this.ParamOnCurve(param))\r\n return NaN;\r\n\r\n //参数 整数\r\n let paramFloor = Math.floor(param);\r\n //需要计算的曲线个数\r\n let cuCout = paramFloor > this.EndParam ? this.EndParam : paramFloor;\r\n\r\n let dist = 0;\r\n //首先计算完整曲线的长度\r\n for (let i = 0; i < cuCout; i++)\r\n {\r\n dist += this.GetCurveAtIndex(i).Length;\r\n }\r\n\r\n //参数已经大于索引,证明参数在线外.\r\n if (paramFloor !== cuCout)\r\n {\r\n dist += this.GetCurveAtParam(param).GetDistAtParam(param - cuCout);\r\n }\r\n else if (param > paramFloor)\r\n {\r\n let lastParam = param - paramFloor;\r\n dist += this.GetCurveAtParam(param).GetDistAtParam(lastParam);\r\n }\r\n\r\n return dist;\r\n }\r\n GetPointAtDistance(dist: number): Vector3\r\n {\r\n let param = this.GetParamAtDist(dist);\r\n return this.GetPointAtParam(param);\r\n }\r\n\r\n /**\r\n * 返回参数所在的点. 如果曲线不闭合,会试图返回延伸点参数\r\n *\r\n * @param {Vector3} pt\r\n * @returns {number}\r\n * @memberof Polyline\r\n */\r\n GetParamAtPoint(pt: Vector3): number\r\n {\r\n let cus = this.Explode();\r\n if (cus.length === 0) return NaN;\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let cu = cus[i];\r\n let param = cu.GetParamAtPoint(pt);\r\n if (cu.ParamOnCurve(param))\r\n return i + param; //返回点在曲线内部的参数\r\n }\r\n\r\n //当曲线闭合时,不需要延伸首尾去判断参数\r\n if (this._ClosedMark) return NaN;\r\n\r\n //起点终点参数集合\r\n let seParams: number[] = [];\r\n //点在第一条曲线上的参数\r\n let startParam = cus[0].GetParamAtPoint(pt);\r\n if (!isNaN(startParam) && startParam < 0)\r\n seParams.push(startParam);\r\n //点在最后一条线上的参数\r\n let endParam = cus[cus.length - 1].GetParamAtPoint(pt);\r\n if (!isNaN(endParam) && endParam > 0)\r\n seParams.push(endParam + this.EndParam - 1);\r\n\r\n if (seParams.length == 1)\r\n {\r\n return seParams[0];\r\n }\r\n else if (seParams.length == 2)\r\n {\r\n //返回较近的参数\r\n if (pt.distanceToSquared(this.StartPoint)\r\n < pt.distanceToSquared(this.EndPoint))\r\n return seParams[0];\r\n else\r\n return seParams[1];\r\n }\r\n return NaN;\r\n }\r\n GetParamAtDist(dist: number): number\r\n {\r\n let cus = this.Explode();\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let cu = cus[i];\r\n let len = cu.Length;\r\n if (dist <= len)\r\n return i + cu.GetParamAtDist(dist);\r\n else if (equaln(dist, len, 1e-8))\r\n return i + 1;\r\n dist -= len;\r\n }\r\n if (!this._ClosedMark)\r\n return cus.length + cus[cus.length - 1].GetParamAtDist(dist);\r\n\r\n return NaN;\r\n }\r\n GetDistAtPoint(pt: Vector3): number\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n if (!this.ParamOnCurve(param)) return NaN;\r\n return this.GetDistAtParam(param);\r\n }\r\n\r\n /**\r\n * 返回曲线的一阶导数.\r\n * 当曲线闭合(标志)且点不在曲线上.\r\n * 或者曲线不闭合(标志) 且点不在曲线上也不在延伸上\r\n *\r\n * @param {(number | Vector3)} param\r\n * @returns {Vector3}\r\n * @memberof Polyline\r\n */\r\n GetFistDeriv(param: number | Vector3): Vector3\r\n {\r\n if (param instanceof Vector3)\r\n param = this.GetParamAtPoint(param);\r\n\r\n if (isNaN(param))\r\n return undefined;\r\n\r\n let cu = this.GetCurveAtParam(param);\r\n\r\n if (!cu) return undefined;\r\n\r\n return cu.GetFistDeriv(this.GetCurveParamAtParam(param));\r\n }\r\n GetSplitCurves(param: number[] | number): Array\r\n {\r\n //参数需要转化为参数数组\r\n let params: number[];\r\n if (typeof param == \"number\")\r\n params = [param];\r\n else\r\n params = param;\r\n\r\n //校验参数在曲线中,修正参数\r\n let endParam = this.EndParam;\r\n params = params.filter(p => this.ParamOnCurve(p) && p > -1e-6)\r\n .map(a =>\r\n {\r\n if (a < 0) return 0;\r\n if (a > endParam) return endParam;\r\n if (equaln(a, Math.floor(a + 0.5), 1e-8))\r\n return Math.floor(a + 0.5);\r\n return a;\r\n });\r\n //排序\r\n params.sort((a, b) => a - b);\r\n let hasEndParam = arrayLast(params) === this.EndParam;\r\n //必须加入最后一个参数,保证切割后的曲线完整\r\n if (!hasEndParam)\r\n params.push(this.EndParam);\r\n arrayRemoveDuplicateBySort(params, (e1, e2) => equaln(e1, e2, 1e-8));\r\n params = params.filter(p => this.ParamOnCurve(p));\r\n if (params.length === 0)\r\n return [];\r\n\r\n //判断是否存在0参数\r\n let hasZeroParam = params[0] === 0;\r\n if (hasZeroParam)\r\n params.shift();\r\n\r\n let { pts, buls } = this.PtsBuls;\r\n\r\n //返回的多段线集合\r\n let pls: Polyline[] = [];\r\n\r\n let len = 0;//已经走过的参数长度(整数)\r\n\r\n //上一个切割参数的位置 0-1\r\n let prePa = 0;\r\n for (let pa of params)\r\n {\r\n //参数所在点\r\n let pt = AsVector2(this.GetPointAtParam(pa).applyMatrix4(this.OCSInv));\r\n pa -= len;\r\n let pafloor = Math.floor(pa);\r\n len += pafloor;\r\n\r\n let plData: PolylineProps[] = [];\r\n\r\n //添加点\r\n for (let i = 0; i < pafloor; i++)\r\n {\r\n if (i === 0 && !equaln(buls[0], 0, 1e-8))\r\n {\r\n buls[0] = Math.tan((1 - prePa) * Math.atan(buls[0]));\r\n }\r\n plData.push({ pt: pts[0], bul: buls[0] });\r\n pts.shift();\r\n buls.shift();\r\n }\r\n\r\n if (equaln(pa, pafloor, 1e-8))//如果pa在点上\r\n {\r\n plData.push({ pt: pts[0].clone(), bul: buls[0] });\r\n }\r\n else //在曲线上\r\n {\r\n let bul: number = buls[0];\r\n if (!equaln(bul, 0, 1e-6))\r\n bul = Math.tan((pa - pafloor - (0 === pafloor ? prePa : 0)) * Math.atan(buls[0])); //->凸度\r\n\r\n //加入顶点+凸度\r\n plData.push({ pt: pts[0].clone(), bul });\r\n //终点\r\n plData.push({ pt, bul: 0 });\r\n\r\n //修正剩余的点表和凸度表\r\n pts[0].copy(pt);\r\n }\r\n\r\n prePa = pa - pafloor;\r\n if (plData.length > 1)\r\n pls.push(new Polyline(plData).ApplyMatrix(this.OCS));\r\n }\r\n\r\n //当曲线为闭合曲线,并且不存在0切割参数时,首尾连接曲线\r\n if (this._ClosedMark && !hasZeroParam && !hasEndParam)\r\n {\r\n let lastPl = pls[pls.length - 1];\r\n if (equalv2(arrayLast(lastPl._LineData).pt, pls[0]._LineData[0].pt))\r\n lastPl._LineData.pop();\r\n\r\n lastPl._LineData.push(...pls[0]._LineData);\r\n\r\n pls.shift();\r\n }\r\n return pls;\r\n }\r\n\r\n //未完善\r\n GetCurveAtParamRange(startParam: number, endParam: number): Array\r\n {\r\n let sfloor = Math.floor(startParam + 0.5);\r\n if (equaln(sfloor, startParam, 1e-8)) startParam = sfloor;\r\n else sfloor = Math.floor(startParam);\r\n let efloor = Math.floor(endParam + 0.5);\r\n if (equaln(efloor, endParam, 1e-8)) endParam = efloor;\r\n else efloor = Math.floor(efloor);\r\n\r\n const GetCurve = (index: number) =>\r\n {\r\n let d = this._LineData[index];\r\n let next = this._LineData[index + 1];\r\n if (!equaln(d.bul, 0, 1e-8))\r\n return new Arc().ParseFromBul(d.pt, next.pt, d.bul);\r\n else\r\n return new Line(AsVector3(d.pt), AsVector3(next.pt));\r\n };\r\n\r\n let lined: PolylineProps[] = [];\r\n if (startParam === sfloor)\r\n {\r\n let d = this._LineData[sfloor];\r\n lined.push({ pt: d.pt.clone(), bul: d.bul });\r\n }\r\n else\r\n {\r\n let d = this._LineData[sfloor];\r\n let cu = GetCurve(sfloor);\r\n let remParam = startParam - sfloor;\r\n let p = cu.GetPointAtParam(remParam);\r\n let bul = d.bul;\r\n if (!equaln(bul, 0))\r\n bul = Math.tan(Math.atan(bul) * (1 - remParam));\r\n lined.push({ pt: AsVector2(p), bul: bul });\r\n }\r\n\r\n for (let i = sfloor + 1; i < efloor; i++)\r\n {\r\n let d = this._LineData[i];\r\n lined.push({ pt: d.pt.clone(), bul: d.bul });\r\n }\r\n\r\n if (efloor !== endParam)\r\n {\r\n let d = this.LineData[efloor];\r\n let remParam = endParam - efloor;\r\n let cu = GetCurve(efloor);\r\n let p = cu.GetPointAtParam(remParam);\r\n let bul = d.bul;\r\n if (!equaln(bul, 0))\r\n {\r\n arrayLast(lined).bul = Math.tan(Math.atan(bul) * remParam);\r\n bul = Math.tan(Math.atan(bul) * (1 - remParam));\r\n }\r\n lined.push({ pt: AsVector2(p), bul });\r\n }\r\n\r\n let pl = new Polyline(lined);\r\n pl.OCS = this.OCSNoClone;\r\n return;\r\n }\r\n\r\n Extend(newParam: number)\r\n {\r\n if (this.CloseMark || this.ParamOnCurve(newParam)) return;\r\n\r\n this.WriteAllObjectRecord();\r\n\r\n let ptIndex: number;\r\n let bulIndex: number;\r\n\r\n if (newParam < 0)\r\n {\r\n ptIndex = 0;\r\n bulIndex = 0;\r\n }\r\n else if (newParam > this.EndParam)\r\n {\r\n ptIndex = this.EndParam;\r\n bulIndex = ptIndex - 1;\r\n }\r\n\r\n //修改顶点\r\n this._LineData[ptIndex].pt = AsVector2(this.GetPointAtParam(newParam).applyMatrix4(this.OCSInv));\r\n\r\n //修改凸度\r\n let oldBul = this._LineData[bulIndex].bul;\r\n if (oldBul != 0)\r\n this._LineData[bulIndex].bul = Math.tan(Math.atan(oldBul) * (1 + newParam - ptIndex));\r\n\r\n this.Update();\r\n }\r\n\r\n //const this\r\n MatrixAlignTo2(toMatrix: Matrix4)\r\n {\r\n if (!matrixIsCoplane(this._Matrix, toMatrix, 1e-4))\r\n return this.PtsBuls;\r\n\r\n let m = matrixAlignCoordSys(this._Matrix, toMatrix);\r\n\r\n let z1 = this.Normal;\r\n let z2 = new Vector3().setFromMatrixColumn(toMatrix, 2);\r\n let isMirror = equalv3(z1, z2.negate());\r\n\r\n let pts: Vector2[] = [];\r\n let buls: number[] = [];\r\n for (let d of this._LineData)\r\n {\r\n let p = AsVector2(AsVector3(d.pt).applyMatrix4(m));\r\n pts.push(p);\r\n buls.push(isMirror ? -d.bul : d.bul);\r\n }\r\n return { pts, buls };\r\n }\r\n\r\n Join(cu: Curve, allowGap = false, tolerance = 1e-4)\r\n {\r\n this.WriteAllObjectRecord();\r\n if (this._ClosedMark)\r\n return Status.False;\r\n\r\n let [sp, ep, cuSp, cuEp] = [this.StartPoint, this.EndPoint, cu.StartPoint, cu.EndPoint];\r\n\r\n let ocsInv = this.OCSInv;\r\n let [cuSp2, cuEp2] = [cuSp, cuEp].map(p => AsVector2(p.clone().applyMatrix4(ocsInv)));\r\n\r\n if (this._LineData.length === 0)\r\n {\r\n if (cu instanceof Line)\r\n {\r\n this._LineData.push({ pt: cuSp2, bul: 0 });\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (cu instanceof Arc)\r\n {\r\n this._LineData.push({ pt: cuSp2, bul: cu.Bul });\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (cu instanceof Polyline)\r\n {\r\n let f = new CADFiler();\r\n cu.WriteFile(f);\r\n this.ReadFile(f);\r\n }\r\n else\r\n return Status.False;\r\n }\r\n else\r\n {\r\n enum LinkType\r\n {\r\n None = 0,\r\n SpSp = 1,\r\n SpEp = 2,\r\n EpSp = 3,\r\n EpEp = 4,\r\n };\r\n\r\n let spspDisSq = cuSp.distanceToSquared(sp);\r\n let spepDisSq = cuSp.distanceToSquared(ep);\r\n let epspDisSq = cuEp.distanceToSquared(sp);\r\n let epepDisSq = cuEp.distanceToSquared(ep);\r\n let minDis = tolerance * tolerance;\r\n\r\n let linkType = LinkType.None;\r\n\r\n if (spspDisSq < minDis)\r\n {\r\n linkType = LinkType.SpSp;\r\n minDis = spspDisSq;\r\n }\r\n\r\n if (spepDisSq < minDis)\r\n {\r\n linkType = LinkType.SpEp;\r\n minDis = spepDisSq;\r\n }\r\n\r\n if (epspDisSq < minDis)\r\n {\r\n linkType = LinkType.EpSp;\r\n minDis = epspDisSq;\r\n }\r\n\r\n if (epepDisSq < minDis)\r\n linkType = LinkType.EpEp;\r\n\r\n if (linkType === LinkType.None)\r\n return Status.False;\r\n\r\n if (cu instanceof Line)\r\n {\r\n if (linkType === LinkType.SpSp)\r\n {\r\n this._LineData.unshift({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.SpEp)\r\n {\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.EpSp)\r\n {\r\n this._LineData.unshift({ pt: cuSp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.EpEp)\r\n {\r\n this._LineData.push({ pt: cuSp2, bul: 0 });\r\n }\r\n }\r\n else if (cu instanceof Arc)\r\n {\r\n let dir = equalv3(this.Normal, cu.Normal.negate()) ? -1 : 1;\r\n let bul = cu.Bul * dir;\r\n if (linkType === LinkType.SpSp)\r\n {\r\n this._LineData.unshift({ pt: cuEp2, bul: -bul });\r\n }\r\n else if (linkType === LinkType.SpEp)\r\n {\r\n arrayLast(this._LineData).bul = bul;\r\n this._LineData.push({ pt: cuEp2, bul: 0 });\r\n }\r\n else if (linkType === LinkType.EpSp)\r\n {\r\n this._LineData.unshift({ pt: cuSp2, bul: bul });\r\n }\r\n else if (linkType === LinkType.EpEp)\r\n {\r\n arrayLast(this._LineData).bul = -bul;\r\n this._LineData.push({ pt: cuSp2, bul: 0 });\r\n }\r\n }\r\n else if (cu instanceof Polyline)\r\n {\r\n if (cu.CloseMark) return Status.False;\r\n\r\n let { pts, buls } = this.PtsBuls;\r\n\r\n if (linkType === LinkType.SpSp)\r\n {\r\n cu.Reverse();\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n cuPtsBul.pts.pop();\r\n cuPtsBul.buls.pop();\r\n pts = cuPtsBul.pts.concat(pts);\r\n buls = cuPtsBul.buls.concat(buls);\r\n }\r\n else if (linkType === LinkType.SpEp)\r\n {\r\n pts.pop();\r\n buls.pop();\r\n\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n pts = pts.concat(cuPtsBul.pts);\r\n buls = buls.concat(cuPtsBul.buls);\r\n }\r\n else if (linkType === LinkType.EpSp)\r\n {\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n cuPtsBul.pts.pop();\r\n cuPtsBul.buls.pop();\r\n pts = cuPtsBul.pts.concat(pts);\r\n buls = cuPtsBul.buls.concat(buls);\r\n }\r\n else if (linkType === LinkType.EpEp)\r\n {\r\n pts.pop();\r\n buls.pop();\r\n\r\n cu.Reverse();\r\n let cuPtsBul = cu.MatrixAlignTo2(this.OCS);\r\n pts = pts.concat(cuPtsBul.pts);\r\n buls = buls.concat(cuPtsBul.buls);\r\n }\r\n\r\n this._LineData.length = 0;\r\n for (let i = 0; i < pts.length; i++)\r\n {\r\n this._LineData.push({ pt: pts[i], bul: buls[i] });\r\n }\r\n }\r\n else\r\n return Status.False;\r\n }\r\n\r\n //在上面的其他分支已经返回了假 所以这里直接返回真.\r\n this.Update();\r\n return Status.True;\r\n }\r\n\r\n /**\r\n * 将曲线数组组合成多段线\r\n * @param curves 已经使用CurveLinked的数组,总是首尾相连\r\n * @returns\r\n */\r\n static Combine(curves: Curve[], tolerance = 1e-5): Polyline | undefined\r\n {\r\n if (!curves || curves.length === 0) return;\r\n\r\n let pl = new Polyline;\r\n pl.OCS = ComputerCurvesNormalOCS(curves);\r\n\r\n for (let cu of curves)\r\n pl.Join(cu, false, tolerance);\r\n\r\n let d = pl.LineData;\r\n if (d.length > 1)\r\n {\r\n let ld = arrayLast(d).pt;\r\n if (equalv2(d[0].pt, ld, tolerance))\r\n ld.copy(d[0].pt);\r\n }\r\n\r\n return pl;\r\n }\r\n\r\n PtOnCurve(pt: Vector3): boolean\r\n {\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let c = this.GetCurveAtIndex(i);\r\n if (c.PtOnCurve(pt))\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let c = this.GetCurveAtIndex(i);\r\n if (c.PtOnCurve3(p, fuzz))\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n PtInCurve(pt: Vector3)\r\n {\r\n return this.IsClose && IsPointInPolyLine(this, pt);\r\n }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n return this.GetClosestPointTo2(pt, extend ? ExtendType.Both : ExtendType.None);\r\n }\r\n GetClosestPointTo2(pt: Vector3, extType: ExtendType): Vector3\r\n {\r\n //当曲线空时,返回空\r\n if (this.EndParam < 1) return undefined;\r\n //当有闭合标志时,曲线在任何位置都不延伸\r\n if (this._ClosedMark) extType = ExtendType.None;\r\n\r\n //最近点\r\n let ptC = undefined;\r\n //最近点的距离\r\n let ptCDist = Infinity;\r\n\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let cu = this.GetCurveAtIndex(i);\r\n\r\n //前延伸\r\n if (i === 0 && (extType & ExtendType.Front) > 0)\r\n {\r\n let ptCFirst = cu.GetClosestPointTo(pt, true);\r\n if (cu.GetParamAtPoint(ptCFirst) <= 1)\r\n {\r\n ptC = ptCFirst;\r\n ptCDist = ptC.distanceToSquared(pt);\r\n }\r\n if (extType === ExtendType.Front)\r\n continue;\r\n }\r\n\r\n let ptCloseNew: Vector3; //新的最近点\r\n\r\n //后延伸 (此处与前延伸分开if 如果线只有一段,那么前后延伸都能同时触发)\r\n if (i === (this.EndParam - 1) && (extType & ExtendType.Back) > 0)\r\n {\r\n let ptCLast = cu.GetClosestPointTo(pt, true);\r\n if (cu.GetParamAtPoint(ptCLast) >= 0)\r\n ptCloseNew = ptCLast;\r\n else //如果延伸之后并不在曲线或者曲线的后延伸上\r\n ptCloseNew = cu.EndPoint;\r\n }\r\n else\r\n {\r\n ptCloseNew = cu.GetClosestPointTo(pt, false);\r\n }\r\n\r\n let newDist = ptCloseNew.distanceToSquared(pt);\r\n if (newDist < ptCDist)\r\n {\r\n ptC = ptCloseNew;\r\n ptCDist = newDist;\r\n }\r\n }\r\n\r\n return ptC;\r\n }\r\n //偏移\r\n GetOffsetCurves(offsetDist: number): Array\r\n {\r\n if (equaln(offsetDist, 0)) return [];\r\n let polyOffestUtil = new OffsetPolyline(this, offsetDist);\r\n let curves = polyOffestUtil.Do();\r\n for (let cu of curves)\r\n cu.ColorIndex = this.ColorIndex;\r\n return curves;\r\n }\r\n GetFeedingToolPath(offsetDist: number): Array\r\n {\r\n if (equaln(offsetDist, 0)) return [];\r\n let polyOffestUtil = new OffsetPolyline(this, offsetDist, true);\r\n return polyOffestUtil.Do();\r\n }\r\n /**\r\n * 分解\r\n */\r\n Explode(): Curve[]\r\n {\r\n let exportCus: Curve[] = [];\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n exportCus.push(this.GetCurveAtIndex(i));\r\n }\r\n return exportCus;\r\n }\r\n\r\n /**\r\n * 根据参数得到参数所在的子曲线.\r\n *\r\n * 当曲线存在闭合标志时,参数必须在曲线内部,否则返回空.\r\n *\r\n * @param {number} param 参数值\r\n * @returns {Curve} 曲线(直线或者圆弧) 或空\r\n * @memberof Polyline\r\n */\r\n GetCurveAtParam(param: number): Curve\r\n {\r\n if (this._ClosedMark && !this.ParamOnCurve(param))\r\n return undefined;\r\n\r\n if (param < 0)\r\n return this.GetCurveAtIndex(0);\r\n else if (param >= this.EndParam)\r\n return this.GetCurveAtIndex(this.EndParam - 1);\r\n else return this.GetCurveAtIndex(Math.floor(param));\r\n }\r\n\r\n /**\r\n * 得到参数在子曲线中的表示\r\n *\r\n * @param {number} param 参数在多段线中表示\r\n * @returns {number} 参数在子曲线中表示\r\n * @memberof Polyline\r\n */\r\n GetCurveParamAtParam(param: number): number\r\n {\r\n if (param >= this.EndParam) param -= this.EndParam - 1;\r\n else if (param > 0) param -= Math.floor(param);\r\n\r\n return param;\r\n }\r\n\r\n /**\r\n * 获得曲线,来自索引位置.\r\n * @param {number} i 索引位置 整数\r\n */\r\n GetCurveAtIndex(i: number): Curve\r\n {\r\n if (i >= this._LineData.length) return undefined;\r\n\r\n if (!this.ParamOnCurve(i)) return undefined;\r\n\r\n if (!this._ClosedMark && i === this._LineData.length - 1) return undefined;\r\n\r\n let d1 = this._LineData[i];\r\n let d2 = this._LineData[FixIndex(i + 1, this._LineData)];\r\n\r\n let curve: Curve;\r\n if (equaln(d1.bul, 0, 1e-8))\r\n curve = new Line(AsVector3(d1.pt), AsVector3(d2.pt)).ApplyMatrix(this.OCS);\r\n else\r\n curve = new Arc().ParseFromBul(d1.pt, d2.pt, d1.bul).ApplyMatrix(this.OCS);\r\n\r\n curve.ColorIndex = this._Color;\r\n return curve;\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-5)\r\n {\r\n return IntersectPolylineAndCurve(this, curve, intType, tolerance);\r\n }\r\n\r\n //计算自交点.\r\n IntersectSelf(): number[]\r\n {\r\n let cus = this.Explode();\r\n if (cus.length === 0) return [];\r\n\r\n let intParams: number[] = [];\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let c = cus[i];\r\n for (let j = i + 2; j < cus.length; j++)\r\n {\r\n let c2 = cus[j];\r\n let pts = c.IntersectWith(c2, IntersectOption.OnBothOperands);\r\n\r\n for (let p of pts)\r\n {\r\n intParams.push(i + c.GetParamAtPoint(p));\r\n intParams.push(j + c2.GetParamAtPoint(p));\r\n }\r\n }\r\n }\r\n return intParams;\r\n }\r\n\r\n get BoundingBox()\r\n {\r\n let box = new Box3();\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n let cu = this.GetCurveAtIndex(i);\r\n box.union(cu.BoundingBox);\r\n }\r\n return box;\r\n }\r\n\r\n /**\r\n * 得到曲线有用的点表和凸度(闭合曲线首尾重复)\r\n */\r\n get PtsBuls(): { pts: Vector2[], buls: number[]; }\r\n {\r\n let pts: Vector2[] = [];\r\n let buls: number[] = [];\r\n\r\n if (this._LineData.length === 0)\r\n return { pts, buls };\r\n\r\n for (let data of this._LineData)\r\n {\r\n pts.push(data.pt.clone());\r\n buls.push(data.bul);\r\n }\r\n //闭合且起点不等于终点\r\n if (this._ClosedMark &&\r\n !this._LineData[0].pt.equals(arrayLast(this._LineData).pt))\r\n {\r\n pts.push(pts[0].clone());\r\n buls.push(buls[0]);\r\n }\r\n\r\n return { pts, buls };\r\n }\r\n get IsBulge()\r\n {\r\n if (!this.IsClose) return false;\r\n\r\n let refDir = Math.sign(this.Area2);\r\n let c1: Curve;\r\n let c2: Curve;\r\n\r\n for (let i = 0; i < this.EndParam; i++)\r\n {\r\n c1 = this.GetCurveAtIndex(i);\r\n c2 = this.GetCurveAtIndex(FixIndex(i + 1, this.EndParam));\r\n\r\n let len1 = c1.Length;\r\n let len2 = c2.Length;\r\n let minLen = Math.min(len1, len2) * 0.2;\r\n\r\n let p = c1.EndPoint;\r\n let p1: Vector3;\r\n let p2: Vector3;\r\n\r\n if (c1 instanceof Arc)\r\n {\r\n let dir = c1.IsClockWise ? -1 : 1;\r\n if (dir !== refDir)\r\n return false;\r\n p1 = c1.GetPointAtDistance(len1 - minLen);\r\n }\r\n else\r\n p1 = c1.StartPoint;\r\n\r\n if (c2 instanceof Arc)\r\n {\r\n let dir = c2.IsClockWise ? -1 : 1;\r\n if (dir !== refDir)\r\n return false;\r\n p2 = c2.GetPointAtDistance(minLen);\r\n }\r\n else\r\n p2 = c2.EndPoint;\r\n\r\n let vec1 = p.clone().sub(p1);\r\n let vec2 = p2.sub(p);\r\n let dir = Math.sign(vec1.cross(vec2).z);\r\n\r\n if (dir !== 0 && dir !== refDir)\r\n return false;\r\n }\r\n return true;\r\n }\r\n get Shape()\r\n {\r\n let { pts, buls } = this.PtsBuls;\r\n let curve = CreateBoardUtil.CreatePath(pts, buls);\r\n return curve;\r\n }\r\n get SVG()\r\n {\r\n let sp = this.StartPoint;\r\n let str = `M${sp.x} ${sp.y} `;\r\n for (let i = 1; i <= this.EndParam; i++)\r\n {\r\n let bul = this.GetBuilgeAt(i - 1);\r\n let p = this.GetPointAtParam(i);\r\n if (bul === 0)\r\n str += `L${p.x} ${p.y} `;\r\n else\r\n {\r\n let arc = this.GetCurveAtIndex(i - 1) as Arc;\r\n str += `A ${arc.Radius} ${arc.Radius} 0 ${Math.abs(bul) >= 1 ? 1 : 0} ${arc.IsClockWise ? 0 : 1} ${p.x} ${p.y}`;\r\n }\r\n }\r\n return str;\r\n }\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe)\r\n {\r\n let shape = this.Shape;\r\n\r\n let geo = BufferGeometryUtils.CreateFromPts(shape.getPoints(50).map(AsVector3));\r\n if (renderType === RenderType.WireframePrint)\r\n {\r\n var geometry = new LineGeometry().setPositions(geo.attributes.position.array as number[]);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n let obj = new TLine(geo, ColorMaterial.GetLineMaterial(this._Color));\r\n return obj;\r\n }\r\n UpdateDrawObject(type: RenderType, en: Object3D)\r\n {\r\n let shape = this.Shape;\r\n let pts = shape.getPoints(50).map(AsVector3);\r\n let plObj = en as TLine;\r\n let geo = plObj.geometry as BufferGeometry;\r\n if (!BufferGeometryUtils.UpdatePts(geo, pts))\r\n {\r\n updateGeometry(plObj, BufferGeometryUtils.CreateFromPts(pts));\r\n }\r\n }\r\n\r\n GetDragPointCount(drag: DragPointType): number\r\n {\r\n if (drag === DragPointType.Grip)\r\n {\r\n let count = this.EndParam * 2 + 1;\r\n if (this.CloseMark) count--;\r\n return count;\r\n }\r\n else\r\n {\r\n return this._LineData.length;\r\n }\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return this.GetStretchPoints();\r\n case ObjectSnapMode.Mid:\r\n let midPts = [];\r\n let enParam = this.EndParam;\r\n for (let i = 0.5; i < enParam; i++)\r\n {\r\n let p = this.GetPointAtParam(i);\r\n p && midPts.push(p);\r\n }\r\n return midPts;\r\n case ObjectSnapMode.Nea:\r\n {\r\n let nea: Vector3[] = [];\r\n for (let cu of this.Explode())\r\n {\r\n let neaa = cu.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform);\r\n if (neaa)\r\n nea.push(...neaa);\r\n }\r\n return nea;\r\n }\r\n case ObjectSnapMode.Ext:\r\n {\r\n let cp = this.GetClosestPointTo(pickPoint, true);\r\n if (cp)\r\n return [cp];\r\n break;\r\n }\r\n case ObjectSnapMode.Cen:\r\n let cenPts: Vector3[] = [];\r\n for (let i = 0; i < this._LineData.length; i++)\r\n {\r\n let data = this._LineData[i];\r\n if (!equaln(data.bul, 0))\r\n {\r\n let cu = this.GetCurveAtIndex(i) as Arc;\r\n if (cu)//end bul !== 0 但是并没有圆弧\r\n cenPts.push(cu.Center);\r\n }\r\n }\r\n return cenPts;\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n let cp = this.GetClosestPointTo(pickPoint, false);\r\n if (!cp) return [];\r\n let cparam = this.GetParamAtPoint(cp);\r\n let cu = this.GetCurveAtParam(cparam);\r\n if (cu)\r\n {\r\n let closestPt = cu.GetClosestPointTo(lastPoint, true);\r\n if (closestPt && this.PtOnCurve(closestPt))\r\n return [closestPt];\r\n }\r\n }\r\n case ObjectSnapMode.Tan:\r\n if (lastPoint)\r\n {\r\n let clostPt = this.GetClosestPointTo(pickPoint, false);\r\n if (!clostPt) return [];\r\n let par = this.GetParamAtPoint(clostPt);\r\n let cu = this.GetCurveAtParam(par);\r\n if (cu instanceof Arc)\r\n return cu.GetObjectSnapPoints(snapMode, pickPoint, lastPoint);\r\n return [];\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n GetGripPoints(): Array\r\n {\r\n let ptList: Vector3[] = [];\r\n if (this._LineData.length < 2)\r\n return ptList;\r\n\r\n let enParam = this.EndParam;\r\n if (this.CloseMark) enParam -= 0.5;\r\n for (let i = 0; i < enParam + 0.5; i += 0.5)\r\n {\r\n let p = this.GetPointAtParam(i);\r\n ptList.push(p);\r\n }\r\n return ptList;\r\n }\r\n MoveGripPoints(indexList: number[], moveVec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n let moveVLoc = AsVector2(moveVec.clone().applyMatrix4(new Matrix4().extractRotation(this.OCSInv)));\r\n\r\n let calcIndexList = indexList;\r\n if (indexList.length > 1)\r\n {\r\n let centerIndexes = indexList.filter(i => i % 2 === 0);\r\n if (centerIndexes.length > 0)\r\n calcIndexList = centerIndexes;\r\n }\r\n\r\n for (let index of calcIndexList)\r\n {\r\n if (index % 2 === 0)\r\n {\r\n let cuIndex = index / 2;\r\n\r\n let ptCout = this._LineData.length;\r\n\r\n let frontIndex = cuIndex - 1;\r\n if (this._ClosedMark)\r\n frontIndex = FixIndex(frontIndex, ptCout);\r\n\r\n if (frontIndex >= 0 && this.GetBuilgeAt(frontIndex))\r\n {\r\n let arc = this.GetCurveAtIndex(frontIndex) as Arc;\r\n arc.MoveGripPoints([2], moveVec);\r\n this._LineData[frontIndex].bul = arc.Bul;\r\n }\r\n if ((cuIndex !== ptCout - 1) && this.GetBuilgeAt(cuIndex))\r\n {\r\n let arc = this.GetCurveAtIndex(cuIndex) as Arc;\r\n arc.MoveGripPoints([0], moveVec);\r\n this._LineData[cuIndex].bul = arc.Bul;\r\n }\r\n this._LineData[cuIndex].pt.add(moveVLoc);\r\n }\r\n else\r\n {\r\n let ptIndex = (index - 1) / 2;\r\n let nextIndex = (FixIndex(ptIndex + 1, this._LineData));\r\n let d = this._LineData[ptIndex];\r\n if (d.bul == 0)\r\n {\r\n this._LineData[ptIndex].pt.add(moveVLoc);\r\n this._LineData[nextIndex].pt.add(moveVLoc);\r\n }\r\n else\r\n {\r\n let arc = this.GetCurveAtIndex(ptIndex) as Arc;\r\n arc.MoveGripPoints([1], moveVec);\r\n this._LineData[ptIndex].bul = arc.Bul;\r\n }\r\n }\r\n }\r\n\r\n this.Update();\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n let ocs = this.OCS;\r\n let ptList: Vector3[] = [];\r\n for (let data of this._LineData)\r\n {\r\n ptList.push(AsVector3(data.pt).applyMatrix4(ocs));\r\n }\r\n return ptList;\r\n }\r\n\r\n /**\r\n * 范围拉伸(stretch),对夹点进行拉伸.\r\n * 如果对圆弧的一侧进行拉伸,那么修改bul\r\n *\r\n * @param {Array} indexList\r\n * @param {Vector3} vec\r\n * @memberof Polyline\r\n */\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n //本地坐标系移动向量\r\n let moveVLoc = vec.clone().applyMatrix4(new Matrix4().extractRotation(this.OCSInv));\r\n\r\n let ptCout = this._LineData.length;\r\n\r\n for (let index of indexList)\r\n {\r\n if (index >= ptCout)\r\n throw \"在拉伸多段线顶点时,尝试拉伸不存在的顶点!(通常是因为模块中的板轮廓被破坏,导致的顶点丢失!)\";\r\n\r\n let frontIndex = index - 1;\r\n let nextIndex = index + 1;\r\n if (this._ClosedMark)\r\n {\r\n frontIndex = FixIndex(frontIndex, ptCout);\r\n nextIndex = FixIndex(nextIndex, ptCout);\r\n }\r\n\r\n /**\r\n * 根据新的拉伸点修改凸度.\r\n *\r\n * @param {number} nextIndex 隔壁点索引\r\n * @param {number} bulIndex 需要修改凸度位置的索引\r\n * @returns\r\n */\r\n const ChangeBul = (nextIndex: number, bulIndex: number) =>\r\n {\r\n //需要修改的点的数据\r\n let d = this._LineData[bulIndex];\r\n if (d === undefined || d.bul == 0) return;\r\n\r\n //如果隔壁点不在拉伸列表中\r\n if (indexList.indexOf(nextIndex) === -1)\r\n {\r\n let needChangeP = this.GetPointAtParam(index);\r\n let notChangeP = this.GetPointAtParam(nextIndex);\r\n\r\n //原先的弦长的一半\r\n let oldChordLengthHalf = needChangeP.distanceTo(notChangeP) * 0.5;\r\n\r\n //弓高\r\n let arcHeight = oldChordLengthHalf * d.bul;\r\n\r\n needChangeP.add(vec);\r\n\r\n let newChordLengthHalf = needChangeP.distanceTo(notChangeP) * 0.5;\r\n\r\n d.bul = arcHeight / newChordLengthHalf;\r\n }\r\n };\r\n\r\n ChangeBul(frontIndex, frontIndex);\r\n ChangeBul(nextIndex, index);\r\n\r\n //修改顶点\r\n this._LineData[index].pt.add(AsVector2(moveVLoc));\r\n }\r\n this.Update();\r\n }\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n this._LineData.length = 0;\r\n let cout = file.Read();\r\n for (let i = 0; i < cout; i++)\r\n {\r\n let v = new Vector2().fromArray(file.Read());\r\n let bul = file.Read();\r\n\r\n this._LineData.push({ pt: v, bul: bul });\r\n }\r\n if (ver > 1)\r\n this._ClosedMark = file.Read();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(2);\r\n file.Write(this._LineData.length);\r\n\r\n for (let l of this._LineData)\r\n {\r\n file.Write(l.pt.toArray());\r\n file.Write(l.bul);\r\n }\r\n file.Write(this._ClosedMark);\r\n }\r\n}\r\n\r\nexport const TempPolyline = new Polyline();\r\n","import { Matrix4, Vector3 } from 'three';\r\nimport { arrayRemoveDuplicateBySort } from '../Common/ArrayExt';\r\nimport { Arc } from '../DatabaseServices/Entity/Arc';\r\nimport { Circle } from '../DatabaseServices/Entity/Circle';\r\nimport { Curve } from '../DatabaseServices/Entity/Curve';\r\nimport { Ellipse } from '../DatabaseServices/Entity/Ellipse';\r\nimport { Line } from '../DatabaseServices/Entity/Line';\r\nimport { Polyline } from '../DatabaseServices/Entity/Polyline';\r\nimport { comparePoint, equaln, equalv3 } from '../Geometry/GeUtils';\r\n\r\n/**\r\n * 相交延伸选项.\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum IntersectOption\r\n{\r\n /**\r\n * 两者都不延伸\r\n */\r\n OnBothOperands = 0,\r\n /**\r\n * 延伸自身\r\n */\r\n ExtendThis = 1,\r\n /**\r\n * 延伸参数\r\n */\r\n ExtendArg = 2,\r\n /**\r\n * 延伸两者\r\n */\r\n ExtendBoth = 3,\r\n}\r\n\r\nexport interface IntersectResult\r\n{\r\n pt: Vector3,\r\n thisParam: number,\r\n argParam: number,\r\n}\r\n\r\n//延伸自身还是参数反转\r\nexport function reverseIntersectOption(intType: IntersectOption)\r\n{\r\n if (intType === IntersectOption.ExtendThis)\r\n intType = IntersectOption.ExtendArg;\r\n else if (intType === IntersectOption.ExtendArg)\r\n intType = IntersectOption.ExtendThis;\r\n return intType;\r\n}\r\n/**\r\n * 校验相交点是否满足延伸选项\r\n * 算法会计算无限延伸状态下的曲线交点,调用该方法进行校验返回校验后的点表\r\n *\r\n * @param {Vector3[]} intRes 相交点.曲线当作完全状态下的相交点\r\n * @param {Curve} c1 曲线1 由this参数传入\r\n * @param {Curve} c2 曲线2 由arg 参数传入\r\n * @param {Intersect} extType 延伸选项.\r\n * @returns {Array} 校验完成后的点表\r\n */\r\nfunction CheckPointOnCurve(intRes: IntersectResult[], c1: Curve, c2: Curve, extType: IntersectOption, tolerance = 1e-6): Array\r\n{\r\n return intRes.filter(r =>\r\n {\r\n if (!(extType & IntersectOption.ExtendThis))\r\n if (!c1.ParamOnCurve(r.thisParam, tolerance))\r\n return false;\r\n\r\n if (!(extType & IntersectOption.ExtendArg))\r\n if (!c2.ParamOnCurve(r.argParam, tolerance))\r\n return false;\r\n return true;\r\n });\r\n}\r\nexport function IntersectCircleAndCircle(cu1: Circle | Arc, cu2: Circle | Arc): IntersectResult[]\r\n{\r\n if (!cu1.IsCoplaneTo(cu2)) return [];\r\n\r\n let c1OcsInv = cu1.OCSInv;\r\n let c1Ocs = cu1.OCS;\r\n\r\n let center1 = cu1.Center.applyMatrix4(c1OcsInv);\r\n let center2 = cu2.Center.applyMatrix4(c1OcsInv);\r\n let radius1 = cu1.Radius;\r\n let radius2 = cu2.Radius;\r\n\r\n let pts: IntersectResult[] = [];\r\n let dist = center2.distanceTo(center1);\r\n\r\n if (dist < Math.abs(radius1 - radius2) - 1e-3\r\n || dist > (radius1 + radius2 + 1e-3))\r\n return pts;\r\n if (equaln(dist, 0, 1e-6)) return pts;\r\n\r\n let dstsqr = dist * dist;\r\n let r1sqr = radius1 * radius1;\r\n let r2sqr = radius2 * radius2;\r\n\r\n let a = (dstsqr - r2sqr + r1sqr) / (2 * dist);\r\n let h = Math.sqrt(Math.abs(r1sqr - (a * a)));\r\n\r\n let ratio_a = a / dist;\r\n let ratio_h = h / dist;\r\n\r\n let dx = center2.x - center1.x;\r\n let dy = center2.y - center1.y;\r\n\r\n let phix = center1.x + (ratio_a * dx);\r\n let phiy = center1.y + (ratio_a * dy);\r\n\r\n dx *= ratio_h;\r\n dy *= ratio_h;\r\n\r\n let p1 = new Vector3(phix + dy, phiy - dx);\r\n let p2 = new Vector3(phix - dy, phiy + dx);\r\n p1.applyMatrix4(c1Ocs);\r\n p2.applyMatrix4(c1Ocs);\r\n\r\n pts.push({\r\n pt: p1,\r\n thisParam: cu1.GetParamAtPoint(p1),\r\n argParam: cu2.GetParamAtPoint(p1),\r\n });\r\n if (!equalv3(p1, p2))//防止点重复\r\n pts.push({\r\n pt: p2,\r\n thisParam: cu1.GetParamAtPoint(p2),\r\n argParam: cu2.GetParamAtPoint(p2),\r\n });\r\n\r\n return pts;\r\n}\r\n/**\r\n * 计算圆与圆弧的交点.\r\n *\r\n * @export\r\n * @param {Circle} circle 圆\r\n * @param {Arc} arc 圆弧\r\n * @param {IntersectOption} extType 延伸选项\r\n * @returns 交点集合\r\n */\r\nexport function IntersectCircleAndArc(circle: Circle, arc: Arc, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let pts = IntersectCircleAndCircle(circle, arc);\r\n return CheckPointOnCurve(pts, circle, arc, extType | IntersectOption.ExtendThis, tolerance);\r\n}\r\n\r\n/**\r\n * 计算圆弧与圆弧的交点\r\n *\r\n * @export\r\n * @param {Arc} arc1 圆弧\r\n * @param {Arc} arc2 圆弧\r\n * @param {IntersectOption} extType 延伸选项\r\n * @returns 交点集合\r\n */\r\nexport function IntersectArcAndArc(arc1: Arc, arc2: Arc, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let pts = IntersectCircleAndCircle(arc1, arc2);\r\n return CheckPointOnCurve(pts, arc1, arc2, extType, tolerance);\r\n}\r\n\r\nexport function IntersectEllipseAndLine(l: Line, el: Ellipse, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let pts = IntersectLineAndEllipseFor2D(l, el);\r\n return CheckPointOnCurve(pts, l, el, extType, tolerance);\r\n}\r\n\r\n/**\r\n * 通用方法:计算直线与圆的交点,默认延伸全部\r\n *\r\n * @export\r\n * @param {Line} line 直线\r\n * @param {(Circle | Arc)} circle 圆或圆弧\r\n * @returns 交点集合\r\n */\r\nfunction IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc): IntersectResult[]\r\n{\r\n let lineOrg = line.StartPoint;\r\n let lineDirection = line.EndPoint.sub(lineOrg);\r\n let dirLen = lineDirection.length();\r\n if (equaln(dirLen, 0)) return [];\r\n lineDirection.divideScalar(dirLen);\r\n\r\n let diff = lineOrg.clone().sub(circle.Center);\r\n let a0 = diff.dot(diff) - circle.Radius ** 2;\r\n let a1 = lineDirection.dot(diff);\r\n let discr = a1 ** 2 - a0;\r\n\r\n if (equaln(discr, 0, 1e-7))\r\n {\r\n let pt = lineOrg.add(lineDirection.multiplyScalar(-a1));\r\n\r\n return [{\r\n pt,\r\n thisParam: -a1 / dirLen,\r\n argParam: circle.GetParamAtPoint(pt)\r\n }];\r\n }\r\n else if (discr > 0)\r\n {\r\n let root = Math.sqrt(discr);\r\n let p1 = lineOrg.clone().add(lineDirection.clone().multiplyScalar(-a1 + root));\r\n let p2 = lineOrg.add(lineDirection.multiplyScalar(-a1 - root));\r\n\r\n return [\r\n {\r\n pt: p1,\r\n thisParam: (-a1 + root) / dirLen,\r\n argParam: circle.GetParamAtPoint(p1)\r\n }, {\r\n pt: p2,\r\n thisParam: (-a1 - root) / dirLen,\r\n argParam: circle.GetParamAtPoint(p2)\r\n }\r\n ];\r\n }\r\n return [];\r\n}\r\n\r\n//直线和圆\r\nexport function IntersectLineAndCircle(line: Line, circle: Circle, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let ptArr = IntersectLineAndCircleOrArc(line, circle);\r\n return CheckPointOnCurve(ptArr, line, circle, extType | IntersectOption.ExtendArg);\r\n}\r\n//直线和圆弧\r\nexport function IntersectLineAndArc(line: Line, arc: Arc, extType: IntersectOption, tolerance = 1e-6)\r\n{\r\n let ptArr = IntersectLineAndCircleOrArc(line, arc);\r\n return CheckPointOnCurve(ptArr, line, arc, extType, tolerance);\r\n}\r\n//直线和直线\r\nexport function IntersectLAndLFor2D(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3\r\n{\r\n let dx1 = p1.x - p2.x;\r\n let dx2 = p3.x - p4.x;\r\n let dx3 = p4.x - p2.x;\r\n let dy1 = p1.y - p2.y;\r\n let dy2 = p3.y - p4.y;\r\n let dy3 = p4.y - p2.y;\r\n\r\n let det = (dx2 * dy1) - (dy2 * dx1);\r\n\r\n if (equaln(det, 0.0, 1e-5))\r\n {\r\n // if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))\r\n // {\r\n // return midPoint(midPoint(p1, p2), midPoint(p3, p4));\r\n // }\r\n return;\r\n }\r\n\r\n let pt = new Vector3;\r\n let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;\r\n pt.x = (ratio * dx2) + p4.x;\r\n pt.y = (ratio * dy2) + p4.y;\r\n\r\n return pt;\r\n}\r\n\r\nexport function IntersectLAndLFor2D2(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3[]\r\n{\r\n let dx1 = p1.x - p2.x;\r\n let dx2 = p3.x - p4.x;\r\n let dx3 = p4.x - p2.x;\r\n let dy1 = p1.y - p2.y;\r\n let dy2 = p3.y - p4.y;\r\n let dy3 = p4.y - p2.y;\r\n\r\n let det = (dx2 * dy1) - (dy2 * dx1);\r\n\r\n if (equaln(det, 0.0, 1e-5))\r\n {\r\n if (equaln(dx2 * dy3, dy2 * dx3, 1e-5))\r\n return [p1, p2, p3, p4];\r\n return [];\r\n }\r\n\r\n let pt = new Vector3;\r\n let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det;\r\n pt.x = (ratio * dx2) + p4.x;\r\n pt.y = (ratio * dy2) + p4.y;\r\n\r\n return [pt];\r\n}\r\n\r\nexport function IntersectLine3AndLine3(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3, epsilon = 1e-6)\r\n{\r\n let pts = ShortestLine3AndLine3(p1, p2, p3, p4);\r\n if (pts) return pts[0];\r\n}\r\n\r\n/**\r\n * 三维中两行之间最短的直线\r\n * ref:https://stackoverflow.com/questions/2316490/the-algorithm-to-find-the-point-of-intersection-of-two-3d-line-segment\r\n * ref:http://paulbourke.net/geometry/pointlineplane/\r\n * ref:http://paulbourke.net/geometry/pointlineplane/calclineline.cs\r\n *\r\n * @export\r\n * @param {Vector3} p1 l1.start\r\n * @param {Vector3} p2 l1.end\r\n * @param {Vector3} p3 l2.start\r\n * @param {Vector3} p4 l2.end\r\n * @returns 交点集合\r\n */\r\nfunction ShortestLine3AndLine3(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3, epsilon = 1e-6)\r\n{\r\n let p43 = p4.clone().sub(p3);\r\n if (p43.lengthSq() < epsilon)\r\n return;\r\n let p21 = p2.clone().sub(p1);\r\n if (p21.lengthSq() < epsilon)\r\n return;\r\n\r\n let p13 = p1.clone().sub(p3);\r\n\r\n let d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z;\r\n let d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z;\r\n let d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z;\r\n let d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z;\r\n let d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z;\r\n\r\n let denom = d2121 * d4343 - d4321 * d4321;\r\n if (Math.abs(denom) < epsilon)\r\n return;\r\n let numer = d1343 * d4321 - d1321 * d4343;\r\n\r\n let mua = numer / denom;\r\n let mub = (d1343 + d4321 * (mua)) / d4343;\r\n\r\n let resultSegmentPoint1 = new Vector3();\r\n resultSegmentPoint1.x = p1.x + mua * p21.x;\r\n resultSegmentPoint1.y = p1.y + mua * p21.y;\r\n resultSegmentPoint1.z = p1.z + mua * p21.z;\r\n let resultSegmentPoint2 = new Vector3();\r\n resultSegmentPoint2.x = p3.x + mub * p43.x;\r\n resultSegmentPoint2.y = p3.y + mub * p43.y;\r\n resultSegmentPoint2.z = p3.z + mub * p43.z;\r\n\r\n return [resultSegmentPoint1, resultSegmentPoint2];\r\n}\r\n\r\n//直线和直线\r\nexport function IntersectLineAndLine(l1: Line, l2: Line, extType: IntersectOption, fuzz = 1e-4): IntersectResult[]\r\n{\r\n let [pt1, pt2, pt3, pt4] = [l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint];\r\n\r\n let ipts: Vector3[];\r\n if (equaln(pt1.z, 0, fuzz) && equaln(pt2.z, 0, fuzz) && equaln(pt3.z, 0, fuzz) && equaln(pt4.z, 0, fuzz))\r\n {\r\n ipts = IntersectLAndLFor2D2(pt1, pt2, pt3, pt4);\r\n ipts.sort(comparePoint(\"xy\"));\r\n arrayRemoveDuplicateBySort(ipts, (p1, p2) => equalv3(p1, p2, fuzz));\r\n }\r\n else\r\n {\r\n ipts = ShortestLine3AndLine3(pt1, pt2, pt3, pt4);\r\n if (!ipts) return [];\r\n if (ipts.length === 2)\r\n ipts.pop();\r\n }\r\n\r\n let ints: IntersectResult[] = [];\r\n for (let pt of ipts)\r\n {\r\n let { closestPt: p1, param: param1 } = l1.GetClosestAtPoint(pt, true);\r\n if (!equalv3(pt, p1, fuzz)) return [];\r\n if (!(extType & IntersectOption.ExtendThis))\r\n if (!(l1.ParamOnCurve(param1, 0) || equalv3(pt1, pt, fuzz) || equalv3(pt2, pt, fuzz)))\r\n return [];\r\n let { closestPt: p2, param: param2 } = l2.GetClosestAtPoint(pt, true);\r\n if (!equalv3(pt, p2, fuzz)) return [];\r\n if (!(extType & IntersectOption.ExtendArg))\r\n if (!(l2.ParamOnCurve(param2, 0) || equalv3(pt3, pt, fuzz) || equalv3(pt4, pt, fuzz)))\r\n return [];\r\n ints.push({ pt, thisParam: param1, argParam: param2 });\r\n }\r\n return ints;\r\n}\r\n\r\nexport function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: IntersectOption, tolerance = 1e-6): IntersectResult[]\r\n{\r\n let cus: Curve[] = pl.Explode();\r\n let cus2: Curve[];\r\n if (cu instanceof Polyline)\r\n cus2 = cu.Explode();\r\n else\r\n cus2 = [cu];\r\n\r\n let intRes: IntersectResult[] = [];\r\n\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let cu1 = cus[i];\r\n for (let j = 0; j < cus2.length; j++)\r\n {\r\n let cu2 = cus2[j];\r\n let ext = extType;\r\n\r\n let isStart = i === 0;\r\n let isEnd = i === cus.length - 1;\r\n\r\n let isStart2 = j === 0;\r\n let isEnd2 = j === cus2.length - 1;\r\n\r\n //当曲线闭合时,或者当前的子曲线不是起始和不是结束,那么不延伸曲线.\r\n if (pl.CloseMark || !(isStart || isEnd))\r\n ext = ext & ~IntersectOption.ExtendThis;\r\n if ((cu instanceof Polyline && cu.CloseMark) || !(isStart2 || isEnd2))\r\n ext = ext & ~IntersectOption.ExtendArg;\r\n\r\n let ptPars = cu1.IntersectWith2(cu2, ext, tolerance).filter(r1 => intRes.every(r2 => !equalv3(r1.pt, r2.pt)));\r\n\r\n //校验延伸\r\n if (IntersectOption.ExtendThis & ext)\r\n {\r\n //如果曲线是起始又是结束,那么不校验.\r\n if (isStart && isEnd)\r\n {\r\n }\r\n else if (isStart)\r\n {\r\n ptPars = ptPars.filter(res => res.thisParam <= 1);\r\n }\r\n else if (isEnd)\r\n {\r\n ptPars = ptPars.filter(res => res.thisParam >= 0);\r\n }\r\n }\r\n if (IntersectOption.ExtendArg & ext)\r\n {\r\n //如果曲线是起始又是结束,那么不校验.\r\n if (isStart2 && isEnd2)\r\n {\r\n }\r\n else if (isStart2)\r\n {\r\n ptPars = ptPars.filter(res => res.argParam + j <= cu2.EndParam);\r\n }\r\n else if (isEnd2)\r\n {\r\n ptPars = ptPars.filter(res => res.argParam + j >= 0);\r\n }\r\n }\r\n\r\n intRes.push(...ptPars.map(r =>\r\n {\r\n return {\r\n pt: r.pt,\r\n thisParam: i + r.thisParam,\r\n argParam: j + r.argParam,\r\n };\r\n }));\r\n }\r\n }\r\n return intRes;\r\n}\r\n\r\nexport function IntersectLineAndEllipseFor2D(l: Line, el: Ellipse)\r\n{\r\n if (!l.IsCoplaneTo(el)) return [];\r\n\r\n let mat = new Matrix4().makeRotationZ(-el.Rotation).multiply(el.OCSInv);\r\n let a = el.RadX;\r\n let b = el.RadY;\r\n let sp = l.StartPoint.applyMatrix4(mat);\r\n let ep = l.EndPoint.applyMatrix4(mat);\r\n let pts: Vector3[] = [];\r\n if (equaln(sp.x, ep.x))\r\n {\r\n let c = sp.x;\r\n let j = (b ** 2) * (1 - (c ** 2) / (a ** 2));\r\n if (equaln(j, 0))\r\n {\r\n pts = [new Vector3(sp.x, 0)];\r\n }\r\n else if (j < 0)\r\n return [];\r\n else\r\n {\r\n let y1 = Math.sqrt(j);\r\n let y2 = -Math.sqrt(j);\r\n pts = [\r\n new Vector3(c, y1),\r\n new Vector3(c, y2)\r\n ];\r\n }\r\n }\r\n else\r\n {\r\n let k = (sp.y - ep.y) / (sp.x - ep.x);\r\n let c = sp.y - sp.x * k;\r\n let j = (2 * a * a * k * c) * (2 * a * a * k * c) - 4 * (b * b + a * a * k * k) * a * a * (c * c - b * b);\r\n if (equaln(j, 0))\r\n {\r\n let x1 = -2 * k * c * a * a / (2 * (b * b + a * a * k * k));\r\n let y1 = k * x1 + c;\r\n pts = [new Vector3(x1, y1)];\r\n }\r\n else if (j < 0)\r\n return [];\r\n else\r\n {\r\n let x1 = (-2 * k * c * a * a + Math.sqrt(j)) / (2 * (b * b + a * a * k * k));\r\n let y1 = k * x1 + c;\r\n let x2 = (-2 * k * c * a * a - Math.sqrt(j)) / (2 * (b * b + a * a * k * k));\r\n let y2 = k * x2 + c;\r\n pts = [\r\n new Vector3(x1, y1),\r\n new Vector3(x2, y2)\r\n ];\r\n }\r\n }\r\n\r\n let matInv = new Matrix4().getInverse(mat);\r\n return pts.map(p =>\r\n {\r\n let pt = p.applyMatrix4(matInv);\r\n return {\r\n pt,\r\n thisParam: l.GetParamAtPoint(pt),\r\n argParam: el.GetParamAtPoint(pt)\r\n };\r\n });\r\n}\r\nexport function IntersectEllipseAndCircleOrArc(el: Ellipse, cir: Circle | Arc, type: IntersectOption)\r\n{\r\n if (!el.IsCoplaneTo(cir)) return [];\r\n\r\n let a = Math.max(el.RadX, el.RadY);\r\n let dist = el.Center.distanceTo(cir.Center);\r\n\r\n let disVail = dist > (a + cir.Radius);\r\n\r\n if (disVail)\r\n return [];\r\n\r\n if (equalv3(el.Center, cir.Center))\r\n {\r\n let a = el.RadX;\r\n let b = el.RadY;\r\n let r = cir.Radius;\r\n let j = ((a * b) ** 2 - (b * r) ** 2) / (a ** 2 - b ** 2);\r\n let pts: Vector3[] = [];\r\n if (equaln(j, 0) || equaln(j, r ** 2))\r\n {\r\n if (equaln(j, 0))\r\n pts = [\r\n new Vector3(a, 0),\r\n new Vector3(-a, 0)\r\n ];\r\n else\r\n pts = [\r\n new Vector3(0, r),\r\n new Vector3(0, -r)\r\n ];\r\n }\r\n else if (j < 0)\r\n return [];\r\n else\r\n {\r\n let y1 = Math.sqrt(j);\r\n let y2 = - Math.sqrt(j);\r\n let n = r ** 2 - j;\r\n let x1 = Math.sqrt(n);\r\n let x2 = - Math.sqrt(n);\r\n pts = [\r\n new Vector3(x1, y1),\r\n new Vector3(x1, y2),\r\n new Vector3(x2, y1),\r\n new Vector3(x2, y2),\r\n ];\r\n }\r\n let ro = new Matrix4().makeRotationZ(el.Rotation);\r\n let res = pts.map(p =>\r\n {\r\n let pt = p.applyMatrix4(ro).applyMatrix4(el.OCS);\r\n return {\r\n pt,\r\n thisParam: el.GetParamAtPoint(pt),\r\n argParam: cir.GetParamAtPoint(pt)\r\n };\r\n });\r\n return CheckPointOnCurve(res, el, cir, type);\r\n }\r\n else\r\n {\r\n let pts = el.Shape.getPoints(60);\r\n let lineData = pts.map(p =>\r\n {\r\n return { pt: p, bul: 0 };\r\n });\r\n let pl = new Polyline(lineData);\r\n let cirClone = cir.Clone().ApplyMatrix(el.OCSInv);\r\n\r\n if (type === IntersectOption.ExtendBoth)\r\n type = IntersectOption.ExtendArg;\r\n else if (type !== IntersectOption.ExtendArg)\r\n type = IntersectOption.OnBothOperands;\r\n\r\n let intPts = IntersectPolylineAndCurve(pl, cirClone, type);\r\n intPts.forEach(r => r.pt.applyMatrix4(el.OCS));\r\n return intPts;\r\n }\r\n}\r\nexport function IntersectEllipse(el1: Ellipse, el2: Ellipse, type: IntersectOption)\r\n{\r\n if (!el1.IsCoplaneTo(el2)) return [];\r\n\r\n let isEqul = equalv3(el1.Center, el2.Center)\r\n && equaln(el1.RadX, el2.RadX)\r\n && equaln(el1.RadY, el2.RadY)\r\n && equalv3(el1.StartPoint, el2.StartPoint);\r\n\r\n if (isEqul)\r\n return [];\r\n\r\n let a1 = Math.max(el1.RadX, el1.RadY);\r\n let a2 = Math.max(el2.RadX, el2.RadY);\r\n\r\n let dist = el1.Center.distanceToSquared(el2.Center);\r\n if (dist > (a1 + a2) ** 2)\r\n {\r\n return [];\r\n }\r\n\r\n if (!el1.BoundingBox.intersectsBox(el2.BoundingBox))\r\n return [];\r\n\r\n let diffMat = el1.OCSInv.multiply(el2.OCS);\r\n let pts1 = el1.Shape.getPoints(60);\r\n let pts2 = el2.Shape.getPoints(60);\r\n\r\n let lineData1 = pts1.map(p =>\r\n {\r\n return { pt: p, bul: 0 };\r\n });\r\n let lineData2 = pts2.map(p =>\r\n {\r\n return { pt: p, bul: 0 };\r\n });\r\n\r\n let pl1 = new Polyline(lineData1);\r\n let pl2 = new Polyline(lineData2).ApplyMatrix(diffMat);\r\n\r\n let intPts = pl1.IntersectWith2(pl2, 0);\r\n intPts.forEach(r => r.pt.applyMatrix4(el1.OCS));\r\n return intPts;\r\n}\r\n","import { Box3, BufferGeometry, EllipseCurve, Line as TLine, Material, Matrix3, Matrix4, Object3D, Vector3 } from 'three';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { arrayLast, arrayRemoveDuplicateBySort } from '../../Common/ArrayExt';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { getArcOrCirNearPts, GetTanPtsOnArcOrCircle } from '../../Common/CurveUtils';\r\nimport { reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { clamp } from '../../Common/Utils';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { angle, AsVector3, equaln, MoveMatrix, polar } from '../../Geometry/GeUtils';\r\nimport { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectEllipseAndCircleOrArc, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { Shape2 } from '../Shape2';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\nimport { Arc } from './Arc';\r\nimport { Curve } from './Curve';\r\nimport { DragPointType } from './DragPointType';\r\nimport { Ellipse } from './Ellipse';\r\nimport { Line } from './Line';\r\nimport { Polyline } from './Polyline';\r\n\r\nlet circleGeometry: BufferGeometry;\r\nfunction GetCircleGeometry()\r\n{\r\n if (!circleGeometry)\r\n circleGeometry = BufferGeometryUtils.CreateFromPts(\r\n new EllipseCurve(0, 0, 1, 1, 0, 2 * Math.PI, false, 0).getPoints(360).map(AsVector3)\r\n );\r\n return circleGeometry;\r\n}\r\n\r\n@Factory\r\nexport class Circle extends Curve\r\n{\r\n constructor(center?: Vector3, radius: number = 1e-6)\r\n {\r\n super();\r\n center && this._Matrix.setPosition(center);\r\n this._Radius = radius;\r\n }\r\n private _Radius: number;\r\n\r\n get Shape()\r\n {\r\n let sp = new Shape2();\r\n sp.ellipse(0, 0, this._Radius, this._Radius, 0, 2 * Math.PI, false, 0);\r\n return sp;\r\n }\r\n\r\n get Center()\r\n {\r\n return new Vector3().setFromMatrixPosition(this._Matrix);\r\n }\r\n set Center(v: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Matrix.setPosition(v);\r\n this.Update();\r\n }\r\n get Radius()\r\n {\r\n return this._Radius;\r\n }\r\n set Radius(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Radius = clamp(v, 1e-9, 1e19);\r\n this.Update();\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this.Center = this.Center.applyMatrix4(m);\r\n this.Radius = this.Radius * m.getMaxScaleOnAxis();\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n reviseMirrorMatrix(this._Matrix);\r\n\r\n return this;\r\n }\r\n\r\n //******************** Curve function start*****************//\r\n\r\n get StartPoint(): Vector3\r\n {\r\n return this.GetPointAtParam(0);\r\n }\r\n get StartParam(): number\r\n {\r\n return 0;\r\n }\r\n get EndPoint(): Vector3\r\n {\r\n return this.GetPointAtParam(0);\r\n }\r\n get EndParam(): number\r\n {\r\n return 1;\r\n }\r\n PtInCurve(pt: Vector3)\r\n {\r\n return pt.distanceToSquared(this.Center) < Math.pow(this.Radius, 2);\r\n }\r\n get Area()\r\n {\r\n return Math.PI * this._Radius ** 2;\r\n }\r\n get Area2()\r\n {\r\n return Math.PI * this._Radius ** 2;\r\n }\r\n get Length()\r\n {\r\n return Math.PI * 2 * this._Radius;\r\n }\r\n\r\n get IsClose(): boolean\r\n {\r\n return true;\r\n }\r\n\r\n //曲线为顺时针\r\n get IsClockWise(): boolean { return false; }\r\n\r\n GetPointAtParam(param: number)\r\n {\r\n return (polar(new Vector3(), param * 2 * Math.PI, this._Radius) as Vector3).applyMatrix4(this._Matrix);\r\n }\r\n\r\n GetPointAtDistance(distance: number)\r\n {\r\n let param = distance / (Math.PI * 2 * this._Radius);\r\n return this.GetPointAtParam(param);\r\n }\r\n\r\n GetDistAtParam(param: number)\r\n {\r\n return Math.PI * 2 * this._Radius * param;\r\n }\r\n\r\n GetDistAtPoint(pt: Vector3)\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n return this.GetDistAtParam(param);\r\n }\r\n\r\n GetParamAtDist(d: number)\r\n {\r\n return d / (Math.PI * 2 * this._Radius);\r\n }\r\n\r\n GetSplitCurves(param: number[] | number)\r\n {\r\n let params: number[];\r\n if (param instanceof Array)\r\n {\r\n params = param.filter(p => this.ParamOnCurve(p));\r\n params.sort((a1, a2) => a2 - a1);//从大到小\r\n arrayRemoveDuplicateBySort(params);\r\n if (params.length < 2) return [];\r\n }\r\n else //圆不能被单个参数切割\r\n return [];\r\n\r\n //补上最后一个到第一个的弧\r\n params.unshift(arrayLast(params));\r\n\r\n let anglelist = params.map(param => Math.PI * 2 * param);\r\n\r\n let curvelist = new Array();\r\n for (let i = 0; i < anglelist.length - 1; i++)\r\n {\r\n let sa = anglelist[i];\r\n let ea = anglelist[i + 1];\r\n if (!equaln(sa, ea, 1e-6))\r\n {\r\n let arc = new Arc(new Vector3(), this._Radius, ea, sa, false);\r\n arc.ApplyMatrix(this.OCS);\r\n curvelist.push(arc);\r\n }\r\n }\r\n return curvelist;\r\n }\r\n\r\n GetParamAtPoint(pt?: Vector3)\r\n {\r\n if (!this.PtOnCurve(pt))\r\n return NaN;\r\n return angle(pt.clone().applyMatrix4(this.OCSInv)) / (Math.PI * 2);\r\n }\r\n\r\n PtOnCurve(pt: Vector3)\r\n {\r\n return equaln(pt.distanceToSquared(this.Center), this._Radius * this._Radius, 1e-5);\r\n }\r\n GetOffsetCurves(offsetDist: number): Curve[]\r\n {\r\n if ((offsetDist + this._Radius) > 0)\r\n {\r\n let circle = this.Clone();\r\n circle.Radius = this._Radius + offsetDist;\r\n return [circle];\r\n }\r\n return [];\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption)\r\n {\r\n if (curve instanceof Arc)\r\n {\r\n return IntersectCircleAndArc(this, curve, intType);\r\n }\r\n if (curve instanceof Line)\r\n {\r\n return SwapParam(IntersectLineAndCircle(curve, this, reverseIntersectOption(intType)));\r\n }\r\n if (curve instanceof Circle)\r\n {\r\n return IntersectCircleAndCircle(this, curve);\r\n }\r\n if (curve instanceof Ellipse)\r\n {\r\n return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));\r\n }\r\n if (curve instanceof Polyline)\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType)));\r\n return [];\r\n }\r\n //******************** Curve function end*****************//\r\n\r\n get BoundingBox(): Box3\r\n {\r\n return new Box3().setFromPoints(this.GetGripPoints());\r\n }\r\n\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe)\r\n {\r\n let obj = new Object3D();\r\n let cirGeo = GetCircleGeometry();\r\n if (renderType === RenderType.WireframePrint)\r\n {\r\n let geometry = new LineGeometry().setPositions(cirGeo.attributes.position.array as number[]);\r\n obj.add(new Line2(geometry, ColorMaterial.PrintLineMatrial));\r\n }\r\n else\r\n {\r\n let line = new TLine(cirGeo, ColorMaterial.GetLineMaterial(this._Color));\r\n obj.add(line);\r\n }\r\n\r\n this.UpdateDrawObject(renderType, obj);\r\n return obj;\r\n }\r\n UpdateDrawObject(type: RenderType, obj: Object3D)\r\n {\r\n obj.children[0].scale.set(this._Radius, this._Radius, this._Radius);\r\n obj.children[0].updateMatrix();\r\n }\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material: Material)\r\n {\r\n if (type === RenderType.WireframePrint)\r\n {\r\n //TODO:打印线需要其他颜色?\r\n }\r\n else\r\n {\r\n let m = obj.children[0] as TLine;\r\n m.material = material ? material : ColorMaterial.GetLineMaterial(this._Color);\r\n return obj;\r\n }\r\n\r\n }\r\n\r\n GetDragPointCount(drag: DragPointType): number\r\n {\r\n if (drag === DragPointType.Grip)\r\n return 5;\r\n else\r\n return 1;\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n let pts = [\r\n new Vector3(),\r\n new Vector3(0, this._Radius),\r\n new Vector3(0, -this._Radius),\r\n new Vector3(-this._Radius, 0),\r\n new Vector3(this._Radius, 0),\r\n ];\r\n\r\n let ocs = this.OCS;\r\n pts.forEach(p => p.applyMatrix4(ocs));\r\n return pts;\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.Nea:\r\n {\r\n return getArcOrCirNearPts(this, pickPoint, viewXform);\r\n }\r\n case ObjectSnapMode.Cen:\r\n return [this.Center];\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))\r\n return [];\r\n let l = new Line(this.Center, lastPoint);\r\n return l.IntersectWith(this, IntersectOption.ExtendBoth);\r\n }\r\n case ObjectSnapMode.Tan:\r\n let pts = GetTanPtsOnArcOrCircle(this, lastPoint);\r\n if (pts)\r\n return pts;\r\n case ObjectSnapMode.End:\r\n {\r\n let pts = this.GetGripPoints();\r\n pts.shift();\r\n return pts;\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n\r\n let pts = this.GetGripPoints();\r\n if (indexList.length > 0)\r\n {\r\n let index = indexList[0];\r\n let p = pts[index];\r\n if (p)\r\n {\r\n if (index > 0)\r\n {\r\n p.add(vec);\r\n this.Radius = p.distanceTo(this.Center);\r\n }\r\n else\r\n {\r\n this.Center = this.Center.add(vec);\r\n }\r\n }\r\n }\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n let pts = [new Vector3()];\r\n let ocs = this.OCS;\r\n pts.forEach(p => p.applyMatrix4(ocs));\r\n return pts;\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n if (indexList.length > 0)\r\n {\r\n let mat = MoveMatrix(vec);\r\n this.ApplyMatrix(mat);\r\n }\r\n }\r\n GetFistDeriv(pt: number | Vector3)\r\n {\r\n if (typeof pt === \"number\")\r\n pt = this.GetPointAtParam(pt);\r\n else\r\n pt = pt.clone();\r\n\r\n pt.applyMatrix4(this.OCSInv);\r\n\r\n let an = angle(pt) + Math.PI * 0.5;\r\n\r\n return polar(new Vector3(), an, 1).applyMatrix4(new Matrix4().extractRotation(this.OCS));\r\n }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n pt = pt.clone().applyMatrix4(this.OCSInv).setZ(0).applyMatrix4(this.OCS);\r\n if (equaln(pt.distanceToSquared(this.Center), 0, 1e-10))\r\n return this.GetPointAtParam(0);\r\n let l = new Line(this.Center, pt);\r\n let pts = l.IntersectWith(this, IntersectOption.ExtendBoth);\r\n pts.sort((p1, p2) =>\r\n {\r\n return p1.distanceToSquared(pt) - p2.distanceToSquared(pt);\r\n });\r\n return pts[0];\r\n }\r\n //#region -------------------------File-------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n this._Radius = file.Read();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);\r\n file.Write(this._Radius);\r\n }\r\n //#endregion\r\n}\r\n","\r\n/**\r\n * 一个简单的计数器实现,本质是使用一个Map来保存元素的个数\r\n * \r\n * 例:\r\n * let count = new Count();\r\n * count.AddCount(\"Test\", 1);\r\n * count.GetCount(\"Test\");//现在 Test 的个数为1\r\n */\r\nexport class Count\r\n{\r\n private m_CountMap = new WeakMap();\r\n GetCount(obj: any): number\r\n {\r\n let count = this.m_CountMap.get(obj);\r\n if (!count)\r\n {\r\n this.m_CountMap.set(obj, 0);\r\n count = 0;\r\n }\r\n return count;\r\n }\r\n AddCount(obj: any, add: number)\r\n {\r\n this.m_CountMap.set(obj, this.GetCount(obj) + add);\r\n }\r\n}\r\n","import { Vector3, MathUtils } from \"three\";\r\nimport { YAxis, ZAxis, equaln } from \"./GeUtils\";\r\n\r\n/**\r\n * 轨道控制的数学类,观察向量和角度的互相转换\r\n * 当x当抬头或者低头到90度时,触发万向锁.\r\n */\r\nexport class Orbit\r\n{\r\n //抬头低头 正数抬头 负数低头\r\n private phi: number = 0;//Φ\r\n\r\n //身体旋转 0为正右边 逆时针旋转\r\n theta: number = 0;//θ\r\n\r\n get RoX()\r\n {\r\n return this.phi;\r\n }\r\n set RoX(v)\r\n {\r\n this.phi = MathUtils.clamp(v, Math.PI * -0.49, Math.PI * 0.49);\r\n }\r\n\r\n /**\r\n * 使用旋转角度 计算观察向量\r\n * @param [outDirection] 引用传入,如果传入,那么就不构造新的向量\r\n * @returns 返回观察向量\r\n */\r\n UpdateDirection(outDirection = new Vector3()): Vector3\r\n {\r\n outDirection.z = Math.sin(this.phi);\r\n //归一化专用.\r\n let d = Math.abs(Math.cos(this.phi));\r\n\r\n outDirection.x = Math.cos(this.theta) * d;\r\n outDirection.y = Math.sin(this.theta) * d;\r\n\r\n return outDirection;\r\n }\r\n\r\n /**\r\n * 使用观察向量,计算旋转角度\r\n * @param dir 这个向量会被修改成单位向量.\r\n */\r\n SetFromDirection(dir: Vector3): void\r\n {\r\n dir.normalize();\r\n this.phi = Math.asin(dir.z);\r\n if (equaln(dir.x, 0) && equaln(dir.y, 0))\r\n if (dir.z > 0)\r\n this.theta = Math.PI * -0.5;\r\n else\r\n this.theta = Math.PI * 0.5;\r\n else\r\n this.theta = Math.atan2(dir.y, dir.x);\r\n }\r\n\r\n /**\r\n * 参考任意轴坐标系算法.\r\n * http://help.autodesk.com/view/ACD/2017/CHS/?guid=GUID-E19E5B42-0CC7-4EBA-B29F-5E1D595149EE\r\n */\r\n static ComputUpDirection(n: Vector3, ay: Vector3 = new Vector3(), ax: Vector3 = new Vector3()): Vector3\r\n {\r\n n.normalize();\r\n if (Math.abs(n.x) < 0.015625 && Math.abs(n.y) < 0.015625)\r\n ax.crossVectors(YAxis, n);\r\n else\r\n ax.crossVectors(ZAxis, n);\r\n ay.crossVectors(n, ax);\r\n ax.normalize();\r\n ay.normalize();\r\n return ay;\r\n }\r\n}\r\n","import { Box3, Line3, Matrix3, Matrix4, Vec2, Vector2, Vector3 } from 'three';\r\nimport { Arc } from '../DatabaseServices/Entity/Arc';\r\nimport { Circle } from '../DatabaseServices/Entity/Circle';\r\nimport { Curve } from '../DatabaseServices/Entity/Curve';\r\nimport { Ellipse } from '../DatabaseServices/Entity/Ellipse';\r\nimport { Line } from '../DatabaseServices/Entity/Line';\r\nimport { Polyline } from '../DatabaseServices/Entity/Polyline';\r\nimport { IsPointInBowArc } from '../DatabaseServices/PointInPolyline';\r\nimport { Count } from '../Geometry/Count';\r\nimport { CurveMap, Vertice } from '../Geometry/CurveMap';\r\nimport { AsVector2, AsVector3, equaln, equalv2, equalv3, isParallelTo, XAxis, ZeroVec, isPerpendicularityTo, YAxis, isIntersect } from '../Geometry/GeUtils';\r\nimport { Vec3 } from '../Geometry/IVec3';\r\nimport { Orbit } from '../Geometry/Orbit';\r\nimport { PlaneExt } from '../Geometry/Plane';\r\nimport { IntersectOption, IntersectResult } from '../GraphicsSystem/IntersectWith';\r\nimport { OffsetPolyline } from '../GraphicsSystem/OffsetPolyline';\r\nimport { arrayLast, changeArrayStartIndex, equalArray } from './ArrayExt';\r\nimport { Status } from './Status';\r\nimport { FixIndex, LINK_FUZZ } from './Utils';\r\n\r\n//3点获取圆心\r\nexport function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3)\r\n{\r\n if (!(pt1 && pt2 && pt3))\r\n return;\r\n let A1 = pt1.x - pt2.x;\r\n let B1 = pt1.y - pt2.y;\r\n let C1 = (Math.pow(pt1.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt1.y, 2) - Math.pow(pt2.y, 2)) / 2;\r\n let A2 = pt3.x - pt2.x;\r\n let B2 = pt3.y - pt2.y;\r\n let C2 = (Math.pow(pt3.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt3.y, 2) - Math.pow(pt2.y, 2)) / 2;\r\n //令temp = A1*B2 - A2*B1\r\n let temp = A1 * B2 - A2 * B1;\r\n let center = new Vector3();\r\n //判断三点是否共线\r\n if (temp === 0)\r\n {\r\n //共线则将第一个点pt1作为圆心\r\n center.x = pt1.x;\r\n center.y = pt1.y;\r\n }\r\n else\r\n {\r\n //不共线则求出圆心:\r\n center.x = (C1 * B2 - C2 * B1) / temp;\r\n center.y = (A1 * C2 - A2 * C1) / temp;\r\n }\r\n\r\n return center;\r\n}\r\n\r\n// 弦长+切线获取圆心角\r\nexport function getCirAngleByChordAndTangent(chord: Vector3, tangentLine: Vector3)\r\n{\r\n let dir = tangentLine.clone().cross(chord).normalize();\r\n\r\n let ctAngle = chord.angleTo(tangentLine);\r\n\r\n // 圆心角\r\n let cirAng = Math.PI - 2 * Math.abs(ctAngle - Math.PI / 2);\r\n\r\n if (ctAngle > Math.PI / 2)\r\n {\r\n cirAng = Math.PI * 2 - cirAng;\r\n }\r\n return cirAng *= dir.z;\r\n}\r\n//行列式\r\nexport function getDeterminantFor2V(v1: Vector2, v2: Vector2): number\r\n{\r\n return v1.x * v2.y - v1.y * v2.x;\r\n}\r\n\r\nexport function getDeterminantFor3V(v1: Vector3, v2: Vector3, v3: Vector3)\r\n{\r\n let mat = new Matrix3();\r\n mat.set(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z);\r\n return mat.determinant();\r\n}\r\n\r\n/**\r\n * 曲线根据连接来分组,每组都是一条首尾相连的曲线表.\r\n *\r\n * @export\r\n * @param {Curve[]} cus 传入的分组的曲线表\r\n * @returns {Array>} 返回如下\r\n * [\r\n * [c1,c2,c3...],//后面的曲线的起点总是等于上一个曲线的终点\r\n * [c1,c2,c3...],\r\n * ]\r\n */\r\nexport function curveLinkGroup(cus: Curve[]): Array>\r\n{\r\n //返回的曲线组\r\n let groupCus = new Array>();\r\n\r\n //将封闭的曲线先提取出来\r\n cus = cus.filter(c =>\r\n {\r\n let isClose = c.IsClose;\r\n if (isClose)\r\n groupCus.push([c]);\r\n return !isClose;\r\n });\r\n if (cus.length === 0) return groupCus;\r\n //曲线节点图\r\n let cuMap = new CurveMap();\r\n cus.forEach(c => cuMap.AddCurveToMap(c));\r\n\r\n //曲线站点表\r\n let stands = cuMap.Stands;\r\n //曲线使用计数\r\n let cuCount = new Count();\r\n\r\n /**\r\n * 从站点的路线中任意取一条,加入到曲线数组中.\r\n *\r\n * @param {Curve[]} cus 已经连接的曲线列表\r\n * @param {boolean} isEndSeach true:从终点搜索,false:从起点搜索\r\n * @returns {Stand} 如果站点中存在可以取得的曲线,返回下个站点,否则返回undefined\r\n */\r\n function linkCurve(stand: Vertice, cus: Curve[], isEndSeach: boolean): Vertice | undefined\r\n {\r\n for (let route of stand.routes)\r\n {\r\n let cu = route.curve;\r\n if (cuCount.GetCount(cu) === 0)\r\n {\r\n if (isEndSeach)\r\n {\r\n //保证曲线总是从起点连接到终点\r\n if (!equalv3(cu.StartPoint, stand.position))\r\n cu.Reverse();\r\n cus.push(cu);\r\n }\r\n else\r\n {\r\n //保证曲线总是从起点连接到终点\r\n if (!equalv3(cu.EndPoint, stand.position))\r\n cu.Reverse();\r\n cus.unshift(cu);\r\n }\r\n\r\n cuCount.AddCount(cu, 1);\r\n return route.to;\r\n }\r\n }\r\n }\r\n\r\n for (let stand of stands)\r\n {\r\n let startStand = stand;\r\n let cus: Curve[] = []; //形成合并轮廓的曲线组\r\n while (startStand)\r\n startStand = linkCurve(startStand, cus, true);\r\n\r\n if (cus.length > 0)\r\n {\r\n startStand = cuMap.GetOnlyVertice(cus[0].StartPoint);\r\n while (startStand)\r\n startStand = linkCurve(startStand, cus, false);\r\n }\r\n\r\n if (cus.length > 0)\r\n groupCus.push(cus);\r\n }\r\n\r\n return groupCus;\r\n}\r\n\r\nexport function equalCurve(cu1: Curve, cu2: Curve, tolerance = 1e-4)\r\n{\r\n if ((cu1 instanceof Polyline) && (cu2 instanceof Polyline))\r\n {\r\n if (cu1.IsClose !== cu2.IsClose || !isParallelTo(cu1.Normal, cu2.Normal))\r\n return false;\r\n\r\n let area1 = cu1.Area2;\r\n let area2 = cu2.Area2;\r\n\r\n if (!equaln(Math.abs(area1), Math.abs(area2), 0.1))\r\n return false;\r\n\r\n let ptsBuls1 = cu1.PtsBuls;\r\n let ptsBuls2 = cu2.PtsBuls;\r\n\r\n let pts1 = ptsBuls1.pts;\r\n let pts2 = ptsBuls2.pts;\r\n let buls1 = ptsBuls1.buls;\r\n let buls2 = ptsBuls2.buls;\r\n\r\n let isEqualArea = equaln(area1, area2, 0.1);\r\n if (!equalv3(cu1.Normal, cu2.Normal))\r\n {\r\n if (isEqualArea)\r\n {\r\n pts2.reverse();\r\n buls2.reverse();\r\n buls2.push(buls2.shift());\r\n }\r\n else\r\n buls2 = buls2.map(bul => -bul);\r\n }\r\n else if (!isEqualArea)\r\n {\r\n pts2.reverse();\r\n buls2.reverse();\r\n buls2 = buls2.map(bul => -bul);\r\n buls2.push(buls2.shift());\r\n }\r\n\r\n if (cu1.IsClose && equalv2(pts1[0], arrayLast(pts1), tolerance))\r\n {\r\n pts1.pop();\r\n buls1.pop();\r\n }\r\n if (cu2.IsClose && equalv2(pts2[0], arrayLast(pts2), tolerance))\r\n {\r\n pts2.pop();\r\n buls2.pop();\r\n }\r\n\r\n let cu1Sp = AsVector2(cu1.StartPoint.applyMatrix4(cu2.OCSInv));\r\n\r\n let index = pts2.findIndex(p => equalv2(cu1Sp, p, tolerance));\r\n changeArrayStartIndex(buls2, index);\r\n changeArrayStartIndex(pts2, index);\r\n\r\n return equalArray(buls1, buls2, equaln) &&\r\n equalArray(pts1, pts2, (p1: Vector2, p2: Vector2) =>\r\n equalv3(\r\n AsVector3(p1).applyMatrix4(cu1.OCS),\r\n AsVector3(p2).applyMatrix4(cu2.OCS),\r\n tolerance\r\n )\r\n );\r\n }\r\n else if (cu1 instanceof Circle && cu2 instanceof Circle)\r\n {\r\n return equalv3(cu1.Center, cu2.Center) && equaln(cu1.Radius, cu2.Radius, 1e-6);\r\n }\r\n else if (cu1 instanceof Arc && cu2 instanceof Arc)\r\n {\r\n if (!equalv3(cu1.StartPoint, cu2.EndPoint)) cu1.Reverse();\r\n return equalv3(cu1.Center, cu2.Center)\r\n && equaln(cu1.Radius, cu2.Radius, 1e-6)\r\n && equaln(cu1.StartAngle, cu2.StartAngle)\r\n && equaln(cu1.EndAngle, cu2.EndAngle);\r\n }\r\n else if (cu1 instanceof Ellipse && cu2 instanceof Ellipse)\r\n {\r\n return equalv3(cu1.Center, cu2.Center)\r\n && equaln(cu1.RadX, cu2.RadX)\r\n && equaln(cu1.RadY, cu2.RadY)\r\n && equalv3(cu1.StartPoint, cu2.StartPoint);\r\n }\r\n else if (cu1 instanceof Line && cu2 instanceof Line)\r\n {\r\n let ps1 = [cu1.StartPoint, cu1.EndPoint];\r\n let ps2 = [cu2.StartPoint, cu2.EndPoint];\r\n return ps1.every(p => ps2.some(p1 => equalv3(p1, p)));\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n* 计算点在曲线前进方向的方位,左边或者右边\r\n*\r\n* @param {Curve} cu\r\n* @param {Vector3} pt\r\n* @returns {boolean} 左边为-1,右边为1\r\n*/\r\nexport function GetPointAtCurveDir(cu: Curve, pt: Vector3): number\r\n{\r\n if (cu instanceof Circle)\r\n return cu.PtInCurve(pt) ? -1 : 1;\r\n else if (cu instanceof Polyline)\r\n {\r\n let u = new OffsetPolyline(cu, 1);\r\n u.InitSubCurves();\r\n return u.GetPointAtCurveDir(pt.clone().applyMatrix4(cu.OCSInv).setZ(0));\r\n }\r\n //最近点\r\n let cp = cu.GetClosestPointTo(pt, false);\r\n if (equalv3(cp, pt, 1e-6)) return 0;\r\n //最近点参数\r\n let cparam = cu.GetParamAtPoint(cp);\r\n let dri = cu.GetFistDeriv(cparam);\r\n let cross = dri.cross(pt.clone().sub(cp)).applyMatrix4(cu.OCSInv);\r\n return -Math.sign(cross.z);\r\n}\r\n\r\n/**\r\n * 点在多段线的某个索引的圆弧(弓形)内\r\n *\r\n * @param {Polyline} pl\r\n * @param {number} index\r\n * @param {Vector3} pt\r\n * @returns {number}\r\n */\r\nfunction PointInPolylineArc(pl: Polyline, index: number, pt: Vector3): number\r\n{\r\n let bul = pl.GetBuilgeAt(index);\r\n if (equaln(bul, 0, 1e-8)) return 0;\r\n\r\n let arc = pl.GetCurveAtIndex(index) as Arc;\r\n\r\n if (IsPointInBowArc(arc, pt, true))\r\n return Math.sign(bul);\r\n\r\n return 0;\r\n}\r\n\r\nexport function ConverCircleToPolyline(cir: Circle): Polyline\r\n{\r\n //该写法不支持三维坐标系\r\n // let pl = new Polyline();\r\n // let bul = Math.tan(Math.PI * 0.125);\r\n // for (let i = 0; i < 4; i++)\r\n // {\r\n // let p = cir.GetPointAtParam(i * 0.25);\r\n // pl.AddVertexAt(i, Vec3DTo2D(p));\r\n // pl.SetBulgeAt(i, bul);\r\n // }\r\n // pl.CloseMark = true;\r\n // return pl;\r\n\r\n let arcs = cir.GetSplitCurves([0, 0.5]);\r\n let pl = new Polyline();\r\n pl.OCS = cir.OCS;\r\n pl.Join(arcs[0]);\r\n pl.Join(arcs[1]);\r\n return pl;\r\n}\r\n\r\nexport function GetTanPtsOnArcOrCircle(cu: Arc | Circle, lastPoint?: Vector3)\r\n{\r\n if (lastPoint)\r\n {\r\n //ref:wykobi\r\n let ocsInv = cu.OCSInv;\r\n let v = lastPoint.clone().applyMatrix4(ocsInv);\r\n\r\n let lengthSq = v.lengthSq();\r\n let radiusSq = cu.Radius ** 2;\r\n\r\n if (lengthSq >= radiusSq)\r\n {\r\n let ratio = 1 / lengthSq;\r\n let deltaDist = Math.sqrt(lengthSq - radiusSq);\r\n\r\n let pts = [\r\n new Vector3(\r\n cu.Radius * (cu.Radius * v.x - v.y * deltaDist) * ratio,\r\n cu.Radius * (cu.Radius * v.y + v.x * deltaDist) * ratio,\r\n ),\r\n new Vector3(\r\n cu.Radius * (cu.Radius * v.x + v.y * deltaDist) * ratio,\r\n cu.Radius * (cu.Radius * v.y - v.x * deltaDist) * ratio,\r\n ),\r\n ];\r\n for (let p of pts)\r\n p.applyMatrix4(cu.OCS);\r\n return pts;\r\n }\r\n }\r\n}\r\n\r\nexport function CircleInternalTangentLines(cir0: Circle, cir1: Circle): Line[]\r\n{\r\n let c0 = new Vector3();\r\n let c1 = cir1.Center.applyMatrix4(cir0.OCSInv);\r\n\r\n let dist = c0.distanceTo(c1);\r\n\r\n if (dist - (cir0.Radius + cir1.Radius) < 0)\r\n return [];\r\n else if (equaln(dist - (cir0.Radius + cir1.Radius), 0))\r\n return [];\r\n else\r\n {\r\n let m = cir0.Radius / cir1.Radius;\r\n let h0 = (m * dist) / (m + 1);\r\n let h1 = dist / (m + 1);\r\n\r\n let i = new Vector3(\r\n (h1 * c0.x + h0 * c1.x) / dist,\r\n (h1 * c0.y + h0 * c1.y) / dist\r\n ).applyMatrix4(cir0.OCS);\r\n\r\n let [c0p0, c0p1] = GetTanPtsOnArcOrCircle(cir0, i);\r\n let [c1p0, c1p1] = GetTanPtsOnArcOrCircle(cir1, i);\r\n\r\n return [\r\n new Line(c0p0, c1p0),\r\n new Line(c0p1, c1p1),\r\n ];\r\n }\r\n}\r\n\r\nexport function CircleOuterTangentLines(circle0: Circle, circle1: Circle): Line[]\r\n{\r\n let c0 = circle0.Center;\r\n let c1 = circle1.Center;\r\n\r\n let dist = c0.distanceTo(c1);\r\n\r\n let rd = Math.abs(circle0.Radius - circle1.Radius);\r\n if (dist < rd)\r\n return [];\r\n else if (equaln(Math.abs(dist - rd), 0))\r\n return [];\r\n else if (equaln(circle0.Radius, circle1.Radius))\r\n {\r\n let cp = circle0.GetClosestPointTo(c1, true);\r\n let derv = circle0.GetFistDeriv(cp).multiplyScalar(circle0.Radius);\r\n let dervn = derv.clone().negate();\r\n\r\n let c0p0 = c0.clone().add(derv);\r\n let c0p1 = c0.clone().add(dervn);\r\n\r\n let c1p0 = c1.clone().add(derv);\r\n let c1p1 = c1.clone().add(dervn);\r\n\r\n return [\r\n new Line(c0p0, c1p0),\r\n new Line(c0p1, c1p1),\r\n ];\r\n }\r\n else\r\n {\r\n let c0 = new Vector3();\r\n let c1 = circle1.Center.applyMatrix4(circle0.OCSInv);\r\n\r\n let p: Vector3;\r\n if (circle0.Radius > circle1.Radius)\r\n p = new Vector3(\r\n c1.x * circle0.Radius - c0.x * circle1.Radius,\r\n c1.y * circle0.Radius - c0.y * circle1.Radius\r\n );\r\n else\r\n p = new Vector3(\r\n c0.x * circle1.Radius - c1.x * circle0.Radius,\r\n c0.y * circle1.Radius - c1.y * circle0.Radius\r\n );\r\n\r\n let diff = Math.abs(circle0.Radius - circle1.Radius);\r\n\r\n p.x /= diff;\r\n p.y /= diff;\r\n\r\n p.applyMatrix4(circle0.OCS);\r\n\r\n let [c0p0, c0p1] = GetTanPtsOnArcOrCircle(circle0, p);\r\n let [c1p0, c1p1] = GetTanPtsOnArcOrCircle(circle1, p);\r\n\r\n return [\r\n new Line(c0p0, c1p0),\r\n new Line(c0p1, c1p1),\r\n ];\r\n }\r\n}\r\n\r\nexport function getArcOrCirNearPts(cu: Circle | Arc | Ellipse, pickPoint: Vector3, viewXform: Matrix3)\r\n{\r\n let viewNormal = new Vector3().fromArray(viewXform.elements, 2 * 3);\r\n\r\n let plane = new PlaneExt(cu.Normal, cu.Center);\r\n\r\n let pickLocal = plane.intersectLine(new Line3(pickPoint, pickPoint.clone().add(viewNormal)), new Vector3(), true);\r\n\r\n if (pickLocal)\r\n {\r\n let x = new Vector3().fromArray(viewXform.elements, 0).add(pickLocal);\r\n let y = new Vector3().fromArray(viewXform.elements, 3).add(pickLocal);\r\n\r\n x = plane.intersectLine(new Line3(x, x.clone().add(viewNormal)), new Vector3(), true);\r\n y = plane.intersectLine(new Line3(y, y.clone().add(viewNormal)), new Vector3(), true);\r\n\r\n let lx = new Line(pickLocal, x);\r\n let ly = new Line(pickLocal, y);\r\n\r\n let ins = cu.IntersectWith(lx, IntersectOption.ExtendBoth);\r\n ins.push(...cu.IntersectWith(ly, IntersectOption.ExtendBoth));\r\n return ins;\r\n }\r\n else\r\n {\r\n let ptLocal = plane.projectPoint(pickPoint, new Vector3());\r\n let lz = new Line(ptLocal, ptLocal.clone().add(viewNormal));\r\n return cu.IntersectWith(lz, IntersectOption.ExtendBoth);\r\n }\r\n}\r\n\r\nexport function getTanPtsOnEllipse(cu: Ellipse, lastPoint: Vector3)\r\n{\r\n return [];\r\n}\r\n\r\nexport function IsRect(cu: Curve): { isRect: boolean, size?: Vector3, box?: Box3, OCS?: Matrix4; }\r\n{\r\n if (cu instanceof Polyline)\r\n {\r\n if (!cu.IsClose) return { isRect: false };\r\n\r\n let pts = cu.GetStretchPoints();\r\n\r\n if (pts.length < 4) return { isRect: false };\r\n\r\n let xVec: Vector3;\r\n let p1 = pts[0];\r\n for (let i = 1; i < pts.length; i++)\r\n {\r\n xVec = pts[i].clone().sub(p1).normalize();\r\n if (!equalv3(xVec, ZeroVec))\r\n break;\r\n }\r\n\r\n if (!xVec) return { isRect: false };\r\n\r\n let zVec = cu.Normal;\r\n let yVec = zVec.clone().cross(xVec).normalize();\r\n\r\n let rectOCS = new Matrix4().makeBasis(xVec, yVec, zVec);\r\n let rectOCSInv = new Matrix4().getInverse(rectOCS);\r\n\r\n for (let p of pts)\r\n p.applyMatrix4(rectOCSInv);\r\n\r\n let box = new Box3().setFromPoints(pts);\r\n\r\n let size = box.getSize(new Vector3);\r\n if (equaln(size.x * size.y, cu.Area, 0.1))\r\n {\r\n return {\r\n isRect: true,\r\n size,\r\n box,\r\n OCS: rectOCS,\r\n };\r\n }\r\n }\r\n return { isRect: false };\r\n}\r\n\r\n/**用4个矩形点构造矩形 */\r\nexport function getRectFrom4Pts(pts: Vector3[])\r\n{\r\n if (pts.length !== 4) return;\r\n let p = pts.shift();\r\n pts.sort((p1, p2) => p.distanceTo(p1) - p.distanceTo(p2));\r\n pts.splice(1, 0, p);\r\n let lineData = pts.map(p =>\r\n {\r\n return {\r\n pt: new Vector2(p.x, p.y),\r\n bul: 0\r\n };\r\n });\r\n let l = new Polyline(lineData);\r\n l.CloseMark = true;\r\n return l;\r\n}\r\n\r\nexport function MergeCurvelist(cus: Curve[])\r\n{\r\n for (let i = 0; i < cus.length; i++)\r\n {\r\n let c1 = cus[i];\r\n let nextI = FixIndex(i + 1, cus);\r\n let c2 = cus[nextI];\r\n\r\n\r\n let status = equaln(c2.Length, 0, LINK_FUZZ) ? Status.True : c1.Join(c2, false, LINK_FUZZ);\r\n if (status === Status.True)\r\n {\r\n cus.splice(nextI, 1);\r\n i--;\r\n }\r\n else if (status === Status.ConverToCircle)\r\n {\r\n cus.length = 0;\r\n let a = c1 as Arc;\r\n cus.push(new Circle(a.Center, a.Radius));\r\n break;\r\n }\r\n }\r\n return cus;\r\n}\r\n\r\nexport function SwapParam(res: IntersectResult[]): IntersectResult[]\r\n{\r\n for (let r of res)\r\n [r.thisParam, r.argParam] = [r.argParam, r.thisParam];\r\n return res;\r\n}\r\n\r\nexport function ComputerCurvesNormalOCS(curves: Curve[], allowAutoCalc: boolean = true): Matrix4 | undefined\r\n{\r\n if (!curves || curves.length === 0) return;\r\n\r\n //准备计算多段线的法向量\r\n let normal: Vector3;\r\n let firstV: Vector3;\r\n for (let c of curves)\r\n {\r\n if (c instanceof Arc)\r\n {\r\n normal = c.Normal;\r\n break;\r\n }\r\n else if (firstV)\r\n {\r\n let v = c.GetFistDeriv(0);\r\n v.cross(firstV);\r\n if (!equalv3(v, ZeroVec))\r\n {\r\n normal = v.normalize();\r\n break;\r\n }\r\n }\r\n else\r\n {\r\n let cus = c.Explode() as Curve[];\r\n let ocs = ComputerCurvesNormalOCS(cus, false);\r\n if (ocs)\r\n return ocs;\r\n firstV = c.GetFistDeriv(0);\r\n }\r\n }\r\n\r\n if (!normal && !allowAutoCalc) return;\r\n\r\n let x = new Vector3();\r\n let y = new Vector3();\r\n if (!normal)\r\n {\r\n normal = firstV.normalize();\r\n Orbit.ComputUpDirection(normal, y, x);\r\n [x, y, normal] = [normal, x, y];\r\n }\r\n else\r\n {\r\n if (equalv3(normal, curves[0].Normal.negate()))\r\n normal.negate();\r\n Orbit.ComputUpDirection(normal, y, x);\r\n }\r\n return new Matrix4().makeBasis(x, y, normal).setPosition(curves[0].StartPoint);\r\n}\r\n\r\n\r\nexport function Pts2Polyline(pts: (Vec3 | Vec2)[], isClose: boolean): Polyline\r\n{\r\n let pl = new Polyline();\r\n for (let i = 0; i < pts.length; i += 2)\r\n {\r\n let p1 = AsVector3(pts[i]);\r\n let arc: Arc | Line;\r\n let p2: Vector3;\r\n let p3: Vector3;\r\n\r\n if (isClose)\r\n {\r\n p2 = AsVector3(pts[FixIndex(i + 1, pts.length)]);\r\n p3 = AsVector3(pts[FixIndex(i + 2, pts.length)]);\r\n }\r\n else\r\n {\r\n if (i >= pts.length - 2) break;\r\n p2 = AsVector3(pts[i + 1]);\r\n p3 = AsVector3(pts[i + 2]);\r\n }\r\n let v1 = p1.clone().sub(p2);\r\n let v2 = p2.clone().sub(p3);\r\n\r\n if (equaln(v1.angleTo(v2), 0))\r\n arc = new Line(p1, p3);\r\n else\r\n arc = new Arc().FromThreePoint(p1, p2, p3);\r\n pl.Join(arc);\r\n }\r\n return pl;\r\n}\r\n\r\n/**获取矩形信息 */\r\nexport function GetRectData(cu: Curve): { isRect: boolean, size?: Vector3, box?: Box3, OCS?: Matrix4; }\r\n{\r\n if (cu instanceof Polyline)\r\n {\r\n if (!cu.IsClose) return { isRect: false };\r\n\r\n let pts = cu.GetStretchPoints();\r\n if (cu.Area2 < 0)\r\n pts.reverse();\r\n\r\n if (equalv3(pts[0], arrayLast(pts)))\r\n pts.pop();\r\n\r\n if (pts.length < 4) return { isRect: false };\r\n\r\n let xVec: Vector3;\r\n let p1 = pts[0];\r\n\r\n let originIndex = 0;\r\n\r\n for (let i = 1; i < pts.length; i++)\r\n {\r\n if (pts[i].y < p1.y)\r\n {\r\n p1 = pts[i];\r\n originIndex = i;\r\n }\r\n else if (equaln(pts[i].y, p1.y))\r\n {\r\n if (pts[i].x < p1.x)\r\n {\r\n p1 = pts[i];\r\n originIndex = i;\r\n }\r\n }\r\n }\r\n\r\n let tempPts = pts.splice(0, originIndex);\r\n pts.push(...tempPts);\r\n\r\n p1 = pts[0];\r\n\r\n\r\n for (let i = 1; i < pts.length; i++)\r\n {\r\n let v = pts[i].clone().sub(p1);\r\n if (equalv3(v, ZeroVec))\r\n continue;\r\n if (!xVec)\r\n xVec = v;\r\n else\r\n {\r\n if (isParallelTo(v, xVec))\r\n xVec.copy(v);\r\n else\r\n break;\r\n }\r\n }\r\n\r\n let yVec: Vector3;\r\n\r\n for (let i = pts.length - 1; i > 0; i--)\r\n {\r\n let v = pts[i].clone().sub(p1);\r\n if (equalv3(v, ZeroVec))\r\n continue;\r\n if (!yVec)\r\n yVec = v;\r\n else\r\n {\r\n if (isParallelTo(v, yVec))\r\n yVec.copy(v);\r\n else\r\n break;\r\n }\r\n }\r\n\r\n if (!xVec || !yVec) return { isRect: false };\r\n\r\n //2向量必须垂直\r\n if (!isPerpendicularityTo(xVec.clone().normalize(), yVec.clone().normalize()))\r\n return { isRect: false };\r\n\r\n if (yVec.length() > xVec.length())\r\n [xVec, yVec] = [yVec.negate(), xVec];\r\n\r\n if (xVec.angleTo(XAxis) > Math.PI / 4)\r\n [xVec, yVec] = [yVec.negate(), xVec];\r\n\r\n\r\n let rectOCS = new Matrix4().makeBasis(xVec.normalize(), yVec.normalize(), xVec.clone().cross(yVec));\r\n let rectOCSInv = new Matrix4().getInverse(rectOCS);\r\n\r\n for (let p of pts)\r\n p.applyMatrix4(rectOCSInv);\r\n\r\n let box = new Box3().setFromPoints(pts);\r\n\r\n let size = box.getSize(new Vector3);\r\n if (equaln(size.x * size.y, cu.Area, 0.1))\r\n {\r\n return {\r\n isRect: true,\r\n size,\r\n box,\r\n OCS: rectOCS,\r\n };\r\n }\r\n }\r\n return { isRect: false };\r\n}\r\n\r\nconst PolylineSpliteRectFuzz = 1e-3;\r\n/**封闭多段线 分割成矩形 */\r\nexport function PolylineSpliteRect(outline: Polyline): Polyline[]\r\n{\r\n if (!outline.IsClose || IsRect(outline).isRect)\r\n return [outline];\r\n\r\n let firstDerv = outline.GetFistDeriv(0).normalize();\r\n if (!isParallelTo(firstDerv, XAxis, PolylineSpliteRectFuzz) && !isParallelTo(firstDerv, YAxis, PolylineSpliteRectFuzz)) return [outline];\r\n\r\n let cus = outline.Explode();\r\n let yCus: Curve[] = [];\r\n\r\n for (let c of cus)\r\n {\r\n if (c instanceof Arc) return [outline];\r\n let derv = c.GetFistDeriv(0).normalize();\r\n if (isParallelTo(derv, YAxis, PolylineSpliteRectFuzz))\r\n yCus.push(c);\r\n else\r\n if (!isParallelTo(derv, XAxis, PolylineSpliteRectFuzz))\r\n {\r\n return [outline];\r\n }\r\n }\r\n\r\n yCus.sort((c1, c2) => c1.StartPoint.x - c2.StartPoint.x);\r\n\r\n\r\n let rects: Polyline[] = [];\r\n\r\n for (let i = 0; i < yCus.length - 1; i++)\r\n {\r\n let c1 = yCus[i];\r\n let c2 = yCus[i + 1];\r\n\r\n let x1 = c1.StartPoint.x;\r\n let x2 = c2.StartPoint.x;\r\n if (equaln(x1, x2))\r\n continue;\r\n\r\n let y1: number;\r\n let y2: number;\r\n\r\n let res = c1.IntersectWith2(outline, IntersectOption.ExtendThis);\r\n\r\n let res2 = c2.IntersectWith2(outline, IntersectOption.ExtendThis);\r\n let pars = [...res.map(r => Math.floor(r.argParam)), ...res2.map(r => Math.floor(r.argParam))];\r\n pars = [...new Set(pars)];\r\n pars.sort((a, b) => a - b);\r\n\r\n let ys: number[] = [];\r\n for (let par of pars)\r\n {\r\n let c = outline.GetCurveAtParam(par);\r\n let derv = c.GetFistDeriv(0).normalize();\r\n if (isParallelTo(derv, XAxis, PolylineSpliteRectFuzz))\r\n {\r\n let x3 = c.StartPoint.x;\r\n let x4 = c.EndPoint.x;\r\n if (x3 > x4)\r\n [x3, x4] = [x4, x3];\r\n if (isIntersect(x1, x2, x3, x4, -PolylineSpliteRectFuzz))\r\n ys.push(c.StartPoint.y);\r\n }\r\n }\r\n\r\n if (ys.length < 2) return [outline];\r\n\r\n ys.sort((a, b) => a - b);\r\n\r\n y1 = ys[0];\r\n y2 = arrayLast(ys);\r\n\r\n rects.push(new Polyline().RectangleFrom2Pt(new Vector3(x1, y1), new Vector3(x2, y2)));\r\n }\r\n\r\n return rects;\r\n\r\n}\r\n","import { Box3, BufferGeometry, Line as TLine, Matrix3, Matrix4, Object3D, Shape, Vector2, Vector3 } from 'three';\r\nimport { Line2 } from 'three/examples/jsm/lines/Line2';\r\nimport { LineGeometry } from 'three/examples/jsm/lines/LineGeometry';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { getArcOrCirNearPts, getCircleCenter, GetTanPtsOnArcOrCircle } from '../../Common/CurveUtils';\r\nimport { matrixSetVector, reviseMirrorMatrix } from '../../Common/Matrix4Utils';\r\nimport { Status } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';\r\nimport { angle, AsVector3, clampRad, equaln, equalv3, midPoint, MoveMatrix, polar } from '../../Geometry/GeUtils';\r\nimport { IntersectArcAndArc, IntersectCircleAndArc, IntersectEllipseAndCircleOrArc, IntersectLineAndArc, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { SwapParam } from './../../Common/CurveUtils';\r\nimport { Circle } from './Circle';\r\nimport { Curve } from './Curve';\r\nimport { Ellipse } from './Ellipse';\r\nimport { Line } from './Line';\r\nimport { Polyline } from './Polyline';\r\n\r\n/**\r\n * 圆弧实体类\r\n * 与ACAD不同,这个类加入了时针变量,并且默认构造的圆弧为顺时针圆弧.\r\n *\r\n * 关于时针圆弧:\r\n * 起始圆弧到终止圆弧总是在0-2PI之间.(一个完整的圆).\r\n * 圆弧的绘制从起始圆弧绘制到终止圆弧. 按照时针绘制.\r\n * 参考计算圆弧的完整角度方法查看该计算方式.\r\n */\r\n@Factory\r\nexport class Arc extends Curve\r\n{\r\n constructor(center: Vector3 = new Vector3(), radius: number = 0.1, startAngle: number = 0.1, endAngle: number = 0, clockwise = true)\r\n {\r\n super();\r\n this._Matrix.setPosition(center);\r\n this._Radius = radius;\r\n this._StartAngle = clampRad(startAngle);\r\n this._EndAngle = clampRad(endAngle);\r\n this._Clockwise = clockwise;\r\n }\r\n private _Radius: number;\r\n private _StartAngle: number;\r\n private _EndAngle: number;\r\n /**\r\n * 曲线为顺时针\r\n */\r\n private _Clockwise = true;\r\n\r\n get Shape()\r\n {\r\n let sp = new Shape();\r\n sp.absarc(0, 0, this._Radius, this._StartAngle, this._EndAngle, this._Clockwise);\r\n return sp;\r\n }\r\n\r\n get Center()\r\n {\r\n return this.Position;\r\n }\r\n set Center(v: Vector3)\r\n {\r\n this.Position = v;\r\n }\r\n\r\n get Normal()\r\n {\r\n return new Vector3().setFromMatrixColumn(this._Matrix, 2);\r\n }\r\n set Normal(v: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n matrixSetVector(this._Matrix, 2, v);\r\n this.Update();\r\n }\r\n\r\n get Area(): number\r\n {\r\n return 0.5 * this.AllAngle * this.Radius * this.Radius;\r\n }\r\n //获得曲线的面积,逆时针为正,顺时针为负.\r\n get Area2(): number\r\n {\r\n let clockwise = this._Clockwise ? -1 : 1;\r\n return 0.5 * this.AllAngle * this.Radius * this.Radius * clockwise;\r\n }\r\n get IsClose(): boolean\r\n {\r\n return false;\r\n }\r\n\r\n get BoundingBox(): Box3\r\n {\r\n let pts = [this.StartPoint, this.EndPoint];\r\n\r\n //TODO:考虑三维圆弧.\r\n let addPts = [\r\n this.Center.add(new Vector3(this._Radius, 0)),\r\n this.Center.add(new Vector3(0, this._Radius)),\r\n this.Center.add(new Vector3(-this._Radius, 0)),\r\n this.Center.add(new Vector3(0, -this._Radius)),\r\n ];\r\n addPts.forEach(p =>\r\n {\r\n if (this.PtOnCurve(p))\r\n pts.push(p);\r\n });\r\n return new Box3().setFromPoints(pts);\r\n }\r\n\r\n get Radius()\r\n {\r\n return this._Radius;\r\n }\r\n set Radius(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Radius = v <= 0 ? 1e-19 : v;\r\n this.Update();\r\n }\r\n\r\n get IsClockWise()\r\n {\r\n return this._Clockwise;\r\n }\r\n set IsClockWise(v: boolean)\r\n {\r\n if (v !== this._Clockwise)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Clockwise = v;\r\n this.Update();\r\n }\r\n }\r\n\r\n get StartAngle()\r\n {\r\n return this._StartAngle;\r\n }\r\n set StartAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._StartAngle = v;\r\n this.Update();\r\n }\r\n\r\n get EndAngle()\r\n {\r\n return this._EndAngle;\r\n }\r\n set EndAngle(v: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._EndAngle = v;\r\n this.Update();\r\n }\r\n\r\n //******************** Curve function start*****************//\r\n get StartPoint()\r\n {\r\n return polar(new Vector3(), this._StartAngle, this._Radius).applyMatrix4(this.OCS);\r\n }\r\n set StartPoint(v: Vector3)\r\n {\r\n let vTemp = v.clone().applyMatrix4(this.OCSInv);\r\n this.StartAngle = angle(vTemp);\r\n }\r\n get EndPoint()\r\n {\r\n return polar(new Vector3(), this._EndAngle, this._Radius).applyMatrix4(this.OCS);\r\n }\r\n set EndPoint(v: Vector3)\r\n {\r\n let vTemp = v.clone().applyMatrix4(this.OCSInv);\r\n this.EndAngle = angle(vTemp);\r\n }\r\n get StartParam()\r\n {\r\n return 0;\r\n }\r\n get EndParam()\r\n {\r\n return 1;\r\n }\r\n get Length()\r\n {\r\n return this.AllAngle * this._Radius;\r\n }\r\n\r\n GetParamAtPoint2(pt: Vector3): number\r\n {\r\n return this.GetParamAtAngle(this.GetAngleAtPoint(pt));\r\n }\r\n //点在曲线上,已经确定点在曲线的延伸线上\r\n PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean\r\n {\r\n let param = this.GetParamAtPoint2(p);\r\n return this.ParamOnCurve(param, fuzz);\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this.Center = this.Center.applyMatrix4(m);\r\n this.Radius = this.Radius * m.getMaxScaleOnAxis();\r\n return this;\r\n }\r\n protected ApplyMirrorMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n\r\n let sp = this.StartPoint;\r\n let ep = this.EndPoint;\r\n\r\n reviseMirrorMatrix(this._Matrix);\r\n\r\n this._Clockwise = !this._Clockwise;\r\n this.StartPoint = sp;\r\n this.EndPoint = ep;\r\n return this;\r\n }\r\n GetPointAtParam(param: number)\r\n {\r\n let an = this.GetAngleAtParam(param);\r\n return polar(new Vector3(), an, this._Radius).applyMatrix4(this.OCS);\r\n }\r\n GetPointAtDistance(distance: number)\r\n {\r\n let len = this.Length;\r\n if (len == 0) return;\r\n return this.GetPointAtParam(distance / len);\r\n }\r\n\r\n GetDistAtParam(param: number)\r\n {\r\n return Math.abs(param * this.Length);\r\n }\r\n\r\n GetDistAtPoint(pt: Vector3)\r\n {\r\n let param = this.GetParamAtPoint(pt);\r\n return this.GetDistAtParam(param);\r\n }\r\n\r\n GetParamAtPoint(pt: Vector3)\r\n {\r\n if (this._Radius == 0 ||\r\n this.AllAngle == 0 ||\r\n !equaln(pt.distanceTo(this.Center), this._Radius, 1e-6))\r\n return NaN;\r\n\r\n return this.GetParamAtAngle(this.GetAngleAtPoint(pt));\r\n }\r\n\r\n /**\r\n * 利用角度计算该角度在圆弧中代表的参数.\r\n * 如果角度在圆弧内,那么返回0-1\r\n * 如果角度不在圆弧内,那么尝试返回离圆弧起始或者结束的较近的参数\r\n *\r\n * @param {number} an\r\n * @returns\r\n * @memberof Arc\r\n */\r\n GetParamAtAngle(an: number)\r\n {\r\n //如果以pt为终点,那么所有的角度为\r\n let ptAllAn = this.ComputeAnlge(an);\r\n let allAn = this.AllAngle;\r\n\r\n //减去圆弧角度,剩余角度的一半\r\n let surplusAngleHalf = Math.PI - allAn / 2;\r\n\r\n if (ptAllAn > allAn + surplusAngleHalf)//返回负数\r\n return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;\r\n else//返回正数\r\n return ptAllAn / allAn;\r\n }\r\n\r\n /**\r\n * 根据角度获得参数,不过在这里我们可以指定我们是要获取前面的参数还是后面的参数(正负)\r\n * @param an\r\n * @param [isStart] true:返回负数,false 返回正数\r\n * @returns\r\n */\r\n GetParamAtAngle2(an: number, isStart = true)\r\n {\r\n //如果以pt为终点,那么所有的角度为\r\n let ptAllAn = this.ComputeAnlge(an);\r\n let allAn = this.AllAngle;\r\n\r\n //减去圆弧角度,剩余角度的一半\r\n let surplusAngleHalf = Math.PI - allAn / 2;\r\n\r\n if (isStart)//返回负数\r\n return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn;\r\n else//返回正数\r\n return ptAllAn / allAn;\r\n }\r\n\r\n GetAngleAtPoint(pt: Vector3)\r\n {\r\n let ptTmp = pt.clone().applyMatrix4(this.OCSInv);\r\n return angle(ptTmp);\r\n }\r\n\r\n GetAngleAtParam(param: number)\r\n {\r\n return clampRad(this._StartAngle + param * this.AllAngle * (this._Clockwise ? -1 : 1));\r\n }\r\n\r\n GetSplitCurves(param: number[] | number): Arc[]\r\n {\r\n let params = this.SplitParamSort(param);\r\n //角度列表\r\n let ans = params.map(p => this.GetAngleAtParam(p));\r\n //返回圆弧表\r\n let arcs: Arc[] = [];\r\n for (let i = 0; i < ans.length - 1; i++)\r\n {\r\n let arc = this.Clone() as Arc;\r\n arc.StartAngle = ans[i];\r\n arc.EndAngle = ans[i + 1];\r\n arcs.push(arc);\r\n }\r\n return arcs;\r\n }\r\n GetOffsetCurves(offsetDist: number)\r\n {\r\n if (this._Clockwise) offsetDist *= -1;\r\n if ((offsetDist + this._Radius) > 0)\r\n {\r\n let arc = this.Clone() as Arc;\r\n arc.Radius = offsetDist + this._Radius;\r\n return [arc];\r\n }\r\n return [];\r\n }\r\n Extend(newParam: number)\r\n {\r\n this.WriteAllObjectRecord();\r\n if (newParam < 0)\r\n {\r\n this._StartAngle = this.GetAngleAtParam(newParam);\r\n }\r\n else if (newParam > 1)\r\n {\r\n this._EndAngle = this.GetAngleAtParam(newParam);\r\n }\r\n this.Update();\r\n }\r\n\r\n Join(cu: Curve): Status\r\n {\r\n if (cu instanceof Arc)\r\n {\r\n if (equalv3(cu.Center, this.Center) && equaln(cu._Radius, this._Radius))\r\n {\r\n this.WriteAllObjectRecord();\r\n let [sa, ea] = [cu.StartAngle, cu.EndAngle];\r\n if (cu._Clockwise != this._Clockwise)\r\n [sa, ea] = [ea, sa];\r\n\r\n let allAn = this.AllAngle;\r\n let saAllan = this.ComputeAnlge(sa);\r\n let eaAllan = this.ComputeAnlge(ea);\r\n\r\n if (equaln(sa, this._StartAngle)) //this起点对起点\r\n {\r\n if (eaAllan > allAn)\r\n this.EndAngle = ea;\r\n\r\n return Status.True;\r\n }\r\n else if (equaln(sa, this._EndAngle))//this终点对起点\r\n {\r\n if (eaAllan < allAn || equaln(ea, this._StartAngle))\r\n return Status.ConverToCircle;\r\n else\r\n this.EndAngle = ea;\r\n\r\n return Status.True;\r\n }\r\n else if (equaln(ea, this.StartAngle))//this起点对终点\r\n {\r\n if (saAllan < allAn)\r\n return Status.ConverToCircle;\r\n else\r\n this.StartAngle = sa;\r\n return Status.True;\r\n }\r\n else if (equaln(ea, this._EndAngle))//this终点对终点\r\n {\r\n if (saAllan > allAn)\r\n this.StartAngle = sa;\r\n return Status.True;\r\n }\r\n else if (this.ParamOnCurve(this.GetParamAtAngle(sa)))\r\n {\r\n if (eaAllan < saAllan)\r\n return Status.ConverToCircle;\r\n else if (eaAllan > allAn)\r\n this.EndAngle = ea;\r\n return Status.True;\r\n }\r\n else if (this.ParamOnCurve(this.GetParamAtAngle(ea)))\r\n {\r\n this.StartAngle = sa;\r\n return Status.True;\r\n }\r\n\r\n //使用按负方向去计算它的参数\r\n let saParam: number;\r\n if (saAllan > allAn)\r\n saParam = (saAllan - Math.PI * 2) / allAn;\r\n else\r\n saParam = saAllan / allAn;\r\n\r\n let eaParam: number;\r\n if (eaAllan > saAllan && saAllan > allAn)\r\n eaParam = (eaAllan - Math.PI * 2) / allAn;\r\n else\r\n eaParam = eaAllan / allAn;\r\n\r\n let pMin = Math.max(0, saParam);\r\n let pMax = Math.min(1, eaParam);\r\n\r\n if (pMin <= pMax + 1e-5)\r\n {\r\n if (saParam < 0)\r\n this.StartAngle = sa;\r\n if (eaParam > 1)\r\n this.EndAngle = ea;\r\n return Status.True;\r\n }\r\n }\r\n }\r\n return Status.False;\r\n }\r\n\r\n Reverse(): this\r\n {\r\n this.WriteAllObjectRecord();\r\n this._Clockwise = !this._Clockwise;\r\n [this._StartAngle, this._EndAngle] = [this._EndAngle, this._StartAngle];\r\n return this;\r\n }\r\n\r\n IntersectWith2(curve: Curve, intType: IntersectOption, tolerance = 1e-4)\r\n {\r\n if (curve instanceof Arc)\r\n {\r\n return IntersectArcAndArc(this, curve, intType);\r\n }\r\n if (curve instanceof Line)\r\n {\r\n return SwapParam(IntersectLineAndArc(curve, this, reverseIntersectOption(intType), tolerance));\r\n }\r\n if (curve instanceof Circle)\r\n {\r\n return SwapParam(IntersectCircleAndArc(curve, this, reverseIntersectOption(intType), tolerance));\r\n }\r\n if (curve instanceof Polyline)\r\n return SwapParam(IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType), tolerance));\r\n\r\n if (curve instanceof Ellipse)\r\n return SwapParam(IntersectEllipseAndCircleOrArc(curve, this, intType));\r\n return [];\r\n }\r\n\r\n /**\r\n * 计算出圆弧所包含的角度\r\n *\r\n * @readonly\r\n * @type {number}\r\n * @memberof Arc\r\n */\r\n get AllAngle(): number\r\n {\r\n return this.ComputeAnlge(this._EndAngle);\r\n }\r\n\r\n get Bul(): number\r\n {\r\n if (equaln(this.AllAngle, Math.PI * 2))\r\n return 1;\r\n return Math.tan(this.AllAngle * 0.25) * (this.IsClockWise ? -1 : 1);\r\n }\r\n\r\n /**\r\n * 计算所包含的角度\r\n *\r\n * @private\r\n * @param {number} endAngle 结束的角度\r\n * @returns\r\n * @memberof Arc\r\n */\r\n ComputeAnlge(endAngle: number)\r\n {\r\n //顺时针\r\n if (this._Clockwise)\r\n {\r\n if (this._StartAngle > endAngle)\r\n return this.StartAngle - endAngle;\r\n else //越过0点绘制圆弧\r\n return (Math.PI * 2) - (endAngle - this._StartAngle);\r\n }\r\n else\r\n {\r\n if (endAngle > this._StartAngle)\r\n return endAngle - this._StartAngle;\r\n else\r\n return (Math.PI * 2) - (this._StartAngle - endAngle);\r\n }\r\n }\r\n\r\n /**\r\n * 解析两点和凸度所构成的圆弧\r\n *\r\n * @param {Vector2} p1\r\n * @param {Vector2} p2\r\n * @param {number} bul 凸度,在cad中,凸度为 <(四分之一圆心角)的正切值>\r\n */\r\n ParseFromBul(p1: Vector3 | Vector2, p2: Vector3 | Vector2, bul: number): Arc\r\n {\r\n if (p1 instanceof Vector2)\r\n p1 = AsVector3(p1);\r\n if (p2 instanceof Vector2)\r\n p2 = AsVector3(p2);\r\n\r\n let ocsInv = this.OCSInv;\r\n p1 = p1.clone().applyMatrix4(ocsInv);\r\n p2 = p2.clone().applyMatrix4(ocsInv);\r\n\r\n //弦向量\r\n let chordV = p2.clone().sub(p1);\r\n //弦角度\r\n let chordAn = angle(chordV);\r\n //弦长度/2\r\n let chordLengthHalf = chordV.length() / 2;\r\n\r\n let allAngle = Math.atan(bul) * 4;\r\n let HalfAngle = allAngle * 0.5;\r\n //半径\r\n this._Radius = chordLengthHalf / Math.sin(HalfAngle);\r\n\r\n //指向圆心的角度\r\n let toCenterAn = chordAn + Math.PI * 0.5;//弦角度转90\r\n\r\n //圆心\r\n let center = midPoint(p1, p2);\r\n polar(center, toCenterAn, this._Radius - (bul * chordLengthHalf));\r\n this.Center = center.clone().applyMatrix4(this.OCS);\r\n\r\n this._Radius = Math.abs(this._Radius);\r\n\r\n this._StartAngle = angle(p1.clone().sub(center));\r\n this._EndAngle = angle(p2.clone().sub(center));\r\n\r\n this._Clockwise = bul < 0;\r\n\r\n return this;\r\n }\r\n FromThreePoint(pt1: Vector3, pt2: Vector3, pt3: Vector3)\r\n {\r\n if (!(pt1 && pt2 && pt3))\r\n return;\r\n\r\n let ocsInv = this.OCSInv;\r\n pt1 = pt1.clone().applyMatrix4(ocsInv);\r\n pt2 = pt2.clone().applyMatrix4(ocsInv);\r\n pt3 = pt3.clone().applyMatrix4(ocsInv);\r\n\r\n let center = getCircleCenter(pt1, pt2, pt3);\r\n this.Center = center.clone().applyMatrix4(this.OCS);\r\n //用圆心和其中一个点求距离得到半径:\r\n this._Radius = center.distanceTo(pt1);\r\n //起始角度 端点角度\r\n this._StartAngle = angle(pt1.clone().sub(center));\r\n this._EndAngle = angle(pt3.clone().sub(center));\r\n //求出向量p1->p2,p1->p3\r\n let p1 = pt2.clone().sub(pt1);\r\n let p2 = pt3.clone().sub(pt1);\r\n\r\n this._Clockwise = p1.cross(p2).z < 0;\r\n return this;\r\n }\r\n\r\n /**\r\n * 重载: 初始化绘制实体.\r\n *\r\n * @param {RenderType} [renderType=RenderType.Wireframe]\r\n */\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe)\r\n {\r\n let geo = BufferGeometryUtils.CreateFromPts(this.Shape.getPoints(60).map(AsVector3));\r\n\r\n if (renderType === RenderType.WireframePrint)\r\n {\r\n var geometry = new LineGeometry();\r\n geometry.setPositions(geo.attributes.position.array as number[]);\r\n return new Line2(geometry, ColorMaterial.PrintLineMatrial);\r\n }\r\n\r\n return new TLine(geo, ColorMaterial.GetLineMaterial(this._Color));\r\n }\r\n\r\n //更新Geometry\r\n private UpdateGeometry(geo: BufferGeometry)\r\n {\r\n let pts = this.Shape.getPoints(60).map(AsVector3);\r\n BufferGeometryUtils.UpdatePts(geo, pts);\r\n }\r\n\r\n /**\r\n * 重载:更新绘制的实体\r\n *\r\n * @param {RenderType} type\r\n * @param {Object3D} obj\r\n * @memberof Arc\r\n */\r\n UpdateDrawObject(type: RenderType, obj: Object3D)\r\n {\r\n let geo = obj[\"geometry\"] as BufferGeometry;\r\n this.UpdateGeometry(geo);\r\n }\r\n\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return [this.StartPoint, this.EndPoint];\r\n case ObjectSnapMode.Mid:\r\n return [this.GetPointAtParam(0.5)];\r\n case ObjectSnapMode.Nea:\r\n return getArcOrCirNearPts(this, pickPoint, viewXform)\r\n .filter(p => this.PtOnCurve(p));\r\n case ObjectSnapMode.Ext:\r\n return [this.GetClosestPointTo(pickPoint, true)];\r\n case ObjectSnapMode.Cen:\r\n return [this.Center];\r\n case ObjectSnapMode.Per:\r\n if (lastPoint)\r\n {\r\n if (equaln(lastPoint.distanceToSquared(this.Center), 0, 1e-10))\r\n return [];\r\n let l = new Line(this.Center, lastPoint);\r\n return l.IntersectWith(this, IntersectOption.ExtendBoth).filter(p => this.PtOnCurve(p));\r\n }\r\n case ObjectSnapMode.Tan:\r\n let pts = GetTanPtsOnArcOrCircle(this, lastPoint);\r\n if (pts)\r\n return pts.filter(p => this.PtOnCurve(p));\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n\r\n GetGripPoints(): Array\r\n {\r\n return [\r\n this.StartPoint,\r\n this.GetPointAtParam(0.5),\r\n this.EndPoint,\r\n this.Center.clone(),\r\n ];\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n if (indexList.length > 0)\r\n {\r\n this.WriteAllObjectRecord();\r\n let ptsArr = this.GetGripPoints();\r\n let index = indexList[0];\r\n let p = ptsArr[index];\r\n if (p)\r\n {\r\n p.add(vec);\r\n if (index > 2)\r\n this.Center = this.Center.add(vec);\r\n else\r\n this.FromThreePoint(ptsArr[0], ptsArr[1], ptsArr[2]);\r\n this.Update();\r\n }\r\n }\r\n }\r\n GetStretchPoints(): Array\r\n {\r\n return [this.StartPoint, this.EndPoint];\r\n }\r\n\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n if (indexList.length === 0)\r\n return;\r\n\r\n this.WriteAllObjectRecord();\r\n\r\n if (indexList.length === 2)\r\n this.ApplyMatrix(MoveMatrix(vec));\r\n else\r\n for (let index of indexList)\r\n {\r\n let pts = [this.StartPoint, this.EndPoint];\r\n let [sp, ep] = pts;\r\n\r\n let oldChordLengthHalf = sp.distanceTo(ep) * 0.5;\r\n\r\n let arcHeight = oldChordLengthHalf * this.Bul;\r\n\r\n pts[index].add(vec);\r\n\r\n let newChordLengthHalf = sp.distanceTo(ep) * 0.5;\r\n\r\n let newBul = arcHeight / newChordLengthHalf;\r\n\r\n //根据凸度构造新的弧\r\n this.ParseFromBul(sp, ep, newBul);\r\n this.Update();\r\n }\r\n }\r\n\r\n GetParamAtDist(d: number)\r\n {\r\n return d / this.Length;\r\n }\r\n GetFistDeriv(pt: number | Vector3)\r\n {\r\n let an: number;\r\n if (typeof pt === \"number\")\r\n an = this.GetAngleAtParam(pt);\r\n else\r\n an = angle(pt.clone().applyMatrix4(this.OCSInv));\r\n\r\n an += Math.PI * 0.5 * (this._Clockwise ? -1 : 1);\r\n\r\n let ocs = new Matrix4().extractRotation(this.OCS);\r\n return polar(new Vector3(), an, this._Radius).applyMatrix4(ocs);\r\n }\r\n GetClosestPointTo(pt: Vector3, extend: boolean): Vector3\r\n {\r\n let l = new Line(this.Center, pt);\r\n let inPts: Vector3[] = this.IntersectWith(l, extend ? IntersectOption.ExtendBoth : IntersectOption.ExtendArg);\r\n if (inPts.length < 2)\r\n inPts.push(this.StartPoint, this.EndPoint);\r\n return inPts.reduce((p1, p2) => p1.distanceToSquared(pt) < p2.distanceToSquared(pt) ? p1 : p2);\r\n }\r\n //#region -------------------------File-------------------------\r\n //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化\r\n\r\n //对象从文件中读取数据,初始化自身\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();\r\n if (ver === 1)\r\n {\r\n this.Center = new Vector3().fromArray(file.Read());\r\n this.Normal = new Vector3().fromArray(file.Read());\r\n }\r\n this._Radius = file.Read();\r\n this._StartAngle = file.Read();\r\n this._EndAngle = file.Read();\r\n this._Clockwise = file.Read();\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(2);\r\n file.Write(this._Radius);\r\n file.Write(this._StartAngle);\r\n file.Write(this._EndAngle);\r\n file.Write(this._Clockwise);\r\n }\r\n //#endregion\r\n}\r\n","\r\ntype LogFunction = (message?: any, ...optionalParams: any[]) => void;\r\n\r\nexport const _LogInjectFunctions: LogFunction[] = [];\r\n\r\nexport function Log(message?: any, ...optionalParams: any[]): void\r\n{\r\n for (let f of _LogInjectFunctions)\r\n f(message, ...optionalParams);\r\n}\r\n\r\nexport const LogEnable = {\r\n Display: false\r\n};\r\n","\r\n\r\nlet instanceMap = new Map();\r\n\r\n/**\r\n * 构造单例类的静态类.\r\n * # Example:\r\n * class A extends Singleton(){};\r\n * //获得单例\r\n * let a = A.GetInstance();\r\n */\r\nexport class Singleton\r\n{\r\n protected constructor() { }\r\n\r\n //FIXME: https://github.com/Microsoft/TypeScript/issues/5863\r\n static GetInstance(): T\r\n {\r\n if (instanceMap.has(this))\r\n return instanceMap.get(this);\r\n //@ts-ignore\r\n let __instance__ = new this.prototype.constructor();\r\n instanceMap.set(this, __instance__);\r\n return __instance__;\r\n }\r\n}\r\n","import { Geometry, Matrix4, Vector3 } from \"three\";\r\n\r\nexport function ScaleUV(geo: Geometry, scale = 1e-3)\r\n{\r\n for (let uvsg of geo.faceVertexUvs)\r\n {\r\n for (let uvs of uvsg)\r\n {\r\n for (let uv of uvs)\r\n {\r\n uv.multiplyScalar(scale);\r\n }\r\n }\r\n }\r\n}\r\nexport function ScaleUV2(geo: Geometry, ocs: Matrix4, xScale = 1e-3, yScale = 1e-3, isInvert = false)\r\n{\r\n for (let uvsg of geo.faceVertexUvs)\r\n {\r\n for (let uvs of uvsg)\r\n {\r\n for (let uv of uvs)\r\n {\r\n let p = new Vector3(uv.x, uv.y).applyMatrix4(ocs);\r\n uv.x = p.x;\r\n uv.y = p.y;\r\n if (isInvert)\r\n {\r\n uv.x /= yScale;\r\n uv.y /= xScale;\r\n }\r\n else\r\n {\r\n uv.x /= xScale;\r\n uv.y /= yScale;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","import { Matrix3, Matrix4, Path, Shape as TShape, Vector3, Box3 } from 'three';\r\nimport { arrayRemoveIf } from '../Common/ArrayExt';\r\nimport { ObjectSnapMode } from '../Editor/ObjectSnapMode';\r\nimport { CADFiler } from './CADFiler';\r\nimport { Contour } from './Contour';\r\nimport { Circle } from './Entity/Circle';\r\nimport { Curve } from './Entity/Curve';\r\nimport { Polyline } from './Entity/Polyline';\r\nimport { equaln } from '../Geometry/GeUtils';\r\nimport { IntersectBox2 } from '../Geometry/Box';\r\n\r\nexport class Shape\r\n{\r\n private _Outline: Contour;\r\n private _Holes: Contour[] = [];\r\n private _Shape: TShape = new TShape();\r\n constructor(out?: Contour, hols?: Contour[])\r\n {\r\n this._Outline = out || new Contour();\r\n hols && this._Holes.push(...hols);\r\n }\r\n\r\n get Outline()\r\n {\r\n return this._Outline;\r\n }\r\n get Holes()\r\n {\r\n return this._Holes;\r\n }\r\n get Area()\r\n {\r\n let outlineArea = this._Outline.Area;\r\n let holeArea = this._Holes.map(l => l.Area).reduce((a1, a2) => a1 + a2, 0);\r\n return outlineArea - holeArea;\r\n }\r\n get BoundingBox()\r\n {\r\n return this._Outline.BoundingBox;\r\n }\r\n set Outline(cus: Contour)\r\n {\r\n this._Outline = cus;\r\n this.UpdateShape();\r\n }\r\n set Holes(cus: Contour[])\r\n {\r\n this._Holes = cus;\r\n this.UpdateShape();\r\n }\r\n get Shape()\r\n {\r\n this.UpdateShape();\r\n return this._Shape;\r\n }\r\n get Position()\r\n {\r\n return this._Outline.Curve.Position;\r\n }\r\n set Position(p: Vector3)\r\n {\r\n let vec = p.clone().sub(this._Outline.Curve.Position);\r\n this._Outline.Curve.Position = p;\r\n for (let h of this._Holes)\r\n h.Curve.Position = h.Curve.Position.add(vec);\r\n }\r\n Z0()\r\n {\r\n this._Outline.Curve.Z0();\r\n for (let h of this._Holes)\r\n h.Curve.Z0();\r\n return this;\r\n }\r\n\r\n MatrixPlanarizere()\r\n {\r\n this._Outline.Curve.MatrixPlanarizere();\r\n for (let h of this._Holes)\r\n h.Curve.MatrixPlanarizere();\r\n }\r\n\r\n ApplyMatrix(m: Matrix4)\r\n {\r\n this._Outline.Curve.ApplyMatrix(m);\r\n this._Holes.forEach(h => h.Curve.ApplyMatrix(m));\r\n return this;\r\n }\r\n ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n\r\n let cu = this.Outline.Curve;\r\n let cus = this._Holes.map(h => h.Curve);\r\n cus.unshift(cu);\r\n for (let c of cus)\r\n {\r\n c.ApplyMatrix(c.OCS);\r\n c.ApplyMatrix(m);\r\n c.ApplyMatrix(c.OCSInv);\r\n }\r\n\r\n return this;\r\n }\r\n Explode()\r\n {\r\n let cus: Curve[] = [];\r\n let contours: Contour[] = [this._Outline, ...this._Holes];\r\n for (let con of contours)\r\n {\r\n if (con.Curve instanceof Polyline)\r\n cus.push(...con.Curve.Explode());\r\n else\r\n cus.push(con.Curve.Clone());\r\n }\r\n return cus;\r\n }\r\n Clone()\r\n {\r\n let shape = new Shape();\r\n shape.Outline = this._Outline.Clone();\r\n shape.Holes = this.Holes.map(h => h.Clone());\r\n return shape;\r\n }\r\n SetColor(color: number)\r\n {\r\n this._Outline.Curve.ColorIndex = color;\r\n this._Holes.forEach(h => h.Curve.ColorIndex = color);\r\n }\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return this.GetStretchPoints();\r\n case ObjectSnapMode.Mid:\r\n case ObjectSnapMode.Cen:\r\n case ObjectSnapMode.Nea:\r\n case ObjectSnapMode.Ext:\r\n case ObjectSnapMode.Per:\r\n case ObjectSnapMode.Tan:\r\n {\r\n let cus: Curve[] = [this._Outline.Curve];\r\n for (let h of this._Holes)\r\n {\r\n cus.push(h.Curve);\r\n }\r\n let pts: Vector3[] = [];\r\n for (let c of cus)\r\n {\r\n pts.push(...c.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));\r\n }\r\n return pts;\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n GetGripPoints()\r\n {\r\n let pts = this.Outline.Curve.GetGripPoints();\r\n for (let h of this._Holes)\r\n {\r\n pts.push(...h.Curve.GetGripPoints());\r\n }\r\n return pts;\r\n }\r\n MoveGripPoints(indexList: Array, vec: Vector3)\r\n {\r\n let i = indexList[0];\r\n let outlineIndex = this._Outline.Curve.GetGripPoints().length;\r\n\r\n let cu = this._Outline.Curve;\r\n\r\n if (i >= outlineIndex)\r\n {\r\n for (let h of this._Holes)\r\n {\r\n let len = h.Curve.GetGripPoints().length;\r\n if (indexList[0] < outlineIndex + len)\r\n {\r\n indexList = [indexList[0] - outlineIndex];\r\n cu = h.Curve;\r\n break;\r\n }\r\n outlineIndex += len;\r\n }\r\n }\r\n cu.MoveGripPoints(indexList, vec);\r\n }\r\n GetStretchPoints()\r\n {\r\n let pts = this.Outline.Curve.GetStretchPoints();\r\n for (let h of this._Holes)\r\n {\r\n pts.push(...h.Curve.GetStretchPoints());\r\n }\r\n return pts;\r\n }\r\n MoveStretchPoints(indexList: Array, vec: Vector3)\r\n {\r\n let outlen = 0;\r\n for (let cu of [this._Outline.Curve, ...this._Holes.map(h => h.Curve)])\r\n {\r\n let count = cu.GetStretchPoints().length;\r\n let refIndex = outlen + count;\r\n let curIndexs = [];\r\n while (indexList.length)\r\n {\r\n if (indexList[0] < refIndex)\r\n curIndexs.push(indexList.shift() - outlen);\r\n else\r\n break;\r\n }\r\n cu.MoveStretchPoints(curIndexs, vec);\r\n\r\n if (indexList.length === 0)\r\n break;\r\n\r\n outlen += count;\r\n }\r\n }\r\n //交集 如果成功返回一个面域 失败返回0个\r\n IntersectionBoolOperation(targetShape: Shape): Shape[]\r\n {\r\n let resOutlines = this._Outline.IntersectionBoolOperation(targetShape._Outline);\r\n let cus = this.targetOutlineSubHoleOutline(resOutlines, Shape.mergeContours([...this._Holes, ...targetShape._Holes]));\r\n return Shape.pairHoleAndOutline(cus);\r\n }\r\n\r\n //并集,如果成功返回1个形状,不成功返回2个形状\r\n UnionBoolOperation(targetShape: Shape): Shape[]\r\n {\r\n let { contours, holes } = this._Outline.UnionBoolOperation(targetShape._Outline);\r\n\r\n let shapes: Shape[] = [];\r\n\r\n //提取出所有的孔洞, 目标线段孔洞和原线段差,如果孔洞和目标相减后有被包围轮廓,应把这个单独提取出来作为形状\r\n let unionHoles: Contour[] = [];\r\n\r\n //合并运算时提取出运算后的孔洞和形状\r\n const pickUpHoleOrShape = (srcHoles: Contour[], tarHoles: Contour[], outline: Contour) =>\r\n {\r\n srcHoles.forEach(cu =>\r\n {\r\n let tmpContours = cu.SubstactBoolOperation(outline).sort((a, b) => b.Area - a.Area);\r\n let isAllContainered = tmpContours.length > 1 && tmpContours.slice(1).every((cu, index) => tmpContours[0].CuInOutline(cu.Curve));\r\n\r\n //洞是否被最大的洞包含,是,则把被包含的洞都提取出来加入形状数组\r\n if (isAllContainered)\r\n {\r\n shapes.push(...this.targetOutlinesSubHoles(tmpContours.slice(1).map(c => new Shape(c)), tarHoles.map(c => new Shape(c))));\r\n } else\r\n unionHoles.push(...tmpContours);\r\n });\r\n\r\n };\r\n pickUpHoleOrShape(targetShape._Holes, this._Holes, this._Outline);\r\n pickUpHoleOrShape(this._Holes, targetShape._Holes, targetShape._Outline);\r\n targetShape._Holes.forEach(cu =>\r\n {\r\n this._Holes.forEach(c =>\r\n {\r\n unionHoles.push(...c.IntersectionBoolOperation(cu));\r\n });\r\n });\r\n\r\n shapes.push(...this.targetOutlinesSubHoles(contours.map(c => new Shape(c, holes)), unionHoles.map(c => new Shape(c))));\r\n return shapes;\r\n }\r\n\r\n /**\r\n * 如果完全被减掉,就返回0个.其他的返回1个或者n个\r\n * @param targetShapes 已经是合并后的形状数组\r\n */\r\n SubstactBoolOperation(targetShapes: Shape[])\r\n {\r\n let originOutline = this.Outline;\r\n let targetOutlines = targetShapes.map(s => s.Outline);\r\n const { holes, outlines } = originOutline.GetSubtractListByMoreTargets(targetOutlines);\r\n holes.push(...this.Holes);\r\n\r\n let newShapes: Shape[] = [];\r\n\r\n if (outlines.length === 1 && equaln(outlines[0].Area, originOutline.Area))\r\n {\r\n newShapes = [new Shape(outlines[0], Shape.mergeContours(holes))];\r\n }\r\n else if (holes.length === 0)\r\n {\r\n newShapes = outlines.map(o => new Shape(o));\r\n }\r\n else\r\n {\r\n for (let outline of outlines)\r\n newShapes.push(...new Shape(outline).SubstactBoolOperation(holes.map(h => new Shape(h))));\r\n }\r\n\r\n let holeShape = this.Holes.map(h => new Shape(h));\r\n\r\n for (let target of targetShapes)\r\n {\r\n let tmpInterList: Contour[] = [];\r\n if (target.Holes.length === 0) continue;\r\n for (let hole of target.Holes)\r\n {\r\n let list = hole.IntersectionBoolOperation(originOutline);\r\n tmpInterList.push(...list);\r\n }\r\n\r\n for (let ot of tmpInterList)\r\n {\r\n let subShapes: Shape[] = [];\r\n subShapes.push(...holeShape);\r\n for (let t of targetShapes)\r\n {\r\n if (t !== target)\r\n subShapes.push(new Shape(t.Outline));\r\n }\r\n\r\n newShapes.push(...new Shape(ot).SubstactBoolOperation(subShapes));\r\n }\r\n\r\n }\r\n\r\n return newShapes;\r\n }\r\n Equal(targetShape: Shape)\r\n {\r\n if (this._Outline.Equal(targetShape._Outline))\r\n {\r\n return this._Holes.length === targetShape._Holes.length\r\n && this._Holes.every(h1 =>\r\n targetShape._Holes.some(h2 => h1.Equal(h2))\r\n );\r\n }\r\n return false;\r\n }\r\n private targetOutlinesSubHoles(targetShapes: Shape[], holeShapes: Shape[])\r\n {\r\n let resultShapes: Shape[] = [];\r\n for (let ts of targetShapes)\r\n {\r\n let res = ts.SubstactBoolOperation(holeShapes);\r\n resultShapes.push(...res);\r\n }\r\n return resultShapes;\r\n\r\n }\r\n /**\r\n * 目标轮廓减去洞\r\n *\r\n * @private\r\n * @param {Contour[]} tarContours 轮廓列表\r\n * @param {Contour[]} holes 洞列表\r\n * @returns {Contour[]} 新的轮廓列表\r\n * @memberof Shape\r\n */\r\n private targetOutlineSubHoleOutline(tarContours: Contour[], holes: Contour[]): Contour[]\r\n {\r\n if (!holes.length)\r\n return tarContours;\r\n\r\n let resultContours: Contour[] = [];\r\n\r\n for (let minuendContour of tarContours)\r\n {\r\n //需要被差集的形状列表\r\n let tmpContour: Contour[] = [minuendContour];\r\n for (let hole of holes)\r\n {\r\n //缓存差集生成的轮廓\r\n let tmps: Contour[] = [];\r\n tmpContour.forEach(r =>\r\n {\r\n let cus = r.SubstactBoolOperation(hole);\r\n tmps.push(...cus);\r\n });\r\n tmpContour = tmps;//使用新生成的进行下一轮计算\r\n }\r\n resultContours.push(...tmpContour);\r\n }\r\n\r\n return resultContours;\r\n }\r\n\r\n //整理轮廓数组,匹配洞和外轮廓\r\n static pairHoleAndOutline(contours: Contour[]): Shape[]\r\n {\r\n let shapes: Shape[] = [];\r\n contours.sort((a, b) => b.Area - a.Area);\r\n while (contours.length)\r\n {\r\n //洞列表\r\n let tmpHoles: Contour[] = [];\r\n let outline: Contour = contours.shift();\r\n\r\n //取出包含的洞\r\n arrayRemoveIf(contours, (con: Contour) =>\r\n {\r\n let bisIn = outline.CuInOutline(con.Curve);\r\n if (bisIn) tmpHoles.push(con);\r\n return bisIn;\r\n });\r\n let holes: Contour[] = Shape.removeBeContaineredHoles(tmpHoles);\r\n shapes.push(new Shape(outline, holes));\r\n }\r\n return shapes;\r\n }\r\n /**\r\n * 合并洞,本质是使用(并集算法)将可以并集的洞合并在一起,减少洞的数量.\r\n * canSidewipe 用于走刀,擦边的是否合并\r\n */\r\n static mergeContours(holes: Contour[], canSidewipe = true): Contour[]\r\n {\r\n if (holes.length <= 1) return holes;\r\n let rets: Contour[] = [];//返回的合并轮廓\r\n let cache = new Map();\r\n\r\n while (holes.length > 0)\r\n {\r\n let c = holes.shift();//取第一个\r\n let b1 = cache.get(c);\r\n if (!b1)\r\n {\r\n b1 = c.BoundingBox;\r\n cache.set(c, b1);\r\n }\r\n\r\n while (true)\r\n {\r\n //剩余的 不相交的形状表 remaining\r\n let remHoles = holes.filter(ic =>\r\n {\r\n let b2 = cache.get(ic);\r\n if (!b2)\r\n {\r\n b2 = ic.BoundingBox;\r\n cache.set(ic, b2);\r\n }\r\n\r\n if (!IntersectBox2(b1, b2))\r\n return true;\r\n\r\n let unions = c.UnionBoolOperation(ic);\r\n\r\n if (unions.holes.length > 0)\r\n console.warn(\"未知情况\");\r\n\r\n if (unions.contours.length === 1)//并集成功\r\n {\r\n if (!canSidewipe)\r\n {\r\n if (equaln(c.Area + ic.Area, unions.contours[0].Area, 0.1))\r\n return true;\r\n }\r\n c = unions.contours[0]; //更新c\r\n b1 = c.BoundingBox;\r\n cache.set(c, b1);\r\n }\r\n\r\n return unions.contours.length !== 1; //过滤出并集失败的形状\r\n });\r\n\r\n //如果c和剩余的轮廓都不相交,那么退出\r\n if (remHoles.length === holes.length)\r\n {\r\n rets.push(c); //c已经是一个独立的轮廓,不和任意轮廓相交(不能合并了)\r\n break;//退出循环.下一个\r\n }\r\n else\r\n holes = remHoles; //更新为剩下的轮廓列表\r\n }\r\n }\r\n\r\n return rets;\r\n }\r\n\r\n /**\r\n * 移除被包含的洞.(移除无效的洞,已经被更大的洞包含)\r\n *\r\n * @private\r\n * @param {Contour[]} tmpHoles 洞列表\r\n * @returns {Contour[]} 返回的洞列表都不会互相包含.\r\n * @memberof Shape\r\n */\r\n private static removeBeContaineredHoles(tmpHoles: Contour[]): Contour[]\r\n {\r\n let holes: Contour[] = [];\r\n if (tmpHoles.length <= 1) return tmpHoles;\r\n tmpHoles.sort((a, b) => b.Area - a.Area);\r\n while (tmpHoles.length)\r\n {\r\n let srcHole = tmpHoles.shift();\r\n holes.push(srcHole);\r\n\r\n //移除包含的洞\r\n arrayRemoveIf(tmpHoles, h => srcHole.CuInOutline(h.Curve));\r\n }\r\n return holes;\r\n }\r\n UpdateShape()\r\n {\r\n this._Shape = this.Outline.Shape;\r\n for (let h of this._Holes)\r\n {\r\n if (h.Curve instanceof Polyline)\r\n h.Curve.UpdateMatrixTo(this.Outline.Curve.OCS);\r\n\r\n if (h.Curve instanceof Circle)\r\n {\r\n let sp = new Path();\r\n let cen = h.Curve.Center.applyMatrix4(this.Outline.Curve.OCSInv);\r\n sp.ellipse(cen.x, cen.y, h.Curve.Radius, h.Curve.Radius, 0, 2 * Math.PI, false, 0);\r\n this._Shape.holes.push(sp);\r\n }\r\n else\r\n this._Shape.holes.push(h.Shape);\r\n }\r\n }\r\n //读写文件\r\n ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();//1\r\n this._Outline = Contour.CreateContour([file.ReadObject() as Curve]);\r\n\r\n let count = file.Read();\r\n for (let i = 0; i < count; i++)\r\n {\r\n this._Holes.push(\r\n Contour.CreateContour([file.ReadObject() as Curve])\r\n );\r\n }\r\n\r\n }\r\n //对象将自身数据写入到文件.\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(1);//ver\r\n file.WriteObject(this._Outline.Curve);\r\n file.Write(this._Holes.length);\r\n this._Holes.forEach(h => file.WriteObject(h.Curve));\r\n }\r\n}\r\n","import { BoolOpeartionType } from '../GraphicsSystem/BoolOperateUtils';\r\nimport { CADFiler } from './CADFiler';\r\nimport { Shape } from './Shape';\r\nimport { Matrix4 } from 'three';\r\nimport { IntersectBox2 } from '../Geometry/Box';\r\n\r\n\r\nexport class ShapeManager\r\n{\r\n private _ShapeList: Shape[] = [];\r\n get ShapeList()\r\n {\r\n return this._ShapeList.slice();\r\n }\r\n get ShapeCount()\r\n {\r\n return this._ShapeList.length;\r\n }\r\n get ShapeArea()\r\n {\r\n return this._ShapeList.map(s => s.Area).reduce((a1, a2) => a1 + a2, 0);\r\n }\r\n AppendShapeList(shapes: Shape | Shape[])\r\n {\r\n Array.isArray(shapes) ? this._ShapeList.push(...shapes) : this._ShapeList.push(shapes);\r\n return this;\r\n }\r\n Clear()\r\n {\r\n this._ShapeList.length = 0;\r\n }\r\n BoolOper(otherMg: ShapeManager, booltype: BoolOpeartionType)\r\n {\r\n switch (booltype)\r\n {\r\n case BoolOpeartionType.Intersection:\r\n return this.IntersectionBoolOperation(otherMg);\r\n case BoolOpeartionType.Union:\r\n return this.UnionBoolOperation(otherMg);\r\n case BoolOpeartionType.Subtract:\r\n return this.SubstactBoolOperation(otherMg);\r\n }\r\n }\r\n //交集 如果成功返回一个面域 失败返回0个\r\n IntersectionBoolOperation(target: ShapeManager)\r\n {\r\n let shapes: Shape[] = [];\r\n for (let srcShape of this._ShapeList)\r\n {\r\n for (let tarShape of target._ShapeList)\r\n {\r\n let tmpShapes = srcShape.IntersectionBoolOperation(tarShape);\r\n shapes.push(...tmpShapes);\r\n }\r\n }\r\n this.Clear();\r\n this._ShapeList = shapes;\r\n return this._ShapeList.length > 0;\r\n }\r\n //并集,如果有一个形状并集成功,就成功\r\n UnionBoolOperation(targetMg: ShapeManager)\r\n {\r\n let isSuccess = false;\r\n let srcShapes = this._ShapeList;\r\n let tarShapes = targetMg._ShapeList;\r\n\r\n let alones: Shape[] = [];//孤立的形状\r\n\r\n const boxCache = new WeakMap();\r\n\r\n for (let src of srcShapes)\r\n {\r\n let notUnions: Shape[] = [];//未被合并的形状列表 来自tarShapes\r\n let srcBox = src.BoundingBox;\r\n for (let tar of tarShapes)\r\n {\r\n let tarBox = boxCache.get(tar);\r\n if (!tarBox)\r\n {\r\n tarBox = tar.BoundingBox;\r\n boxCache.set(tar, tarBox);\r\n }\r\n if (!IntersectBox2(srcBox, tarBox))\r\n {\r\n notUnions.push(tar);\r\n continue;\r\n }\r\n let unions = src.UnionBoolOperation(tar);\r\n if (unions.length === 1)//并集成功\r\n {\r\n isSuccess = true;\r\n src = unions[0];//src设置为 合并完的形状\r\n }\r\n else//并集失败\r\n notUnions.push(tar); //设置为未计算\r\n }\r\n\r\n //如果发现src和任意一个形状并集成功,那么\r\n if (notUnions.length != tarShapes.length)\r\n {\r\n notUnions.push(src); //加入src 进行下一轮\r\n tarShapes = notUnions;\r\n }\r\n else\r\n alones.push(src);//它是孤独的一个形状\r\n }\r\n\r\n this._ShapeList = alones.concat(tarShapes);\r\n return isSuccess;\r\n }\r\n SubstactBoolOperation(target: ShapeManager)\r\n {\r\n let newShapes: Shape[] = [];\r\n for (let s of this._ShapeList)\r\n {\r\n let ss = s.SubstactBoolOperation(target.ShapeList);\r\n newShapes.push(...ss);\r\n }\r\n this._ShapeList = newShapes;\r\n return true;\r\n }\r\n\r\n /**\r\n * 与region.ApplyMatrix不同的是,这个是直接操作内部对象.\r\n * 通常用来计算布尔运算时需要真实的移动这个位置.\r\n * 并且将不会刷新显示\r\n *\r\n * @param {Matrix4} mat4\r\n * @memberof ShapeManager\r\n */\r\n ApplyMatrix(mat4: Matrix4)\r\n {\r\n for (let s of this._ShapeList)\r\n {\r\n s.Outline.Curve.ApplyMatrix(mat4);\r\n s.Holes.forEach(o => o.Curve.ApplyMatrix(mat4));\r\n }\r\n\r\n }\r\n ReadFile(file: CADFiler)\r\n {\r\n let ver = file.Read();//1\r\n let cout = file.Read();\r\n for (let i = 0; i < cout; i++)\r\n {\r\n let obj = new Shape();\r\n obj.ReadFile(file);\r\n this._ShapeList.push(obj);\r\n }\r\n }\r\n WriteFile(file: CADFiler)\r\n {\r\n file.Write(1);//ver\r\n file.Write(this.ShapeList.length);\r\n for (let s of this.ShapeList)\r\n {\r\n s.WriteFile(file);\r\n }\r\n }\r\n}\r\n","import { Box3, BufferGeometry, LineSegments, Material, Matrix3, Matrix4, Mesh, Object3D, ShapeGeometry, Vector2, Vector3 } from 'three';\r\nimport { ColorMaterial } from '../../Common/ColorPalette';\r\nimport { DisposeThreeObj, Object3DRemoveAll } from '../../Common/Dispose';\r\nimport { UpdateDraw } from '../../Common/Status';\r\nimport { ObjectSnapMode } from '../../Editor/ObjectSnapMode';\r\nimport { BufferGeometryUtils, BufferGeometryUtils as BufferGeometryUtils2 } from '../../Geometry/BufferGeometryUtils';\r\nimport { AsVector3, MoveMatrix } from '../../Geometry/GeUtils';\r\nimport { ScaleUV } from '../../Geometry/UVUtils';\r\nimport { BoolOpeartionType } from '../../GraphicsSystem/BoolOperateUtils';\r\nimport { RenderType } from '../../GraphicsSystem/RenderType';\r\nimport { Factory } from '../CADFactory';\r\nimport { CADFiler } from '../CADFiler';\r\nimport { Contour } from '../Contour';\r\nimport { Shape } from '../Shape';\r\nimport { ShapeManager } from '../ShapeManager';\r\nimport { Curve } from './Curve';\r\nimport { Entity } from './Entity';\r\n\r\n@Factory\r\nexport class Region extends Entity\r\n{\r\n static CreateFromCurves(cus: Curve[]): Region | undefined\r\n {\r\n let shapes = Contour.GetAllContour(cus).map(out => new Shape(out));\r\n if (shapes.length > 0)\r\n {\r\n let reg = new Region();\r\n //MarkX:曲线同面域一起移动\r\n reg.ApplyMatrix(shapes[0].Outline.Curve.OCS);\r\n reg.ShapeManager.AppendShapeList(shapes);\r\n return reg;\r\n }\r\n }\r\n\r\n constructor(private _ShapeManager: ShapeManager = new ShapeManager())\r\n {\r\n super();\r\n }\r\n\r\n //如果需要修改获取到的属性,需要Clone后进行操作,否则会对原实体进行破坏\r\n get ShapeManager()\r\n {\r\n return this._ShapeManager;\r\n }\r\n get Area()\r\n {\r\n return this.ShapeManager.ShapeArea;\r\n }\r\n get BoundingBox()\r\n {\r\n let box = new Box3();\r\n for (let s of this._ShapeManager.ShapeList)\r\n box.union(s.BoundingBox);\r\n return box;\r\n }\r\n Explode()\r\n {\r\n let shapeList = this._ShapeManager.ShapeList;\r\n if (shapeList.length <= 1)\r\n {\r\n return shapeList[0].Explode();\r\n }\r\n else\r\n {\r\n let regs: Region[] = [];\r\n shapeList.forEach(s =>\r\n {\r\n let reg = new Region().ApplyMatrix(this.OCS);\r\n reg.ShapeManager.AppendShapeList(s);\r\n regs.push(reg);\r\n });\r\n return regs;\r\n }\r\n }\r\n\r\n /**\r\n * 对于布尔操作,这个将会变换内部轮廓到对方坐标系.\r\n * 并且这个变换不会更新图形绘制.\r\n * @param {Matrix4} m\r\n * @memberof Region\r\n */\r\n ShapeApplyMatrix(m: Matrix4)\r\n {\r\n this.WriteAllObjectRecord();\r\n this._ShapeManager.ApplyMatrix(m);\r\n }\r\n GetObjectSnapPoints(\r\n snapMode: ObjectSnapMode,\r\n pickPoint: Vector3,\r\n lastPoint: Vector3,\r\n viewXform?: Matrix3\r\n ): Vector3[]\r\n {\r\n switch (snapMode)\r\n {\r\n case ObjectSnapMode.End:\r\n return this.GetGripPoints();\r\n case ObjectSnapMode.Mid:\r\n case ObjectSnapMode.Cen:\r\n case ObjectSnapMode.Nea:\r\n case ObjectSnapMode.Ext:\r\n case ObjectSnapMode.Per:\r\n case ObjectSnapMode.Tan:\r\n {\r\n let pts: Vector3[] = [];\r\n for (let s of this._ShapeManager.ShapeList)\r\n {\r\n pts.push(...s.GetObjectSnapPoints(snapMode, pickPoint, lastPoint, viewXform));\r\n }\r\n return pts;\r\n }\r\n default:\r\n break;\r\n }\r\n return [];\r\n }\r\n GetGripPoints(): Array\r\n {\r\n let pts: Vector3[] = [];\r\n for (let s of this._ShapeManager.ShapeList)\r\n pts.push(...s.GetStretchPoints());\r\n return pts;\r\n }\r\n MoveGripPoints(indexList: number[], moveVec: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n let moveVLoc = moveVec.clone().applyMatrix4(new Matrix4().extractRotation(this.OCSInv));\r\n this.ApplyMatrix(MoveMatrix(moveVLoc));\r\n }\r\n ApplyMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n //面域移动,组成面域的曲线也要移动 MarkX:曲线同面域一起移动\r\n this._ShapeManager.ShapeList.forEach(s => s.ApplyMatrix(m));\r\n return super.ApplyMatrix(m);\r\n }\r\n\r\n get Position()\r\n {\r\n return super.Position;\r\n }\r\n set Position(pt: Vector3)\r\n {\r\n this.WriteAllObjectRecord();\r\n let moveX = pt.x - this._Matrix.elements[12];\r\n let moveY = pt.y - this._Matrix.elements[13];\r\n let moveZ = pt.z - this._Matrix.elements[14];\r\n this._Matrix.setPosition(pt);\r\n this._SpaceOCS.elements[12] += moveX;\r\n this._SpaceOCS.elements[13] += moveY;\r\n this._SpaceOCS.elements[14] += moveZ;\r\n\r\n let m = new Matrix4().setPosition(moveX, moveY, moveZ);\r\n for (let s of this.ShapeManager.ShapeList)\r\n s.ApplyMatrix(m);\r\n\r\n this.Update(UpdateDraw.Matrix);\r\n }\r\n\r\n protected ApplyScaleMatrix(m: Matrix4): this\r\n {\r\n this.WriteAllObjectRecord();\r\n for (let s of this._ShapeManager.ShapeList)\r\n s.ApplyScaleMatrix(m);\r\n\r\n this.Update(UpdateDraw.Geometry);\r\n return this;\r\n }\r\n\r\n //Z轴归0\r\n Z0()\r\n {\r\n super.Z0();\r\n for (let s of this._ShapeManager.ShapeList)\r\n s.Z0();\r\n\r\n return this;\r\n }\r\n MatrixPlanarizere()\r\n {\r\n super.MatrixPlanarizere();\r\n for (let s of this._ShapeManager.ShapeList)\r\n s.MatrixPlanarizere();\r\n return this;\r\n }\r\n\r\n protected ApplyMirrorMatrix(m: Matrix4)\r\n {\r\n return this;\r\n }\r\n /**\r\n * 请注意:该计算会操作otherRegion的矩阵\r\n * @param {Region} otherRegion\r\n * @param {BoolOpeartionType} boolType\r\n */\r\n BooleanOper(otherRegion: Region, boolType: BoolOpeartionType): boolean\r\n {\r\n if (this.IsCoplaneTo(otherRegion))\r\n {\r\n this.WriteAllObjectRecord();\r\n let oldOcs = this.OCS;\r\n\r\n //把形状曲线转移到二维屏幕计算后还原回来\r\n this.ShapeApplyMatrix(this.OCSInv);\r\n otherRegion.ShapeApplyMatrix(this.OCSInv);\r\n let isSuccess = this._ShapeManager.BoolOper(otherRegion._ShapeManager, boolType);\r\n this.ShapeApplyMatrix(oldOcs);\r\n this.Update();\r\n return isSuccess;\r\n }\r\n return false;\r\n }\r\n\r\n private _MeshGeometry: BufferGeometry;\r\n get MeshGeometry(): BufferGeometry\r\n {\r\n if (this._MeshGeometry)\r\n return this._MeshGeometry;\r\n this.UpdateGeometry();\r\n return this._MeshGeometry;\r\n }\r\n\r\n private _EdgeGeometry: BufferGeometry;\r\n private get EdgeGeometry()\r\n {\r\n if (this._EdgeGeometry)\r\n return this._EdgeGeometry;\r\n this.UpdateGeometry();\r\n return this._EdgeGeometry;\r\n }\r\n\r\n private UpdateGeometry()\r\n {\r\n let shapeList = this._ShapeManager.ShapeList;\r\n\r\n let edgePts: Vector3[] = [];\r\n let meshGeoms: BufferGeometry[] = [];\r\n\r\n const AddEdgePts = (pts: Vector2[], diffMat: Matrix4) =>\r\n {\r\n for (let i = 0; i < pts.length; i++)\r\n {\r\n let p = AsVector3(pts[i]);\r\n p.applyMatrix4(diffMat);\r\n edgePts.push(p);\r\n if (i !== 0 && i !== pts.length - 1)\r\n edgePts.push(p);\r\n }\r\n };\r\n\r\n for (let i = 0; i < shapeList.length; i++)\r\n {\r\n let shape = shapeList[i];\r\n let geometry = new ShapeGeometry(shape.Shape, 60);//60 可以优化.\r\n let diffMat = this.OCSInv.clone().multiply(shape.Outline.Curve.OCSNoClone);\r\n geometry.applyMatrix4(diffMat);\r\n ScaleUV(geometry);\r\n meshGeoms.push(new BufferGeometry().fromGeometry(geometry));\r\n\r\n let shapeInfo = shape.Shape.extractPoints(60);\r\n\r\n let pts = shapeInfo.shape;\r\n AddEdgePts(pts, diffMat);\r\n\r\n let holePtss = shapeInfo.holes;\r\n for (let holePts of holePtss)\r\n AddEdgePts(holePts, diffMat);\r\n }\r\n\r\n this._EdgeGeometry = BufferGeometryUtils.CreateFromPts(edgePts);\r\n this._MeshGeometry = BufferGeometryUtils2.MergeBufferGeometries(meshGeoms);\r\n this._MeshGeometry[\"IsMesh\"] = true;\r\n this._MeshGeometry.computeVertexNormals();\r\n }\r\n\r\n UpdateDrawGeometry()\r\n {\r\n this._EdgeGeometry = undefined;\r\n this._MeshGeometry = undefined;\r\n }\r\n\r\n InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D\r\n {\r\n if (renderType === RenderType.Wireframe)\r\n {\r\n return new LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex));\r\n }\r\n else if (renderType === RenderType.Conceptual)\r\n {\r\n return new Object3D().add(\r\n new LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex)),\r\n new Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)),\r\n );\r\n }\r\n else if (renderType === RenderType.Physical)\r\n {\r\n let mesh = new Mesh(this.MeshGeometry, this.MeshMaterial);\r\n mesh.castShadow = true;\r\n mesh.receiveShadow = true;\r\n return mesh;\r\n }\r\n }\r\n\r\n UpdateDrawObject(renderType: RenderType, obj: Object3D)\r\n {\r\n DisposeThreeObj(obj);\r\n Object3DRemoveAll(obj);\r\n if (renderType === RenderType.Wireframe)\r\n {\r\n let l = obj as LineSegments;\r\n l.geometry = this.EdgeGeometry;\r\n l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);\r\n }\r\n else if (renderType === RenderType.Conceptual)\r\n {\r\n return obj.add(\r\n new LineSegments(this.EdgeGeometry, ColorMaterial.GetLineMaterial(this.ColorIndex)),\r\n new Mesh(this.MeshGeometry, ColorMaterial.GetConceptualMaterial(this.ColorIndex)),\r\n );\r\n }\r\n else if (renderType === RenderType.Physical)\r\n {\r\n let mesh = obj as Mesh;\r\n mesh.geometry = this.MeshGeometry;\r\n mesh.material = this.MeshMaterial;\r\n }\r\n }\r\n\r\n /**\r\n * 当实体需要被更新时,更新实体材质\r\n */\r\n UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material?: Material)\r\n {\r\n if (type === RenderType.Wireframe)\r\n {\r\n for (let l of obj.children)\r\n {\r\n let line = l as LineSegments;\r\n line.material = ColorMaterial.GetLineMaterial(this.ColorIndex);\r\n }\r\n }\r\n else if (type === RenderType.Conceptual)\r\n {\r\n for (let i = 0; i < obj.children.length; i++)\r\n {\r\n if (i % 2 === 0)\r\n {\r\n let l = obj.children[i] as LineSegments;\r\n l.material = ColorMaterial.GetLineMaterial(this.ColorIndex);\r\n }\r\n else\r\n {\r\n let mesh = obj.children[i] as Mesh;\r\n mesh.material = ColorMaterial.GetConceptualMaterial(this.ColorIndex);\r\n }\r\n }\r\n }\r\n else\r\n {\r\n for (let m of obj.children)\r\n {\r\n let mesh = m as Mesh;\r\n mesh.material = this.MeshMaterial;\r\n }\r\n }\r\n }\r\n\r\n protected _ReadFile(file: CADFiler)\r\n {\r\n super._ReadFile(file);\r\n let ver = file.Read();//1\r\n this._ShapeManager.Clear();\r\n this._ShapeManager.ReadFile(file);\r\n }\r\n WriteFile(file: CADFiler)\r\n {\r\n super.WriteFile(file);\r\n file.Write(1);//ver\r\n this._ShapeManager.WriteFile(file);\r\n }\r\n}\r\n","import { Matrix4, Vector3 } from \"three\";\r\nimport { ConverCircleToPolyline } from \"../../Common/CurveUtils\";\r\nimport { Board } from \"../../DatabaseServices/Entity/Board\";\r\nimport { Circle } from \"../../DatabaseServices/Entity/Circle\";\r\nimport { Line } from \"../../DatabaseServices/Entity/Line\";\r\nimport { Polyline } from \"../../DatabaseServices/Entity/Polyline\";\r\nimport { Region } from \"../../DatabaseServices/Entity/Region\";\r\n\r\n/**\r\n * 把板件炸开成面域,0,1为正反面,其余的为边面(没有圆弧面)\r\n */\r\nexport function Board2Regions(br: Board): Region[]\r\n{\r\n let ocs = br.OCS;\r\n\r\n let cu = br.ContourCurve.Clone();\r\n\r\n if (cu instanceof Circle)\r\n cu = ConverCircleToPolyline(cu);\r\n\r\n let frontReg = Region.CreateFromCurves([cu.Clone()]);\r\n let regFrontOcs = ocs.clone();\r\n regFrontOcs.setPosition(br.Position.add(br.Normal.multiplyScalar(br.Thickness)));\r\n frontReg.ApplyMatrix(regFrontOcs);\r\n\r\n let backReg = Region.CreateFromCurves([cu.Flip()]);\r\n backReg.ApplyMatrix(ocs);\r\n\r\n let resultRegs = [frontReg, backReg];\r\n\r\n //edges\r\n let lines = cu.Explode().filter(c => c instanceof Line);\r\n\r\n\r\n for (let l of lines)\r\n {\r\n let rectPl = new Polyline().Rectangle(l.Length, br.Thickness);\r\n let reg = Region.CreateFromCurves([rectPl]);\r\n if (!reg) continue;\r\n\r\n let p = l.StartPoint.applyMatrix4(ocs);\r\n let x = l.GetFistDeriv(0).transformDirection(ocs);\r\n let y = br.Normal;\r\n let z = new Vector3().crossVectors(x, y);\r\n\r\n let mtx = new Matrix4().makeBasis(x, y, z).setPosition(p);\r\n reg.ApplyMatrix(mtx);\r\n resultRegs.push(reg);\r\n }\r\n\r\n return resultRegs;\r\n}\r\n","\r\n/**统一板件属性key的命名,修改值会导致无法 .xxx该属性 */\r\nexport enum EBoardKeyList\r\n{\r\n Height = \"height\",\r\n Width = \"width\",\r\n Thick = \"thickness\",\r\n RoomName = \"roomName\",\r\n CabinetName = \"cabinetName\",\r\n BrMat = \"boardName\", //板材\r\n Mat = \"material\", //材料\r\n Color = \"color\",\r\n Lines = \"lines\", //纹路\r\n ProcessGroup = \"ProcessGroup\",\r\n BigHole = \"bigHoleDir\",\r\n /**\r\n * 排钻类型,当没有定义每个边的排钻数据时,使用统一的排钻类型\r\n */\r\n DrillType = \"drillType\",\r\n ComposingFace = \"composingFace\",\r\n /**\r\n * 封边数组,定义每个边的封边信息\r\n */\r\n HighSealed = \"highSealed\",\r\n UpSealed = \"sealedUp\",\r\n DownSealed = \"sealedDown\",\r\n LeftSealed = \"sealedLeft\",\r\n RightSealed = \"sealedRight\",\r\n KnifeRad = \"knifeRadius\",\r\n}\r\n","import { BoardProcessOption } from \"../../UI/Store/BoardInterface\";\r\nimport { EBoardKeyList } from \"../../Common/BoardKeyList\";\r\nimport { CADFiler } from \"../../DatabaseServices/CADFiler\";\r\n\r\n/**序列化板件数据 */\r\nexport function serializeBoardData(file: CADFiler, processData: BoardProcessOption)\r\n{\r\n file.Write(processData[EBoardKeyList.RoomName]);\r\n file.Write(processData[EBoardKeyList.CabinetName]);\r\n file.Write(processData[EBoardKeyList.BrMat]);\r\n file.Write(processData[EBoardKeyList.Mat]);\r\n file.Write(processData[EBoardKeyList.Color]);\r\n file.Write(processData[EBoardKeyList.Lines]);\r\n file.Write(processData[EBoardKeyList.BigHole]);\r\n file.Write(processData[EBoardKeyList.DrillType]);\r\n file.Write(processData[EBoardKeyList.ComposingFace]);\r\n file.Write(processData[EBoardKeyList.HighSealed].length);\r\n for (let n of processData[EBoardKeyList.HighSealed])\r\n {\r\n file.Write(n.size);\r\n }\r\n file.Write(processData[EBoardKeyList.UpSealed]);\r\n file.Write(processData[EBoardKeyList.DownSealed]);\r\n file.Write(processData[EBoardKeyList.LeftSealed]);\r\n file.Write(processData[EBoardKeyList.RightSealed]);\r\n file.Write(processData.spliteHeight);\r\n file.Write(processData.spliteWidth);\r\n file.Write(processData.spliteThickness);\r\n\r\n file.Write(processData.highDrill.length);\r\n for (let n of processData.highDrill)\r\n file.Write(n);\r\n\r\n file.Write(processData.frontDrill);\r\n file.Write(processData.backDrill);\r\n file.Write(processData.remarks.length);\r\n for (let d of processData.remarks)\r\n {\r\n file.Write(d[0]);\r\n file.Write(d[1]);\r\n }\r\n}\r\n\r\n//反序列化板件数据\r\nexport function deserializationBoardData(file: CADFiler, processData: BoardProcessOption, ver: number)\r\n{\r\n processData[EBoardKeyList.RoomName] = file.Read();\r\n processData[EBoardKeyList.CabinetName] = file.Read();\r\n processData[EBoardKeyList.BrMat] = file.Read();\r\n processData[EBoardKeyList.Mat] = file.Read();\r\n processData[EBoardKeyList.Color] = file.Read();\r\n processData[EBoardKeyList.Lines] = file.Read();\r\n processData[EBoardKeyList.BigHole] = file.Read();\r\n processData[EBoardKeyList.DrillType] = file.Read();\r\n processData[EBoardKeyList.ComposingFace] = file.Read();\r\n\r\n let count = file.Read();\r\n processData[EBoardKeyList.HighSealed].length = 0;\r\n for (let i = 0; i < count; i++)\r\n {\r\n let size = file.Read();\r\n if (ver < 4)\r\n {\r\n file.Read();\r\n }\r\n processData[EBoardKeyList.HighSealed].push({ size });\r\n }\r\n\r\n processData[EBoardKeyList.UpSealed] = file.Read();\r\n processData[EBoardKeyList.DownSealed] = file.Read();\r\n processData[EBoardKeyList.LeftSealed] = file.Read();\r\n processData[EBoardKeyList.RightSealed] = file.Read();\r\n processData.spliteHeight = file.Read();\r\n processData.spliteWidth = file.Read();\r\n processData.spliteThickness = file.Read();\r\n\r\n count = file.Read();\r\n processData.highDrill = file.ReadArray(count);\r\n\r\n processData.frontDrill = file.Read();\r\n processData.backDrill = file.Read();\r\n\r\n if (ver >= 7)\r\n {\r\n let count = file.Read();\r\n processData.remarks.length = 0;\r\n for (let i = 0; i < count; i++)\r\n {\r\n let d: [string, string] = [\"\", \"\"];\r\n d[0] = file.Read();\r\n d[1] = file.Read();\r\n processData.remarks.push(d);\r\n }\r\n }\r\n}\r\n","import { ExtrudeBufferGeometry, UVGenerator, Vector2 } from \"three\";\r\n\r\nclass BoardUVGenerator implements UVGenerator\r\n{\r\n generateTopUV(geometry: ExtrudeBufferGeometry, vertices: number[], indexA: number, indexB: number, indexC: number)\r\n {\r\n var a_x = vertices[indexA * 3];\r\n var a_y = vertices[indexA * 3 + 1];\r\n var b_x = vertices[indexB * 3];\r\n var b_y = vertices[indexB * 3 + 1];\r\n var c_x = vertices[indexC * 3];\r\n var c_y = vertices[indexC * 3 + 1];\r\n\r\n return [\r\n new Vector2(a_x, a_y),\r\n new Vector2(b_x, b_y),\r\n new Vector2(c_x, c_y)\r\n ];\r\n }\r\n generateSideWallUV(geometry: ExtrudeBufferGeometry, vertices: number[], indexA: number, indexB: number, indexC: number, indexD: number)\r\n {\r\n var a_x = vertices[indexA * 3];\r\n var a_y = vertices[indexA * 3 + 1];\r\n var a_z = vertices[indexA * 3 + 2];\r\n var b_x = vertices[indexB * 3];\r\n var b_y = vertices[indexB * 3 + 1];\r\n var b_z = vertices[indexB * 3 + 2];\r\n var c_x = vertices[indexC * 3];\r\n var c_y = vertices[indexC * 3 + 1];\r\n var c_z = vertices[indexC * 3 + 2];\r\n var d_x = vertices[indexD * 3];\r\n var d_y = vertices[indexD * 3 + 1];\r\n var d_z = vertices[indexD * 3 + 2];\r\n let pts: Vector2[];\r\n if (Math.abs(a_y - b_y) < 0.01)\r\n {\r\n pts = [\r\n new Vector2(a_z - 1, a_x),\r\n new Vector2(b_z - 1, b_x),\r\n new Vector2(c_z - 1, c_x),\r\n new Vector2(d_z - 1, d_x)\r\n ];\r\n\r\n }\r\n else\r\n {\r\n pts = [\r\n new Vector2(a_z - 1, a_y),\r\n new Vector2(b_z - 1, b_y),\r\n new Vector2(c_z - 1, c_y),\r\n new Vector2(d_z - 1, d_y)\r\n ];\r\n }\r\n return pts;\r\n }\r\n}\r\n\r\nclass BoardUVGenerator2 extends BoardUVGenerator\r\n{\r\n generateTopUV(geometry: ExtrudeBufferGeometry, vertices: number[], indexA: number, indexB: number, indexC: number)\r\n {\r\n var a_x = vertices[indexA * 3];\r\n var a_y = vertices[indexA * 3 + 1];\r\n var b_x = vertices[indexB * 3];\r\n var b_y = vertices[indexB * 3 + 1];\r\n var c_x = vertices[indexC * 3];\r\n var c_y = vertices[indexC * 3 + 1];\r\n\r\n return [\r\n new Vector2(a_y, a_x),\r\n new Vector2(b_y, b_x),\r\n new Vector2(c_y, c_x)\r\n ];\r\n }\r\n}\r\n\r\nexport let boardUVGenerator = new BoardUVGenerator();\r\nexport let boardUVGenerator2 = new BoardUVGenerator2();\r\n","import { EBoardKeyList } from \"../../Common/BoardKeyList\";\r\nimport { ObjectId } from \"../../DatabaseServices/ObjectId\";\r\n\r\nexport enum BoardType\r\n{\r\n Layer = 0, //层板\r\n Vertical = 1, //立板\r\n Behind = 2 //背板\r\n}\r\n\r\n/**\r\n *勿随意更改属性名,若更改,需更改对应UI模态框的属性和检验方法的key\r\n *\r\n */\r\nexport interface IBaseOption\r\n{\r\n version?: number;\r\n}\r\n\r\n//板件数据,配置信息+加工信息\r\nexport interface BoardData\r\n{\r\n boardConfig: BoardConfigOption;\r\n boardProcess: BoardProcessOption;\r\n}\r\n//排钻类型\r\nexport enum DrillType\r\n{\r\n Yes = \"排\",\r\n None = \"不排\",\r\n More = \"**多种**\",\r\n Invail = \"无效配置\",\r\n}\r\n//偏心轮类型\r\nexport enum FaceDirection\r\n{\r\n Front = 0,\r\n Back = 1,\r\n}\r\n\r\n//纹路类型\r\nexport enum LinesType\r\n{\r\n /** 正纹 */\r\n Positive = 0,\r\n /** 反纹 */\r\n Reverse = 1,\r\n /** 可翻转 */\r\n CanReversal = 2,\r\n}\r\n\r\n// 排版面\r\nexport enum ComposingType\r\n{\r\n Positive, Reverse, Arbitrary\r\n}\r\n/**\r\n *背板靠上还是靠下\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum BehindHeightPositon\r\n{\r\n ForTop = \"top\", //靠上\r\n ForBottom = \"bottom\",//靠下\r\n AllHeight = \"all\" //总高\r\n}\r\n\r\n/**\r\n *板件相对位置\r\n *\r\n * @export\r\n * @enum {number}\r\n */\r\nexport enum BrRelativePos\r\n{\r\n Front = \"front\",\r\n Back = \"back\",\r\n Top = \"top\",\r\n Bottom = \"bottom\",\r\n Left = \"left\",\r\n Right = \"right\",\r\n Div = \"div\"\r\n}\r\n\r\nexport interface IHighSealedItem\r\n{\r\n size: number;\r\n}\r\n\r\nexport interface BoardProcessOption extends IBaseOption\r\n{\r\n [EBoardKeyList.RoomName]?: string;\r\n [EBoardKeyList.CabinetName]?: string;//柜名\r\n [EBoardKeyList.BrMat]?: string;//板材名\r\n [EBoardKeyList.Mat]?: string;//材料\r\n [EBoardKeyList.Color]?: string;\r\n [EBoardKeyList.Lines]?: LinesType;//纹路\r\n [EBoardKeyList.ProcessGroup]?: ObjectId[];//纹路\r\n [EBoardKeyList.BigHole]?: FaceDirection;//大孔面\r\n [EBoardKeyList.DrillType]?: string;//排钻类型\r\n [EBoardKeyList.ComposingFace]?: ComposingType;//排版面\r\n [EBoardKeyList.HighSealed]?: IHighSealedItem[];//封边数据\r\n [EBoardKeyList.UpSealed]?: string;//封边上下左右\r\n [EBoardKeyList.DownSealed]?: string;\r\n [EBoardKeyList.LeftSealed]?: string;\r\n [EBoardKeyList.RightSealed]?: string;\r\n spliteHeight?: string;//拆单高/宽/厚\r\n spliteWidth?: string;\r\n spliteThickness?: string;\r\n highDrill?: string[];\r\n frontDrill: boolean;\r\n backDrill: boolean;\r\n remarks: [string, string][];\r\n useBoardProcessOption?: boolean;\r\n}\r\n\r\n/**\r\n *板件参数\r\n */\r\nexport interface BoardConfigOption extends IBaseOption\r\n{\r\n type: BoardType;\r\n name: string;\r\n thickness?: number;\r\n height?: number;\r\n width?: number;\r\n}\r\nexport interface SideBoardOption extends BoardConfigOption\r\n{\r\n spaceSize?: number; //空间宽度\r\n leftShrink: number; //左侧板内缩\r\n rightShrink: number;\r\n}\r\n\r\n/**\r\n *背板参数\r\n *\r\n * @export\r\n * @interface BehindBoardOption\r\n * @extends {BoardConfigOption}\r\n */\r\nexport interface BehindBoardOption extends BoardConfigOption\r\n{\r\n //上下左右延伸\r\n leftExt: number;\r\n rightExt: number;\r\n topExt: number;\r\n bottomExt: number;\r\n //板件位置\r\n boardPosition: BehindHeightPositon;\r\n moveDist: number;\r\n\r\n spaceSize?: number;\r\n count?: number;\r\n //板件相对位置\r\n boardRelative?: BrRelativePos;\r\n calcHeight: string;//高度表达式\r\n calcSpaceSize: string;\r\n calcMoveDist: string;\r\n}\r\n\r\n/**\r\n *层板参数\r\n *\r\n * @export\r\n * @interface LayerBoardOption\r\n * @extends {BoardConfigOption}\r\n */\r\nexport interface LayerBoardOption extends BoardConfigOption\r\n{\r\n calcHeight: string;\r\n frontShrink: number;\r\n leftShrink: number;\r\n rightShrink: number;\r\n isTotalLength: boolean;\r\n isActive: boolean;\r\n spaceSize?: number;\r\n count?: number;\r\n boardRelative?: BrRelativePos;\r\n calcSpaceSize: string;\r\n calcFrontShrink: string;\r\n calcLeftShrink: string;\r\n calcRightShrink: string;\r\n}\r\n\r\n/**\r\n *层板钉参数\r\n *\r\n * @export\r\n * @interface LayerNailOption\r\n */\r\nexport interface LayerNailOption extends IBaseOption\r\n{\r\n isDraw: boolean; //是否绘制\r\n addCount: number;//增\r\n dist: number;\r\n isGroup: boolean;\r\n isInBack: boolean; //是否在背板绘制\r\n front: number;\r\n behind: number;\r\n count: number;\r\n rad: number;\r\n length: number;\r\n depth: number;\r\n}\r\n\r\n/**\r\n *立板参数\r\n */\r\nexport interface VerticalBoardOption extends BoardConfigOption\r\n{\r\n frontShrink: number; //前缩\r\n bottomShrink: number;//底缩\r\n isTotalLength: boolean; //是否取总高\r\n isTotalWidth: boolean;//是否取总宽\r\n count?: number;\r\n spaceSize?: number;\r\n boardRelative?: BrRelativePos;\r\n calcWidth: string; //板深表达式\r\n calcHeight: string;\r\n calcSpaceSize: string;\r\n calcFrontShrink: string;\r\n calcBottomShrink: string;\r\n}\r\nexport interface TBBoardOption extends BoardConfigOption\r\n{\r\n isDraw: boolean;\r\n frontDist: number; //前距\r\n behindDistance: number; //后距\r\n isWrapSide: boolean; //顶包侧\r\n useLFData: boolean;\r\n leftExt: number;\r\n rightExt: number;\r\n offset: number;//上留或者下留\r\n isDrawFooter?: boolean;\r\n footThickness?: number; //地脚厚\r\n footBehindShrink?: number;//内缩\r\n isDrawBackFooter?: boolean;\r\n footerOffset?: number;\r\n isDrawStrengthenStrip?: boolean;\r\n divCount?: number;\r\n}\r\nexport interface SingleBoardOption extends BoardConfigOption\r\n{\r\n rotateX: number;\r\n rotateY: number;\r\n rotateZ: number;\r\n\r\n}\r\nexport enum StripType\r\n{\r\n H = \"h\",\r\n V = \"v\",\r\n}\r\nexport interface ClosingStripOption extends BoardConfigOption\r\n{\r\n boardRelative: BrRelativePos;\r\n striptype: StripType;//收口条类型\r\n frontShrink: number; //前缩\r\n}\r\n\r\nexport interface IGrooveOption extends IBaseOption\r\n{\r\n grooveAddLength: string;//槽加长/宽/高\r\n grooveAddWidth: string;\r\n grooveAddDepth: string;\r\n knifeRadius?: string;\r\n}\r\n\r\nexport interface IShinkOption extends IBaseOption\r\n{\r\n left: number;\r\n right: number;\r\n front: number;\r\n back: number;\r\n isLREqual: boolean;\r\n isFBEqual: boolean;\r\n}\r\n\r\nexport type IUiOption = {\r\n [P in (keyof T)]: T[P] extends number ? string : T[P]\r\n};\r\n\r\nexport interface INailRule extends IBaseOption\r\n{\r\n startDist: number;\r\n endDist: number;\r\n count: number;\r\n}\r\n\r\nexport interface IHightDrillOption\r\n{\r\n up: string;\r\n down: string;\r\n left: string;\r\n right: string;\r\n}\r\nexport enum CurtailType\r\n{\r\n PerBr = \"0\",\r\n Total = \"1\",\r\n}\r\n\r\nexport interface IBoardBatchCurtailOption extends IBaseOption\r\n{\r\n type: CurtailType;\r\n front: number;\r\n back: number;\r\n left: number;\r\n right: number;\r\n moveBrs: boolean;\r\n}\r\n\r\nexport enum BoardOpenDir\r\n{\r\n Left = 1,\r\n Right = 2,\r\n Up = 3,\r\n Down = 4,\r\n None = 0,\r\n}\r\n\r\nexport type AnyObject = { [key: string]: any; };\r\n\r\n//见光面封边设置\r\nexport interface ISmoothEdgeOption extends IBaseOption\r\n{\r\n smoothEdge: number;//见光面\r\n edge: number;//非见光面\r\n scale: number;//见光比例\r\n filterArr: string[];//\r\n}\r\n\r\nexport interface IDrawBoardAutoCutOption\r\n{\r\n isAutoCut: boolean;//是否自动切割\r\n isRelevance: boolean;//是否关联切割\r\n}\r\n","import { Object3D } from \"three\";\r\nimport { Entity } from \"../DatabaseServices/Entity/Entity\";\r\nimport { RenderType } from \"../GraphicsSystem/RenderType\";\r\n\r\n//将嵌入的实体绘制对象添加到当前的绘制对象(由于内嵌的实体可能被重复引用)\r\nexport function AddEntityDrawObject(obj: Object3D, embedEntity: Entity, renderType: RenderType = RenderType.Wireframe)\r\n{\r\n let embedObject = embedEntity.GetDrawObjectFromRenderType(renderType);\r\n if (embedObject.parent)\r\n obj.children.push(embedObject);//为了避免这个内嵌实体加入到不同的Object中(因为我们有PrintObject),这个写法能行,是因为我们会在其他地方更新它的矩阵\r\n else\r\n obj.add(embedObject);\r\n}\r\n","import { Matrix4, Vector3 } from \"three\";\r\n\r\nlet x = new Vector3();\r\nlet y = new Vector3();\r\nlet z = new Vector3();\r\nexport function IsMirror(mtx: Matrix4): boolean\r\n{\r\n mtx.extractBasis(x, y, z);\r\n // for a true orthogonal, non-mirrored base, u.cross(v) == w\r\n // If they have an opposite direction then we are mirroring\r\n const mirrorvalue = x.cross(y).dot(z);\r\n const ismirror = (mirrorvalue < 0);\r\n return ismirror;\r\n}\r\n","export const _CSGDEBUG = false;\r\n\r\n/** Epsilon used during determination of near zero distances.\r\n * @default\r\n */\r\nexport const EPS = 1e-5;\r\n\r\n// Tag factory: we can request a unique tag through CSG.getTag()\r\nexport let staticTag = 1;\r\nexport const getTag = () => staticTag++;\r\n","import { Vector3 } from \"three\";\r\n/** Class Vector3D\r\n * Represents a 3D vector with X, Y, Z coordinates.\r\n */\r\nexport class Vector3D extends Vector3\r\n{\r\n clone()\r\n {\r\n return new Vector3D(this.x, this.y, this.z) as this;\r\n }\r\n // find a vector that is somewhat perpendicular to this one\r\n randomNonParallelVector()\r\n {\r\n let x = Math.abs(this.x);\r\n let y = Math.abs(this.y);\r\n let z = Math.abs(this.z);\r\n\r\n if (x <= y && x <= z)\r\n return new Vector3D(1, 0, 0);\r\n else if (y <= x && y <= z)\r\n return new Vector3D(0, 1, 0);\r\n else\r\n return new Vector3D(0, 0, 1);\r\n }\r\n\r\n toString()\r\n {\r\n return (\r\n \"(\" +\r\n this.x.toFixed(5) +\r\n \", \" +\r\n this.y.toFixed(5) +\r\n \", \" +\r\n this.z.toFixed(5) +\r\n \")\"\r\n );\r\n }\r\n}\r\n","import { Vector3D } from \"./Vector3\";\r\nimport { Vector2 } from \"three\";\r\n\r\nexport class Vector2D extends Vector2\r\n{\r\n // extend to a 3D vector by adding a z coordinate:\r\n toVector3D(z: number)\r\n {\r\n return new Vector3D(this.x, this.y, z);\r\n }\r\n clone()\r\n {\r\n return new Vector2D(this.x, this.y) as this;\r\n }\r\n // returns the vector rotated by 90 degrees clockwise\r\n normal()\r\n {\r\n return new Vector2D(this.y, -this.x);\r\n }\r\n\r\n cross(a: Vector2)\r\n {\r\n return this.x * a.y - this.y * a.x;\r\n }\r\n}\r\n","import { getTag } from \"../constants\";\r\nimport { Vector2D } from \"./Vector2\";\r\nimport { Vector3D } from \"./Vector3\";\r\nimport { Matrix4 } from \"three\";\r\n\r\n// # class Vertex\r\n// Represents a vertex of a polygon. Use your own vertex class instead of this\r\n// one to provide additional features like texture coordinates and vertex\r\n// colors. Custom vertex classes need to provide a `pos` property\r\n// `flipped()`, and `interpolate()` methods that behave analogous to the ones\r\n// FIXME: And a lot MORE (see plane.fromVector3Ds for ex) ! This is fragile code\r\n// defined by `Vertex`.\r\nexport class Vertex3D\r\n{\r\n tag: number;\r\n constructor(public pos: Vector3D, public uv = new Vector2D()) { }\r\n\r\n clone()\r\n {\r\n return new Vertex3D(this.pos.clone(), this.uv.clone());\r\n }\r\n\r\n // Return a vertex with all orientation-specific data (e.g. vertex normal) flipped. Called when the\r\n // orientation of a polygon is flipped.\r\n flipped()\r\n {\r\n return this;\r\n }\r\n\r\n getTag()\r\n {\r\n let result = this.tag;\r\n if (!result)\r\n {\r\n result = getTag();\r\n this.tag = result;\r\n }\r\n return result;\r\n }\r\n\r\n // Create a new vertex between this vertex and `other` by linearly\r\n // interpolating all properties using a parameter of `t`. Subclasses should\r\n // override this to interpolate additional properties.\r\n interpolate(other: Vertex3D, t: number)\r\n {\r\n let pos = this.pos.clone().lerp(other.pos, t);\r\n let uv = this.uv.clone().lerp(other.uv, t);\r\n return new Vertex3D(pos, uv);\r\n }\r\n\r\n // Affine transformation of vertex. Returns a new Vertex\r\n\r\n transform(matrix4x4: Matrix4)\r\n {\r\n const newpos = this.pos.clone().applyMatrix4(matrix4x4);\r\n return new Vertex3D(newpos, this.uv);\r\n }\r\n}\r\n","import { Matrix4 } from \"three\";\r\nimport { equaln, equalv3 } from \"../../../Geometry/GeUtils\";\r\nimport { getTag } from \"../constants\";\r\nimport { IsMirror } from \"./IsMirrot\";\r\nimport { Vector3D } from \"./Vector3\";\r\nimport { Vertex3D } from \"./Vertex3\";\r\n\r\n// # class Plane\r\n// Represents a plane in 3D space.\r\nexport class Plane\r\n{\r\n normal: Vector3D;\r\n w: number;\r\n tag: number;\r\n constructor(normal: Vector3D, w: number)\r\n {\r\n this.normal = normal;\r\n this.w = w;\r\n }\r\n\r\n flipped()\r\n {\r\n return new Plane(this.normal.clone().negate(), -this.w);\r\n }\r\n\r\n getTag()\r\n {\r\n if (!this.tag)\r\n this.tag = getTag();\r\n return this.tag;\r\n }\r\n\r\n coplanarTo(plane: Plane)\r\n {\r\n return equalv3(this.normal, plane.normal, 1e-4) && equaln(this.w, plane.w, 1e-4);\r\n }\r\n\r\n transform(matrix4x4: Matrix4)\r\n {\r\n // get two vectors in the plane:\r\n let r = this.normal.randomNonParallelVector();\r\n let u = this.normal.clone().cross(r);\r\n let v = this.normal.clone().cross(u);\r\n // get 3 points in the plane:\r\n let point1 = this.normal.clone().multiplyScalar(this.w);\r\n let point2 = u.add(point1);\r\n let point3 = v.add(point1);\r\n // transform the points:\r\n point1.applyMatrix4(matrix4x4);\r\n point2.applyMatrix4(matrix4x4);\r\n point3.applyMatrix4(matrix4x4);\r\n // and create a new plane from the transformed points:\r\n let newplane = Plane.fromVector3Ds(point1, point2, point3);\r\n if (IsMirror(matrix4x4))\r\n {\r\n // the transform is mirroring\r\n // We should mirror the plane:\r\n newplane = newplane.flipped();\r\n }\r\n return newplane;\r\n }\r\n\r\n splitLineBetweenPoints(p1: Vertex3D, p2: Vertex3D): Vertex3D\r\n {\r\n let direction = p2.pos.clone().sub(p1.pos);\r\n let labda = (this.w - this.normal.dot(p1.pos)) / this.normal.dot(direction);\r\n if (isNaN(labda)) labda = 0;\r\n if (labda > 1) labda = 1;\r\n if (labda < 0) labda = 0;\r\n let pos = p1.pos.clone().add(direction.multiplyScalar(labda));\r\n let uv = p1.uv.clone().lerp(p2.uv, labda);\r\n return new Vertex3D(pos, uv);\r\n }\r\n\r\n static fromVector3Ds(a: Vector3D, b: Vector3D, c: Vector3D)\r\n {\r\n let n = b.clone()\r\n .sub(a)\r\n .cross(c.clone().sub(a))\r\n .normalize();\r\n return new Plane(n, n.dot(a));\r\n }\r\n}\r\n","import { _CSGDEBUG, EPS } from \"../constants\";\r\nimport { Plane } from \"./Plane\";\r\nimport { Vector3D } from \"./Vector3\";\r\nimport { Vertex3D } from \"./Vertex3\";\r\nimport { arrayRemoveDuplicateBySort } from \"../../../Common/ArrayExt\";\r\nimport { Matrix4 } from \"three\";\r\nimport { IsMirror } from \"./IsMirrot\";\r\n\r\nexport enum Type\r\n{\r\n CoplanarFront = 0,\r\n CoplanarBack = 1,\r\n Front = 2,\r\n Back = 3,\r\n Spanning = 4,\r\n}\r\n\r\n\r\ninterface SplitPolygonData\r\n{\r\n type: Type;\r\n front: Polygon;\r\n back: Polygon;\r\n}\r\n\r\n/** Class Polygon\r\n * Represents a convex polygon. The vertices used to initialize a polygon must\r\n * be coplanar and form a convex loop. They do not have to be `Vertex`\r\n * instances but they must behave similarly (duck typing can be used for\r\n * customization).\r\n *
\r\n * Each convex polygon has a `shared` property, which is shared between all\r\n * polygons that are clones of each other or were split from the same polygon.\r\n * This can be used to define per-polygon properties (such as surface color).\r\n *
\r\n * The plane of the polygon is calculated from the vertex coordinates if not provided.\r\n * The plane can alternatively be passed as the third argument to avoid calculations.\r\n *\r\n *表示凸多边形。 用于初始化多边形的顶点必须共面并形成凸环。\r\n *多边形是彼此克隆或从同一多边形分割的多边形。\r\n *这可用于定义每个多边形属性(例如表面颜色)。\r\n */\r\nexport class Polygon\r\n{\r\n cachedBoundingSphere: [Vector3D, number];\r\n cachedBoundingBox: [Vector3D, Vector3D];\r\n constructor(public vertices: Vertex3D[], public plane?: Plane)\r\n {\r\n if (!plane)\r\n this.plane = Plane.fromVector3Ds(vertices[0].pos, vertices[1].pos, vertices[2].pos);\r\n\r\n if (_CSGDEBUG)\r\n if (!this.checkIfConvex()) throw new Error(\"Not convex!\");\r\n }\r\n\r\n /** Check whether the polygon is convex. (it should be, otherwise we will get unexpected results)*/\r\n checkIfConvex(): boolean\r\n {\r\n return Polygon.verticesConvex(this.vertices, this.plane.normal);\r\n }\r\n\r\n // returns an array with a Vector3D (center point) and a radius\r\n\r\n boundingSphere()\r\n {\r\n if (!this.cachedBoundingSphere)\r\n {\r\n let box = this.boundingBox();\r\n let middle = box[0].clone().add(box[1]).multiplyScalar(0.5);\r\n let radius3 = box[1].clone().sub(middle);\r\n let radius = radius3.length();\r\n this.cachedBoundingSphere = [middle, radius];\r\n }\r\n return this.cachedBoundingSphere;\r\n }\r\n\r\n // returns an array of two Vector3Ds (minimum coordinates and maximum coordinates)\r\n\r\n boundingBox(): Vector3D[]\r\n {\r\n if (!this.cachedBoundingBox)\r\n {\r\n let minpoint: Vector3D;\r\n let maxpoint: Vector3D;\r\n let vertices = this.vertices;\r\n let numvertices = vertices.length;\r\n if (numvertices === 0)\r\n minpoint = new Vector3D(0, 0, 0);\r\n else\r\n minpoint = vertices[0].pos.clone();\r\n maxpoint = minpoint.clone();\r\n for (let i = 1; i < numvertices; i++)\r\n {\r\n let point = vertices[i].pos;\r\n minpoint.min(point);\r\n maxpoint.max(point);\r\n }\r\n this.cachedBoundingBox = [minpoint, maxpoint];\r\n }\r\n return this.cachedBoundingBox;\r\n }\r\n\r\n flipped()\r\n {\r\n let newvertices = this.vertices.map(v => v.flipped());\r\n newvertices.reverse();\r\n let newplane = this.plane.flipped();\r\n return new Polygon(newvertices, newplane);\r\n }\r\n\r\n // Affine transformation of polygon. Returns a new Polygon\r\n transform(matrix4x4: Matrix4)\r\n {\r\n let newvertices = this.vertices.map(v => v.transform(matrix4x4));\r\n let newplane = this.plane.transform(matrix4x4);\r\n if (IsMirror(matrix4x4))\r\n {\r\n // need to reverse the vertex order\r\n // in order to preserve the inside/outside orientation:\r\n newvertices.reverse();\r\n }\r\n return new Polygon(newvertices, newplane);\r\n }\r\n\r\n splitByPlane(plane: Plane): SplitPolygonData\r\n {\r\n let result: SplitPolygonData = { type: null, front: null, back: null };\r\n // cache in local lets (speedup):\r\n let planeNormal = plane.normal;\r\n let vertices = this.vertices;\r\n let numVertices = vertices.length;\r\n if (this.plane.coplanarTo(plane))\r\n {\r\n result.type = Type.CoplanarFront;\r\n }\r\n else\r\n {\r\n let thisW = plane.w;\r\n let hasFront = false;\r\n let hasBack = false;\r\n let vertexIsBack: boolean[] = [];\r\n let MINEPS = -EPS;\r\n for (let i = 0; i < numVertices; i++)\r\n {\r\n let t = planeNormal.dot(vertices[i].pos) - thisW;\r\n let isBack = t < 0;\r\n vertexIsBack.push(isBack);\r\n if (t > EPS) hasFront = true;\r\n if (t < MINEPS) hasBack = true;\r\n }\r\n if (!hasFront && !hasBack)\r\n {\r\n // all points coplanar\r\n let t = planeNormal.dot(this.plane.normal);\r\n result.type = t >= 0 ? Type.CoplanarFront : Type.CoplanarBack;\r\n }\r\n else if (!hasBack)\r\n result.type = Type.Front;\r\n else if (!hasFront)\r\n result.type = Type.Back;\r\n else\r\n {\r\n result.type = Type.Spanning;\r\n let frontVertices: Vertex3D[] = [];\r\n let backVertices: Vertex3D[] = [];\r\n let isBack = vertexIsBack[0];\r\n for (\r\n let vertexIndex = 0;\r\n vertexIndex < numVertices;\r\n vertexIndex++\r\n )\r\n {\r\n let vertex = vertices[vertexIndex];\r\n let nextVertexindex = vertexIndex + 1;\r\n if (nextVertexindex >= numVertices) nextVertexindex = 0;\r\n let nextIsBack = vertexIsBack[nextVertexindex];\r\n if (isBack === nextIsBack)\r\n {\r\n // line segment is on one side of the plane:\r\n if (isBack)\r\n backVertices.push(vertex);\r\n else\r\n frontVertices.push(vertex);\r\n }\r\n else\r\n {\r\n let intersectionVertex = plane.splitLineBetweenPoints(vertex, vertices[nextVertexindex]);\r\n if (isBack)\r\n {\r\n backVertices.push(vertex);\r\n backVertices.push(intersectionVertex);\r\n frontVertices.push(intersectionVertex);\r\n }\r\n else\r\n {\r\n frontVertices.push(vertex);\r\n frontVertices.push(intersectionVertex);\r\n backVertices.push(intersectionVertex);\r\n }\r\n }\r\n isBack = nextIsBack;\r\n } // for vertexindex\r\n // remove duplicate vertices:\r\n let EPS_SQUARED = EPS * EPS;\r\n arrayRemoveDuplicateBySort(backVertices, (v1, v2) =>\r\n {\r\n return v1.pos.distanceToSquared(v2.pos) < EPS_SQUARED;\r\n });\r\n arrayRemoveDuplicateBySort(frontVertices, (v1, v2) =>\r\n {\r\n return v1.pos.distanceToSquared(v2.pos) < EPS_SQUARED;\r\n });\r\n if (frontVertices.length >= 3)\r\n result.front = new Polygon(frontVertices, this.plane);\r\n if (backVertices.length >= 3)\r\n result.back = new Polygon(backVertices, this.plane);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n static verticesConvex(vertices: Vertex3D[], planenormal: Vector3D)\r\n {\r\n let count = vertices.length;\r\n if (count < 3) return false;\r\n\r\n let prevPrevPos = vertices[count - 2].pos;\r\n let prevPos = vertices[count - 1].pos;\r\n for (let i = 0; i < count; i++)\r\n {\r\n let pos = vertices[i].pos;\r\n if (!Polygon.isConvexPoint(prevPrevPos, prevPos, pos, planenormal))\r\n return false;\r\n\r\n prevPrevPos = prevPos;\r\n prevPos = pos;\r\n }\r\n return true;\r\n }\r\n\r\n // 计算3点是否凸角\r\n static isConvexPoint(prevpoint: Vector3D, point: Vector3D, nextpoint: Vector3D, normal: Vector3D)\r\n {\r\n let crossproduct = point.clone().sub(prevpoint).cross(nextpoint.clone().sub(point));\r\n let crossdotnormal = crossproduct.dot(normal);\r\n return crossdotnormal >= 0;\r\n }\r\n}\r\n","import { EPS, _CSGDEBUG } from \"./constants\";\r\nimport { Plane } from \"./math/Plane\";\r\nimport { Polygon, Type } from \"./math/Polygon3\";\r\nimport { Vector3D } from \"./math/Vector3\";\r\n\r\n// # class PolygonTreeNode\r\n// This class manages hierarchical splits of polygons\r\n// At the top is a root node which doesn hold a polygon, only child PolygonTreeNodes\r\n// Below that are zero or more 'top' nodes; each holds a polygon. The polygons can be in different planes\r\n// splitByPlane() splits a node by a plane. If the plane intersects the polygon, two new child nodes\r\n// are created holding the splitted polygon.\r\n// getPolygons() retrieves the polygon from the tree. If for PolygonTreeNode the polygon is split but\r\n// the two split parts (child nodes) are still intact, then the unsplit polygon is returned.\r\n// This ensures that we can safely split a polygon into many fragments. If the fragments are untouched,\r\n// getPolygons() will return the original unsplit polygon instead of the fragments.\r\n// remove() removes a polygon from the tree. Once a polygon is removed, the parent polygons are invalidated\r\n// since they are no longer intact.\r\n// constructor creates the root node:\r\n//此类管理多边形的层次分割\r\n//顶部是一个根节点,它不包含多边形,只有子PolygonTreeNodes\r\n//下面是零个或多个“顶部”节点; 每个都有一个多边形。 多边形可以位于不同的平面中\r\n// splitByPlane()按平面拆分节点。 如果平面与多边形相交,则会有两个新的子节点\r\n//创建持有分割多边形。\r\n// getPolygons()从树中检索多边形。 如果对于PolygonTreeNode,则多边形被拆分但是\r\n//两个分割部分(子节点)仍然完好无损,然后返回未分割的多边形。\r\n//这确保我们可以安全地将多边形拆分为多个片段。 如果碎片未受影响,\r\n// getPolygons()将返回原始的未分割多边形而不是片段。\r\n// remove()从树中删除多边形。 删除多边形后,父多边形将失效\r\n//因为它们不再完好无损\r\n//构造函数创建根节点:\r\nclass PolygonTreeNode\r\n{\r\n parent: PolygonTreeNode;\r\n children: PolygonTreeNode[] = [];\r\n polygon: Polygon;\r\n removed: boolean = false;\r\n constructor(polygon?: Polygon)\r\n {\r\n this.polygon = polygon;\r\n }\r\n\r\n // fill the tree with polygons. Should be called on the root node only; child nodes must\r\n // always be a derivate (split) of the parent node.\r\n addPolygons(polygons: Polygon[])\r\n {\r\n // new polygons can only be added to root node; children can only be splitted polygons\r\n if (!this.isRootNode())\r\n throw new Error(\"Assertion failed\");\r\n\r\n for (let polygon of polygons)\r\n this.addChild(polygon);\r\n }\r\n\r\n // remove a node\r\n // - the siblings become toplevel nodes\r\n // - the parent is removed recursively\r\n\r\n remove()\r\n {\r\n if (this.removed) return;\r\n\r\n this.removed = true;\r\n\r\n if (_CSGDEBUG)\r\n {\r\n if (this.isRootNode()) throw new Error(\"Assertion failed\"); // can't remove root node\r\n if (this.children.length) throw new Error(\"Assertion failed\"); // we shouldn't remove nodes with children\r\n }\r\n\r\n // remove ourselves from the parent's children list:\r\n let parentschildren = this.parent.children;\r\n let i = parentschildren.indexOf(this);\r\n if (i < 0) throw new Error(\"Assertion failed\");\r\n parentschildren.splice(i, 1);\r\n\r\n // invalidate the parent's polygon, and of all parents above it:\r\n this.parent.recursivelyInvalidatePolygon();\r\n }\r\n\r\n isRemoved()\r\n {\r\n return this.removed;\r\n }\r\n\r\n isRootNode()\r\n {\r\n return !this.parent;\r\n }\r\n\r\n // invert all polygons in the tree. Call on the root node\r\n\r\n invert()\r\n {\r\n if (!this.isRootNode()) throw new Error(\"Assertion failed\"); // can only call this on the root node\r\n this.invertSub();\r\n }\r\n\r\n getPolygon(): Polygon\r\n {\r\n if (!this.polygon) throw new Error(\"Assertion failed\"); // doesn't have a polygon, which means that it has been broken down\r\n return this.polygon;\r\n }\r\n\r\n getPolygons(outPolygons: Polygon[] = []): Polygon[]\r\n {\r\n let children: PolygonTreeNode[] = [this];\r\n let queue = [children];\r\n for (let i = 0; i < queue.length; ++i)\r\n {\r\n // queue size can change in loop, don't cache length\r\n children = queue[i];\r\n for (let node of children)\r\n {\r\n if (node.polygon)\r\n // the polygon hasn't been broken yet. We can ignore the children and return our polygon:\r\n outPolygons.push(node.polygon);\r\n else\r\n // our polygon has been split up and broken, so gather all subpolygons from the children\r\n queue.push(node.children);\r\n }\r\n }\r\n\r\n return outPolygons;\r\n }\r\n\r\n // split the node by a plane; add the resulting nodes to the frontnodes and backnodes array\r\n // If the plane doesn't intersect the polygon, the 'this' object is added to one of the arrays\r\n // If the plane does intersect the polygon, two new child nodes are created for the front and back fragments,\r\n // and added to both arrays.\r\n\r\n splitByPlane(\r\n plane: Plane,\r\n coplanarFrontNodes: PolygonTreeNode[],\r\n coplanarBackNodes: PolygonTreeNode[],\r\n frontNodes: PolygonTreeNode[],\r\n backNodes: PolygonTreeNode[]\r\n )\r\n {\r\n if (this.children.length)\r\n {\r\n let queue = [this.children];\r\n for (let i = 0; i < queue.length; i++)\r\n {\r\n // queue.length can increase, do not cache\r\n let nodes = queue[i];\r\n for (let j = 0, l = nodes.length; j < l; j++)\r\n {\r\n // ok to cache length\r\n let node = nodes[j];\r\n if (node.children.length)\r\n queue.push(node.children);\r\n else\r\n {\r\n // no children. Split the polygon:\r\n node.splitByPlaneNotChildren(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes);\r\n }\r\n }\r\n }\r\n }\r\n else\r\n {\r\n this.splitByPlaneNotChildren(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes);\r\n }\r\n }\r\n\r\n // only to be called for nodes with no children\r\n // 仅用于没有子节点的节点\r\n private splitByPlaneNotChildren(\r\n plane: Plane,\r\n coplanarFrontNodes: PolygonTreeNode[],\r\n coplanarBackNodes: PolygonTreeNode[],\r\n frontNodes: PolygonTreeNode[],\r\n backNodes: PolygonTreeNode[]\r\n )\r\n {\r\n if (!this.polygon) return;\r\n\r\n let polygon = this.polygon;\r\n let bound = polygon.boundingSphere();\r\n let sphereradius = bound[1] + EPS; // FIXME Why add imprecision?\r\n let planenormal = plane.normal;\r\n let spherecenter = bound[0];\r\n let d = planenormal.dot(spherecenter) - plane.w;\r\n if (d > sphereradius)\r\n frontNodes.push(this);\r\n else if (d < -sphereradius)\r\n backNodes.push(this);\r\n else\r\n {\r\n let splitresult = polygon.splitByPlane(plane);\r\n switch (splitresult.type)\r\n {\r\n case Type.CoplanarFront:\r\n coplanarFrontNodes.push(this);\r\n break;\r\n\r\n case Type.CoplanarBack:\r\n coplanarBackNodes.push(this);\r\n break;\r\n\r\n case Type.Front:\r\n frontNodes.push(this);\r\n break;\r\n\r\n case Type.Back:\r\n backNodes.push(this);\r\n break;\r\n\r\n case Type.Spanning:\r\n if (splitresult.front)\r\n {\r\n let frontNode = this.addChild(splitresult.front);\r\n frontNodes.push(frontNode);\r\n }\r\n if (splitresult.back)\r\n {\r\n let backNode = this.addChild(splitresult.back);\r\n backNodes.push(backNode);\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // add child to a node\r\n // this should be called whenever the polygon is split\r\n // a child should be created for every fragment of the split polygon\r\n // returns the newly created child\r\n addChild(polygon: Polygon): PolygonTreeNode\r\n {\r\n let newchild = new PolygonTreeNode(polygon);\r\n newchild.parent = this;\r\n this.children.push(newchild);\r\n return newchild;\r\n }\r\n\r\n invertSub()\r\n {\r\n let queue: PolygonTreeNode[][] = [[this]];\r\n for (let i = 0; i < queue.length; i++)\r\n {\r\n let children = queue[i];\r\n for (let j = 0, l = children.length; j < l; j++)\r\n {\r\n let node = children[j];\r\n if (node.polygon)\r\n node.polygon = node.polygon.flipped();\r\n queue.push(node.children);\r\n }\r\n }\r\n }\r\n\r\n recursivelyInvalidatePolygon()\r\n {\r\n let node: PolygonTreeNode = this;\r\n while (node.polygon)\r\n {\r\n node.polygon = null;\r\n if (node.parent)\r\n node = node.parent;\r\n }\r\n }\r\n}\r\n\r\n// # class Tree\r\n// This is the root of a BSP tree\r\n// We are using this separate class for the root of the tree, to hold the PolygonTreeNode root\r\n// The actual tree is kept in this.rootnode\r\nexport class Tree\r\n{\r\n polygonTree = new PolygonTreeNode();\r\n rootNode = new Node(null);\r\n constructor(polygons: Polygon[])\r\n {\r\n this.addPolygons(polygons);\r\n }\r\n\r\n invert()\r\n {\r\n this.polygonTree.invert();\r\n this.rootNode.invert();\r\n }\r\n\r\n // Remove all polygons in this BSP tree that are inside the other BSP tree\r\n /**\r\n * this 减去 tree 删除此BSP树中位于其他BSP树内的所有多边形\r\n * @param tree 不会被修改\r\n * @param [alsoRemovecoplanarFront=false] 同时删除共面\r\n */\r\n clipTo(tree: Tree, alsoRemovecoplanarFront = false)\r\n {\r\n this.rootNode.clipTo(tree, alsoRemovecoplanarFront);\r\n }\r\n\r\n allPolygons()\r\n {\r\n return this.polygonTree.getPolygons();\r\n }\r\n\r\n addPolygons(polygons: Polygon[])\r\n {\r\n if (polygons.length > 1e4)\r\n return;\r\n let polygonTreeNodes = polygons.map((p) => this.polygonTree.addChild(p));\r\n this.rootNode.addPolygonTreeNodes(polygonTreeNodes);\r\n }\r\n}\r\n\r\n// # class Node\r\n// Holds a node in a BSP tree. A BSP tree is built from a collection of polygons\r\n// by picking a polygon to split along.\r\n// Polygons are not stored directly in the tree, but in PolygonTreeNodes, stored in\r\n// this.polygontreenodes. Those PolygonTreeNodes are children of the owning\r\n// Tree.polygonTree\r\n// This is not a leafy BSP tree since there is\r\n// no distinction between internal and leaf nodes.\r\nclass Node\r\n{\r\n plane: Plane;\r\n front: Node;\r\n back: Node;\r\n polygonTreeNodes: PolygonTreeNode[] = [];\r\n parent: Node;\r\n constructor(parent: Node)\r\n {\r\n this.parent = parent;\r\n }\r\n\r\n // Convert solid space to empty space and empty space to solid space.\r\n invert()\r\n {\r\n let queue: Node[] = [this];\r\n for (let i = 0; i < queue.length; i++)\r\n {\r\n let node = queue[i];\r\n if (node.plane) node.plane = node.plane.flipped();\r\n if (node.front) queue.push(node.front);\r\n if (node.back) queue.push(node.back);\r\n let temp = node.front;\r\n node.front = node.back;\r\n node.back = temp;\r\n }\r\n }\r\n\r\n // clip polygontreenodes to our plane\r\n // calls remove() for all clipped PolygonTreeNodes\r\n //将polygontreenodes剪辑到我们的飞机上\r\n //为所有剪切的PolygonTreeNodes调用remove()\r\n clipPolygons(polygonTreeNodes: PolygonTreeNode[], alsoRemoveCoplanarFront: boolean)\r\n {\r\n interface D\r\n {\r\n node: Node;\r\n polygonTreeNodes: PolygonTreeNode[];\r\n }\r\n\r\n let args: D = { node: this, polygonTreeNodes };\r\n let stack: D[] = [];\r\n\r\n do\r\n {\r\n let node = args.node;\r\n let polygonTreeNodes1 = args.polygonTreeNodes;\r\n\r\n // begin \"function\"\r\n if (node.plane)\r\n {\r\n let backnodes: PolygonTreeNode[] = [];\r\n let frontnodes: PolygonTreeNode[] = [];\r\n let coplanarfrontnodes = alsoRemoveCoplanarFront ? backnodes : frontnodes;\r\n let plane = node.plane;\r\n for (let node1 of polygonTreeNodes1)\r\n {\r\n if (!node1.isRemoved())\r\n node1.splitByPlane(plane, coplanarfrontnodes, backnodes, frontnodes, backnodes);\r\n }\r\n\r\n if (node.front && frontnodes.length > 0)\r\n stack.push({ node: node.front, polygonTreeNodes: frontnodes });\r\n\r\n let numbacknodes = backnodes.length;\r\n if (node.back && numbacknodes > 0)\r\n stack.push({ node: node.back, polygonTreeNodes: backnodes });\r\n else\r\n {\r\n // there's nothing behind this plane. Delete the nodes behind this plane:\r\n // 这架飞机背后什么也没有。 删除此平面后面的节点:\r\n for (let i = 0; i < numbacknodes; i++)\r\n backnodes[i].remove();\r\n }\r\n }\r\n args = stack.pop();\r\n }\r\n while (args);\r\n }\r\n\r\n // Remove all polygons in this BSP tree that are inside the other BSP tree\r\n // `tree`.\r\n clipTo(tree: Tree, alsoRemovecoplanarFront: boolean)\r\n {\r\n let node: Node = this;\r\n let stack: Node[] = [];\r\n do\r\n {\r\n if (node.polygonTreeNodes.length > 0)\r\n {\r\n tree.rootNode.clipPolygons(\r\n node.polygonTreeNodes,\r\n alsoRemovecoplanarFront\r\n );\r\n }\r\n if (node.front) stack.push(node.front);\r\n if (node.back) stack.push(node.back);\r\n node = stack.pop();\r\n }\r\n while (node);\r\n }\r\n\r\n addPolygonTreeNodes(polygonTreeNodes: PolygonTreeNode[])\r\n {\r\n interface D\r\n {\r\n node: Node;\r\n polygontreenodes: PolygonTreeNode[];\r\n }\r\n let args: D = { node: this, polygontreenodes: polygonTreeNodes };\r\n let stack: D[] = [];\r\n do\r\n {\r\n let node = args.node;\r\n polygonTreeNodes = args.polygontreenodes;\r\n\r\n if (polygonTreeNodes.length === 0)\r\n {\r\n args = stack.pop();\r\n continue;\r\n }\r\n if (!node.plane)\r\n {\r\n let bestplane = polygonTreeNodes[Math.floor(polygonTreeNodes.length / 2)].getPolygon().plane;\r\n node.plane = bestplane;\r\n }\r\n let frontNodes: PolygonTreeNode[] = [];\r\n let backNodes: PolygonTreeNode[] = [];\r\n\r\n for (let i = 0, n = polygonTreeNodes.length; i < n; ++i)\r\n {\r\n polygonTreeNodes[i].splitByPlane(\r\n node.plane,\r\n node.polygonTreeNodes,\r\n backNodes,\r\n frontNodes,\r\n backNodes\r\n );\r\n }\r\n\r\n if (frontNodes.length > 0)\r\n {\r\n if (!node.front) node.front = new Node(node);\r\n stack.push({ node: node.front, polygontreenodes: frontNodes });\r\n }\r\n if (backNodes.length > 0)\r\n {\r\n if (!node.back) node.back = new Node(node);\r\n stack.push({ node: node.back, polygontreenodes: backNodes });\r\n }\r\n\r\n args = stack.pop();\r\n }\r\n while (args);\r\n }\r\n\r\n getParentPlaneNormals(normals: Vector3D[], maxdepth: number)\r\n {\r\n if (maxdepth > 0)\r\n {\r\n if (this.parent)\r\n {\r\n normals.push(this.parent.plane.normal);\r\n this.parent.getParentPlaneNormals(normals, maxdepth - 1);\r\n }\r\n }\r\n }\r\n}\r\n","\r\n// //////////////////////////////\r\n// ## class fuzzyFactory\r\n// This class acts as a factory for objects. We can search for an object with approximately\r\n// the desired properties (say a rectangle with width 2 and height 1)\r\n// The lookupOrCreate() method looks for an existing object (for example it may find an existing rectangle\r\n// with width 2.0001 and height 0.999. If no object is found, the user supplied callback is\r\n// called, which should generate a new object. The new object is inserted into the database\r\n// so it can be found by future lookupOrCreate() calls.\r\n// Constructor:\r\n// numdimensions: the number of parameters for each object\r\n// for example for a 2D rectangle this would be 2\r\n// tolerance: The maximum difference for each parameter allowed to be considered a match\r\nexport class FuzzyFactory\r\n{\r\n lookuptable: {};\r\n multiplier: number;\r\n constructor(numdimensions: number, tolerance: number)\r\n {\r\n this.lookuptable = {};\r\n this.multiplier = 1.0 / tolerance;\r\n }\r\n\r\n // let obj = f.lookupOrCreate([el1, el2, el3], function(elements) {/* create the new object */});\r\n // Performs a fuzzy lookup of the object with the specified elements.\r\n // If found, returns the existing object\r\n // If not found, calls the supplied callback function which should create a new object with\r\n // the specified properties. This object is inserted in the lookup database.\r\n lookupOrCreate(els: number[], object: T): T\r\n {\r\n let hash = \"\";\r\n let multiplier = this.multiplier;\r\n for (let el of els)\r\n {\r\n let valueQuantized = Math.round(el * multiplier);\r\n hash += valueQuantized + \"/\";\r\n }\r\n if (hash in this.lookuptable) return this.lookuptable[hash];\r\n else\r\n {\r\n let hashparts = els.map(el =>\r\n {\r\n let q0 = Math.floor(el * multiplier);\r\n let q1 = q0 + 1;\r\n return [\"\" + q0 + \"/\", \"\" + q1 + \"/\"];\r\n });\r\n let numelements = els.length;\r\n let numhashes = 1 << numelements;\r\n for (let hashmask = 0; hashmask < numhashes; ++hashmask)\r\n {\r\n let hashmaskShifted = hashmask;\r\n hash = \"\";\r\n hashparts.forEach(hashpart =>\r\n {\r\n hash += hashpart[hashmaskShifted & 1];\r\n hashmaskShifted >>= 1;\r\n });\r\n this.lookuptable[hash] = object;\r\n }\r\n return object;\r\n }\r\n }\r\n}\r\n","import { FuzzyFactory } from \"./FuzzyFactory\";\r\nimport { EPS } from \"./constants\";\r\nimport { Polygon } from \"./math/Polygon3\";\r\nimport { Plane } from \"./math/Plane\";\r\nimport { Vertex3D } from \"./math/Vertex3\";\r\n\r\nexport class FuzzyCSGFactory\r\n{\r\n vertexfactory = new FuzzyFactory(3, EPS);\r\n planefactory = new FuzzyFactory(4, EPS);\r\n constructor() { }\r\n\r\n getVertex(sourcevertex: Vertex3D): Vertex3D\r\n {\r\n let elements = [sourcevertex.pos.x, sourcevertex.pos.y, sourcevertex.pos.z];\r\n let result = this.vertexfactory.lookupOrCreate(elements, sourcevertex);\r\n return result;\r\n }\r\n\r\n getPlane(sourceplane: Plane): Plane\r\n {\r\n let elements: number[] = [sourceplane.normal.x, sourceplane.normal.y, sourceplane.normal.z, sourceplane.w];\r\n let result = this.planefactory.lookupOrCreate(elements, sourceplane);\r\n return result;\r\n }\r\n\r\n getPolygon(sourcePolygon: Polygon, outputPolygon = sourcePolygon): Polygon\r\n {\r\n let newPlane = this.getPlane(sourcePolygon.plane);\r\n let newVertices = sourcePolygon.vertices.map(vertex => this.getVertex(vertex));\r\n // two vertices that were originally very close may now have become\r\n // truly identical (referring to the same Vertex object).\r\n // Remove duplicate vertices:\r\n let newVerticesDedup: Vertex3D[] = [];//新的顶点列表(已过滤重复)\r\n if (newVertices.length > 0)\r\n {\r\n let prevVertexTag = newVertices[newVertices.length - 1].getTag();\r\n for (let vertex of newVertices)\r\n {\r\n let vertextag = vertex.getTag();\r\n if (vertextag !== prevVertexTag)\r\n newVerticesDedup.push(vertex);\r\n prevVertexTag = vertextag;\r\n }\r\n }\r\n // If it's degenerate, remove all vertices:\r\n if (newVerticesDedup.length < 3)\r\n newVerticesDedup = [];\r\n\r\n outputPolygon.vertices = newVertices;\r\n outputPolygon.plane = newPlane;\r\n return outputPolygon;\r\n }\r\n}\r\n","import { FuzzyCSGFactory } from \"../FuzzyFactory3d\";\r\nimport { FuzzyCAGFactory } from \"../FuzzyFactory2d\";\r\nimport { CSG } from \"../CSG\";\r\nimport { CAG } from \"../CAG\";\r\nimport { EPS } from \"../constants\";\r\nimport { Polygon } from \"../math/Polygon3\";\r\n\r\n/**\r\n * Returns a cannoicalized version of the input csg : ie every very close\r\n * points get deduplicated\r\n * \r\n * 返回删除重复点的csg,重复点将被合并\r\n */\r\nexport function canonicalizeCSG(csg: CSG): CSG\r\n{\r\n const factory = new FuzzyCSGFactory();\r\n let result = CSGFromCSGFuzzyFactory(factory, csg);\r\n result.isCanonicalized = true;\r\n result.isRetesselated = csg.isRetesselated;\r\n return result;\r\n}\r\n\r\nexport function canonicalizeCAG(cag: CAG)\r\n{\r\n let factory = new FuzzyCAGFactory();\r\n let result = CAGFromCAGFuzzyFactory(factory, cag);\r\n result.isCanonicalized = true;\r\n return result;\r\n}\r\n\r\nexport function CSGFromCSGFuzzyFactory(factory: FuzzyCSGFactory, sourcecsg: CSG)\r\n{\r\n let newpolygons: Polygon[] = sourcecsg.polygons.filter(poly =>\r\n {\r\n return factory.getPolygon(poly).vertices.length >= 3;\r\n });\r\n return new CSG(newpolygons);\r\n}\r\n\r\nfunction CAGFromCAGFuzzyFactory(factory: FuzzyCAGFactory, sourcecag: CAG)\r\n{\r\n let newsides = sourcecag.sides\r\n .map(side => factory.getSide(side))\r\n // remove bad sides (mostly a user input issue)\r\n .filter((side) => side.length() > EPS);\r\n return new CAG(newsides);\r\n};\r\n","import { Vector3D } from \"../math/Vector3\";\r\nimport { CSG } from \"../CSG\";\r\n/**\r\n * Returns an array of Vector3D, providing minimum coordinates and maximum coordinates\r\n * of this solid.\r\n * @example\r\n * let bounds = A.getBounds()\r\n * let minX = bounds[0].x\r\n */\r\nexport function bounds(csg: CSG): Vector3D[]\r\n{\r\n if (!csg.cachedBoundingBox)\r\n {\r\n let minpoint: Vector3D;\r\n let maxpoint: Vector3D;\r\n let polygons = csg.polygons;\r\n let numpolygons = polygons.length;\r\n for (let i = 0; i < numpolygons; i++)\r\n {\r\n let polygon = polygons[i];\r\n let bounds = polygon.boundingBox();\r\n if (i === 0)\r\n {\r\n minpoint = bounds[0].clone();\r\n maxpoint = bounds[1].clone();\r\n }\r\n else\r\n {\r\n minpoint.min(bounds[0]);\r\n maxpoint.max(bounds[1]);\r\n }\r\n }\r\n // FIXME: not ideal, we are mutating the input, we need to move some of it out\r\n csg.cachedBoundingBox = [minpoint, maxpoint];\r\n }\r\n return csg.cachedBoundingBox;\r\n};\r\n","import { Vector2D } from \"./math/Vector2\";\r\n\r\nexport function fnNumberSort(a, b)\r\n{\r\n return a - b;\r\n}\r\n\r\nexport const solve2Linear = function (a: number, b: number, c: number, d: number, u: number, v: number)\r\n{\r\n let det = a * d - b * c;\r\n let invdet = 1.0 / det;\r\n let x = u * d - b * v;\r\n let y = -u * c + a * v;\r\n x *= invdet;\r\n y *= invdet;\r\n return [x, y];\r\n};\r\n\r\nexport function insertSorted(array: T[], element: T, comparefunc: (a: T, b: T) => number)\r\n{\r\n let leftbound = 0;\r\n let rightbound = array.length;\r\n while (rightbound > leftbound)\r\n {\r\n let testindex = Math.floor((leftbound + rightbound) / 2);\r\n let testelement = array[testindex];\r\n let compareresult = comparefunc(element, testelement);\r\n if (compareresult > 0)\r\n // element > testelement\r\n leftbound = testindex + 1;\r\n else\r\n rightbound = testindex;\r\n }\r\n array.splice(leftbound, 0, element);\r\n}\r\n\r\n// Get the x coordinate of a point with a certain y coordinate, interpolated between two\r\n// points (CSG.Vector2D).\r\n// Interpolation is robust even if the points have the same y coordinate\r\nexport function interpolateBetween2DPointsForY(point1: Vector2D, point2: Vector2D, y: number)\r\n{\r\n let f1 = y - point1.y;\r\n let f2 = point2.y - point1.y;\r\n if (f2 < 0)\r\n {\r\n f1 = -f1;\r\n f2 = -f2;\r\n }\r\n let t: number;\r\n if (f1 <= 0)\r\n t = 0.0;\r\n else if (f1 >= f2)\r\n t = 1.0;\r\n else if (f2 < 1e-10)\r\n // FIXME Should this be CSG.EPS?\r\n t = 0.5;\r\n else\r\n t = f1 / f2;\r\n let result = point1.x + t * (point2.x - point1.x);\r\n return result;\r\n}\r\n","import { Vector2D } from \"./Vector2\";\r\n\r\n/** class Line2D\r\n * Represents a directional line in 2D space\r\n * A line is parametrized by its normal vector (perpendicular to the line, rotated 90 degrees counter clockwise)\r\n * and w. The line passes through the point .times(w).\r\n * Equation: p is on line if normal.dot(p)==w\r\n */\r\nexport class Line2D\r\n{\r\n normal: Vector2D;\r\n w: number;\r\n constructor(normal: Vector2D, w: number)\r\n {\r\n this.normal = normal.clone();\r\n let l = this.normal.length();\r\n w *= l;\r\n this.normal.normalize();\r\n this.w = w;\r\n }\r\n\r\n direction()\r\n {\r\n return this.normal;\r\n }\r\n static fromPoints(p1: Vector2D, p2: Vector2D)\r\n {\r\n let direction = p2.clone().sub(p1);\r\n let normal = direction\r\n .normal()\r\n .negate()\r\n .normalize();\r\n let w = p1.dot(normal);\r\n return new Line2D(normal, w);\r\n }\r\n}\r\n","import { Plane } from \"./Plane\";\r\nimport { Vector2D } from \"./Vector2\";\r\nimport { Vector3D } from \"./Vector3\";\r\n\r\n/** class OrthoNormalBasis\r\n * Reprojects points on a 3D plane onto a 2D plane\r\n * or from a 2D plane back onto the 3D plane\r\n */\r\n\r\nexport class OrthoNormalBasis\r\n{\r\n v: Vector3D;\r\n u: Vector3D;\r\n planeorigin: Vector3D;\r\n constructor(public plane: Plane, rightVector: Vector3D = plane.normal.randomNonParallelVector())\r\n {\r\n this.v = plane.normal.clone().cross(rightVector).normalize();\r\n this.u = this.v.clone().cross(plane.normal);\r\n this.plane = plane;\r\n this.planeorigin = plane.normal.clone().multiplyScalar(plane.w);\r\n }\r\n to2D(vec3: Vector3D)\r\n {\r\n return new Vector2D(vec3.dot(this.u), vec3.dot(this.v));\r\n }\r\n\r\n to3D(vec2: Vector2D)\r\n {\r\n return this.planeorigin.clone()\r\n .add(this.u.clone().multiplyScalar(vec2.x))\r\n .add(this.v.clone().multiplyScalar(vec2.y));\r\n }\r\n}\r\n","import { EPS } from \"../constants\";\r\nimport { fnNumberSort, insertSorted, interpolateBetween2DPointsForY } from \"../utils\";\r\nimport { Line2D } from \"./Line2\";\r\nimport { OrthoNormalBasis } from \"./OrthoNormalBasis\";\r\nimport { Polygon } from \"./Polygon3\";\r\nimport { Vector2D } from \"./Vector2\";\r\nimport { Vertex3D } from \"./Vertex3\";\r\n\r\n//在这个文件中 Top 表示的是 y最小.\r\n// Bottom 表示的是 y最大\r\n\r\ninterface ActivePolygon\r\n{\r\n polygonindex: number;\r\n leftvertexindex: number;\r\n rightvertexindex: number;\r\n\r\n topleft: Vector2D;\r\n bottomleft: Vector2D;\r\n\r\n topright: Vector2D;\r\n bottomright: Vector2D;\r\n}\r\n\r\ninterface OutPolygon\r\n{\r\n topleft: Vector2D;\r\n topright: Vector2D;\r\n bottomleft: Vector2D;\r\n bottomright: Vector2D;\r\n leftline: Line2D;\r\n rightline: Line2D;\r\n outpolygon?: { leftpoints: Vector2D[]; rightpoints: Vector2D[]; };\r\n leftlinecontinues?: boolean;\r\n rightlinecontinues?: boolean;\r\n}\r\n\r\n//一组共面多边形的Retesselation函数。 请参阅此文件顶部的介绍。\r\nexport function reTesselateCoplanarPolygons(sourcePolygons: Polygon[], destpolygons: Polygon[] = []): void\r\n{\r\n let numPolygons = sourcePolygons.length;\r\n if (numPolygons < 2)\r\n {\r\n destpolygons.push(...sourcePolygons);\r\n return;\r\n }\r\n\r\n let plane = sourcePolygons[0].plane;\r\n let orthobasis = new OrthoNormalBasis(plane);\r\n\r\n // let xcoordinatebins = {}\r\n let yCoordinateBins: { [key: number]: number; } = {}; //整数map\r\n let yCoordinateBinningFactor = (1.0 / EPS) * 10;\r\n\r\n let polygonVertices2d: (Vector2D[])[] = []; // (Vector2[])[];\r\n let polygonTopVertexIndexes: number[] = []; // 每个多边形最顶层顶点的索引数组 minIndex\r\n let topY2PolygonIndexes: { [key: number]: number[]; } = {}; // Map\r\n let yCoordinateToPolygonIndexes: { [key: string]: { [key: number]: boolean; }; } = {}; // Map > Y坐标映射所有的多边形\r\n\r\n //将多边形转换为2d点表 polygonVertices2d\r\n //建立y对应的多边形Map yCoordinateToPolygonIndexes\r\n for (let polygonIndex = 0; polygonIndex < numPolygons; polygonIndex++)\r\n {\r\n let poly3d = sourcePolygons[polygonIndex];\r\n let numVertices = poly3d.vertices.length;\r\n\r\n if (numVertices === 0) continue;\r\n\r\n let vertices2d: Vector2D[] = []; //Vector2d[];\r\n let minIndex = -1;\r\n let miny: number, maxy: number;\r\n for (let i = 0; i < numVertices; i++)\r\n {\r\n let pos2d = orthobasis.to2D(poly3d.vertices[i].pos);\r\n // perform binning of y coordinates: If we have multiple vertices very\r\n // close to each other, give them the same y coordinate:\r\n let yCoordinatebin = Math.floor(pos2d.y * yCoordinateBinningFactor);\r\n let newy: number;\r\n if (yCoordinatebin in yCoordinateBins)\r\n newy = yCoordinateBins[yCoordinatebin];\r\n else if (yCoordinatebin + 1 in yCoordinateBins)\r\n newy = yCoordinateBins[yCoordinatebin + 1];\r\n else if (yCoordinatebin - 1 in yCoordinateBins)\r\n newy = yCoordinateBins[yCoordinatebin - 1];\r\n else\r\n {\r\n newy = pos2d.y;\r\n yCoordinateBins[yCoordinatebin] = pos2d.y;\r\n }\r\n pos2d = new Vector2D(pos2d.x, newy);\r\n vertices2d.push(pos2d);\r\n if (i === 0 || newy < miny)\r\n {\r\n miny = newy;\r\n minIndex = i;\r\n }\r\n if (i === 0 || newy > maxy) maxy = newy;\r\n\r\n if (!(newy in yCoordinateToPolygonIndexes))\r\n yCoordinateToPolygonIndexes[newy] = {};\r\n\r\n yCoordinateToPolygonIndexes[newy][polygonIndex] = true;\r\n }\r\n\r\n //退化多边形,所有顶点都具有相同的y坐标。 从现在开始忽略它:\r\n if (miny >= maxy) continue;\r\n\r\n if (!(miny in topY2PolygonIndexes)) topY2PolygonIndexes[miny] = [];\r\n\r\n topY2PolygonIndexes[miny].push(polygonIndex);\r\n\r\n // reverse the vertex order:\r\n vertices2d.reverse();\r\n minIndex = numVertices - minIndex - 1;\r\n polygonVertices2d.push(vertices2d);\r\n polygonTopVertexIndexes.push(minIndex);\r\n }\r\n\r\n //所有的y坐标,从小到大排序\r\n let yCoordinates: string[] = [];\r\n for (let ycoordinate in yCoordinateToPolygonIndexes)\r\n yCoordinates.push(ycoordinate);\r\n yCoordinates.sort(fnNumberSort);\r\n\r\n //迭代y坐标 从低到高\r\n\r\n // activepolygons :'active'的源多边形,即与y坐标相交\r\n // 多边形是从左往右排序的\r\n // activepolygons 中的每个元素都具有以下属性:\r\n // polygonindex 源多边形的索引(即sourcepolygons的索引 和polygonvertices2d数组)\r\n // leftvertexindex 左边 在当前y坐标处或刚好在当前y坐标之上\r\n // rightvertexindex 右边\r\n // topleft bottomleft 与当前y坐标交叉的多边形左侧的坐标\r\n // topright bottomright 与当前y坐标交叉的多边形右侧的坐标\r\n\r\n let activePolygons: ActivePolygon[] = [];\r\n let prevOutPolygonRow: OutPolygon[] = []; //上一个输出多边形行?\r\n for (let yindex = 0; yindex < yCoordinates.length; yindex++)\r\n {\r\n let yCoordinateStr = yCoordinates[yindex];\r\n let yCoordinate = Number(yCoordinateStr);\r\n\r\n // 用当前的y 更新 activePolygons\r\n // - 删除以y坐标结尾的所有多边形 删除polygon maxy = y 的多边形\r\n // - 更新 leftvertexindex 和 rightvertexindex (指向当前顶点索引)\r\n // 在多边形的左侧和右侧\r\n\r\n // 迭代在Y坐标处有一个角的所有多边形\r\n let polygonIndexeSwithCorner = yCoordinateToPolygonIndexes[yCoordinateStr];\r\n for (\r\n let activePolygonIndex = 0;\r\n activePolygonIndex < activePolygons.length;\r\n activePolygonIndex++\r\n )\r\n {\r\n let activepolygon = activePolygons[activePolygonIndex];\r\n let polygonindex = activepolygon.polygonindex;\r\n\r\n if (!polygonIndexeSwithCorner[polygonindex])//如果不在角内\r\n continue;\r\n\r\n //多边形在此y坐标处有一个角\r\n let vertices2d = polygonVertices2d[polygonindex];\r\n let numvertices = vertices2d.length;\r\n let newleftvertexindex = activepolygon.leftvertexindex;\r\n let newrightvertexindex = activepolygon.rightvertexindex;\r\n\r\n //看看我们是否需要增加 leftvertexindex 或减少 rightvertexindex :\r\n while (true)\r\n {\r\n let nextleftvertexindex = newleftvertexindex + 1;\r\n if (nextleftvertexindex >= numvertices) nextleftvertexindex = 0;\r\n if (vertices2d[nextleftvertexindex].y !== yCoordinate) break;\r\n newleftvertexindex = nextleftvertexindex;\r\n }\r\n //减少 rightvertexindex\r\n let nextrightvertexindex = newrightvertexindex - 1;\r\n if (nextrightvertexindex < 0)\r\n nextrightvertexindex = numvertices - 1;\r\n if (vertices2d[nextrightvertexindex].y === yCoordinate)\r\n newrightvertexindex = nextrightvertexindex;\r\n\r\n if (\r\n newleftvertexindex !== activepolygon.leftvertexindex //有向上更新\r\n && newleftvertexindex === newrightvertexindex //指向同一个点\r\n )\r\n {\r\n\r\n // We have increased leftvertexindex or decreased rightvertexindex, and now they point to the same vertex\r\n // This means that this is the bottom point of the polygon. We'll remove it:\r\n //我们增加了leftvertexindex或减少了rightvertexindex,现在它们指向同一个顶点\r\n //这意味着这是多边形的底点。 我们将删除它:\r\n activePolygons.splice(activePolygonIndex, 1);\r\n --activePolygonIndex;\r\n } else\r\n {\r\n activepolygon.leftvertexindex = newleftvertexindex;\r\n activepolygon.rightvertexindex = newrightvertexindex;\r\n activepolygon.topleft = vertices2d[newleftvertexindex];\r\n activepolygon.topright = vertices2d[newrightvertexindex];\r\n let nextleftvertexindex = newleftvertexindex + 1;\r\n if (nextleftvertexindex >= numvertices) nextleftvertexindex = 0;\r\n activepolygon.bottomleft = vertices2d[nextleftvertexindex];\r\n let nextrightvertexindex = newrightvertexindex - 1;\r\n if (nextrightvertexindex < 0) nextrightvertexindex = numvertices - 1;\r\n activepolygon.bottomright = vertices2d[nextrightvertexindex];\r\n }\r\n }\r\n\r\n let nextYCoordinate: number; // number y\r\n if (yindex >= yCoordinates.length - 1)\r\n {\r\n // last row, all polygons must be finished here:\r\n // 最后一行,所有多边形必须在这里完成:\r\n activePolygons = [];\r\n }\r\n else // yindex < ycoordinates.length-1\r\n {\r\n nextYCoordinate = Number(yCoordinates[yindex + 1]);\r\n let middleYCoordinate = 0.5 * (yCoordinate + nextYCoordinate);\r\n // update activepolygons by adding any polygons that start here:\r\n // 添加从这里开始的多边形 到 activePolygons\r\n let startingPolygonIndexes = topY2PolygonIndexes[yCoordinateStr];\r\n for (let polygonindex_key in startingPolygonIndexes)\r\n {\r\n let polygonindex = startingPolygonIndexes[polygonindex_key];\r\n let vertices2d = polygonVertices2d[polygonindex];\r\n let numvertices = vertices2d.length;\r\n let topVertexIndex = polygonTopVertexIndexes[polygonindex];\r\n // the top of the polygon may be a horizontal line. In that case topvertexindex can point to any point on this line.\r\n // Find the left and right topmost vertices which have the current y coordinate:\r\n // 顶部可以是一条直线,寻找最左边的点和最右边的点\r\n let topleftvertexindex = topVertexIndex;\r\n while (true)\r\n {\r\n let i = topleftvertexindex + 1;\r\n if (i >= numvertices) i = 0;\r\n if (vertices2d[i].y !== yCoordinate) break;\r\n if (i === topVertexIndex) break; // should not happen, but just to prevent endless loops\r\n topleftvertexindex = i;\r\n }\r\n let toprightvertexindex = topVertexIndex;\r\n while (true)\r\n {\r\n let i = toprightvertexindex - 1;\r\n if (i < 0) i = numvertices - 1;\r\n if (vertices2d[i].y !== yCoordinate) break;\r\n if (i === topleftvertexindex) break; // should not happen, but just to prevent endless loops\r\n toprightvertexindex = i;\r\n }\r\n\r\n let nextleftvertexindex = topleftvertexindex + 1;\r\n if (nextleftvertexindex >= numvertices) nextleftvertexindex = 0;\r\n let nextrightvertexindex = toprightvertexindex - 1;\r\n if (nextrightvertexindex < 0) nextrightvertexindex = numvertices - 1;\r\n let newactivepolygon: ActivePolygon = {\r\n polygonindex: polygonindex,\r\n leftvertexindex: topleftvertexindex,\r\n rightvertexindex: toprightvertexindex,\r\n topleft: vertices2d[topleftvertexindex],\r\n topright: vertices2d[toprightvertexindex],\r\n bottomleft: vertices2d[nextleftvertexindex],\r\n bottomright: vertices2d[nextrightvertexindex]\r\n };\r\n\r\n //二分插入\r\n insertSorted(activePolygons, newactivepolygon, function (el1: ActivePolygon, el2: ActivePolygon)\r\n {\r\n let x1 = interpolateBetween2DPointsForY(\r\n el1.topleft,\r\n el1.bottomleft,\r\n middleYCoordinate\r\n );\r\n let x2 = interpolateBetween2DPointsForY(\r\n el2.topleft,\r\n el2.bottomleft,\r\n middleYCoordinate\r\n );\r\n if (x1 > x2) return 1;\r\n if (x1 < x2) return -1;\r\n return 0;\r\n });\r\n }\r\n }\r\n\r\n //#region\r\n // if( (yindex === ycoordinates.length-1) || (nextycoordinate - ycoordinate > EPS) )\r\n // if(true)\r\n // {\r\n\r\n let newOutPolygonRow: OutPolygon[] = []; //输出多边形\r\n\r\n // Build the output polygons for the next row in newOutPolygonRow:\r\n //现在 activepolygons 是最新的\r\n //为 newOutPolygonRow 中的下一行构建输出多边形:\r\n for (let activepolygonKey in activePolygons)\r\n {\r\n let activepolygon = activePolygons[activepolygonKey];\r\n\r\n let x = interpolateBetween2DPointsForY(\r\n activepolygon.topleft,\r\n activepolygon.bottomleft,\r\n yCoordinate\r\n );\r\n let topleft = new Vector2D(x, yCoordinate);\r\n x = interpolateBetween2DPointsForY(\r\n activepolygon.topright,\r\n activepolygon.bottomright,\r\n yCoordinate\r\n );\r\n let topright = new Vector2D(x, yCoordinate);\r\n x = interpolateBetween2DPointsForY(\r\n activepolygon.topleft,\r\n activepolygon.bottomleft,\r\n nextYCoordinate\r\n );\r\n let bottomleft = new Vector2D(x, nextYCoordinate);\r\n x = interpolateBetween2DPointsForY(\r\n activepolygon.topright,\r\n activepolygon.bottomright,\r\n nextYCoordinate\r\n );\r\n let bottomright = new Vector2D(x, nextYCoordinate);\r\n let outPolygon = {\r\n topleft: topleft,\r\n topright: topright,\r\n bottomleft: bottomleft,\r\n bottomright: bottomright,\r\n leftline: Line2D.fromPoints(topleft, bottomleft),\r\n rightline: Line2D.fromPoints(bottomright, topright)\r\n };\r\n\r\n if (newOutPolygonRow.length > 0)\r\n {\r\n let prevoutpolygon =\r\n newOutPolygonRow[newOutPolygonRow.length - 1];\r\n let d1 = outPolygon.topleft.distanceTo(prevoutpolygon.topright);\r\n let d2 = outPolygon.bottomleft.distanceTo(\r\n prevoutpolygon.bottomright\r\n );\r\n if (d1 < EPS && d2 < EPS)\r\n {\r\n // we can join this polygon with the one to the left:\r\n outPolygon.topleft = prevoutpolygon.topleft;\r\n outPolygon.leftline = prevoutpolygon.leftline;\r\n outPolygon.bottomleft = prevoutpolygon.bottomleft;\r\n newOutPolygonRow.splice(newOutPolygonRow.length - 1, 1);\r\n }\r\n }\r\n\r\n newOutPolygonRow.push(outPolygon);\r\n }\r\n\r\n if (yindex > 0)\r\n {\r\n // try to match the new polygons against the previous row:\r\n //尝试将新多边形与上一行匹配:\r\n let prevContinuedIndexes: { [key: number]: boolean; } = {};\r\n let matchedIndexes: { [key: number]: boolean; } = {};\r\n for (let i = 0; i < newOutPolygonRow.length; i++)\r\n {\r\n let thispolygon = newOutPolygonRow[i];\r\n for (let ii = 0; ii < prevOutPolygonRow.length; ii++)\r\n {\r\n if (!matchedIndexes[ii])\r\n {\r\n // not already processed?\r\n // We have a match if the sidelines are equal or if the top coordinates\r\n // are on the sidelines of the previous polygon\r\n let prevpolygon = prevOutPolygonRow[ii];\r\n if (prevpolygon.bottomleft.distanceTo(thispolygon.topleft) < EPS)\r\n {\r\n if (prevpolygon.bottomright.distanceTo(thispolygon.topright) < EPS)\r\n {\r\n // Yes, the top of this polygon matches the bottom of the previous:\r\n matchedIndexes[ii] = true;\r\n // Now check if the joined polygon would remain convex:\r\n let d1 = thispolygon.leftline.direction().x - prevpolygon.leftline.direction().x;\r\n let d2 = thispolygon.rightline.direction().x - prevpolygon.rightline.direction().x;\r\n let leftlinecontinues = Math.abs(d1) < EPS;\r\n let rightlinecontinues = Math.abs(d2) < EPS;\r\n let leftlineisconvex = leftlinecontinues || d1 >= 0;\r\n let rightlineisconvex = rightlinecontinues || d2 >= 0;\r\n if (leftlineisconvex && rightlineisconvex)\r\n {\r\n // yes, both sides have convex corners:\r\n // This polygon will continue the previous polygon\r\n thispolygon.outpolygon = prevpolygon.outpolygon;\r\n thispolygon.leftlinecontinues = leftlinecontinues;\r\n thispolygon.rightlinecontinues = rightlinecontinues;\r\n prevContinuedIndexes[ii] = true;\r\n }\r\n break;\r\n }\r\n }\r\n } // if(!prevcontinuedindexes[ii])\r\n } // for ii\r\n } // for i\r\n for (let ii = 0; ii < prevOutPolygonRow.length; ii++)\r\n {\r\n if (!prevContinuedIndexes[ii])\r\n {\r\n // polygon ends here\r\n // Finish the polygon with the last point(s):\r\n let prevpolygon = prevOutPolygonRow[ii];\r\n prevpolygon.outpolygon.rightpoints.push(prevpolygon.bottomright);\r\n if (prevpolygon.bottomright.distanceTo(prevpolygon.bottomleft) > EPS)\r\n {\r\n // polygon ends with a horizontal line:\r\n prevpolygon.outpolygon.leftpoints.push(prevpolygon.bottomleft);\r\n }\r\n // reverse the left half so we get a counterclockwise circle:\r\n prevpolygon.outpolygon.leftpoints.reverse();\r\n let points2d = prevpolygon.outpolygon.rightpoints.concat(prevpolygon.outpolygon.leftpoints);\r\n\r\n let vertices = points2d.map(v => new Vertex3D(orthobasis.to3D(v)));\r\n let polygon = new Polygon(vertices, plane);\r\n destpolygons.push(polygon);\r\n }\r\n }\r\n }\r\n\r\n for (let i = 0; i < newOutPolygonRow.length; i++)\r\n {\r\n let thispolygon = newOutPolygonRow[i];\r\n if (!thispolygon.outpolygon)\r\n {\r\n // polygon starts here:\r\n thispolygon.outpolygon = {\r\n leftpoints: [],\r\n rightpoints: []\r\n };\r\n thispolygon.outpolygon.leftpoints.push(thispolygon.topleft);\r\n if (thispolygon.topleft.distanceTo(thispolygon.topright) > EPS)\r\n {\r\n // we have a horizontal line at the top:\r\n thispolygon.outpolygon.rightpoints.push(thispolygon.topright);\r\n }\r\n }\r\n else\r\n {\r\n // continuation of a previous row\r\n if (!thispolygon.leftlinecontinues)\r\n {\r\n thispolygon.outpolygon.leftpoints.push(thispolygon.topleft);\r\n }\r\n if (!thispolygon.rightlinecontinues)\r\n {\r\n thispolygon.outpolygon.rightpoints.push(thispolygon.topright);\r\n }\r\n }\r\n }\r\n\r\n prevOutPolygonRow = newOutPolygonRow;\r\n // }\r\n //#endregion\r\n } // for yindex\r\n}\r\n","import { CSG } from \"../CSG\";\r\nimport { FuzzyCSGFactory } from \"../FuzzyFactory3d\";\r\nimport { Polygon } from \"../math/Polygon3\";\r\nimport { reTesselateCoplanarPolygons } from \"../math/reTesselateCoplanarPolygons\";\r\n\r\nexport function reTesselate(csg: CSG): CSG\r\n{\r\n if (csg.isRetesselated) return csg;\r\n\r\n let polygonsPerPlane: { [key: number]: Polygon[]; } = {};\r\n let isCanonicalized = csg.isCanonicalized;\r\n let fuzzyfactory = new FuzzyCSGFactory();\r\n\r\n for (let polygon of csg.polygons)\r\n {\r\n let plane = polygon.plane;\r\n if (!isCanonicalized)\r\n {\r\n // in order to identify polygons having the same plane, we need to canonicalize the planes\r\n // We don't have to do a full canonizalization (including vertices), to save time only do the planes and the shared data:\r\n plane = fuzzyfactory.getPlane(plane);\r\n }\r\n let tag = plane.getTag();\r\n if (!(tag in polygonsPerPlane)) polygonsPerPlane[tag] = [polygon];\r\n else polygonsPerPlane[tag].push(polygon);\r\n }\r\n\r\n let destpolygons: Polygon[] = [];\r\n for (let planetag in polygonsPerPlane)\r\n {\r\n let sourcepolygons = polygonsPerPlane[planetag];\r\n reTesselateCoplanarPolygons(sourcepolygons, destpolygons);\r\n }\r\n let resultCSG = new CSG(destpolygons);\r\n resultCSG.isRetesselated = true;\r\n return resultCSG;\r\n};\r\n","import { Matrix4 } from \"three\";\r\nimport { IsMirror } from \"./math/IsMirrot\";\r\nimport { Plane } from \"./math/Plane\";\r\nimport { Polygon } from \"./math/Polygon3\";\r\nimport { Vector3D } from \"./math/Vector3\";\r\nimport { Vertex3D } from \"./math/Vertex3\";\r\nimport { Tree } from \"./trees\";\r\nimport { canonicalizeCSG } from \"./utils/canonicalize\";\r\nimport { bounds } from \"./utils/csgMeasurements\";\r\nimport { reTesselate } from \"./utils/retesellate\";\r\n\r\n/** Class CSG\r\n * Holds a binary space partition tree representing a 3D solid. Two solids can\r\n * be combined using the `union()`, `subtract()`, and `intersect()` methods.\r\n * @constructor\r\n */\r\nexport class CSG\r\n{\r\n /** # 是否已精简重复点 */\r\n isCanonicalized: boolean = false;\r\n /** # 是否已合并轮廓 */\r\n isRetesselated: boolean = false;\r\n cachedBoundingBox: Vector3D[];\r\n constructor(public polygons: Polygon[] = [])\r\n {\r\n }\r\n /**\r\n * Return a new CSG solid representing the space in either this solid or\r\n * in the given solids. Neither this solid nor the given solids are modified.\r\n * @param {CSG[]} csg - list of CSG objects\r\n * @returns {CSG} new CSG object\r\n * @example\r\n * let C = A.union(B)\r\n * @example\r\n * +-------+ +-------+\r\n * | | | |\r\n * | A | | |\r\n * | +--+----+ = | +----+\r\n * +----+--+ | +----+ |\r\n * | B | | |\r\n * | | | |\r\n * +-------+ +-------+\r\n */\r\n union(csg: CSG | CSG[]): CSG\r\n {\r\n let csgs: CSG[];\r\n if (csg instanceof Array)\r\n {\r\n csgs = csg.slice(0);\r\n csgs.push(this);\r\n }\r\n else csgs = [this, csg];\r\n\r\n let i: number;\r\n // combine csg pairs in a way that forms a balanced binary tree pattern\r\n for (i = 1; i < csgs.length; i += 2)\r\n {\r\n csgs.push(csgs[i - 1].unionSub(csgs[i]));\r\n }\r\n return csgs[i - 1].reTesselated().canonicalized();\r\n }\r\n\r\n unionSub(csg: CSG, retesselate = false, canonicalize = false): CSG\r\n {\r\n if (!this.mayOverlap(csg))\r\n return this.unionForNonIntersecting(csg);\r\n\r\n let a = new Tree(this.polygons);\r\n let b = new Tree(csg.polygons);\r\n a.clipTo(b);\r\n\r\n // b.clipTo(a, true); // ERROR: this doesn't work\r\n b.clipTo(a);\r\n b.invert();\r\n b.clipTo(a);\r\n b.invert();\r\n\r\n let newpolygons = [...a.allPolygons(), ...b.allPolygons()];\r\n let resultCSG = new CSG(newpolygons);\r\n if (retesselate) resultCSG = resultCSG.reTesselated();\r\n if (canonicalize) resultCSG = resultCSG.canonicalized();\r\n return resultCSG;\r\n }\r\n\r\n // Like union, but when we know that the two solids are not intersecting\r\n // Do not use if you are not completely sure that the solids do not intersect!\r\n unionForNonIntersecting(csg: CSG): CSG\r\n {\r\n let newpolygons = [...this.polygons, ...csg.polygons];\r\n let result = new CSG(newpolygons);\r\n result.isCanonicalized = this.isCanonicalized && csg.isCanonicalized;\r\n result.isRetesselated = this.isRetesselated && csg.isRetesselated;\r\n return result;\r\n }\r\n\r\n /**\r\n * Return a new CSG solid representing space in this solid but\r\n * not in the given solids. Neither this solid nor the given solids are modified.\r\n * @returns new CSG object\r\n * @example\r\n * let C = A.subtract(B)\r\n * @example\r\n * +-------+ +-------+\r\n * | | | |\r\n * | A | | |\r\n * | +--+----+ = | +--+\r\n * +----+--+ | +----+\r\n * | B |\r\n * | |\r\n * +-------+\r\n */\r\n subtract(csg: CSG | CSG[]): CSG\r\n {\r\n let csgs: CSG[];\r\n if (csg instanceof Array)\r\n csgs = csg;\r\n else\r\n csgs = [csg];\r\n let result: CSG = this;\r\n for (let i = 0; i < csgs.length; i++)\r\n {\r\n let islast = i === csgs.length - 1;\r\n result = result.subtractSub(csgs[i], islast, islast);\r\n }\r\n return result;\r\n }\r\n\r\n subtractSub(csg: CSG, retesselate = false, canonicalize = false): CSG\r\n {\r\n let a = new Tree(this.polygons);\r\n let b = new Tree(csg.polygons);\r\n a.invert();\r\n a.clipTo(b);\r\n b.clipTo(a, true);\r\n a.addPolygons(b.allPolygons());\r\n a.invert();\r\n let result = new CSG(a.allPolygons());\r\n // if (retesselate) result = result.reTesselated();\r\n // if (canonicalize) result = result.canonicalized();\r\n return result;\r\n }\r\n\r\n /**\r\n * Return a new CSG solid representing space in both this solid and\r\n * in the given solids. Neither this solid nor the given solids are modified.\r\n * let C = A.intersect(B)\r\n * @returns new CSG object\r\n * @example\r\n * +-------+\r\n * | |\r\n * | A |\r\n * | +--+----+ = +--+\r\n * +----+--+ | +--+\r\n * | B |\r\n * | |\r\n * +-------+\r\n */\r\n intersect(csg: CSG | CSG[]): CSG\r\n {\r\n let csgs: CSG[];\r\n if (csg instanceof Array)\r\n csgs = csg;\r\n else\r\n csgs = [csg];\r\n let result: CSG = this;\r\n for (let i = 0; i < csgs.length; i++)\r\n {\r\n let islast = i === csgs.length - 1;\r\n result = result.intersectSub(csgs[i], islast, islast);\r\n }\r\n return result;\r\n }\r\n\r\n intersectSub(csg: CSG, retesselate = false, canonicalize = false): CSG\r\n {\r\n let a = new Tree(this.polygons);\r\n let b = new Tree(csg.polygons);\r\n a.invert();\r\n b.clipTo(a);\r\n b.invert();\r\n a.clipTo(b);\r\n b.clipTo(a);\r\n a.addPolygons(b.allPolygons());\r\n a.invert();\r\n let result = new CSG(a.allPolygons());\r\n // if (retesselate) result = result.reTesselated();\r\n // if (canonicalize) result = result.canonicalized();\r\n return result;\r\n }\r\n\r\n /**\r\n * Return a new CSG solid with solid and empty space switched.\r\n * This solid is not modified.\r\n */\r\n invert(): CSG\r\n {\r\n let flippedpolygons = this.polygons.map(p => p.flipped());\r\n return new CSG(flippedpolygons);\r\n }\r\n\r\n // Affine transformation of CSG object. Returns a new CSG object\r\n transform1(matrix4x4: Matrix4)\r\n {\r\n let newpolygons = this.polygons.map(p =>\r\n {\r\n return p.transform(matrix4x4);\r\n });\r\n let result = new CSG(newpolygons);\r\n result.isCanonicalized = this.isCanonicalized;\r\n result.isRetesselated = this.isRetesselated;\r\n return result;\r\n }\r\n\r\n /**\r\n * Return a new CSG solid that is transformed using the given Matrix.\r\n * Several matrix transformations can be combined before transforming this solid.\r\n * @param {CSG.Matrix4x4} matrix4x4 - matrix to be applied\r\n * @returns {CSG} new CSG object\r\n * @example\r\n * var m = new CSG.Matrix4x4()\r\n * m = m.multiply(CSG.Matrix4x4.rotationX(40))\r\n * m = m.multiply(CSG.Matrix4x4.translation([-.5, 0, 0]))\r\n * let B = A.transform(m)\r\n */\r\n transform(matrix4x4: Matrix4): this\r\n {\r\n let ismirror = IsMirror(matrix4x4);\r\n let transformedvertices = {};\r\n let transformedplanes = {};\r\n let newpolygons = this.polygons.map(p =>\r\n {\r\n let newplane: Plane;\r\n let plane = p.plane;\r\n let planetag = plane.getTag();\r\n if (planetag in transformedplanes)\r\n {\r\n newplane = transformedplanes[planetag];\r\n } else\r\n {\r\n newplane = plane.transform(matrix4x4);\r\n transformedplanes[planetag] = newplane;\r\n }\r\n let newvertices = p.vertices.map(v =>\r\n {\r\n let newvertex: Vertex3D;\r\n let vertextag = v.getTag();\r\n if (vertextag in transformedvertices)\r\n {\r\n newvertex = transformedvertices[vertextag];\r\n }\r\n else\r\n {\r\n newvertex = v.transform(matrix4x4);\r\n transformedvertices[vertextag] = newvertex;\r\n }\r\n return newvertex;\r\n });\r\n if (ismirror) newvertices.reverse();\r\n return new Polygon(newvertices, newplane);\r\n });\r\n let result = new CSG(newpolygons);\r\n result.isRetesselated = this.isRetesselated;\r\n result.isCanonicalized = this.isCanonicalized;\r\n return result as this;\r\n }\r\n canonicalized()\r\n {\r\n if (this.isCanonicalized) return this;\r\n return canonicalizeCSG(this);\r\n }\r\n reTesselated()\r\n {\r\n if (this.isRetesselated) return this;\r\n return reTesselate(this);\r\n }\r\n\r\n //如果两个实体有可能重叠,返回true\r\n mayOverlap(csg: CSG): boolean\r\n {\r\n if (this.polygons.length === 0 || csg.polygons.length === 0)\r\n return false;\r\n\r\n let mybounds = bounds(this);\r\n let otherbounds = bounds(csg);\r\n if (mybounds[1].x < otherbounds[0].x) return false;\r\n if (mybounds[0].x > otherbounds[1].x) return false;\r\n if (mybounds[1].y < otherbounds[0].y) return false;\r\n if (mybounds[0].y > otherbounds[1].y) return false;\r\n if (mybounds[1].z < otherbounds[0].z) return false;\r\n if (mybounds[0].z > otherbounds[1].z) return false;\r\n return true;\r\n }\r\n\r\n toTriangles(): Polygon[]\r\n {\r\n let polygons: Polygon[] = [];\r\n for (let poly of this.polygons)\r\n {\r\n let firstVertex = poly.vertices[0];\r\n for (let i = poly.vertices.length - 3; i >= 0; i--)\r\n {\r\n polygons.push(\r\n new Polygon(\r\n [\r\n firstVertex,\r\n poly.vertices[i + 1],\r\n poly.vertices[i + 2]\r\n ],\r\n poly.plane\r\n )\r\n );\r\n }\r\n }\r\n return polygons;\r\n }\r\n}\r\n","import { BufferGeometry, Face3, Geometry, Vector2, Vector3 } from \"three\";\r\nimport { equalv3, ZeroVec } from \"../../Geometry/GeUtils\";\r\nimport { CSG } from \"./CSG\";\r\nimport { Polygon } from \"./math/Polygon3\";\r\nimport { Vector2D } from \"./math/Vector2\";\r\nimport { Vector3D } from \"./math/Vector3\";\r\nimport { Vertex3D } from \"./math/Vertex3\";\r\n\r\nexport function Geometry2CSG(geometry: Geometry | BufferGeometry): CSG\r\n{\r\n if (geometry instanceof BufferGeometry)\r\n geometry = new Geometry().fromBufferGeometry(geometry);\r\n\r\n let polygons: Polygon[] = [];\r\n for (let i = 0; i < geometry.faces.length; i++)\r\n {\r\n let face = geometry.faces[i];\r\n let faceVertexUvs = geometry.faceVertexUvs[0][i];\r\n let vertices: Vertex3D[] = [];\r\n\r\n if (face instanceof Face3)\r\n {\r\n let uv = faceVertexUvs ? faceVertexUvs[0].clone() : null;\r\n let vertex1 = new Vertex3D(Vector3ToVector3D(geometry.vertices[face.a]), new Vector2D(uv.x, uv.y));\r\n vertices.push(vertex1);\r\n\r\n uv = faceVertexUvs ? faceVertexUvs[1].clone() : null;\r\n let vertex2 = new Vertex3D(Vector3ToVector3D(geometry.vertices[face.b]), new Vector2D(uv.x, uv.y));\r\n vertices.push(vertex2);\r\n\r\n uv = faceVertexUvs ? faceVertexUvs[2].clone() : null;\r\n let vertex3 = new Vertex3D(Vector3ToVector3D(geometry.vertices[face.c]), new Vector2D(uv.x, uv.y));\r\n vertices.push(vertex3);\r\n }\r\n\r\n let polygon = new Polygon(vertices);\r\n let normal = Vector3DToVector3(polygon.plane.normal);\r\n if (!isNaN(polygon.plane.w) && !equalv3(normal, new Vector3()))\r\n polygons.push(polygon);\r\n }\r\n\r\n return new CSG(polygons);\r\n}\r\n\r\nexport function CSG2Geometry(csg: CSG): Geometry\r\n{\r\n let geo = new Geometry;\r\n let uvs: Vector2[][] = geo.faceVertexUvs[0];\r\n\r\n for (let poly of csg.polygons)\r\n {\r\n let normal = Vector3DToVector3(poly.plane.normal);\r\n if (equalv3(normal, ZeroVec)) continue;\r\n for (let v of poly.vertices)\r\n {\r\n v.tag = geo.vertices.length;\r\n geo.vertices.push(Vector3DToVector3(v.pos));\r\n }\r\n\r\n let firstVertex = poly.vertices[0];\r\n\r\n for (let i = poly.vertices.length - 3; i >= 0; i--)\r\n {\r\n let [a, b, c] = [\r\n firstVertex.tag,\r\n poly.vertices[i + 1].tag,\r\n poly.vertices[i + 2].tag\r\n ];\r\n let f = new Face3(a, b, c, normal);\r\n\r\n geo.faces.push(f);\r\n uvs.push([\r\n Vector2DToVector2(firstVertex.uv),\r\n Vector2DToVector2(poly.vertices[i + 1].uv),\r\n Vector2DToVector2(poly.vertices[i + 2].uv)\r\n ]);\r\n }\r\n }\r\n return geo;\r\n}\r\n\r\nfunction Vector3ToVector3D(v: Vector3): Vector3D\r\n{\r\n return new Vector3D(v.x, v.y, v.z);\r\n}\r\n\r\nexport function Vector3DToVector3(v: Vector3D): Vector3\r\n{\r\n return new Vector3(v.x, v.y, v.z);\r\n}\r\nfunction Vector2DToVector2(v: Vector2D): Vector2\r\n{\r\n return new Vector2(v.x, v.y);\r\n}\r\n","import { Vector3 } from \"three\";\r\nimport { ToFixed } from \"../Common/Utils\";\r\nimport { CSG } from \"../csg/core/CSG\";\r\nimport { Polygon } from \"../csg/core/math/Polygon3\";\r\nimport { Vec3 } from \"./IVec3\";\r\n\r\n/**\r\n * 解决 THREEBSP(CSG) 产生的结果没有办法得到分裂的个数.\r\n * 本类分析了THREEBSP的组合情况.\r\n * \r\n * Example:\r\n * \r\n * let topology = new BSPGroupParse(csg);\r\n * topology.parse();\r\n */\r\nexport class BSPGroupParse\r\n{\r\n constructor(bsp?: CSG, public fractionDigits = 1)\r\n {\r\n if (bsp)\r\n for (let poly of bsp.polygons)\r\n this.Add(poly);\r\n }\r\n Add(poly: Polygon)\r\n {\r\n let strs = poly.vertices.map(p => this.GenerateP(p.pos));\r\n let str0 = strs[0];\r\n let s0 = this.Get(str0);\r\n for (let i = 1; i < strs.length; i++)\r\n {\r\n let stri = strs[i];\r\n s0.add(stri);\r\n this.Get(stri).add(str0);\r\n }\r\n }\r\n\r\n /**\r\n * 返回组合点\r\n */\r\n Parse(): Vector3[][]\r\n {\r\n let set = new Set([...this.map.keys()]);\r\n let res: Vector3[][] = [];\r\n while (set.size > 0)\r\n {\r\n let fp = set[Symbol.iterator]().next().value;\r\n set.delete(fp);\r\n let cset = new Set();\r\n cset.add(fp);\r\n this.GetPts(fp, cset, set);\r\n let pts = [...cset].map(str =>\r\n {\r\n let v3 = this.vecMap.get(str);\r\n return new Vector3(v3.x, v3.y, v3.z);\r\n });\r\n res.push(pts);\r\n }\r\n return res;\r\n }\r\n private map = new Map>();\r\n private Get(vstr: string): Set\r\n {\r\n if (!this.map.has(vstr))\r\n {\r\n let s = new Set();\r\n this.map.set(vstr, s);\r\n return s;\r\n }\r\n return this.map.get(vstr);\r\n }\r\n private GetPts(p: string, cset: Set, oset: Set)\r\n {\r\n let strs = this.map.get(p);\r\n for (let str of strs)\r\n {\r\n if (!cset.has(str))\r\n {\r\n cset.add(str);\r\n oset.delete(str);\r\n this.GetPts(str, cset, oset);\r\n }\r\n }\r\n }\r\n private vecMap = new Map();\r\n private GenerateP(v: Vec3)\r\n {\r\n let str = [v.x, v.y, v.z].map(n => ToFixed(n, this.fractionDigits)).join(\",\");\r\n this.vecMap.set(str, v);\r\n return str;\r\n }\r\n}\r\n","import { BufferGeometry, Vector3 } from \"three\";\r\nimport { arrayLast } from \"../Common/ArrayExt\";\r\nimport { equalv3 } from \"./GeUtils\";\r\nimport { FixIndex } from \"../Common/Utils\";\r\n\r\nexport function GenerateExtrudeEdgeGeometry(contourPoints: Vector3[][], height: number): BufferGeometry\r\n{\r\n let pts: Vector3[] = [];\r\n for (let cs of contourPoints)\r\n pts.push(...GenerateExtrudeEdgeGeometryPoints(cs, height));\r\n let geo = new BufferGeometry().setFromPoints(pts);\r\n return geo;\r\n}\r\n\r\nfunction GenerateExtrudeEdgeGeometryPoints(contourPoints: Vector3[], height: number): Vector3[]\r\n{\r\n if (contourPoints.length < 3) return [];\r\n if (equalv3(contourPoints[0], arrayLast(contourPoints)))\r\n contourPoints.pop();\r\n let pts: Vector3[] = [];\r\n let hpts = contourPoints.map(p => new Vector3(p.x, p.y, height));\r\n let count = contourPoints.length;\r\n for (let i = 0; i < count; i++)\r\n {\r\n pts.push(contourPoints[i], contourPoints[FixIndex(i + 1, count)], hpts[i], hpts[FixIndex(i + 1, count)], contourPoints[i], hpts[i]);\r\n }\r\n return pts;\r\n}\r\n\r\nexport function GenerateBoxEdgeGeometry(length: number, width: number, height: number): BufferGeometry\r\n{\r\n let pts = [new Vector3(), new Vector3(length), new Vector3(length, width), new Vector3(0, width)];\r\n return GenerateExtrudeEdgeGeometry([pts], height);\r\n}\r\n","import { BufferGeometry, Float32BufferAttribute, MathUtils, Matrix4, Shape as TShape, ShapeUtils, Vector3 } from \"three\";\r\nimport { arrayRemoveDuplicateBySort, arraySortByNumber } from \"../Common/ArrayExt\";\r\nimport { curveLinkGroup } from \"../Common/CurveUtils\";\r\nimport { clamp, FixIndex } from \"../Common/Utils\";\r\nimport { Contour } from \"../DatabaseServices/Contour\";\r\nimport { Arc } from \"../DatabaseServices/Entity/Arc\";\r\nimport { Board } from \"../DatabaseServices/Entity/Board\";\r\nimport { Circle } from \"../DatabaseServices/Entity/Circle\";\r\nimport { Curve } from \"../DatabaseServices/Entity/Curve\";\r\nimport { ExtrudeSolid, ExtureContourCurve } from \"../DatabaseServices/Entity/Extrude\";\r\nimport { Line } from \"../DatabaseServices/Entity/Line\";\r\nimport { Polyline, PolylineProps } from \"../DatabaseServices/Entity/Polyline\";\r\nimport { IntersectOption, IntersectResult } from \"../GraphicsSystem/IntersectWith\";\r\nimport { LinesType } from \"../UI/Store/BoardInterface\";\r\nimport { IntersectsBox } from \"./Box\";\r\nimport { AsVector2, equaln, equalv3, IdentityMtx4 } from \"./GeUtils\";\r\nimport { RegionParse } from \"./RegionParse\";\r\n\r\nexport enum DepthType\r\n{\r\n Front = 1,\r\n Back = 2,\r\n All = 3,\r\n}\r\n\r\n/**\r\n * 槽的几何数据,包括槽的墙面和槽的盖子\r\n */\r\nexport class Groove\r\n{\r\n contourWall: ExtudeWall;//槽轮廓的墙\r\n holeWalls: ExtudeWall[] = [];//槽的网洞的墙\r\n private lid: CurveTapeShape;//槽的盖子\r\n constructor(contour: Contour,\r\n holes: Contour[],\r\n public depthType: DepthType,\r\n public depth: number,\r\n public allDepth: number,\r\n private box = contour.BoundingBox\r\n )\r\n {\r\n this.contourWall = new ExtudeWall(contour.Curve, depthType, depth, allDepth, DirectionType.Inner);\r\n for (let h of holes)\r\n this.holeWalls.push(new ExtudeWall(h.Curve, depthType, depth, allDepth, DirectionType.Outer));\r\n\r\n this.lid = new CurveTapeShape(contour, holes);\r\n }\r\n\r\n /**\r\n * @param groove this - groove\r\n * @param [eachOther=true] 相互裁剪\r\n */\r\n ClipTo(groove: Groove, eachOther = true)\r\n {\r\n //相同深度和面不用操作\r\n if (groove.depthType === this.depthType && groove.depth === this.depth) return;\r\n\r\n if (!IntersectsBox(this.box, groove.box)) return;\r\n\r\n this.ClipLid(groove);\r\n groove.ClipLid(this);\r\n\r\n //一正一反,不交集\r\n if (this.depthType + groove.depthType === 3 && this.depth + groove.depth < this.allDepth)\r\n return;\r\n\r\n this.contourWall.ClipTo(groove, true);\r\n for (let wall of this.holeWalls)\r\n wall.ClipTo(groove, true);\r\n\r\n if (eachOther)\r\n {\r\n groove.contourWall.ClipTo(this, false);\r\n for (let wall of groove.holeWalls)\r\n wall.ClipTo(this, false);\r\n }\r\n }\r\n\r\n private ClipLid(groove: Groove)\r\n {\r\n if (this.depthType === DepthType.All) return;\r\n if (groove.depthType === DepthType.All) return;\r\n\r\n if (this.depthType === groove.depthType)\r\n {\r\n if (groove.depth > this.depth)\r\n this.lid.ClipTo(groove.lid, true);\r\n else\r\n this.lid.SplitTo(groove.lid);\r\n }\r\n else\r\n {\r\n if (this.depth + groove.depth >= this.allDepth)\r\n this.lid.ClipTo(groove.lid, true);\r\n else\r\n this.lid.SplitTo(groove.lid);\r\n }\r\n }\r\n\r\n Draw(verticesArray: number[], uvArray: number[], edgeBuild: EdgeGeometryBuild, rotateUv: boolean)\r\n {\r\n this.contourWall.Draw(verticesArray, uvArray, edgeBuild);\r\n for (let wall of this.holeWalls)\r\n wall.Draw(verticesArray, uvArray, edgeBuild);\r\n\r\n if (this.depthType === DepthType.All) return;\r\n\r\n let isFront = this.depthType === DepthType.Front;\r\n this.lid.Draw(verticesArray, uvArray, isFront, isFront ? this.allDepth - this.depth : this.depth, rotateUv);\r\n }\r\n}\r\n\r\nfunction GetShape(cu: ExtureContourCurve): TShape\r\n{\r\n if (cu instanceof Circle)\r\n {\r\n let sp = new TShape();\r\n let cen = cu.Center;\r\n sp.ellipse(cen.x, cen.y, cu.Radius, cu.Radius, 0, 2 * Math.PI, false, 0);\r\n return sp;\r\n }\r\n else\r\n {\r\n if (cu.OCSNoClone !== IdentityMtx4)\r\n cu.UpdateMatrixTo(IdentityMtx4);\r\n return cu.Shape;\r\n }\r\n}\r\n\r\nfunction CreateTape(faceType: DepthType, startParam: number, endParam: number, depth: number, allDepth: number): Tape\r\n{\r\n if (faceType === DepthType.Front)\r\n return new Tape(startParam, endParam, allDepth - depth, allDepth);\r\n else\r\n return new Tape(startParam, endParam, 0, depth);\r\n}\r\n\r\n//朝向类型\r\nenum DirectionType\r\n{\r\n Outer = 0,//外墙\r\n Inner = 1 //内墙\r\n}\r\n\r\n//轮廓树节点,用于重新确认外墙和网洞的关系\r\nexport class ContourTreeNode\r\n{\r\n parent: ContourTreeNode;//当存在Parent时,表示它是一个洞\r\n constructor(public contour: Contour, public children: ContourTreeNode[] = []) { }\r\n\r\n SetParent(node: ContourTreeNode)\r\n {\r\n this.parent = node;\r\n node.children.push(this);\r\n }\r\n\r\n Draw(verticesArray: number[], uvArray: number[], front: boolean, z: number, rotateUv: boolean)//, depth = 1\r\n {\r\n // TestDraw(this.contour.Curve, depth);\r\n let pts = this.contour.Curve.GetStretchPoints();\r\n\r\n let vertices = [...pts];\r\n let holes = this.children.map(h =>\r\n {\r\n // TestDraw(h.contour.Curve, depth + 1);\r\n let pts = h.contour.Curve.GetStretchPoints();\r\n vertices.push(...pts);\r\n return pts;\r\n });\r\n\r\n let faces = ShapeUtils.triangulateShape(pts, holes);\r\n\r\n for (let f of faces)\r\n {\r\n if (front)\r\n {\r\n AddVertice(vertices[f[0]]);\r\n AddVertice(vertices[f[1]]);\r\n AddVertice(vertices[f[2]]);\r\n }\r\n else\r\n {\r\n AddVertice(vertices[f[0]]);\r\n AddVertice(vertices[f[2]]);\r\n AddVertice(vertices[f[1]]);\r\n }\r\n }\r\n\r\n function AddVertice(v: Vector3)\r\n {\r\n verticesArray.push(v.x, v.y, z);\r\n if (rotateUv)\r\n uvArray.push(v.y * 1e-3, v.x * 1e-3);\r\n else\r\n uvArray.push(v.x * 1e-3, v.y * 1e-3);\r\n }\r\n\r\n for (let hole of this.children)\r\n {\r\n for (let h of hole.children)\r\n {\r\n h.Draw(verticesArray, uvArray, front, z, rotateUv);//, depth + 2\r\n }\r\n }\r\n }\r\n\r\n static ParseContourTree(contourNodes: ContourTreeNode[]): void\r\n {\r\n contourNodes.sort((c1, c2) => c1.contour.Curve.Area - c2.contour.Curve.Area);\r\n for (let i = 0; i < contourNodes.length; i++)\r\n {\r\n const node1 = contourNodes[i];\r\n let p = node1.contour.Curve.StartPoint;\r\n for (let j = i + 1; j < contourNodes.length; j++)\r\n {\r\n const node2 = contourNodes[j];\r\n if (node2.contour.BoundingBox.intersectsBox(node1.contour.BoundingBox)\r\n && node2.contour.Curve.PtInCurve(p))\r\n {\r\n node1.SetParent(node2);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nclass EdgeGeometryBuild\r\n{\r\n lineVerticesArray: number[] = [];\r\n\r\n frontLines: Line[] = [];\r\n backLines: Line[] = [];\r\n constructor(public allDepth: number) { }\r\n AddLidLine(p1: Vector3, p2: Vector3, depth: number)\r\n {\r\n if (depth === 0)\r\n {\r\n p1 = p1.clone().setZ(0);\r\n p2 = p2.clone().setZ(0);\r\n let line = new Line(p1, p2);\r\n this.backLines.push(line);\r\n }\r\n else if (depth === this.allDepth)\r\n {\r\n p1 = p1.clone().setZ(0);\r\n p2 = p2.clone().setZ(0);\r\n let line = new Line(p1, p2);\r\n this.frontLines.push(line);\r\n }\r\n }\r\n\r\n BuildLid(verticesArray: number[], uvArray: number[], rotateUv: boolean)\r\n {\r\n let arr = [this.backLines, this.frontLines];\r\n\r\n for (let index = 0; index < 2; index++)\r\n {\r\n let lines = arr[index];\r\n let parse = new RegionParse(lines);\r\n let contourNodes: ContourTreeNode[] = [];\r\n for (let routes of parse.RegionsOutline)\r\n {\r\n let cs: Curve[] = [];\r\n for (let r of routes)\r\n cs.push(r.curve);\r\n let c = Contour.CreateContour(cs, false);\r\n if (c)\r\n contourNodes.push(new ContourTreeNode(c));\r\n else\r\n console.error(\"未能构建盖子\");\r\n }\r\n\r\n ContourTreeNode.ParseContourTree(contourNodes);\r\n\r\n for (let j = contourNodes.length; j--;)\r\n {\r\n let node = contourNodes[j];\r\n if (node.parent) continue;\r\n\r\n node.Draw(verticesArray, uvArray, index === 1, this.allDepth * index, rotateUv);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 胶带\r\n */\r\nclass Tape\r\n{\r\n constructor(\r\n public start: number,\r\n public end: number,\r\n\r\n public bottom: number,\r\n public top: number\r\n )\r\n {\r\n\r\n }\r\n\r\n //用于测试\r\n get Curve()\r\n {\r\n return new Polyline().RectangleFrom2Pt(new Vector3(this.start, this.bottom), new Vector3(this.end, this.top));\r\n }\r\n\r\n Clip(t: this): Tape[]\r\n {\r\n let yr = IntersectRange(this.bottom, this.top, t.bottom, t.top, 1e5);\r\n if (yr === undefined) return [this];\r\n\r\n let xr = IntersectRange(this.start, this.end, t.start, t.end, 1e5);\r\n if (xr === undefined) return [this];\r\n\r\n let rem = SubtractRange(this.start, this.end, t.start, t.end, 1e5).map(r =>\r\n {\r\n return new Tape(r[0], r[1], this.bottom, this.top);\r\n });\r\n\r\n let remR = SubtractRange(this.bottom, this.top, t.bottom, t.top, 1e5);\r\n for (let hr of remR)\r\n {\r\n rem.push(new Tape(xr[0], xr[1], hr[0], hr[1]));\r\n }\r\n return rem;\r\n }\r\n\r\n Split(xlst: number[]): Tape[]\r\n {\r\n let ret: Tape[] = [];\r\n let pre = this.start;\r\n for (let x of xlst)\r\n {\r\n if (x > pre)\r\n {\r\n if (x >= this.end) x = this.end;\r\n if (equaln(pre, x)) continue;\r\n ret.push(new Tape(pre, x, this.bottom, this.top));\r\n pre = x;\r\n if (x === this.end) break;\r\n }\r\n }\r\n return ret;\r\n }\r\n}\r\n\r\n/**\r\n * 二维形状,内部用曲线胶带表示(用来计算盖子差集算法)\r\n */\r\nexport class CurveTapeShape\r\n{\r\n children: CurveTapeShape[] = [];\r\n contour: CurveTape;\r\n holes: CurveTape[];\r\n constructor(contour: Contour, holes: Contour[])\r\n {\r\n this.contour = new CurveTape(contour, DirectionType.Outer);\r\n this.holes = holes.map(h => new CurveTape(h, DirectionType.Inner));\r\n }\r\n\r\n CloneNew()\r\n {\r\n let s = new CurveTapeShape(this.contour.contour, this.holes.map(h => h.contour));\r\n return s;\r\n }\r\n\r\n /**\r\n * 删除包含,同向\r\n */\r\n ClipTo(s: CurveTapeShape, append: boolean = false)\r\n {\r\n for (let c of [this.contour, ... this.holes])\r\n if (c.tapes.length > 0)\r\n c.ClipTo(s);\r\n\r\n if (append)\r\n {\r\n let sn = s.CloneNew();\r\n sn.ReverseClipTo(this);\r\n this.children.push(sn);\r\n }\r\n }\r\n\r\n //合理打断(以保证三维网格对齐(否则圆弧点将无法正确的对齐))\r\n SplitTo(s: CurveTapeShape)\r\n {\r\n for (let c of [this.contour, ...this.holes])\r\n {\r\n for (let c2 of [s.contour, ...s.holes])\r\n {\r\n let int = GetIntersection(c.contour.Curve, c2.contour.Curve);\r\n c.splitParams.push(...int.map(i => i.thisParam));\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 只保留被包含部分\r\n */\r\n private ReverseClipTo(s: CurveTapeShape): this\r\n {\r\n for (let c of [this.contour, ... this.holes])\r\n if (c.tapes.length > 0)\r\n c.ReverseClipTo(s);\r\n\r\n return this;\r\n }\r\n\r\n ChildrenClip()\r\n {\r\n for (let i = 0; i < this.children.length; i++)\r\n {\r\n let s1 = this.children[i];\r\n for (let j = i + 1; j < this.children.length; j++)\r\n {\r\n let s2 = this.children[j];\r\n\r\n s1.ClipTo(s2, false);\r\n s2.ClipTo(s1, false);\r\n }\r\n }\r\n }\r\n\r\n Draw(verticesArray: number[], uvArray: number[], front: boolean, z: number, rotateUv: boolean)\r\n {\r\n this.ChildrenClip();\r\n\r\n let polylines: Polyline[] = this.contour.Curves;\r\n\r\n for (let h of this.holes)\r\n polylines.push(...h.Curves);\r\n\r\n for (let s of this.children)\r\n {\r\n polylines.push(...s.contour.Curves);\r\n for (let h of s.holes)\r\n polylines.push(...h.Curves);\r\n }\r\n\r\n // TestDraw(polylines, z);\r\n let groups = curveLinkGroup(polylines);\r\n let contourNodes: ContourTreeNode[] = [];\r\n for (let cus of groups)\r\n {\r\n let c = Contour.CreateContour(cus, false);\r\n if (c)\r\n contourNodes.push(new ContourTreeNode(c));\r\n else\r\n console.error(\"出错\");\r\n }\r\n\r\n ContourTreeNode.ParseContourTree(contourNodes);\r\n\r\n for (let j = contourNodes.length; j--;)\r\n {\r\n let node = contourNodes[j];\r\n // TestDraw(s.contour.Curve.Clone(), z);\r\n if (node.parent) continue;\r\n\r\n node.Draw(verticesArray, uvArray, front, z, rotateUv);\r\n }\r\n }\r\n}\r\n\r\nconst SplitLength = 4;\r\nconst MinSplitCount = 12;\r\nconst MaxSplitCount = 360;\r\nfunction SplitCurveParams(cu: ExtureContourCurve): number[]\r\n{\r\n let xparams: number[] = [];\r\n if (cu instanceof Circle)\r\n {\r\n let splitCount = cu.Radius / SplitLength;\r\n splitCount = clamp(Math.floor(splitCount), MinSplitCount, MaxSplitCount);\r\n for (let i = 0; i < splitCount; i++)\r\n xparams.push(i / splitCount);\r\n }\r\n else\r\n //分段1\r\n for (let i = 0; i < cu.EndParam; i++)\r\n {\r\n xparams.push(i);\r\n if (cu.GetBuilgeAt(i) !== 0)\r\n {\r\n let arc = cu.GetCurveAtIndex(i) as Arc;\r\n let splitCount = arc.Radius / SplitLength;\r\n splitCount = clamp(Math.floor(splitCount), MinSplitCount, MaxSplitCount);\r\n if (splitCount === 0) continue;\r\n\r\n let a = Math.PI * 2 / splitCount;\r\n let params: number[] = [];\r\n for (let j = 0; j < splitCount; j++)\r\n {\r\n let param = arc.GetParamAtAngle(a * j);\r\n if (arc.ParamOnCurve(param))\r\n params.push(param);\r\n }\r\n arraySortByNumber(params);\r\n if (params.length === 0) continue;\r\n\r\n for (let p of params)\r\n {\r\n if (p > 1e-5 && p < 9.99999)\r\n xparams.push(p + i);\r\n }\r\n }\r\n }\r\n xparams.push(cu.EndParam);\r\n return xparams;\r\n}\r\n\r\n/**\r\n * 曲线胶带(一维)\r\n */\r\nclass CurveTape\r\n{\r\n tapes: Range[];\r\n splitParams: number[] = [];\r\n constructor(public contour: Contour, public wallType: DirectionType)\r\n {\r\n this.tapes = [[0, this.contour.Curve.EndParam]];\r\n }\r\n\r\n get Curves(): Polyline[]\r\n {\r\n let xparams: number[] = SplitCurveParams(this.contour.Curve);\r\n if (this.splitParams.length > 0)\r\n {\r\n xparams.push(...this.splitParams);\r\n arraySortByNumber(xparams);\r\n arrayRemoveDuplicateBySort(xparams, (p1, p2) => equaln(p1, p2));\r\n }\r\n\r\n let polylines: Polyline[] = [];\r\n\r\n function TD(p: Vector3): PolylineProps\r\n {\r\n return { pt: AsVector2(p), bul: 0 };\r\n }\r\n\r\n const addPolyline = (t: Range) =>\r\n {\r\n let pts = [TD(this.contour.Curve.GetPointAtParam(t[0]))];\r\n for (let x of xparams)\r\n {\r\n if (x <= t[0]) continue;\r\n if (x >= t[1]) break;\r\n\r\n pts.push(TD(this.contour.Curve.GetPointAtParam(x)));\r\n }\r\n pts.push(TD(this.contour.Curve.GetPointAtParam(t[1])));\r\n\r\n let pl = new Polyline(pts);\r\n polylines.push(pl);\r\n };\r\n\r\n for (let t of this.tapes)\r\n {\r\n if (t[0] > t[1])\r\n {\r\n addPolyline([0, t[1]]);\r\n addPolyline([t[0], this.contour.Curve.EndParam]);\r\n }\r\n else\r\n addPolyline(t);\r\n }\r\n return polylines;\r\n }\r\n\r\n /**\r\n * 分析与另一个形状的包含关系\r\n */\r\n Parse(s: CurveTapeShape): CurveParamRangeRelation\r\n {\r\n let [res1] = ParseCurveParamRangeRelation(this.contour.Curve, s.contour.contour.Curve);\r\n if (this.wallType === DirectionType.Inner)\r\n [res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy];\r\n if (res1.container.length > 0)\r\n {\r\n for (let h of s.holes)\r\n {\r\n let [res2] = ParseCurveParamRangeRelation(this.contour.Curve, h.contour.Curve);\r\n if (this.wallType === DirectionType.Outer)\r\n [res2.syntropy, res2.reverse] = [res2.reverse, res2.syntropy];\r\n\r\n res1.syntropy.push(...res2.syntropy);\r\n res1.reverse.push(...res2.reverse);\r\n\r\n res1.container = SubtractRanges(res1.container, res2.container, this.contour.Curve.EndParam);\r\n res1.container = SubtractRanges(res1.container, res2.syntropy, this.contour.Curve.EndParam);\r\n res1.container = SubtractRanges(res1.container, res2.reverse, this.contour.Curve.EndParam);\r\n }\r\n }\r\n return res1;\r\n }\r\n\r\n /**\r\n * 删除包含,同向面\r\n */\r\n ClipTo(s: CurveTapeShape): this\r\n {\r\n let d = this.Parse(s);\r\n\r\n this.tapes = SubtractRanges(this.tapes, d.container, this.contour.Curve.EndParam);\r\n this.tapes = SubtractRanges(this.tapes, d.syntropy, this.contour.Curve.EndParam);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * 保留被包含的部分\r\n */\r\n ReverseClipTo(s: CurveTapeShape): this\r\n {\r\n this.tapes = this.Parse(s).container;\r\n return this;\r\n }\r\n}\r\n\r\nclass ExtudeWall\r\n{\r\n //胶带(立面)\r\n private Tape: Tape[];\r\n constructor(public curve: ExtureContourCurve,\r\n public depthType: DepthType,\r\n public depth: number,\r\n public allDepth: number,\r\n public wallType: DirectionType\r\n )\r\n {\r\n //一整段\r\n this.Tape = [CreateTape(depthType, 0, this.curve.EndParam, depth, allDepth)];\r\n }\r\n\r\n /**\r\n * 减去在另一个groove内的部分\r\n * @param groove this - groove\r\n * @param [clipSyntropy=false] 删除同向的面\r\n */\r\n ClipTo(groove: Groove, clipSyntropy = false)\r\n {\r\n let [res1] = ParseCurveParamRangeRelation(this.curve, groove.contourWall.curve);\r\n if (this.wallType !== groove.contourWall.wallType)\r\n [res1.syntropy, res1.reverse] = [res1.reverse, res1.syntropy];\r\n if (res1.container.length > 0)\r\n {\r\n for (let h of groove.holeWalls)\r\n {\r\n let [resh1] = ParseCurveParamRangeRelation(this.curve, h.curve);\r\n\r\n //翻转\r\n if (this.wallType !== h.wallType)\r\n [resh1.syntropy, resh1.reverse] = [resh1.reverse, resh1.syntropy];\r\n\r\n //删除在网洞内的\r\n let subParams: [number, number][];\r\n if (clipSyntropy)\r\n subParams = resh1.container;//删除共面,\r\n else\r\n subParams = [...resh1.container, ...resh1.syntropy];//保留共面部分\r\n\r\n for (let i of subParams)\r\n {\r\n let rems: [number, number][] = [];\r\n for (let r of res1.container)\r\n rems.push(...SubtractRange(r[0], r[1], i[0], i[1], this.curve.EndParam));\r\n res1.container = rems;\r\n }\r\n }\r\n }\r\n\r\n let params = [...res1.container, ...res1.reverse];\r\n if (clipSyntropy)\r\n params.push(...res1.syntropy);\r\n\r\n for (let c of params)\r\n this.ClipFromParam(c[0], c[1], groove.depthType, groove.depth);\r\n }\r\n\r\n ClipReverse(wall: this)\r\n {\r\n let [res1] = ParseCurveParamRangeRelation(this.curve, wall.curve);\r\n for (let c of res1.syntropy)\r\n this.ClipFromParam(c[0], c[1], wall.depthType, wall.depth);\r\n }\r\n\r\n /**\r\n * 当起始参数大于终止参数时,裁剪的区域经过终点\r\n *\r\n * @param startParam 起始参数\r\n * @param endParam 终止参数\r\n * @param faceType 裁剪面朝向\r\n * @param depth 裁剪面的深度\r\n */\r\n ClipFromParam(startParam: number, endParam: number, faceType: DepthType, depth: number)\r\n {\r\n if (equaln(startParam, endParam)) return;\r\n if (startParam > endParam)\r\n {\r\n this.ClipFromParam(startParam, this.curve.EndParam, faceType, depth);\r\n this.ClipFromParam(0, endParam, faceType, depth);\r\n return this;\r\n }\r\n\r\n let subTape = CreateTape(faceType, startParam, endParam, depth, this.allDepth);\r\n let taps: Tape[] = [];\r\n for (let t of this.Tape)\r\n taps.push(...t.Clip(subTape));\r\n\r\n this.Tape = taps;\r\n return this;\r\n }\r\n\r\n Draw(verticesArray: number[], uvArray: number[], edgeBuild: EdgeGeometryBuild)\r\n {\r\n let xparams = SplitCurveParams(this.curve);\r\n\r\n function AddVertice(v: Vector3)\r\n {\r\n verticesArray.push(v.x);\r\n verticesArray.push(v.y);\r\n verticesArray.push(v.z);\r\n }\r\n\r\n let tapes: Tape[] = [];\r\n this.Tape.sort((t1, t2) => t1.start - t2.start);\r\n for (let tape of this.Tape)\r\n tapes.push(...tape.Split(xparams));\r\n for (let i = 0; i < tapes.length; i++)\r\n {\r\n let preIndex = FixIndex(i - 1, tapes);\r\n let nextIndex = FixIndex(i + 1, tapes);\r\n\r\n let tape = tapes[i];\r\n let preTape = tapes[preIndex];\r\n let nextTape = tapes[nextIndex];\r\n\r\n let p1 = this.curve.GetPointAtParam(tape.start).setZ(tape.bottom);\r\n let p2 = this.curve.GetPointAtParam(tape.end).setZ(tape.bottom);\r\n let vs = [p1, p2, p2.clone().setZ(tape.top), p1.clone().setZ(tape.top), p1];\r\n edgeBuild.AddLidLine(p1, p2, tape.bottom);\r\n edgeBuild.AddLidLine(p1, p2, tape.top);\r\n\r\n //#region 构造线框\r\n {\r\n let leftRanges: Range[];\r\n let rightRange: Range[];\r\n\r\n const IsInteger = (n: number) => equaln(n, Math.round(n), 1e-8);\r\n\r\n if (!IsInteger(tape.start) && equaln(tape.start, preTape.end))\r\n leftRanges = SubtractRange(tape.bottom, tape.top, preTape.bottom, preTape.top, this.allDepth);\r\n else\r\n leftRanges = [[tape.bottom, tape.top]];\r\n\r\n if (equaln(tape.end, nextTape.start))\r\n rightRange = SubtractRange(tape.bottom, tape.top, nextTape.bottom, nextTape.top, this.allDepth);\r\n else\r\n rightRange = [[tape.bottom, tape.top]];\r\n\r\n //上下两条线\r\n edgeBuild.lineVerticesArray.push(\r\n p1.x, p1.y, p1.z,\r\n p2.x, p2.y, p2.z,\r\n\r\n p1.x, p1.y, tape.top,\r\n p2.x, p2.y, tape.top,\r\n );\r\n\r\n //左右线\r\n for (let range of leftRanges)\r\n {\r\n edgeBuild.lineVerticesArray.push(\r\n p1.x, p1.y, range[0],\r\n p1.x, p1.y, range[1]);\r\n }\r\n for (let range of rightRange)\r\n {\r\n edgeBuild.lineVerticesArray.push(\r\n p2.x, p2.y, range[0],\r\n p2.x, p2.y, range[1]);\r\n }\r\n }\r\n //#endregion\r\n\r\n //和X平行平行\r\n let isXPar = (vs[0].y + vs[1].y + vs[2].y) < 0.01;\r\n\r\n function AddUv(p: Vector3)\r\n {\r\n if (isXPar)\r\n uvArray.push((p.z - 1) * 1e-3, p.y * 1e-3);\r\n else\r\n uvArray.push((p.z - 1) * 1e-3, p.x * 1e-3);\r\n }\r\n if (this.wallType === DirectionType.Outer)\r\n {\r\n AddVertice(vs[0]);\r\n AddUv(vs[0]);\r\n AddVertice(vs[1]);\r\n AddUv(vs[1]);\r\n AddVertice(vs[2]);\r\n AddUv(vs[2]);\r\n\r\n AddVertice(vs[0]);\r\n AddUv(vs[0]);\r\n AddVertice(vs[2]);\r\n AddUv(vs[2]);\r\n AddVertice(vs[3]);\r\n AddUv(vs[3]);\r\n }\r\n else\r\n {\r\n AddVertice(vs[0]);\r\n AddUv(vs[0]);\r\n AddVertice(vs[2]);\r\n AddUv(vs[2]);\r\n AddVertice(vs[1]);\r\n AddUv(vs[1]);\r\n\r\n AddVertice(vs[0]);\r\n AddUv(vs[0]);\r\n AddVertice(vs[3]);\r\n AddUv(vs[3]);\r\n AddVertice(vs[2]);\r\n AddUv(vs[2]);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 曲线参数范围关系(包含,分离,同向共线,反向共线)\r\n * 用来表示某一曲线在另一个曲线内的关系\r\n */\r\ninterface CurveParamRangeRelation\r\n{\r\n outer: Range[];//外部\r\n container: Range[];//被包含\r\n syntropy: Range[];//同向\r\n reverse: Range[];//反向\r\n}\r\n\r\nfunction CloneCurveRange(r: CurveParamRangeRelation): CurveParamRangeRelation\r\n{\r\n return {\r\n outer: r.outer.slice(),\r\n container: r.container.slice(),\r\n syntropy: r.syntropy.slice(),\r\n reverse: r.reverse.slice(),\r\n };\r\n}\r\n\r\ninterface CurveSegs\r\n{\r\n outer: Curve[];//外部\r\n container: Curve[];//被包含\r\n syntropy: Curve[];//同向\r\n reverse: Curve[];//反向\r\n}\r\n\r\nfunction binarySearch(ar: number[], el: number): number\r\n{\r\n let m = 0;\r\n let n = ar.length - 1;\r\n while (m <= n)\r\n {\r\n let k = (n + m) >> 1;\r\n let cmp = (el - ar[k]);\r\n if (cmp > 1e8)\r\n m = k + 1;\r\n else if (cmp < -1e8)\r\n n = k - 1;\r\n else\r\n return k;\r\n }\r\n return -m - 1;\r\n}\r\n\r\nfunction CurveSplit(cu: Curve, range: CurveParamRangeRelation): CurveSegs\r\n{\r\n let segs = { outer: [], container: [], syntropy: [], reverse: [] };\r\n\r\n let ranges: Range[] = [...range.outer, ...range.container, ...range.syntropy, ...range.reverse];\r\n\r\n ranges.sort((r1, r2) => r1[0] - r2[0]);\r\n\r\n let params: number[] = ranges.flat();\r\n arrayRemoveDuplicateBySort(params, (p1, p2) => equaln(p1, p2));\r\n let cus = cu.GetSplitCurves(params);\r\n\r\n for (let key in range)\r\n {\r\n for (let r of range[key])\r\n {\r\n let i = binarySearch(params, r[0]);\r\n segs[key].push(cus[i]);\r\n }\r\n }\r\n\r\n return segs;\r\n}\r\n\r\n/**\r\n * 分析两个曲线关系(包含,分离,同向共线,反向共线)(用参数范围表示)\r\n */\r\nfunction ParseCurveParamRangeRelation(cu1: ExtureContourCurve, cu2: ExtureContourCurve, reverseParse = false): [CurveParamRangeRelation, CurveParamRangeRelation]\r\n{\r\n let ins = GetIntersection(cu1, cu2);\r\n\r\n let c1Res: CurveParamRangeRelation = { container: [], syntropy: [], reverse: [], outer: [] };\r\n let c2Res: CurveParamRangeRelation = { container: [], syntropy: [], reverse: [], outer: [] };\r\n if (ins.length === 0)\r\n {\r\n if (cu2.PtInCurve(cu1.StartPoint))\r\n c1Res.container.push([0, cu1.EndParam]);\r\n else\r\n c1Res.outer.push([0, cu1.EndParam]);\r\n\r\n if (cu1.PtInCurve(cu2.StartPoint))\r\n c2Res.container.push([0, cu2.EndParam]);\r\n else\r\n c2Res.outer.push([0, cu2.EndParam]);\r\n\r\n return [c1Res, c2Res];\r\n }\r\n\r\n type CurveSeg = {\r\n startParam: number;\r\n endParam: number;\r\n startPoint: Vector3;\r\n endPoint: Vector3;\r\n used?: boolean;\r\n };\r\n\r\n //解析出线段列表\r\n let c1Curves: CurveSeg[] = [];\r\n let c2Curves: CurveSeg[] = [];\r\n\r\n ins.sort((a1, a2) => a1.thisParam - a2.thisParam);\r\n //点重复->下方ins会sort,导致交点对应不上,导致错误\r\n arrayRemoveDuplicateBySort(ins, (i1, i2) => equalv3(i1.pt, i2.pt, 1e-4));\r\n if (ins.length > 1 && equalv3(ins[0].pt, ins[ins.length - 1].pt, 1e-4)) ins.pop();\r\n for (let i = 0; i < ins.length; i++)\r\n {\r\n let n1 = ins[i];\r\n let n2 = ins[FixIndex(i + 1, ins)];\r\n c1Curves.push({ startParam: n1.thisParam, endParam: n2.thisParam, startPoint: n1.pt, endPoint: n2.pt });\r\n }\r\n ins.sort((a1, a2) => a1.argParam - a2.argParam);\r\n for (let i = 0; i < ins.length; i++)\r\n {\r\n let n1 = ins[i];\r\n let n2 = ins[FixIndex(i + 1, ins)];\r\n c2Curves.push({ startParam: n1.argParam, endParam: n2.argParam, startPoint: n1.pt, endPoint: n2.pt });\r\n }\r\n\r\n //分析共边关系和包含关系\r\n for (let c of c1Curves)\r\n {\r\n let c1MidPoint = CenterPoint(cu1, c.startParam, c.endParam);\r\n for (let c2 of c2Curves)\r\n {\r\n if (c2.used)\r\n continue;\r\n\r\n let c2MidPoint = CenterPoint(cu2, c2.startParam, c2.endParam);\r\n if (!equalv3(c1MidPoint, c2MidPoint, 1e-4))\r\n continue;\r\n\r\n c.used = true;\r\n if (c.startPoint === c2.startPoint\r\n && c.endPoint === c2.endPoint)\r\n {\r\n c1Res.syntropy.push([c.startParam, c.endParam]);\r\n c2Res.syntropy.push([c2.startParam, c2.endParam]);\r\n c2.used = true;\r\n break;\r\n }\r\n else if (c.startPoint === c2.endPoint\r\n && c.endPoint === c2.startPoint)\r\n {\r\n c1Res.reverse.push([c.startParam, c.endParam]);\r\n c2Res.reverse.push([c2.startParam, c2.endParam]);\r\n c2.used = true;\r\n break;\r\n }\r\n else\r\n c.used = false;\r\n }\r\n\r\n if (!c.used)\r\n {\r\n if (cu2.PtInCurve(c1MidPoint))\r\n c1Res.container.push([c.startParam, c.endParam]);\r\n else\r\n c1Res.outer.push([c.startParam, c.endParam]);\r\n }\r\n }\r\n\r\n //只分析包含关系\r\n if (reverseParse)\r\n for (let c of c2Curves)\r\n {\r\n if (c.used) continue;\r\n let p = CenterPoint(cu2, c.startParam, c.endParam);\r\n if (cu1.PtInCurve(p))\r\n c2Res.container.push([c.startParam, c.endParam]);\r\n else\r\n c2Res.outer.push([c.startParam, c.endParam]);\r\n }\r\n return [c1Res, c2Res];\r\n}\r\n\r\nfunction CenterPoint(cu: ExtureContourCurve, start: number, end: number)\r\n{\r\n let lenStart = cu.GetDistAtParam(start);\r\n let lenEnd = cu.GetDistAtParam(end);\r\n if (end > start)\r\n return cu.GetPointAtDistance((lenEnd + lenStart) * 0.5);\r\n\r\n let lenAll = cu.Length;\r\n let lenDiv = ((lenAll - lenStart) + lenEnd) * 0.5;\r\n\r\n if (lenStart + lenDiv >= lenAll)\r\n return cu.GetPointAtDistance(lenStart + lenDiv - lenAll);\r\n else\r\n return cu.GetPointAtDistance(lenStart + lenDiv);\r\n}\r\n\r\n//求参数并集部分,交集部分,差集部分\r\n\r\n//求 ab 和 cd 的并集部分\r\nfunction UnionRange(a: number, b: number, c: number, d: number, end: number): [number, number][]\r\n{\r\n let b1 = b < a ? b + end : b;\r\n let d1 = d < c ? d + end : d;\r\n let a1 = a;\r\n let c1 = c;\r\n\r\n if (c < a)\r\n [a1, b1, c1, d1] = [c1, d1, a1, b1];\r\n\r\n if (c1 > b1)\r\n return [[a, b], [c, d]];\r\n\r\n let e = Math.max(b1, d1);\r\n if (e >= end)\r\n {\r\n e -= end;\r\n if (e > a1)\r\n return [[0, end]];\r\n }\r\n\r\n return [[a1, e]];\r\n}\r\n\r\n// //0-1\r\n// UnionRange(0.5, 0.3, 0.3, 0.5, 1);//?\r\n\r\n// //0-1\r\n// UnionRange(0.4, 0.3, 0.3, 0.5, 1);//?\r\n\r\n// //[ [ 0.8, 0.1 ], [ 0.3, 0.5 ] ]\r\n// UnionRange(0.8, 0.1, 0.3, 0.5, 1);//?\r\n\r\n// //[ 0.3, 0.10000000000000009 ] ] \r\n// UnionRange(0.8, 0.1, 0.3, 0.9, 1);//?\r\n\r\nfunction SubtractRange(a: number, b: number, c: number, d: number, end: number): Range[]\r\n{\r\n if (a < 0 || b < 0) return [];\r\n\r\n if (a > b)\r\n return [...SubtractRange(a, end, c, d, end), ...SubtractRange(0, b, c, d, end)];\r\n if (c > d)\r\n {\r\n let arr = SubtractRange(a, b, c, end, end);\r\n let rem: [number, number][] = [];\r\n for (let s of arr)\r\n rem.push(...SubtractRange(s[0], s[1], 0, d, end));\r\n return rem;\r\n }\r\n\r\n if (c >= b || d <= a)\r\n return [[a, b]];\r\n\r\n if (c <= a)// c1 a1 b1\r\n {\r\n if (d >= b) return [];\r\n return [[d, b]];\r\n }\r\n\r\n if (d < b)\r\n return [[a, c], [d, b]];\r\n return [[a, c]];\r\n}\r\n\r\nfunction SubtractRange2(r: Range, sr: Range, end: number): Range[]\r\n{\r\n return SubtractRange(r[0], r[1], sr[0], sr[1], end);\r\n}\r\n\r\ntype Range = [number, number];\r\nfunction SubtractRanges(ranges: Range[], subRanges: Range[], end: number): Range[]\r\n{\r\n let rets: Range[] = ranges;\r\n for (let sr of subRanges)\r\n {\r\n let temps: Range[] = [];\r\n for (let r of rets)\r\n temps.push(...SubtractRange2(r, sr, end));\r\n\r\n rets = temps;\r\n }\r\n return rets;\r\n}\r\n\r\nfunction IntersectRange(a: number, b: number, c: number, d: number, end: number): Range\r\n{\r\n let b1 = b < a ? b + end : b;\r\n let d1 = d < c ? d + end : d;\r\n let a1 = a;\r\n let c1 = c;\r\n\r\n if (c < a)\r\n [a1, b1, c1, d1] = [c1, d1, a1, b1];\r\n\r\n if (c1 > b1)\r\n return;\r\n\r\n return [c1, Math.min(b1, d1)];\r\n}\r\n\r\nconst alMatrix4 = new Matrix4;\r\n\r\nexport class ExtrudeGeometryBuilder\r\n{\r\n verticesArray: number[] = [];//用于构建三维网格\r\n uvArray: number[] = [];//uv\r\n\r\n edgeAndLidBuilder: EdgeGeometryBuild;\r\n\r\n constructor(private br: ExtrudeSolid)\r\n {\r\n this.edgeAndLidBuilder = new EdgeGeometryBuild(this.br.Thickness);\r\n let rotateUv = (br instanceof Board && br.BoardProcessOption.lines === LinesType.Reverse);\r\n //计算墙(创建轮廓取出,为了得到正确的轮廓曲线(逆时针之类的))\r\n let outerWall = new ExtudeWall(Contour.CreateContour(br.ContourCurve.Clone()).Curve, DepthType.All, br.Thickness, br.Thickness, DirectionType.Outer);\r\n let grooves = this.ParseGrooves();\r\n for (let i = 0; i < grooves.length; i++)\r\n {\r\n let s1 = grooves[i];\r\n outerWall.ClipTo(s1, false);\r\n s1.contourWall.ClipReverse(outerWall);\r\n for (let j = i + 1; j < grooves.length; j++)\r\n {\r\n let s2 = grooves[j];\r\n s1.ClipTo(s2, true);\r\n }\r\n\r\n s1.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder, rotateUv);\r\n }\r\n outerWall.Draw(this.verticesArray, this.uvArray, this.edgeAndLidBuilder);\r\n\r\n //这里构建盖子\r\n this.edgeAndLidBuilder.BuildLid(this.verticesArray, this.uvArray, rotateUv);\r\n\r\n intCache.clear();\r\n }\r\n\r\n get MeshGeometry()\r\n {\r\n let geo = new BufferGeometry();\r\n geo.setAttribute('position', new Float32BufferAttribute(this.verticesArray, 3));\r\n geo.setAttribute('uv', new Float32BufferAttribute(this.uvArray, 2));\r\n geo.computeVertexNormals();\r\n return geo;\r\n }\r\n\r\n get EdgeGeometry()\r\n {\r\n let geo = new BufferGeometry();\r\n geo.setAttribute('position', new Float32BufferAttribute(this.edgeAndLidBuilder.lineVerticesArray, 3));\r\n return geo;\r\n }\r\n\r\n private ParseGrooves()\r\n {\r\n let br = this.br;\r\n const brOcsInv = br.OCSInv;\r\n let grooves: Groove[] = [];\r\n for (let groove of br.Grooves)\r\n {\r\n //判断槽正反面\r\n let type: DepthType;\r\n if (equaln(groove.Thickness, br.Thickness))\r\n type = DepthType.All;\r\n else\r\n {\r\n if (equaln(groove.Position.applyMatrix4(brOcsInv).z, 0))\r\n type = DepthType.Back;\r\n else\r\n type = DepthType.Front;\r\n }\r\n alMatrix4.multiplyMatrices(brOcsInv, groove.OCSNoClone);\r\n //槽轮廓\r\n let grooveContourCurve = groove.ContourCurve.Clone();\r\n grooveContourCurve.ApplyMatrix(alMatrix4);\r\n grooveContourCurve.Z0();\r\n if (grooveContourCurve instanceof Polyline) grooveContourCurve.UpdateMatrixTo(IdentityMtx4);//不可能改变这个\r\n let grooveContour = Contour.CreateContour(grooveContourCurve);\r\n\r\n let grooveHoleContours: Contour[] = [];\r\n //孤岛\r\n for (let grooveChild of groove.Grooves)\r\n {\r\n let grooveChildContourCurve = grooveChild.ContourCurve.Clone();\r\n alMatrix4.multiplyMatrices(brOcsInv, grooveChild.OCSNoClone);\r\n grooveChildContourCurve.ApplyMatrix(alMatrix4).Z0();\r\n if (grooveChildContourCurve instanceof Polyline) grooveChildContourCurve.UpdateMatrixTo(IdentityMtx4);\r\n let grooveChildContour = Contour.CreateContour(grooveChildContourCurve);\r\n grooveHoleContours.push(grooveChildContour);\r\n }\r\n\r\n grooves.push(new Groove(grooveContour, grooveHoleContours, type, groove.Thickness, br.Thickness));\r\n }\r\n\r\n return grooves;\r\n }\r\n}\r\n\r\nlet intCache = new Map>();\r\nfunction GetIntersection(cu1: Curve, cu2: Curve): IntersectResult[]\r\n{\r\n let m = intCache.get(cu1);\r\n if (m)\r\n {\r\n let r = m.get(cu2);\r\n if (r) return r;\r\n }\r\n else\r\n m = new Map();\r\n\r\n intCache.set(cu1, m);\r\n let r = cu1.IntersectWith2(cu2, IntersectOption.OnBothOperands);\r\n\r\n let cu1EndParam = cu1.EndParam;\r\n let cu2EndParam = cu2.EndParam;\r\n for (let d of r)\r\n {\r\n d.thisParam = MathUtils.clamp(d.thisParam, 0, cu1EndParam);\r\n d.argParam = MathUtils.clamp(d.argParam, 0, cu2EndParam);\r\n }\r\n\r\n m.set(cu2, r);\r\n\r\n let r2: IntersectResult[] = r.map(r =>\r\n {\r\n return { thisParam: r.argParam, argParam: r.thisParam, pt: r.pt };\r\n });\r\n\r\n let m2 = intCache.get(cu2);\r\n if (!m2)\r\n {\r\n m2 = new Map();\r\n intCache.set(cu2, m2);\r\n }\r\n m2.set(cu1, r2);\r\n\r\n return r;\r\n}\r\n","import { Vector3, Matrix4 } from 'three';\r\n\r\n// Quote from:\r\n// https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js\r\n// 即obb.js(本项目中已存在)\r\n\r\n// Reference material:\r\n//https://stackoverflow.com/questions/28499800/oriented-box-intersection-in-threejs\r\n//http://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html\r\n//https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js\r\n\r\nexport class OBB\r\n{\r\n _EPSILON = 1e-3;\r\n\r\n public center: Vector3;\r\n\r\n constructor(public ocs: Matrix4, public halfSizes: Vector3)\r\n {\r\n this.center = halfSizes.clone().applyMatrix4(ocs);\r\n }\r\n\r\n intersectsOBB(obb: OBB, is2D?: boolean, ucsInv?: Matrix4): boolean\r\n {\r\n let newCenter: Vector3;\r\n let newObbCenter: Vector3;\r\n let cs: Matrix4;\r\n let obbcs: Matrix4;\r\n if (is2D)\r\n {\r\n let mtx1 = new Matrix4().multiplyMatrices(ucsInv, this.ocs);\r\n let mtx2 = new Matrix4().multiplyMatrices(ucsInv, obb.ocs);\r\n cs = mtx1;\r\n obbcs = mtx2;\r\n cs.elements[14] = 0;\r\n obbcs.elements[14] = 0;\r\n newCenter = this.halfSizes.clone().applyMatrix4(cs);\r\n newObbCenter = obb.halfSizes.clone().applyMatrix4(obbcs);\r\n }\r\n let xAxisA = new Vector3();\r\n let yAxisA = new Vector3();\r\n let zAxisA = new Vector3();\r\n\r\n let xAxisB = new Vector3();\r\n let yAxisB = new Vector3();\r\n let zAxisB = new Vector3();\r\n\r\n let translation = new Vector3();\r\n\r\n let vector = new Vector3();\r\n\r\n let axisA: Vector3[] = [];\r\n let axisB: Vector3[] = [];\r\n let rotationMatrix = [[], [], []];\r\n let rotationMatrixAbs = [[], [], []];\r\n\r\n let halfSizeA: number, halfSizeB: number;\r\n let t: number, i: number;\r\n\r\n // extract each axis\r\n (cs ?? this.ocs).extractBasis(xAxisA, yAxisA, zAxisA);\r\n (obbcs ?? obb.ocs).extractBasis(xAxisB, yAxisB, zAxisB);\r\n\r\n // push basis vectors into arrays, so you can access them via indices\r\n axisA.push(xAxisA, yAxisA, zAxisA);\r\n axisB.push(xAxisB, yAxisB, zAxisB);\r\n\r\n // get displacement vector\r\n vector.subVectors(newObbCenter ?? obb.center, newCenter ?? this.center);\r\n\r\n // express the translation vector in the coordinate frame of the current\r\n // OBB (this)\r\n for (i = 0; i < 3; i++)\r\n {\r\n translation.setComponent(i, vector.dot(axisA[i]));\r\n }\r\n\r\n // generate a rotation matrix that transforms from world space to the\r\n // OBB's coordinate space\r\n for (i = 0; i < 3; i++)\r\n {\r\n for (let j = 0; j < 3; j++)\r\n {\r\n rotationMatrix[i][j] = axisA[i].dot(axisB[j]);\r\n rotationMatrixAbs[i][j] = Math.abs(rotationMatrix[i][j]) + this._EPSILON;\r\n }\r\n }\r\n\r\n // test the three major axes of this OBB\r\n for (i = 0; i < 3; i++)\r\n {\r\n vector.set(rotationMatrixAbs[i][0], rotationMatrixAbs[i][1], rotationMatrixAbs[i][2]);\r\n\r\n halfSizeA = this.halfSizes.getComponent(i);\r\n halfSizeB = obb.halfSizes.dot(vector);\r\n\r\n if (Math.abs(translation.getComponent(i)) > halfSizeA + halfSizeB)\r\n {\r\n return false;\r\n }\r\n }\r\n\r\n // test the three major axes of other OBB\r\n for (i = 0; i < 3; i++)\r\n {\r\n vector.set(rotationMatrixAbs[0][i], rotationMatrixAbs[1][i], rotationMatrixAbs[2][i]);\r\n\r\n halfSizeA = this.halfSizes.dot(vector);\r\n halfSizeB = obb.halfSizes.getComponent(i);\r\n\r\n vector.set(rotationMatrix[0][i], rotationMatrix[1][i], rotationMatrix[2][i]);\r\n t = translation.dot(vector);\r\n\r\n if (Math.abs(t) > halfSizeA + halfSizeB)\r\n {\r\n return false;\r\n }\r\n }\r\n\r\n // test the 9 different cross-axes\r\n\r\n // A.x B.x\r\n halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][0] + this.halfSizes.z * rotationMatrixAbs[1][0];\r\n halfSizeB = obb.halfSizes.y * rotationMatrixAbs[0][2] + obb.halfSizes.z * rotationMatrixAbs[0][1];\r\n\r\n t = translation.z * rotationMatrix[1][0] - translation.y * rotationMatrix[2][0];\r\n\r\n if (Math.abs(t) > halfSizeA + halfSizeB)\r\n {\r\n return false;\r\n }\r\n\r\n // A.x < cross> B.y\r\n halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][1] + this.halfSizes.z * rotationMatrixAbs[1][1];\r\n halfSizeB = obb.halfSizes.x * rotationMatrixAbs[0][2] + obb.halfSizes.z * rotationMatrixAbs[0][0];\r\n\r\n t = translation.z * rotationMatrix[1][1] - translation.y * rotationMatrix[2][1];\r\n\r\n if (Math.abs(t) > halfSizeA + halfSizeB)\r\n {\r\n return false;\r\n }\r\n\r\n // A.x