!463 模块设计器

pull/463/MERGE
ZoeLeeFZ 5 years ago committed by ChenX
parent f26b2028d3
commit 75495b4503

@ -53,8 +53,6 @@ export class Command_Extend implements Command
if (exSs.Status !== PromptStatus.OK)
break;
if (exSs.SelectSet.SelectEntityList.length === 0)
break;
this.Extend(exSs.SelectSet, exRefCus, false);
}
}

@ -304,18 +304,32 @@ export class FilletUtils
else//经过起点
{
let sp = AsVector2(fres.arc.EndPoint.applyMatrix4(pln.OCSInv));
let keepF1 = 0;
if (parF2 + 1 <= pln.LineData.length)
pln.AddVertexAt(parF2 + 1, sp)
{
if (parF1 === 0 || pln.GetBuilgeAt(parF1 - 1) == 0)
pln.AddVertexAt(parF2 + 1, sp);
else
{
pln.SetPointAt(parF1 - 1, sp);
keepF1 = -1;//保留圆弧位
}
}
else
pln.SetPointAt(parF2 + 1, sp);
pln.SetBulgeAt(parF2 + 1, -fres.arc.Bul);
if (keepF1 === 0)
pln.SetBulgeAt(parF2 + 1, -fres.arc.Bul);
else
pln.SetBulgeAt(parF1 - 1, -fres.arc.Bul);
let ep = AsVector2(fres.cu1.StartPoint.applyMatrix4(pln.OCSInv));
pln.SetPointAt(parF1, ep);
pln.CloseMark = true;
pln.LineData.splice(parF2 + 2);
pln.LineData.splice(0, parF1);
pln.LineData.splice(parF2 + 2 + keepF1);
pln.LineData.splice(0, parF1 + keepF1);
pln.Update();
return { cu1: pln };
}

@ -0,0 +1,31 @@
import { app } from "../../ApplicationServices/Application";
import { Board } from "../../DatabaseServices/Entity/Board";
import { InitTemplate } from "../../DatabaseServices/Template/TempateUtils";
import { Command } from "../../Editor/CommandMachine";
import { PromptStatus } from "../../Editor/PromptResult";
import { ModalPosition } from "../../UI/Components/Modal/ModalsManage";
import { TemplateEditor } from "../../UI/Components/Template/TemplateEditor";
import { TempalteEditorStore } from "../../UI/Store/TemplateEditorStore";
export class ShowTemplateDesign implements Command
{
async exec()
{
let enRes = await app.Editor.GetSelection({
Msg: "请选择构建模块的板件",
Filter: { filterTypes: [Board] }
});
if (enRes.Status !== PromptStatus.OK)
return;
let brs = enRes.SelectSet.SelectEntityList as Board[];
let template = await InitTemplate(brs);
if (!template) return;
let store = TempalteEditorStore.GetInstance() as TempalteEditorStore;
template.Name = "模板";
store.Template = template;
store.InitParams();
app.Editor.ModalManage.RenderModeless(TemplateEditor, ModalPosition.Center, { store });
}
}

@ -13,7 +13,8 @@ export enum InputState
Entsel = 16,
GetKeyWord = 32,
GetRect = 64,
All = ~(~0 << 7)
GetString = 128,
All = ~(~0 << 8)
}

@ -330,4 +330,5 @@ export enum StoreageKeys
UserName = "userName",
RenderType = "renderType",
ExactDrill = "openExactDrill",
ConfigName = "configName_",
}

@ -25,7 +25,7 @@ export function StretchParse(ss: SelectSet): StretchData
}
else if (set instanceof SelectBox)
{
if (set.m_SelectType == SelectType.W)
if (set.m_SelectType === SelectType.W)
{
for (let en of set.SelectEntityList)
data.moveEntityList.push(en);

@ -54,7 +54,7 @@ export function FixIndex(index: number, arr: Array<any> | number)
{
let count = (arr instanceof Array) ? arr.length : arr;
if (index < 0)
return count - 1;
return count + index;
else if (index >= count)
return index - count;
else
@ -155,6 +155,7 @@ export function FixedNotZero(v: number | string, fractionDigits: number = 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(".");

@ -1,4 +1,4 @@
import { Box3, BufferGeometry, EllipseCurve, Material, Matrix3, Matrix4, Object3D, Shape, Vector3, Line as TLine } from 'three';
import { Box3, BufferGeometry, EllipseCurve, Line as TLine, Material, Matrix3, Matrix4, Object3D, Shape, Vector3 } from 'three';
import { arrayLast, arrayRemoveDuplicateBySort } from '../../Common/ArrayExt';
import { ColorMaterial } from '../../Common/ColorPalette';
import { getArcOrCirNearPts, GetTanPtsOnArcOrCircle } from '../../Common/CurveUtils';
@ -6,16 +6,17 @@ import { reviseMirrorMatrix } from '../../Common/Matrix4Utils';
import { clamp } from '../../Common/Utils';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';
import { angle, equaln, MoveMatrix, polar, AsVector3 } from '../../Geometry/GeUtils';
import { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption, IntersectEllipseAndCircleOrArc } from '../../GraphicsSystem/IntersectWith';
import { angle, AsVector3, equaln, MoveMatrix, polar } from '../../Geometry/GeUtils';
import { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectEllipseAndCircleOrArc, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../../GraphicsSystem/IntersectWith';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { Arc } from './Arc';
import { Factory } from '../CADFactory';
import { CADFiler } from '../CADFiler';
import { Arc } from './Arc';
import { Curve } from './Curve';
import { DragPointType } from './DragPointType';
import { Ellipse } from './Ellipse';
import { Line } from './Line';
import { Polyline } from './Polyline';
import { Ellipse } from './Ellipse';
let circleGeometry: BufferGeometry;
function GetCircleGeometry()
@ -249,6 +250,14 @@ export class Circle extends Curve
m.material = material ? material : ColorMaterial.GetLineMaterial(this._Color);
}
GetDragPointCount(drag: DragPointType): number
{
if (drag === DragPointType.Grip)
return 5;
else
return 1;
}
GetGripPoints(): Array<Vector3>
{
let pts = [
@ -263,6 +272,7 @@ export class Circle extends Curve
pts.forEach(p => p.applyMatrix4(ocs));
return pts;
}
GetObjectSnapPoints(
snapMode: ObjectSnapMode,
pickPoint: Vector3,

@ -1,11 +1,12 @@
import { Line, Object3D, Shape, Vector3, Material } from 'three';
import { Line, Material, Object3D, Shape, Vector3 } from 'three';
import { arrayRemoveDuplicateBySort, arraySortByNumber } from '../../Common/ArrayExt';
import { ColorMaterial } from '../../Common/ColorPalette';
import { Status } from '../../Common/Status';
import { equaln, equalv3 } from '../../Geometry/GeUtils';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { IntersectOption } from '../../GraphicsSystem/IntersectWith';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { Factory } from '../CADFactory';
import { DragPointType } from './DragPointType';
import { Entity } from './Entity';
export enum ExtendType
@ -153,6 +154,11 @@ export abstract class Curve extends Entity
*/
IntersectWith(curve: Curve, intType: IntersectOption, tolerance = 1e-6): Vector3[] { return []; }
/**
*
*/
GetDragPointCount(drag: DragPointType): number { return 0; }
//------------------绘制相关------------------
//重载
protected OnlyRenderType = true;

@ -0,0 +1,5 @@
export enum DragPointType
{
Grip = 0,
Stretch = 1
}

@ -24,6 +24,7 @@ import { Contour } from "../Contour";
import { Shape } from "../Shape";
import { ShapeManager } from "../ShapeManager";
import { Circle } from "./Circle";
import { DragPointType } from "./DragPointType";
import { Entity } from "./Entity";
import { Polyline } from "./Polyline";
import { Region } from "./Region";
@ -31,12 +32,6 @@ import { Region } from "./Region";
export type ExtureContourCurve = Polyline | Circle;
export type ExtureContour = Polyline | Circle | ExtrudeSolid | Region;
enum DragPointType
{
Grip = 0,
Stretch = 1,
}
@Factory
export class ExtrudeSolid extends Entity
{
@ -150,7 +145,6 @@ export class ExtrudeSolid extends Entity
Clone()
{
let en = super.Clone();
en.strectchPointCountList = this.strectchPointCountList;
return en;
}
@ -449,16 +443,12 @@ export class ExtrudeSolid extends Entity
//#region Stretch
/**
* ,
*/
private strectchPointCountList: number[];
private GetStrectchPointCountList(dragType: DragPointType)
private GetStrectchPointCountList(dragType: DragPointType): number[]
{
if (!this.strectchPointCountList)
this.GetGripOrStretchPoints(dragType);
return this.strectchPointCountList;
let counts: number[] = [this.ContourCurve.GetDragPointCount(dragType) * 2];
for (let g of this.grooves)
counts.push(g.ContourCurve.GetDragPointCount(dragType) * 2);
return counts;
}
GetGripOrStretchPoints(dragType: DragPointType)
{
@ -469,12 +459,9 @@ export class ExtrudeSolid extends Entity
pts.push(...pts.map(p => p.clone().add(v)));
pts.forEach(p => { p.applyMatrix4(this.OCS) });
this.strectchPointCountList = [pts.length];
for (let g of this.grooves)
{
let gpts = g.GetGripOrStretchPoints(dragType);
this.strectchPointCountList.push(gpts.length);
pts.push(...gpts);
}
return pts;
@ -560,14 +547,7 @@ export class ExtrudeSolid extends Entity
*/
MoveGripOrStretchPointsOnly(indexList: Array<number>, vec: Vector3, dragType: DragPointType)
{
let stretchCount =
this.strectchPointCountList
? this.strectchPointCountList[0] / 2
: (
dragType === DragPointType.Grip
? this.ContourCurve.GetGripPoints()
: this.ContourCurve.GetStretchPoints()
).length;
let stretchCount = this.ContourCurve.GetDragPointCount(dragType);
if (dragType === DragPointType.Stretch)
{

@ -1,23 +1,24 @@
import { Box3, BufferGeometry, Matrix4, Object3D, Vector2, Vector3, Matrix3, Line as TLine } from 'three';
import { Box3, BufferGeometry, Line as TLine, Matrix3, Matrix4, Object3D, Vector2, Vector3 } from 'three';
import { CreateBoardUtil } from '../../ApplicationServices/mesh/createBoard';
import { arrayLast, arrayRemoveDuplicateBySort, changeArrayStartIndex } from '../../Common/ArrayExt';
import { ColorMaterial } from '../../Common/ColorPalette';
import { getDeterminantFor2V } from '../../Common/CurveUtils';
import { matrixAlignCoordSys, reviseMirrorMatrix, matrixIsCoplane } from '../../Common/Matrix4Utils';
import { matrixAlignCoordSys, matrixIsCoplane, reviseMirrorMatrix } from '../../Common/Matrix4Utils';
import { Status } from '../../Common/Status';
import { FixIndex } from '../../Common/Utils';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';
import { equaln, equalv2, equalv3, updateGeometry, AsVector3, AsVector2 } from '../../Geometry/GeUtils';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { AsVector2, AsVector3, equaln, equalv2, equalv3, updateGeometry } from '../../Geometry/GeUtils';
import { IntersectOption, IntersectPolylineAndCurve } from '../../GraphicsSystem/IntersectWith';
import { PolyOffsetUtil } from '../../GraphicsSystem/OffsetPolyline';
import { Arc } from './Arc';
import { RenderType } from '../../GraphicsSystem/RenderType';
import { Factory } from '../CADFactory';
import { CADFiler } from '../CADFiler';
import { IsPointInPolyLine } from '../PointInPolyline';
import { Arc } from './Arc';
import { Curve, ExtendType } from './Curve';
import { DragPointType } from './DragPointType';
import { Line } from './Line';
import { IsPointInPolyLine } from '../PointInPolyline';
export interface PolylineProps
{
@ -1140,6 +1141,21 @@ export class Polyline extends Curve
updateGeometry(plObj, BufferGeometryUtils.CreateFromPts(pts));
}
}
GetDragPointCount(drag: DragPointType): number
{
if (drag === DragPointType.Grip)
{
let count = this.EndParam * 2 + 1;
if (this.CloseMark) count--;
return count;
}
else
{
return this.m_LineData.length;
}
}
GetObjectSnapPoints(
snapMode: ObjectSnapMode,
pickPoint: Vector3,

@ -0,0 +1,94 @@
import { Factory } from "../../CADFactory";
import { Board } from "../../Entity/Board";
import { TemplateAction } from "./TemplateAction";
import { CADFiler } from "../../CADFiler";
import { ObjectId } from "../../ObjectId";
export enum ThicknessDirection
{
Center = 0,
Back = 1,
Front = 2,
}
export interface ThicknessActionData
{
//方向
Direction: ThicknessDirection;
/**
*
*/
Actions: TemplateAction[];
}
/**
*
*/
@Factory
export class TempateThicknessAction extends TemplateAction
{
//正 true 反 false
EntityDirectionMap: Map<ObjectId, ThicknessActionData> = new Map();
protected _Update(paramDiff: number, newValue: number)
{
for (let [id, d] of this.EntityDirectionMap)
{
if (id.IsErase) continue;
let br = id.Object as Board;
br.Thickness += paramDiff;
if (d.Direction === ThicknessDirection.Back)
br.Position = br.Position.sub(br.Normal.multiplyScalar(paramDiff));
else if (d.Direction === ThicknessDirection.Center)
br.Position = br.Position.sub(br.Normal.multiplyScalar(paramDiff * 0.5));
for (let a of d.Actions)
{
a.parent = this.parent;
a.Update(paramDiff, newValue);
}
}
}
//#region -------------------------File-------------------------
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
//对象从文件中读取数据,初始化自身
ReadFile(file: CADFiler)
{
let ver = file.Read();
super.ReadFile(file);
let count = file.Read() as number;
this.EntityDirectionMap.clear();
for (let i = 0; i < count; i++)
{
let id = file.ReadObjectId();
let direction = file.Read() as ThicknessDirection;
let actionsCount = file.Read() as number;
let actions: TemplateAction[] = [];
for (let j = 0; j < actionsCount; j++)
{
actions.push(file.ReadObject() as TemplateAction);
}
this.EntityDirectionMap.set(id, { Direction: direction, Actions: actions });
}
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(1);
super.WriteFile(file);
file.Write(this.EntityDirectionMap.size);
for (let [id, d] of this.EntityDirectionMap)
{
file.WriteObjectId(id);
file.Write(d.Direction);
file.Write(d.Actions.length);
for (let a of d.Actions)
file.WriteObject(a);
}
}
}

@ -1,7 +1,8 @@
import { safeEval } from "../../../Common/eval";
import { AutoRecord } from "../../AutoRecord";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { TemplateParam } from "../Param/TemplateParam";
import { AutoRecord } from "../../AutoRecord";
/**
*
@ -9,7 +10,10 @@ import { AutoRecord } from "../../AutoRecord";
@Factory
export class TemplateAction
{
@AutoRecord Name: string;
@AutoRecord Name: string = "动作";
/** 表达式应该只能依赖自身 */
@AutoRecord Expr: string;
@AutoRecord Description: string;
parent: TemplateParam;
WriteAllObjectRecord()
{
@ -18,20 +22,47 @@ export class TemplateAction
}
Update(paramDiff: number | string, newValue: number | string)
{
if (this.Expr)
{
let varDefines = {};
varDefines[this.parent.name] = newValue;
newValue = safeEval(this.Expr, varDefines) || newValue;
varDefines[this.parent.name] = paramDiff;
paramDiff = safeEval(this.Expr, varDefines) || paramDiff;
}
this._Update(paramDiff, newValue);
}
/**
* @
*/
protected _Update(paramDiff: number | string, newValue: number | string)
{
}
//#region -------------------------File-------------------------
//对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化
//对象从文件中读取数据,初始化自身
ReadFile(file: CADFiler)
{
let ver = file.Read();
if (ver > 1)
this.Name = file.Read();
this.Name = file.Read();
if (ver > 2)
{
this.Expr = file.Read();
this.Description = file.Read();
}
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(2);
file.Write(3);
file.Write(this.Name);
file.Write(this.Expr);
file.Write(this.Description);
}
}

@ -1,46 +1,61 @@
import { FilletUtils } from "../../../Add-on/FilletUtils";
import { FixIndex } from "../../../Common/Utils";
import { PromptEntityResult } from "../../../Editor/PromptResult";
import { Factory } from "../../CADFactory";
import { TemplateAction } from "./TemplateAction";
import { CADFiler } from "../../CADFiler";
import { ObjectId } from "../../ObjectId";
import { Board } from "../../Entity/Board";
import { FilletUtils } from "../../../Add-on/FilletUtils";
import { PromptEntityResult } from "../../../Editor/PromptResult";
import { Polyline } from "../../Entity/Polyline";
import { Circle } from "../../Entity/Circle";
import { ExtureContourCurve } from "../../Entity/Extrude";
import { Polyline } from "../../Entity/Polyline";
import { ObjectId } from "../../ObjectId";
import { TemplateAction } from "./TemplateAction";
@Factory
export class TemplateFilletAction extends TemplateAction
{
constructor(protected _FilletEntity?: ObjectId,
protected _CurveParam1?: number,
protected _CurveParam2?: number
)
FilletDatas: { Entity: ObjectId, ArcParams: number[] }[] = [];
constructor()
{
super();
}
Update(paramDiff: number | string, newValue: number | string)
protected _Update(paramDiff: number, newValue: number)
{
if (this._FilletEntity.IsErase) return;
for (let d of this.FilletDatas)
{
if (d.Entity.IsErase)
continue;
let br = d.Entity.Object as Board;
let cu = br.ContourCurve;
if (cu instanceof Circle)
return;
let br = this._FilletEntity.Object as Board;
let cu = br.ContourCurve;
if (cu instanceof Circle)
return;
let fillet = new FilletUtils();
fillet.FilletRadius = Math.max(newValue, 0.1);
let fillet = new FilletUtils();
fillet.FilletRadius = newValue as number;
let cuOld = cu as Polyline;
for (let arcParam of d.ArcParams)
{
let param1 = FixIndex(arcParam - 1, cu.EndParam);
let param2 = FixIndex(arcParam + 1, cu.EndParam);
let p1 = cu.GetPointAtParam(param1);
let p2 = cu.GetPointAtParam(param2);
let p1 = cu.GetPointAtParam(this._CurveParam1);
let p2 = cu.GetPointAtParam(this._CurveParam2);
let res1 = new PromptEntityResult(cu, p1);
let res2 = new PromptEntityResult(cu, p2);
let res1 = new PromptEntityResult(cu, p1);
let res2 = new PromptEntityResult(cu, p2);
let fres = fillet.FilletPolyLineSelf(res1, res2);
if (fres)
cu = fres.cu1 as ExtureContourCurve;
}
let fres = fillet.FilletPolyLineSelf(res1, res2);
if (fres)
br.ContourCurve = fres.cu1 as Polyline;
if (cu !== cuOld)
br.ContourCurve = cu;
}
}
//#region -------------------------File-------------------------
@ -49,16 +64,44 @@ export class TemplateFilletAction extends TemplateAction
ReadFile(file: CADFiler)
{
let ver = file.Read();
this._FilletEntity = file.ReadObjectId();
this._CurveParam1 = file.Read();
this._CurveParam2 = file.Read();
super.ReadFile(file);
this.FilletDatas.length = 0;
if (ver === 1)
{
let id = file.ReadObjectId();
let param1 = file.Read();
let param2 = file.Read();
let arcParam: number = param2 !== 0 ? param2 - 1 : param1 + 1;
this.FilletDatas.push({ Entity: id, ArcParams: [arcParam] });
}
else
{
let count = file.Read();
for (let i = 0; i < count; i++)
{
let id = file.ReadObjectId();
let params: number[] = [];
let parCount = file.Read();
for (let i = 0; i < parCount; i++)
{
params.push(file.Read());
}
this.FilletDatas.push({ Entity: id, ArcParams: params });
}
}
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(1);
file.WriteObjectId(this._FilletEntity);
file.Write(this._CurveParam1);
file.Write(this._CurveParam2);
file.Write(2);
super.WriteFile(file);
file.Write(this.FilletDatas.length);
for (let d of this.FilletDatas)
{
file.WriteObjectId(d.Entity);
file.Write(d.ArcParams.length);
for (let param of d.ArcParams)
file.Write(param);
}
}
}

@ -1,5 +1,5 @@
import { Vector3 } from "three";
import { MoveMatrix } from "../../../Geometry/GeUtils";
import { MoveMatrix, ZeroVec } from "../../../Geometry/GeUtils";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { Entity } from "../../Entity/Entity";
@ -11,15 +11,19 @@ export class TemplateMoveAction extends TemplateAction
{
constructor(public StretchDirection = new Vector3,
public Entitys: ObjectId[] = []
public MoveEntitys: ObjectId[] = []
)
{
super();
}
Update(paramDiff: number)
protected _Update(paramDiff: number)
{
let moveMatrix = MoveMatrix(this.StretchDirection.clone().multiplyScalar(paramDiff));
for (let id of this.Entitys)
let v = this.StretchDirection.clone()
.applyMatrix4(this.parent.parent.GetTemplateSpaceCS().setPosition(ZeroVec))
.multiplyScalar(paramDiff);
let moveMatrix = MoveMatrix(v);
for (let id of this.MoveEntitys)
{
let ent = id.Object as Entity;
ent.ApplyMatrix(moveMatrix);
@ -31,21 +35,23 @@ export class TemplateMoveAction extends TemplateAction
ReadFile(file: CADFiler)
{
let ver = file.Read();
super.ReadFile(file);
this.StretchDirection.fromArray(file.Read());
this.Entitys.length = 0;
this.MoveEntitys.length = 0;
let count = file.Read();
for (let i = 0; i < count; i++)
{
this.Entitys.push(file.ReadObjectId());
this.MoveEntitys.push(file.ReadObjectId());
}
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(1);
super.WriteFile(file);
file.Write(this.StretchDirection.toArray());
file.Write(this.Entitys.length);
for (let ent of this.Entitys)
file.Write(this.MoveEntitys.length);
for (let ent of this.MoveEntitys)
file.WriteObjectId(ent);
}
}

@ -1,29 +1,28 @@
import { Vector3 } from "three";
import { arrayClone } from "../../../Common/ArrayExt";
import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { Entity } from "../../Entity/Entity";
import { ObjectId } from "../../ObjectId";
import { TemplateAction } from "./TemplateAction";
import { TemplateMoveAction } from "./TemplateMoveAction";
import { ZeroVec } from "../../../Geometry/GeUtils";
/**
* Stretch
*/
@Factory
export class TemplateStretchGripAction extends TemplateAction
export class TemplateStretchGripAction extends TemplateMoveAction
{
/**
* 2,, `this.WriteAllObjectRecord`;
* .
*/
StretchDirection: Vector3 = new Vector3();
EntityStretchPointMap: {
entity: ObjectId;
indexs: number[];
}[] = [];
Update(dist: number)
protected _Update(dist: number)
{
let v = this.StretchDirection.clone().multiplyScalar(dist);
super._Update(dist);
let v = this.StretchDirection.clone()
.applyMatrix4(this.parent.parent.GetTemplateSpaceCS().setPosition(ZeroVec))
.multiplyScalar(dist);
for (let { entity, indexs } of this.EntityStretchPointMap)
{
let ent = entity.Object as Entity;
@ -37,7 +36,6 @@ export class TemplateStretchGripAction extends TemplateAction
{
let ver = file.Read();
super.ReadFile(file);
this.StretchDirection.fromArray(file.Read());
this.EntityStretchPointMap.length = 0;
let count = file.Read() as number;
for (let i = 0; i < count; i++)
@ -52,7 +50,6 @@ export class TemplateStretchGripAction extends TemplateAction
{
file.Write(1);
super.WriteFile(file);
file.Write(this.StretchDirection.toArray());
file.Write(this.EntityStretchPointMap.length);
for (let d of this.EntityStretchPointMap)
{

@ -3,13 +3,14 @@ import { Factory } from "../../CADFactory";
import { CADFiler } from "../../CADFiler";
import { Entity } from "../../Entity/Entity";
import { ObjectId } from "../../ObjectId";
import { TemplateAction } from "./TemplateAction";
import { TemplateMoveAction } from "./TemplateMoveAction";
import { ZeroVec } from "../../../Geometry/GeUtils";
/**
*
*/
@Factory
export class TemplateStretchScaleBoxAction extends TemplateAction
export class TemplateStretchScaleBoxAction extends TemplateMoveAction
{
/**
* 2,, `this.WriteAllObjectRecord`;
@ -23,9 +24,13 @@ export class TemplateStretchScaleBoxAction extends TemplateAction
super();
}
Update(dist: number)
protected _Update(dist: number)
{
let v = this.StretchDirection.clone().multiplyScalar(dist);
super._Update(dist);
let v = this.StretchDirection.clone()
.applyMatrix4(this.parent.parent.GetTemplateSpaceCS().setPosition(ZeroVec))
.multiplyScalar(dist);
for (let { entity, scaleBox } of this.EntityStretchData)
{
let ent = entity.Object as Entity;
@ -54,7 +59,6 @@ export class TemplateStretchScaleBoxAction extends TemplateAction
{
let ver = file.Read();
super.ReadFile(file);
this.StretchDirection.fromArray(file.Read());
this.EntityStretchData.length = 0;
let count = file.Read() as number;
for (let i = 0; i < count; i++)
@ -70,7 +74,6 @@ export class TemplateStretchScaleBoxAction extends TemplateAction
{
file.Write(1);
super.WriteFile(file);
file.Write(this.StretchDirection.toArray());
file.Write(this.EntityStretchData.length);
for (let d of this.EntityStretchData)
{

@ -27,7 +27,7 @@ export class TemplateParam
@AutoRecord value: string | number;
@AutoRecord default: string | number;
@AutoRecord description: string;
@AutoRecord type: TemplateParamType;
@AutoRecord type: TemplateParamType = TemplateParamType.Float;
@AutoRecord min: number;
@AutoRecord max: number;
//可选值
@ -78,12 +78,12 @@ export class TemplateParam
let newV = value as number;
if (!equaln(oldV, newV))
{
this.WriteAllObjectRecord();
this.value = newV;
let diff = newV - oldV;
for (let a of this.actions)
a.Update(diff, newV);
this.WriteAllObjectRecord();
this.value = newV;
}
break;
case TemplateParamType.Int:

@ -40,9 +40,7 @@ export class PositioningClampSpace extends Positioning
await parse.Parse();
if (parse.ParseOK)
{
this.SpaceCS = parse.SpaceOCS;
let p = parse.SpaceBox.min.clone().applyMatrix4(this.SpaceCS);
this.SpaceCS.setPosition(p);
this.SpaceCS = parse.DrawCS;
this.SpaceSize = parse.Size;
}
else

@ -1,4 +1,25 @@
import { Intent } from "@blueprintjs/core";
import { Box3, Matrix4, Vector3 } from "three";
import { app } from "../../ApplicationServices/Application";
import { StretchParse } from "../../Common/StretchParse";
import { FixedNotZero, log } from "../../Common/Utils";
import { PromptStatus } from "../../Editor/PromptResult";
import { SelectBox } from "../../Editor/SelectBox";
import { SelectPick } from "../../Editor/SelectPick";
import { AxisSnapMode } from "../../Editor/SnapServices";
import { Box3Ext } from "../../Geometry/Box";
import { AsVector3, equaln, isParallelTo, isPerpendicularityTo, ZAxis, ZeroVec, XAxis } from "../../Geometry/GeUtils";
import { AppToaster } from "../../UI/Components/Toaster";
import { Board } from "../Entity/Board";
import { Polyline } from "../Entity/Polyline";
import { ObjectId } from "../ObjectId";
import { TempateThicknessAction, ThicknessActionData, ThicknessDirection } from "./Action/TempateThicknessAction";
import { TemplateAction } from "./Action/TemplateAction";
import { TemplateFilletAction } from "./Action/TemplateFilletAction";
import { TemplateMoveAction } from "./Action/TemplateMoveAction";
import { TemplateStretchGripAction } from "./Action/TemplateStretchGripAction";
import { TemplateStretchScaleBoxAction } from "./Action/TemplateStretchScaleBoxAction";
import { TemplateParam } from "./Param/TemplateParam";
import { TemplateRecord } from "./TemplateRecord";
/**
@ -23,3 +44,778 @@ export function GetDeepestTemplate(brs: Board[]): TemplateRecord | undefined
return deepestTemplate;
}
/**
*
*/
export function GetTempateSize(template: TemplateRecord): Vector3
{
return new Vector3(template.LParam.value as number, template.WParam.value as number, template.HParam.value as number);
}
export function GetTempateBoards(template: TemplateRecord): Board[]
{
let brs: Board[] = [];
for (let id of template.Objects)
{
if (!id.IsErase)
brs.push(id.Object as Board);
}
return brs;
}
/**
*
*
* , ()
* ,.
* ,.
*
* @param brs
* @returns
*/
export async function InitTemplate(brs: Board[]): Promise<TemplateRecord | undefined>
{
let templates: Set<TemplateRecord> = new Set();
for (let br of brs)
{
if (!br.Template)
templates.add(undefined);
else
{
let template = (br.Template.Object as TemplateRecord);
templates.add(template);
}
}
let templateSize: Vector3;
if (templates.size > 1)
{
let keyRes = await app.Editor.GetKeyWords({
Msg: "选择的实体存在多个模块内,是否忽略原先模块,创建新的模块?",
KeyWordList: [
{ key: "1", msg: "是" },
{ key: "2", msg: "否" },
],
Default: "1"
});
if (keyRes.StringResult !== "1")
return undefined;
templates.delete(undefined);
}
else // (templates.size === 1)//都在一个模块内或者都不在模块内
{
templates.delete(undefined);
if (templates.size === 1)//都在模块内
{
let keyRes = await app.Editor.GetKeyWords({
Msg: "编辑当前模块或者重新创建",
KeyWordList: [
{ key: "Y", msg: "创建新模块" },
{ key: "N", msg: "编辑当前模块" },
],
Default: "N"
});
if (keyRes.Status === PromptStatus.Cancel) return;
if (keyRes.StringResult === "N")
return [...templates][0];
}
}
let keyRes = await app.Editor.GetKeyWords({
Msg: "将选择实体移动到世界坐标系0点?",
KeyWordList: [
{ key: "1", msg: "是" },
{ key: "2", msg: "否" },
],
Default: "1"
});
if (keyRes.Status === PromptStatus.Cancel) return;
let box = new Box3();
for (let br of brs)
box.union(br.BoundingBox);
templateSize = box.max;
if (keyRes.StringResult === "1")
{
let m = new Matrix4().setPosition(box.min.negate());
for (let br of brs)
br.ApplyMatrix(m);
templateSize.add(box.min);
}
//清空旧模块信息(这里的代码能多余,因为模块中可能还有其他的板件没有被重新创建?)
for (let template of templates)
app.Database.TemplateTable.Remove(template);
//初始化模块
let template = new TemplateRecord().InitBaseParams();
let bhParam = new TemplateParam();
bhParam.value = 18;
bhParam.name = "BH";
bhParam.description = "板厚";
template.Params.push(bhParam);
if (templateSize)
{
template.LParam.value = templateSize.x;
template.WParam.value = templateSize.y;
template.HParam.value = templateSize.z;
}
app.Database.TemplateTable.Append(template);
let wcs = new Matrix4();
for (let br of brs)
{
template.Objects.push(br.Id);
br.SpaceOCS = wcs;
}
return template;
}
/**
* 使
*/
export function UpdateTemplateSizeOffBoards(template: TemplateRecord)
{
let box = new Box3();
let spaceCSInv: Matrix4;
for (let id of template.Objects)
{
if (id.IsErase) continue;
let br = id.Object as Board;
if (!spaceCSInv)
spaceCSInv = br.SpaceOCSInv;
let brbox = br.GetBoardBoxInMtx(spaceCSInv);
box.union(brbox);
}
let size = box.max;
let parmas = template.Params;
parmas[0].value = FixedNotZero(size.x, 2);
parmas[1].value = FixedNotZero(size.y, 2);
parmas[2].value = FixedNotZero(size.z, 2);
}
/**
*
*
* `UpdateTemplateSizeOffBoards`
*/
export async function SetTempateCoordinate(template: TemplateRecord)
{
let ptRes = await app.Editor.GetPoint({
Msg: "选择模板基点",
});
if (ptRes.Status !== PromptStatus.OK) return;
let basePt = ptRes.Point;
ptRes = await app.Editor.GetPoint({
Msg: "请选择X轴方向(空格使用世界坐标系方向):",
BasePoint: basePt,
AllowDrawRubberBand: true,
AllowNone: true,
});
if (ptRes.Status === PromptStatus.Cancel) return;
let spaceCS = new Matrix4();
if (ptRes.Status === PromptStatus.None)
{
spaceCS.setPosition(basePt);
}
else
{
let xVec = ptRes.Point.sub(basePt).normalize();
let yVec: Vector3;
let canAllowNone = isPerpendicularityTo(xVec, ZAxis);
while (true)
{
ptRes = await app.Editor.GetPoint({
Msg: canAllowNone ? "请选择Y轴方向(空格使用标准平面方向):" : "请选择Y轴方向:",
BasePoint: basePt,
AllowDrawRubberBand: true,
AllowNone: canAllowNone,
});
if (ptRes.Status === PromptStatus.Cancel)
return;
if (ptRes.Status === PromptStatus.None)
yVec = ZAxis.clone().cross(xVec);
else
yVec = ptRes.Point.sub(basePt).normalize();
if (!isPerpendicularityTo(xVec, yVec))
{
AppToaster.show({
message: "x轴和y轴必须垂直",
timeout: 2000,
intent: Intent.DANGER
});
}
else break;
}
let zVec = xVec.clone().cross(yVec);
spaceCS.makeBasis(xVec, yVec, zVec).setPosition(basePt);
}
for (let id of template.Objects)
{
if (!id.IsErase)
{
let br = id.Object as Board;
br.SpaceOCS = spaceCS;
}
}
}
/**
*
*
*
* ,,.
* @param template
* @param [useScaleBox=true] 使?`=false`使.
*/
export function InitTempateSizeActions(template: TemplateRecord, useScaleBox = true)
{
//清除原先的动作
template.LParam.actions.length = 0;
template.WParam.actions.length = 0;
template.HParam.actions.length = 0;
//模块信息
let scs = template.GetTemplateSpaceCS();
let scsInv = new Matrix4().getInverse(scs);
let size = GetTempateSize(template);
//拉伸盒子范围
let max = size.clone().addScalar(1);
let backBox = new Box3Ext(new Vector3(-1, size.y / 2, -1), max);
let rightBox = new Box3Ext(new Vector3(size.x / 2, -1, -1), max);
let topBox = new Box3Ext(new Vector3(-1, -1, size.z / 2), max);
//板件列表
let brs = GetTempateBoards(template);
//动作列表
let ActionType = useScaleBox ? TemplateStretchScaleBoxAction : TemplateStretchGripAction;
let lAction = new ActionType(new Vector3(1, 0, 0));
let wAction = new ActionType(new Vector3(0, 1, 0));
let hAction = new ActionType(new Vector3(0, 0, 1));
for (let br of brs)
{
let sps = br.GetStretchPoints();
let boxContainsIndexMap = [
{ box: rightBox, indexs: [], action: lAction },
{ box: backBox, indexs: [], action: wAction },
{ box: topBox, indexs: [], action: hAction }
];
for (let i = 0; i < sps.length; i++)
{
const p = sps[i].applyMatrix4(scsInv);
for (let d of boxContainsIndexMap)
{
if (d.box.containsPoint(p))
d.indexs.push(i);
}
}
let spaceToLocalMtx: Matrix4;
if (useScaleBox)
spaceToLocalMtx = br.OCSInv.multiply(scs);
for (let d of boxContainsIndexMap)
{
if (d.indexs.length === 0)
continue;
if (d.indexs.length === sps.length || br.IsStretchThickness(d.indexs))
d.action.MoveEntitys.push(br.Id);
else
{
if (useScaleBox)
{
let scaleBox = d.box.clone().applyMatrix4(spaceToLocalMtx);
let size = new Vector3(br.Width, br.Height, br.Thickness);
scaleBox.min.divide(size);
scaleBox.max.divide(size);
let action = d.action as TemplateStretchScaleBoxAction;
action.EntityStretchData.push({ entity: br.Id, scaleBox });
}
else
{
let action = d.action as TemplateStretchGripAction;
action.EntityStretchPointMap.push({ entity: br.Id, indexs: d.indexs });
}
}
}
}
template.LParam.actions.push(lAction);
template.WParam.actions.push(wAction);
template.HParam.actions.push(hAction);
}
/**
*
*
* ,.
* @param template
* @param [autoCalculate=true] ,
*/
export async function InitTempateBoardThicknessActions(template: TemplateRecord, autoCalculate = true)
{
//清理所有的动作
let param = template.GetParam("BH");
if (!param)
return;
param.actions.length = 0;
//开启正交
let snapModeBak = app.Editor.GetPointServices.snapServices.AxisSnapMode;
let ucsBak = app.Editor.UCSMatrix;
app.Editor.GetPointServices.snapServices.AxisSnapMode = AxisSnapMode.Ortho;
//模块信息
let scs = template.GetTemplateSpaceCS();
let scsInv = new Matrix4().getInverse(scs).setPosition(ZeroVec);
let size = GetTempateSize(template);
let brs = GetTempateBoards(template);
let center = size.clone().multiplyScalar(0.5).applyMatrix4(scs);
let directionMap: Map<ObjectId, ThicknessActionData> = new Map();
for (let br of brs)
{
let p: Vector3;
if (!autoCalculate)
{
//亮显它
app.Viewer.OutlinePass.selectedObjects = [br.DrawObject];
app.Editor.UpdateScreen();
//板件中心
let boardCenter = new Vector3(br.Width, br.Height, br.Thickness).multiplyScalar(.5);
boardCenter.applyMatrix4(br.OCS);
//设置UCS
app.Editor.UCSMatrix = br.OCS;
let ptRes = await app.Editor.GetPoint({ BasePoint: boardCenter, AllowDrawRubberBand: true });
if (ptRes.Status !== PromptStatus.OK)
{
//还原
app.Editor.GetPointServices.snapServices.AxisSnapMode = snapModeBak;
app.Editor.UCSMatrix = ucsBak;
return;
}
p = ptRes.Point;
}
else
p = center.clone();
//构建板厚动作
GeneralBoardThicknessAction(br, p, scsInv, brs, directionMap);
}
let action = new TempateThicknessAction();
action.EntityDirectionMap = directionMap;
param.actions.push(action);
//还原
app.Editor.GetPointServices.snapServices.AxisSnapMode = snapModeBak;
app.Editor.UCSMatrix = ucsBak;
}
/**
*
* @param br
* @param p wcs,
* @param scsInv
* @param brs
* @param directionMap
*/
function GeneralBoardThicknessAction(br: Board, p: Vector3, scsInv: Matrix4, brs: Board[], directionMap: Map<ObjectId, ThicknessActionData>)
{
p.applyMatrix4(br.OCSInv);
let direction: ThicknessDirection;
let actions: TemplateAction[] = [];
let frontBox = new Box3Ext(new Vector3(0, 0, br.Thickness).subScalar(1), new Vector3(br.Width, br.Height, br.Thickness).addScalar(1));
let backBox = new Box3Ext(new Vector3().subScalar(1), new Vector3(br.Width, br.Height, 0).addScalar(1));
let frontStretchMap: { entity: ObjectId; indexs: number[]; }[] = [];
let backStretchMap: { entity: ObjectId; indexs: number[]; }[] = [];
let frontVec = br.Normal.applyMatrix4(scsInv);
let backVec = frontVec.clone().negate();
let brOcsInv = br.OCSInv;
let brN = br.Normal;
for (let br2 of brs)
{
if (br === br2) continue;
if (isParallelTo(brN, br2.Normal)) continue;
let sps = br2.GetStretchPoints();
let frontIndexs: number[] = [];
let backIndexs: number[] = [];
for (let i = 0; i < sps.length; i++)
{
let p = sps[i];
p.applyMatrix4(brOcsInv);
if (frontBox.containsPoint(p))
frontIndexs.push(i);
else if (backBox.containsPoint(p))
backIndexs.push(i);
}
if (frontIndexs.length > 0)
frontStretchMap.push({ entity: br2.Id, indexs: frontIndexs });
if (backIndexs.length > 0)
backStretchMap.push({ entity: br2.Id, indexs: backIndexs });
}
//判断拉伸方向
if (equaln(p.z, 0))//居中
{
direction = ThicknessDirection.Center;
let frontAction = new TemplateStretchGripAction(frontVec);
frontAction.EntityStretchPointMap = frontStretchMap;
frontAction.Expr = "BH*0.5";
actions.push(frontAction);
let backAction = new TemplateStretchGripAction(backVec);
backAction.EntityStretchPointMap = backStretchMap;
backAction.Expr = "BH*0.5";
actions.push(backAction);
}
else
{
if (p.z > 0)
{
direction = ThicknessDirection.Front;
let frontAction = new TemplateStretchGripAction(frontVec);
frontAction.EntityStretchPointMap = frontStretchMap;
actions.push(frontAction);
}
else
{
direction = ThicknessDirection.Back;
let backAction = new TemplateStretchGripAction(backVec);
backAction.EntityStretchPointMap = backStretchMap;
actions.push(backAction);
}
}
directionMap.set(br.Id, { Direction: direction, Actions: actions });
}
/**
*
*
*
*/
export async function UpdateTempateBoardThicknessAction(template: TemplateRecord)
{
let param = template.GetParam("BH");
if (!param)
return;
//模块信息
let scs = template.GetTemplateSpaceCS();
let scsInv = new Matrix4().getInverse(scs).setPosition(ZeroVec);
let brs = GetTempateBoards(template);
let sbrs = new Set(brs);
let ssRes = await app.Editor.GetSelection({
Filter: {
filterFunction: (obj, ent) =>
{
return sbrs.has(<Board>ent);
}
}
});
if (ssRes.Status !== PromptStatus.OK) return;
let cbrs = ssRes.SelectSet.SelectEntityList as Board[];
//开启正交
let snapModeBak = app.Editor.GetPointServices.snapServices.AxisSnapMode;
let ucsBak = app.Editor.UCSMatrix;
app.Editor.GetPointServices.snapServices.AxisSnapMode = AxisSnapMode.Ortho;
let thicknessAction = param.actions.find(a => a instanceof TempateThicknessAction) as TempateThicknessAction;
if (!thicknessAction)
{
thicknessAction = new TempateThicknessAction();
param.actions.push(thicknessAction);
}
else
param.WriteAllObjectRecord();
for (let br of cbrs)
{
//亮显它
app.Viewer.OutlinePass.selectedObjects = [br.DrawObject];
app.Editor.UpdateScreen();
//板件中心
let boardCenter = new Vector3(br.Width, br.Height, br.Thickness).multiplyScalar(.5);
boardCenter.applyMatrix4(br.OCS);
//设置UCS
app.Editor.UCSMatrix = br.OCS;
let ptRes = await app.Editor.GetPoint({ BasePoint: boardCenter, AllowDrawRubberBand: true });
if (ptRes.Status !== PromptStatus.OK)
{
//还原
app.Editor.GetPointServices.snapServices.AxisSnapMode = snapModeBak;
app.Editor.UCSMatrix = ucsBak;
return;
}
let p = ptRes.Point;
//构建板厚动作
GeneralBoardThicknessAction(br, p, scsInv, brs, thicknessAction.EntityDirectionMap);
}
//还原
app.Editor.GetPointServices.snapServices.AxisSnapMode = snapModeBak;
app.Editor.UCSMatrix = ucsBak;
}
//拉伸盒子的最大和最小
const SCALEMIN = new Vector3(-0.1, -0.1, -0.1);
const SCALEMAX = new Vector3(1.1, 1.1, 1.1);
/**
*
*
* ,,
* @param [useScaleBox=false] 使,使
*/
export async function AddStretchAction(template: TemplateRecord, useScaleBox = false): Promise<TemplateAction>
{
//模块信息
let scs = template.GetTemplateSpaceCS();
let scsInv = new Matrix4().getInverse(scs);
let brs = GetTempateBoards(template);
let sbrs = new Set(brs);
//拾取需要增加的板件
let ssRes = await app.Editor.GetSelection({
Msg: "选择要增加动作的板件(空格全选):",
AllowNone: true,
Filter: {
filterFunction: (obj, ent) =>
{
return sbrs.has(<Board>ent);
}
}
});
if (ssRes.Status === PromptStatus.Cancel) return;
if (ssRes.Status === PromptStatus.OK)
sbrs = new Set(ssRes.SelectSet.SelectEntityList as Board[]);
ssRes = await app.Editor.GetSelection({
Msg: "选择拉伸范围:",
Filter: {
filterFunction: (obj, ent) =>
{
return sbrs.has(<Board>ent);
}
}
});
if (ssRes.Status !== PromptStatus.OK) return;
//方向拾取
let p1Res = await app.Editor.GetPoint({});
if (p1Res.Status !== PromptStatus.OK) return;
let p2Res = await app.Editor.GetPoint({ Msg: "点击下一个点确认方向:", BasePoint: p1Res.Point });
if (p2Res.Status !== PromptStatus.OK) return;
let direction = p2Res.Point.sub(p1Res.Point);
direction.transformDirection(scsInv);
//构建动作
let action: TemplateMoveAction;
let stretchData = StretchParse(ssRes.SelectSet);
if (useScaleBox)
{
let saction = new TemplateStretchScaleBoxAction();
action = saction;
for (let set of ssRes.SelectSet.SelectSetList)
{
if (set instanceof SelectBox)
{
let selectBox3 = new Box3(AsVector3(set.SelectBox.min).setZ(-6e6), AsVector3(set.SelectBox.max).setZ(6e6));
let widthHalf = set.m_ViewerWidth * 0.5;
let heightHalf = set.m_ViewerHeight * 0.5;
let dcs = new Matrix4()
.setPosition(new Vector3(widthHalf, heightHalf))
.multiply(new Matrix4().set(widthHalf, 0, 0, 0, 0, -heightHalf, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1))
.multiply(set.m_ProjScreenMatrix);
let dcsInv = new Matrix4().getInverse(dcs);
for (let e of set.SelectEntityList)
{
if (stretchData.moveEntityList.includes(e))
continue;
let br = e as Board;
let mtx = new Matrix4().multiplyMatrices(br.OCSInv, dcsInv);
let scaleBox = selectBox3.clone().applyMatrix4(mtx);
let size = new Vector3(br.Width, br.Height, br.Thickness);
scaleBox.min.divide(size);
scaleBox.max.divide(size);
scaleBox.min.clamp(SCALEMIN, SCALEMAX);
scaleBox.max.clamp(SCALEMIN, SCALEMAX);
saction.EntityStretchData.push({
entity: br.Id,
scaleBox
});
}
}
}
}
else
{
let saction = new TemplateStretchGripAction();
action = saction;
for (let { ent, indexs } of stretchData.stretchEntityMap)
{
saction.EntityStretchPointMap.push({ entity: ent.Id, indexs });
}
}
action.MoveEntitys = stretchData.moveEntityList.map(ent => ent.Id);
action.StretchDirection = direction;
return action;
}
/**
*
*
* ,
* @param template
* @returns
*/
export async function AddFilletAction(template: TemplateRecord): Promise<TemplateFilletAction | undefined>
{
//模块信息
let brs = GetTempateBoards(template);
let objs = brs.map(br => br.DrawObject);
let brParamMap: Map<Board, Set<number>> = new Map();
while (true)
{
let ptRes = await app.Editor.GetPoint({
Msg: "请点击需要添加动作的圆弧",
AllowNone: true,
});
if (ptRes.Status === PromptStatus.OK)
{
//选择添加圆角动作的板件
let ptScreen = ptRes.Point;
app.Viewer.WorldToScreen(ptScreen);
let selectPick = new SelectPick(app.Viewer, ptScreen);
selectPick.Select(objs);
let ens = selectPick.SelectEntityList as Board[];
for (let br of ens)
{
let cu = (ens[0] as Board).ContourCurve;
if (cu instanceof Polyline)
{
let pOCS = ptRes.Point.applyMatrix4(br.OCSInv).setZ(0);
let par = cu.GetParamAtPoint(pOCS);
if (isNaN(par))
{
log("点取的点不在圆弧上!");
continue;
}
par = Math.floor(par);
let bul = cu.GetBuilgeAt(par);
if (!equaln(bul, 0))
{
//避免统一圆弧添加多个参数,修正为圆弧中心
par = par + 0.5;
if (brParamMap.has(br))
brParamMap.get(br).add(par);
else
brParamMap.set(br, new Set([par]));
log("成功添加!");
}
else
log("点取的点不在圆弧上!");
}
}
}
else if (ptRes.Status === PromptStatus.Cancel)
{
log("取消添加动作!");
return;
}
else break;
}
if (brParamMap.size === 0) return;
let action = new TemplateFilletAction();
for (let [br, pars] of brParamMap)
{
action.FilletDatas.push({
Entity: br.Id,
ArcParams: [...pars]
});
}
return action;
}

@ -13,6 +13,9 @@ import { PositioningClampSpace } from "./Positioning/PositioningClampSpace";
import { PositioningTemporary } from "./Positioning/PositioningTemporary";
import { TemplateSplitType, TemplateType } from "./TemplateType";
const TemplateDefaultParams = ["L", "W", "H", "PX", "PY", "PZ", "RX", "RY", "RZ"];
export const TempateDefaultParamCount = TemplateDefaultParams.length;
/**
* ###
* ,,
@ -76,6 +79,19 @@ export class TemplateRecord extends SymbolTableRecord
);
}
get Name()
{
return this.name;
}
set Name(name: string)
{
if (name !== this.name)
{
this.WriteAllObjectRecord();
this.name = name;
}
}
get Root(): TemplateRecord
{
if (this.Parent)
@ -148,14 +164,10 @@ export class TemplateRecord extends SymbolTableRecord
//#region param
static BaseParamName = ["L", "W", "H",
"PX", "PY", "PZ",
"RX", "RY", "RZ"];
/** 初始化基础参数 */
InitBaseParams()
{
for (let paramName of TemplateRecord.BaseParamName)
for (let paramName of TemplateDefaultParams)
{
let value = 0;
let param = new TemplateParam();
@ -164,6 +176,9 @@ export class TemplateRecord extends SymbolTableRecord
param.value = value;
this.Params.push(param);
}
this.LParam.description = "宽";
this.WParam.description = "深";
this.HParam.description = "高";
return this;
}
@ -179,22 +194,18 @@ export class TemplateRecord extends SymbolTableRecord
get RYParam() { return this.Params[7]; }
get RZParam() { return this.Params[8]; }
/**
*
* ,,
*/
UpdateParam(name: string, value: any, expr?: string)
GetParam(paramName: string): TemplateParam | undefined
{
let param = this.GetParam(name);
if (param)
param.UpdateParam(value);
return this.Params.find(param => param.name === paramName);
}
GetParam(paramName: string): TemplateParam | undefined
DeleteParam(paramName: string)
{
return this.Params.find(param => param.name === paramName);
let index = this.Params.findIndex(p => p.name === paramName);
if (index !== -1 && index > TempateDefaultParamCount)//LWH P R 禁止删除
this.Params.splice(index, 1);
return this;
}
//#endregion param
@ -224,17 +235,16 @@ export class TemplateRecord extends SymbolTableRecord
*
* - `LWH``positioning`,.
*
* - (),().
* - ,().
*
*/
protected async Update()
{
let varDefines = this.GetParameterDefinition(false);
this._CacheParamVars = this.GetParameterDefinition(false);
let brs = this.Objects.filter(id => !id.IsErase).map(id => id.Object as Board);
let evaled = new Set<TemplateParam>();
let spaceCS = this.GetTemplateSpaceCS(false);
let spaceSize: Vector3;
this._CacheSpaceCS = this.GetTemplateSpaceCS(false);
let paramMap = new Map<string, TemplateParam>();
for (let param of this.Params)
@ -250,16 +260,16 @@ export class TemplateRecord extends SymbolTableRecord
if (!this.positioning.SpaceCS)
return;//出事故
spaceCS = this.positioning.SpaceCS;
spaceSize = this.positioning.SpaceSize;
this._CacheSpaceCS = this.positioning.SpaceCS;
this._CacheSpaceSize = this.positioning.SpaceSize;
spaceCS = this.RotateSpaceCS(varDefines, paramMap, evaled, spaceCS, spaceSize);
this._CacheSpaceCS = this.RotateSpaceCS(this._CacheParamVars, paramMap, evaled, this._CacheSpaceCS, this._CacheSpaceSize);
//更新LWH(通过定位空间)
this.LParam.UpdateParam(spaceSize.x);
this.LParam.UpdateParam(this._CacheSpaceSize.x);
this.LParam.expr = "";
this.WParam.UpdateParam(spaceSize.y);
this.WParam.UpdateParam(this._CacheSpaceSize.y);
this.WParam.expr = "";
this.HParam.UpdateParam(spaceSize.z);
this.HParam.UpdateParam(this._CacheSpaceSize.z);
this.HParam.expr = "";
if (this.positioning instanceof PositioningTemporary)
@ -268,24 +278,24 @@ export class TemplateRecord extends SymbolTableRecord
else
{
this.LParam.EvalUpdate(varDefines, paramMap, evaled);
this.WParam.EvalUpdate(varDefines, paramMap, evaled);
this.HParam.EvalUpdate(varDefines, paramMap, evaled);
this.LParam.EvalUpdate(this._CacheParamVars, paramMap, evaled);
this.WParam.EvalUpdate(this._CacheParamVars, paramMap, evaled);
this.HParam.EvalUpdate(this._CacheParamVars, paramMap, evaled);
this.PXParam.EvalUpdate(varDefines, paramMap, evaled);
this.PYParam.EvalUpdate(varDefines, paramMap, evaled);
this.PZParam.EvalUpdate(varDefines, paramMap, evaled);
this.PXParam.EvalUpdate(this._CacheParamVars, paramMap, evaled);
this.PYParam.EvalUpdate(this._CacheParamVars, paramMap, evaled);
this.PZParam.EvalUpdate(this._CacheParamVars, paramMap, evaled);
let l = this.LParam.value as number;
let w = this.WParam.value as number;
let h = this.HParam.value as number;
spaceSize = new Vector3(l, w, h);
this._CacheSpaceSize = new Vector3(l, w, h);
//相对定位. use PX PY pZ
let baseP = new Vector3(this.PXParam.value as number, this.PYParam.value as number, this.PZParam.value as number);
baseP.applyMatrix4(spaceCS);
spaceCS.setPosition(baseP);
spaceCS = this.RotateSpaceCS(varDefines, paramMap, evaled, spaceCS, spaceSize);
baseP.applyMatrix4(this._CacheSpaceCS);
this._CacheSpaceCS.setPosition(baseP);
this._CacheSpaceCS = this.RotateSpaceCS(this._CacheParamVars, paramMap, evaled, this._CacheSpaceCS, this._CacheSpaceSize);
if (!this.Parent)
{
@ -307,14 +317,14 @@ export class TemplateRecord extends SymbolTableRecord
}
//更新LWH(通过定位空间)
this.LParam.UpdateParam(spaceSize.x);
this.WParam.UpdateParam(spaceSize.y);
this.HParam.UpdateParam(spaceSize.z);
this.LParam.UpdateParam(this._CacheSpaceSize.x);
this.WParam.UpdateParam(this._CacheSpaceSize.y);
this.HParam.UpdateParam(this._CacheSpaceSize.z);
}
varDefines["L"] = spaceSize.x;
varDefines["W"] = spaceSize.y;
varDefines["H"] = spaceSize.z;
this._CacheParamVars["L"] = this._CacheSpaceSize.x;
this._CacheParamVars["W"] = this._CacheSpaceSize.y;
this._CacheParamVars["H"] = this._CacheSpaceSize.z;
//#endregion
@ -323,26 +333,21 @@ export class TemplateRecord extends SymbolTableRecord
//变换到新的模版空间
for (let br of brs)
br.ApplyMatrix(spaceCS);
br.ApplyMatrix(this._CacheSpaceCS);
//#endregion
//更新其他参数变量 Eval local params
for (const param of this.Params)
{
param.EvalUpdate(varDefines, paramMap, evaled);
param.EvalUpdate(this._CacheParamVars, paramMap, evaled);
}
//保持SpaceCS
for (let ent of brs)
{
ent.SpaceOCS = spaceCS;
ent.SpaceOCS = this._CacheSpaceCS;
}
//Cache
this._CacheParamVars = varDefines;
this._CacheSpaceCS = spaceCS;
this._CacheSpaceSize = spaceSize;
}
/**
@ -434,7 +439,6 @@ export class TemplateRecord extends SymbolTableRecord
protected _CacheParamVars: any;
protected _CacheSpaceCS: Matrix4;
protected _CacheSpaceSize: Vector3;
/**
* .()
* @param [useCache=true] ,使,()
@ -493,7 +497,7 @@ export class TemplateRecord extends SymbolTableRecord
*
* @param [useCache=true] ,使,()
*/
private GetTemplateSpaceCS(useCache = true): Matrix4
GetTemplateSpaceCS(useCache = true): Matrix4
{
if (useCache && this._CacheSpaceCS)
return this._CacheSpaceCS.clone();

@ -1,145 +1,139 @@
import { Box3, Matrix4, Vector3 } from "three";
import { app } from "../../ApplicationServices/Application";
import { StretchParse } from "../../Common/StretchParse";
import { Sleep } from "../../Common/Sleep";
import { DuplicateRecordCloning } from "../../Common/Status";
import { commandMachine } from "../../Editor/CommandMachine";
import { PromptSsgetResult, PromptStatus } from "../../Editor/PromptResult";
import { SelectBox, SelectType } from "../../Editor/SelectBox";
import { AsVector3, equalv3, MoveMatrix, ZeroVec } from "../../Geometry/GeUtils";
import { PromptStatus } from "../../Editor/PromptResult";
import { ClampSpaceParse } from "../../Geometry/SpaceParse/ClampSpaceParse";
import { EnableSelectType } from "../../Geometry/SpaceParse/PointSelectSpace";
import { PointSelectSpaceClamp } from "../../Geometry/SpaceParse/PointSelectSpaceClamp";
import { Database } from "../Database";
import { Board } from "../Entity/Board";
import { TemplateAction } from "./Action/TemplateAction";
import { TemplateMoveAction } from "./Action/TemplateMoveAction";
import { TemplateStretchGripAction } from "./Action/TemplateStretchGripAction";
import { TemplateStretchScaleBoxAction } from "./Action/TemplateStretchScaleBoxAction";
import { TemplateRecord } from "./TemplateRecord";
import { ClampSpaceParse } from "../../Geometry/SpaceParse/ClampSpaceParse";
import { PositioningClampSpace } from "./Positioning/PositioningClampSpace";
import { Sleep } from "../../Common/Sleep";
import { AddFilletAction, AddStretchAction, InitTempateBoardThicknessActions, InitTempateSizeActions, InitTemplate, SetTempateCoordinate, UpdateTemplateSizeOffBoards } from "./TempateUtils";
import { TemplateRecord } from "./TemplateRecord";
import { TemplateSplitType } from "./TemplateType";
import { TemplateParam } from "./Param/TemplateParam";
import { TemplateParamType } from "./Param/TemplateParamType";
import { FilletUtils } from "../../Add-on/FilletUtils";
import { Polyline } from "../Entity/Polyline";
import { Line } from "../Entity/Line";
import { IntersectOption } from "../../GraphicsSystem/IntersectWith";
import { TemplateFilletAction } from "./Action/TemplateFilletAction";
import { Database } from "../Database";
import { DuplicateRecordCloning } from "../../Common/Status";
import { TemplateWineRackRecord } from "./ProgramTempate/TemplateWineRackRecord";
export function GetDefaultTemplate()
export async function SelectTempate(): Promise<TemplateRecord>
{
let templates = app.Database.TemplateTable.Objects;
if (templates.length === 0)
{
let template = new TemplateRecord().InitBaseParams();
app.Database.TemplateTable.Append(template);
return template;
}
else
return templates[0];
}
let enRes = await app.Editor.GetEntity({
Msg: "选择模块:",
NotNone: true,
Filter: {
filterFunction: (obj, ent) =>
{
return ent.Template !== undefined;
}
}
});
if (enRes.Status !== PromptStatus.OK) return;
const SCALEMIN = new Vector3(-0.1, -0.1, -0.1);
const SCALEMAX = new Vector3(1.1, 1.1, 1.1);
let e = enRes.Entity;
let template = e.Template.Object as TemplateRecord;
return template;
}
export class AddTemplateAction
{
constructor(public name: string = "L")
{
}
async exec()
{
//不能在透视相机下执行这个工作.
let template = await SelectTempate();
let keyRes = await app.Editor.GetKeyWords({
Msg: "选择变量",
KeyWordList: template.Params.map(p =>
{
return {
key: p.name,
msg: ``
}
})
});
let ssRes = await app.Editor.GetSelection({ SelectType: SelectType.C });
if (ssRes.Status !== PromptStatus.OK)
return;
if (keyRes.Status !== PromptStatus.Keyword) return;
let bpRes = await app.Editor.GetPoint({ Msg: "指定方向的基点:" });
if (bpRes.Status !== PromptStatus.OK)
return;
let paramname = keyRes.StringResult;
let toRes = await app.Editor.GetPoint({ Msg: "指定方向的终点:", BasePoint: bpRes.Point, AllowDrawRubberBand: true });
if (toRes.Status !== PromptStatus.OK)
return;
keyRes = await app.Editor.GetKeyWords({
Msg: "动作类型:",
KeyWordList: [
{ key: "1", msg: "夹点" },
{ key: "2", msg: "盒子" },
{ key: "3", msg: "倒角" },
{ key: "4", msg: "板厚" },
],
Default: "1"
});
let direction = toRes.Point.sub(bpRes.Point).normalize();
if (equalv3(direction, ZeroVec))
return;
let action: TemplateAction;
switch (keyRes.StringResult)
{
case "1":
action = await AddStretchAction(template, false);
break;
case "2":
action = await AddStretchAction(template, true);
break;
case "3":
action = await AddFilletAction(template);
break;
case "4":
keyRes = await app.Editor.GetKeyWords({
Msg: "类型:",
KeyWordList: [
{ key: "1", msg: "自动" },
{ key: "2", msg: "手动" },
],
Default: "1"
});
await InitTempateBoardThicknessActions(template, keyRes.StringResult === "1");
break;
default:
break;
}
if (action)
{
let exprRes = await app.Editor.GetString({ Msg: "表达式:" });
if (!exprRes.StringResult)
{
action.Expr = exprRes.StringResult;
}
this.GripStretchAction(direction, ssRes);
// this.ScaleBoxStretchAction(direction, ssRes);
template.WriteAllObjectRecord();
template.GetParam(paramname).actions.push(action);
}
}
}
private GripStretchAction(direction: Vector3, ssRes: PromptSsgetResult)
export class TemplateAddParam
{
async exec()
{
let stretchData = StretchParse(ssRes.SelectSet);
let template = await SelectTempate();
let nameRes = await app.Editor.GetString({ Msg: "名称" });
if (!nameRes.StringResult) return;
let stretchAction = new TemplateStretchGripAction();
stretchAction.StretchDirection = direction;
let vRes = await app.Editor.GetDistance({ Msg: "值" });
if (vRes.Status !== PromptStatus.OK) return;
let moveAction = new TemplateMoveAction();
moveAction.StretchDirection = direction;
let param = new TemplateParam();
param.name = nameRes.StringResult;
param.value = vRes.Distance;
for (let { ent, indexs } of stretchData.stretchEntityMap)
{
stretchAction.EntityStretchPointMap.push({
entity: ent.Id,
indexs
});
}
if (stretchData.stretchEntityMap.length > 0)
{
GetDefaultTemplate().GetParam(this.name).actions.push(stretchAction);
}
moveAction.Entitys = stretchData.moveEntityList.map(ent => ent.Id);
if (moveAction.Entitys.length > 0)
{
GetDefaultTemplate().GetParam(this.name).actions.push(moveAction);
}
template.Params.push(param);
}
}
private ScaleBoxStretchAction(direction: Vector3, ssRes: PromptSsgetResult)
export class TemplateSetCoordinate
{
async exec()
{
let action = new TemplateStretchScaleBoxAction();
action.StretchDirection = direction;
for (let set of ssRes.SelectSet.SelectSetList)
{
if (set instanceof SelectBox)
{
let selectBox3 = new Box3(AsVector3(set.SelectBox.min).setZ(-6e6), AsVector3(set.SelectBox.max).setZ(6e6));
let widthHalf = set.m_ViewerWidth * 0.5;
let heightHalf = set.m_ViewerHeight * 0.5;
let dcs = new Matrix4()
.setPosition(new Vector3(widthHalf, heightHalf))
.multiply(new Matrix4().set(widthHalf, 0, 0, 0, 0, -heightHalf, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1))
.multiply(set.m_ProjScreenMatrix);
let dcsInv = new Matrix4().getInverse(dcs);
for (let e of set.SelectEntityList)
{
let br = e as Board;
let mtx = new Matrix4().multiplyMatrices(br.OCSInv, dcsInv);
let scaleBox = selectBox3.clone().applyMatrix4(mtx);
let size = new Vector3(br.Width, br.Height, br.Thickness);
scaleBox.min.divide(size);
scaleBox.max.divide(size);
scaleBox.min.clamp(SCALEMIN, SCALEMAX);
scaleBox.max.clamp(SCALEMIN, SCALEMAX);
action.EntityStretchData.push({
entity: br.Id,
scaleBox
});
}
}
}
if (action.EntityStretchData.length > 0)
{
GetDefaultTemplate().GetParam(this.name).actions.push(action);
}
let template = await SelectTempate();
await SetTempateCoordinate(template);
await UpdateTemplateSizeOffBoards(template);
}
}
@ -152,139 +146,31 @@ export class AutoTempateSizeAction
if (brsRes.Status !== PromptStatus.OK) return;
let brs = brsRes.SelectSet.SelectEntityList as Board[];
let m0 = new Matrix4();
let box = new Box3();
for (let br of brs)
{
box.union(br.BoundingBox);
br.SpaceOCS = m0;
}
let template = await InitTemplate(brs);
//归0?
let keyRes = await app.Editor.GetKeyWords({
Msg: "自动将所有的板件移动到0点后初始化动作?",
Msg: "初始化大小动作?",
KeyWordList: [
{ key: "Y", msg: "是" },
{ key: "N", msg: "否" },
]
{ key: "1", msg: "是" },
{ key: "2", msg: "否" },
],
Default: "1"
});
if (keyRes.StringResult === "1")
InitTempateSizeActions(template, true);
let isToZero = keyRes.Status === PromptStatus.Keyword && keyRes.StringResult === "Y";
if (isToZero)
{
//将板件移动到0点.
{
let m = MoveMatrix(box.min.clone().negate());
for (let br of brs)
{
br.ApplyMatrix(m);
br.SpaceOCS = m0;
}
}
//休整box
box.max.sub(box.min);
}
box.min.set(0, 0, 0);
let size = box.max;
let v = new Vector3(1, 1, 1);
//后
let frontBox = new Box3(box.min.clone().add(new Vector3(-1, size.y / 2, -1)), box.max.clone().add(v));
//右缩
let rightBox = new Box3(box.min.clone().add(new Vector3(size.x / 2, -1, -1)), box.max.clone().add(v));
//上缩
let topBox = new Box3(box.min.clone().add(new Vector3(-1, -1, size.z / 2)), box.max.clone().add(v));
let template = new TemplateRecord().InitBaseParams();
let rParam = new TemplateParam();
rParam.name = "R";
rParam.value = 0;
rParam.type = TemplateParamType.Float;
template.Params.push(rParam);
app.Database.TemplateTable.Append(template);
template.GetParam("L").value = size.x;
template.GetParam("W").value = size.y;
template.GetParam("H").value = size.z;
template.Objects = brs.map(br => br.Id);
let mmp = [
{
ParamName: "L", Box: rightBox, Direction: new Vector3(1),
StretchAction: new TemplateStretchScaleBoxAction(new Vector3(1)),
MoveAction: new TemplateMoveAction(new Vector3(1)),
MoveThicknessAction: new TemplateMoveAction(new Vector3(0.5)),
},
{
ParamName: "W", Box: frontBox, Direction: new Vector3(0, 1),
StretchAction: new TemplateStretchScaleBoxAction(new Vector3(0, 1)),
MoveAction: new TemplateMoveAction(new Vector3(0, 1)),
MoveThicknessAction: new TemplateMoveAction(new Vector3(0, 0.5)),
},
{
ParamName: "H", Box: topBox, Direction: new Vector3(0, 0, 1),
StretchAction: new TemplateStretchScaleBoxAction(new Vector3(0, 0, 1)),
MoveAction: new TemplateMoveAction(new Vector3(0, 0, 1)),
MoveThicknessAction: new TemplateMoveAction(new Vector3(0, 0, 0.5)),
},
];
//构建scalebox
for (let br of brs)
{
for (let m of mmp)
{
if (br.BoundingBox.intersect(m.Box))
{
let pts = br.GetStretchPoints();
let indexs: number[] = [];
for (let i = 0; i < pts.length; i++)
{
const p = pts[i];
if (m.Box.containsPoint(p))
indexs.push(i);
}
if (br.IsStretchThickness(indexs))
{
m.MoveThicknessAction.Entitys.push(br.Id);
}
else if (indexs.length === pts.length)
{
m.MoveAction.Entitys.push(br.Id);
}
else if (indexs.length > 0)
{
let scaleBox = m.Box.clone().applyMatrix4(br.OCSInv);
let size = new Vector3(br.Width, br.Height, br.Thickness);
scaleBox.min.divide(size);
scaleBox.max.divide(size);
m.StretchAction.EntityStretchData.push({ entity: br.Id, scaleBox });
}
}
}
}
for (let m of mmp)
{
let param = template.GetParam(m.ParamName);
if (m.MoveAction.Entitys.length > 0)
param.actions.push(m.MoveAction);
if (m.StretchAction.EntityStretchData.length > 0)
param.actions.push(m.StretchAction);
if (m.MoveThicknessAction.Entitys.length > 0)
param.actions.push(m.MoveThicknessAction);
}
keyRes = await app.Editor.GetKeyWords({
Msg: "初始化板厚动作?",
KeyWordList: [
{ key: "1", msg: "是" },
{ key: "2", msg: "否" },
],
Default: "1"
});
if (keyRes.StringResult === "1")
await InitTempateBoardThicknessActions(template, true);
}
}
@ -431,16 +317,6 @@ export class UpdateParam2
}
}
export class Clear
{
async exec()
{
GetDefaultTemplate().GetParam("L").actions.length = 0;
GetDefaultTemplate().GetParam("L").actions.push(new TemplateAction())
GetDefaultTemplate().GetParam("L").value = 0;
}
}
export class TemplateAttach
{
async exec()
@ -681,133 +557,18 @@ export class TemplateAttach3
}
}
export class TemplateAddFilletAction
{
async exec()
{
let brRes = await app.Editor.GetEntity({
Msg: "选择附加的模版",
NotNone: true,
Filter: {
filterFunction: (obj, ent) =>
{
if (ent instanceof Board)
return ent.Template !== undefined;
return false;
}
}
});
if (brRes.Status !== PromptStatus.OK) return;
//------1.画辅助线
let ptRes = await app.Editor.GetPoint({
BasePoint: brRes.Point,
AllowDrawRubberBand: true,
AllowNone: true,
Msg: "选择下一个点:"
});
if (ptRes.Status === PromptStatus.Cancel)
return;
//------2.倒角
let fillet = new FilletUtils();
fillet.FilletRadius = 100;
let fres = fillet.FilletBoard(brRes, ptRes);
if (fres instanceof Polyline)
{
let br = brRes.Entity as Board;
br.ContourCurve = fres;
let brContour = fres;
//------1.求交
let brResPt = brRes.Point.clone().applyMatrix4(br.OCSInv).setZ(0);
let ptResPt = ptRes.Point.clone().applyMatrix4(br.OCSInv).setZ(0);
let l = new Line(brResPt, ptResPt);
let ipts = l.IntersectWith(brContour, IntersectOption.ExtendThis);
if (ipts.length > 2)//超过2个则有可能有多余交点
//找最近点
ipts = [fillet.FindNearestPt(ipts, brResPt), fillet.FindNearestPt(ipts, ptResPt)]
if (ipts.length !== 2)
return "倒角失败!交点个数异常.";
let param1 = brContour.GetParamAtPoint(ipts[0]);
let param2 = brContour.GetParamAtPoint(ipts[1]);
let filletAction = new TemplateFilletAction(br.Id, param1, param2);
let template = br.Template.Object as TemplateRecord;
let rParam = template.GetParam("R");
rParam.actions.push(filletAction);
}
else
app.Editor.Prompt(fres);
}
}
export class Command_TemplateWineRack
{
async exec()
{
let selectSpace = new PointSelectSpaceClamp();
selectSpace.Enable = EnableSelectType.Stretch;
await selectSpace.Select();
if (!selectSpace.ParseOK)
{
app.Editor.Prompt("未能分析出有效空间!");
return;
}
let brs = selectSpace.SpaceParse.Boards;
let tbrs = brs.filter(br => br.Template !== undefined);
tbrs.sort((b1, b2) =>
{
let t1 = b1.Template.Object as TemplateRecord;
let t2 = b2.Template.Object as TemplateRecord;
return t2.NodeDepth - t1.NodeDepth;
});
let templateSource: TemplateRecord;
if (tbrs.length > 0)
templateSource = tbrs[0].Template.Object as TemplateRecord;
let parse = selectSpace.SpaceParse as ClampSpaceParse;
let positioning = new PositioningClampSpace();
positioning.FromSpaceParse(parse);
let wineRack = new TemplateWineRackRecord().InitBaseParams();
app.Database.TemplateTable.Append(wineRack);
wineRack.Positioning = positioning;
if (templateSource)
templateSource.Children.push(wineRack.Id);
wineRack.UpdateTemplateTree();
}
}
commandMachine.RegisterCommand("Attach", new TemplateAttach());
commandMachine.RegisterCommand("Attach2", new TemplateAttach2());
commandMachine.RegisterCommand("Attach3", new TemplateAttach3());
commandMachine.RegisterCommand("Attach4", new Command_TemplateWineRack());
commandMachine.RegisterCommand("templateAddFilletAction", new TemplateAddFilletAction());
commandMachine.RegisterCommand("as", new AddTemplateAction());
commandMachine.RegisterCommand("ap", new TemplateAddParam());
commandMachine.RegisterCommand("tsc", new TemplateSetCoordinate());
commandMachine.RegisterCommand("al", new AddTemplateAction("L"));
commandMachine.RegisterCommand("aw", new AddTemplateAction("W"));
commandMachine.RegisterCommand("ah", new AddTemplateAction("H"));
commandMachine.RegisterCommand("uu", new UpdateTemplate());
commandMachine.RegisterCommand("uur", new UpdateTemplateRo());
commandMachine.RegisterCommand("uuu", new UpdateParam2());
commandMachine.RegisterCommand("clear", new Clear);
commandMachine.RegisterCommand("uu", new UpdateTemplate());
// commandMachine.RegisterCommand("uur", new UpdateTemplateRo());
// commandMachine.RegisterCommand("uuu", new UpdateParam2());
// commandMachine.RegisterCommand("clear", new Clear);

@ -112,6 +112,7 @@ window["end"] = commandMachine.CommandEnd;
export async function CommandWrap(exec: Function, cmdName: string = "")
{
await app.Editor.ModalManage.EndExecingCmd();
if (!commandMachine.CommandStart(cmdName))
return;

@ -106,6 +106,7 @@ import { Command_SwitchCamera } from '../Add-on/SwitchCamera';
import { CMD_Conceptual, CMD_Physical, CMD_Wireframe } from '../Add-on/SwitchVisualStyles';
import { DrawTangentLine } from '../Add-on/Tangent';
import { ShowTemplate } from '../Add-on/Template/ShowTemplate';
import { ShowTemplateDesign } from "../Add-on/Template/ShowTemplateDesign";
import { ShowTopLine } from '../Add-on/Template/ShowTopline';
import { Command_TemplateSearch } from '../Add-on/TemplateSearch';
// import { DrawFloor } from '../Add-on/DrawFloor';
@ -352,6 +353,7 @@ export function registerCommand()
commandMachine.RegisterCommand("batchmodify", new BatchModify());
commandMachine.RegisterCommand("template", new ShowTemplate());
commandMachine.RegisterCommand("templatedesign", new ShowTemplateDesign());
commandMachine.RegisterCommand("TemplateSearch", new Command_TemplateSearch());

@ -18,12 +18,13 @@ import { SsgetServiecs } from './GetSelectionServices';
import { GripDragServices } from './GripDragServices';
import { KeyBoardControls } from './KeyBoardControls';
import { MouseControls } from './MouseControls';
import { GetDistendPrompt, GetEntityPrompt, GetKeyWordPrommpt, GetPointPrompt, GetSelectionPrompt, PromptRectPointOptions } from "./PromptOptions";
import { GetDistendPrompt, GetEntityPrompt, GetKeyWordPrommpt, GetPointPrompt, GetSelectionPrompt, PromptRectPointOptions, GetStringPrompt } from "./PromptOptions";
import { PromptDistendResult, PromptEntityResult, PromptPointResult, PromptRectResult, PromptResult, PromptSsgetResult } from './PromptResult';
import { SelectControls } from './SelectControls';
import { TransformServicess } from './TranstrolControl/TransformServices';
import { UCSServices } from './UCSServices';
import { SpeechBoxManage } from '../UI/Components/SpeechBox/SpeechBoxManage';
import { GetStringService } from './GetStringService';
//用户交互编辑工具
@ -51,6 +52,7 @@ export class Editor
KeywordsServices: GetKeyWordsServices;
ContextMenuServices: ContextMenuServices;
InteractiveServices: EditorService[] = [];
GetStringService: any;
//用户坐标系
constructor(app: ApplicationService)
@ -71,6 +73,7 @@ export class Editor
this.KeywordsServices = new GetKeyWordsServices(this);
this.ContextMenuServices = new ContextMenuServices(this);
this.GetStringService = new GetStringService();
xaop.end(this.MouseCtrl, this.MouseCtrl.onMouseMove, () =>
{
@ -157,6 +160,12 @@ export class Editor
{
return this.KeywordsServices.Start(prompt);
}
GetString(prompt: GetStringPrompt): Promise<PromptResult>
{
return this.GetStringService.Start(prompt);
}
GetEntity(prompt?: GetEntityPrompt): Promise<PromptEntityResult>
{
return this.GetEntitytServices.Start(prompt);

@ -177,8 +177,7 @@ export class GetPointServices implements EditorService
{
this.removeCalls.push(xaop.end(app.Editor.KeyCtrl, app.Editor.KeyCtrl.OnKeyDown, (e: KeyboardEvent) =>
{
if (e.keyCode == KeyBoard.Escape)
if (e.keyCode === KeyBoard.Escape)
{
this.Cancel();
return true;

@ -0,0 +1,101 @@
import { EditorService } from "./Editor";
import { GetStringPrompt } from "./PromptOptions";
import { PromptResult, PromptStatus } from "./PromptResult";
import { InitKeyWord } from "./InitKeyword";
import { end, begin } from "xaop";
import { app } from "../ApplicationServices/Application";
import { KeyBoard } from "../Common/KeyEnum";
import { InputState } from "../Common/InputState";
export class GetStringService implements EditorService
{
IsReady: boolean = true;
private _prompt: GetStringPrompt;
protected removeCalls: Function[] = []; //结束回调
private promisResolve: (value?: any) => void;
async Doit(e: MouseEvent): Promise<boolean>
{
return true;
}
Start(prompt?: GetStringPrompt): Promise<PromptResult>
{
prompt = prompt ? prompt : {};
this._prompt = prompt;
this.InitState();
this.InitPrompt(prompt);
this.removeCalls.push(InitKeyWord(prompt));
this.InitHandleInput(prompt);
this.InitHandleKeyDown();
return new Promise<PromptResult>((resolve, reject) =>
{
this.promisResolve = resolve;
});
}
Cancel()
{
let v = new PromptResult();
v.Status = PromptStatus.Cancel;
this.ReturnResult(v);
}
protected InitState()
{
app.Editor.InputState |= InputState.GetString;
}
private RestState()
{
this.IsReady = false;
app.Editor.InputState &= ~InputState.GetString;
this.removeCalls.forEach(f => f());
this.removeCalls.length = 0;
}
protected ReturnResult(retValue: PromptResult)
{
if (!this.promisResolve) return;
this.RestState();
this.promisResolve(retValue);
this.promisResolve = undefined;
}
protected InitPrompt(prompt: GetStringPrompt)
{
prompt.Msg = prompt.Msg || "请输入一个点:";
if (prompt.Msg)
{
app.Editor.CommandStore.commandPrompt = prompt.Msg;
this.removeCalls.push(() =>
{
app.Editor.CommandStore.commandPrompt = "";
});
}
}
protected InitHandleInput(prompt: GetStringPrompt)
{
this.removeCalls.push(begin(app.Editor, app.Editor.InputEvent, (inputData: string) =>
{
let res = new PromptResult();
res.Status = PromptStatus.OK;
res.StringResult = inputData;
this.ReturnResult(res);
}));
}
private InitHandleKeyDown()
{
this.removeCalls.push(end(app.Editor.KeyCtrl, app.Editor.KeyCtrl.OnKeyDown, (e: KeyboardEvent) =>
{
if (e.keyCode === KeyBoard.Escape)
{
this.Cancel();
return true;
}
}));
}
}

@ -17,6 +17,11 @@ export interface GetKeyWordPrommpt extends PromptOptions
Modal?: boolean;
}
export interface GetStringPrompt extends PromptOptions
{
Default?: string;
}
export interface GetPointPrompt extends PromptOptions
{
//基点

@ -14,13 +14,13 @@ export class SelectSet
*
*/
private m_SelectSetList = new Array<SelectSetBase>();
private m_IdSelect = new Map<number, SelectSetBase>();
IdSelectMap = new Map<number, SelectSetBase>();
AddSelect(selectData: SelectSetBase)
{
let selectCount = selectData.m_SelectList.length;
//1.校验重复
selectData.m_SelectList = selectData.m_SelectList.filter(obj => !this.m_IdSelect.has(obj.id));
selectData.m_SelectList = selectData.m_SelectList.filter(obj => !this.IdSelectMap.has(obj.id));
let dupCount = selectCount - selectData.m_SelectList.length;
//加入集合
@ -28,7 +28,7 @@ export class SelectSet
for (let obj of selectData.m_SelectList)
{
this.m_IdSelect.set(obj.id, selectData);
this.IdSelectMap.set(obj.id, selectData);
}
//Group 操作
@ -42,10 +42,10 @@ export class SelectSet
{
let ent = entId.Object as Entity;
let obj = ent.DrawObject;
if (!this.m_IdSelect.has(obj.id))
if (!this.IdSelectMap.has(obj.id))
{
selectData.m_SelectList.push(obj);
this.m_IdSelect.set(obj.id, selectData);
this.IdSelectMap.set(obj.id, selectData);
groupCount++;
}
@ -71,10 +71,14 @@ export class SelectSet
log(`取消选择${selectData.m_SelectList.length}个.`);
for (let obj of selectData.m_SelectList)
{
if (this.m_IdSelect.has(obj.id))
if (this.IdSelectMap.has(obj.id))
{
arrayRemoveOnce(this.m_IdSelect.get(obj.id).m_SelectList, obj);
this.m_IdSelect.delete(obj.id);
let set = this.IdSelectMap.get(obj.id);
arrayRemoveOnce(set.m_SelectList, obj);
this.IdSelectMap.delete(obj.id);
if (set.m_SelectList.length === 0)
arrayRemoveOnce(this.m_SelectSetList, set);
}
}
}
@ -82,7 +86,7 @@ export class SelectSet
Clear()
{
this.m_SelectSetList.length = 0;
this.m_IdSelect.clear();
this.IdSelectMap.clear();
}
get SelectSetList()

@ -33,6 +33,7 @@ export enum BoardModalType
Find = "findBr", // 查找
JG = "jg", //酒格
Lat = "lattice", // 格子抽
TempDes="templatedesign",
}
export interface BoardModalProps
{

@ -2,13 +2,13 @@ import { Button, InputGroup, Intent, Menu, MenuItem, Popover, Position } from '@
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { arrayLast } from '../../../Common/ArrayExt';
import { BoardProcessOption, IGrooveOption, LayerNailOption, TBBoardOption } from '../../Store/BoardInterface';
import { IConfigStore } from '../../Store/BoardStore';
import { DrillingOption } from '../../Store/drillInterface';
import { userConfigStore, UserConfigStore } from '../../Store/UserConfigStore';
import { BoardModalType } from './BoardModal';
import { IDoorInfo } from '../../Store/DoorInterface';
import { StoreageKeys } from '../../../Common/KeyEnum';
//保存的配置
export interface IConfigOption
@ -68,6 +68,12 @@ export class UserConfig extends React.Component<IConfigProps, UserConfigState>{
//更新配置
private updateBoardOption = async (k: string) =>
{
if (this.props.type === BoardModalType.TempDes)
{
if (!confirm("你确定要初始化参数列表?"))
return;
}
await this._userConfigStore.UpdateBoardOption(k, this.props.type, this.props.store);
}
async UNSAFE_componentWillMount()
@ -85,14 +91,19 @@ export class UserConfig extends React.Component<IConfigProps, UserConfigState>{
}
else
{
let curName = localStorage.getItem("configName_" + type);
let curName = localStorage.getItem(StoreageKeys.ConfigName + type);
if (!curName || !confNames.includes(curName))
curName = confNames[0];
this._userConfigStore.configName = curName;
if (type !== BoardModalType.Zx && !this._userConfigStore.readConfigs.has(type))
if (type !== BoardModalType.Zx && type !== BoardModalType.TempDes && !this._userConfigStore.readConfigs.has(type))
this.updateBoardOption(curName);
}
if (type === BoardModalType.TempDes)
{
this._userConfigStore.configsNames.push("");
this._userConfigStore.configName = "";
}
this._userConfigStore.readConfigs.add(type);
}

@ -0,0 +1,49 @@
import * as React from 'react';
import { Popover, Position, Button, Intent, Classes, Card, IconName, MaybeElement } from '@blueprintjs/core';
export interface IPopOverButtonProps
{
position: Position;
disabled?: boolean;
confirmCallback: () => void;
message: string;
targetTitle: string;
icon?: IconName | MaybeElement;
}
export class PopoverButton extends React.Component<IPopOverButtonProps> {
public render()
{
return (
<Popover
position={this.props.position}
disabled={this.props.disabled}
content={
<Card>
<p>{this.props.message}</p>
<div>
<Button style={{ marginRight: 10 }}
className={Classes.POPOVER_DISMISS}
text="取消" />
<Button
className={Classes.POPOVER_DISMISS}
intent={Intent.PRIMARY}
onClick={this.props.confirmCallback}
text="确定" />
</div>
</Card>
}
target={
<Button
icon={this.props.icon}
style={{
marginRight: 10
}}
disabled={this.props.disabled}
text={this.props.targetTitle}
intent={Intent.DANGER}
/>}
/>
);
}
}

@ -110,6 +110,10 @@ export class ModalManage
case KeyBoard.Enter:
e.preventDefault();
break;
case KeyBoard.KeyS:
if (e.ctrlKey)
e.preventDefault();
break;
}
e.stopPropagation();
}

@ -0,0 +1,48 @@
import * as React from 'react';
import { H5, Label, Classes, Button, Intent } from '@blueprintjs/core';
import { observer } from 'mobx-react';
export interface ISimpleDialogProps
{
title: string;
childern: JSX.Element[];
onclose: Function;
isOpen: boolean;
}
@observer
export class SimpleDialog extends React.Component<ISimpleDialogProps> {
public render()
{
let { title, childern } = this.props;
return (
<>
{
this.props.isOpen && <div className="simple-dialog">
<H5>{title}
<Button
aria-label="Close"
minimal
icon="cross"
className={Classes.DIALOG_CLOSE_BUTTON}
/>
</H5>
<div className="simple-dialog-body">
{childern}
</div>
<div className="simple-dialog-footer">
<Button
text="确定"
intent={Intent.SUCCESS}
/>
<Button
text="取消"
intent={Intent.DANGER}
/>
</div>
</div>
}
</>
);
}
}

@ -9,6 +9,7 @@ import { AppToaster } from '../Toaster';
import { HandleDirComponent } from './HandleDirComponent';
import { Pagination } from './Pagination';
import './TexturePanel.less';
import { PopoverButton } from '../Common/PopoverButton';
export interface IDirectoryProps
{
@ -557,34 +558,13 @@ export class CommonPanel extends React.Component<ICommonPanelProps, ICommonPanel
}
{
this.props.canDelete && <>
<Popover
<PopoverButton
position={Position.LEFT}
disabled={!this.state.isSelectAll && this.needDeleteData.size === 0}
content={
<Card>
<p></p>
<div>
<Button style={{ marginRight: 10 }}
className={Classes.POPOVER_DISMISS}
text="取消" />
<Button
className={Classes.POPOVER_DISMISS}
intent={Intent.PRIMARY}
onClick={() => this.handDeleteData()}
text="确定" />
</div>
</Card>
}
target={<Button
icon="trash"
style={{
marginRight: 10
}}
disabled={!this.state.isSelectAll && this.needDeleteData.size === 0}
text="删除"
intent={Intent.DANGER}
/>}
message="确认删除选中项"
confirmCallback={() => this.handDeleteData()}
targetTitle="删除"
icon="trash"
/>
<Checkbox
label="全选"

@ -48,7 +48,7 @@ export default class SoucePanel extends React.Component<{ store?: TopPanelStore
top: 0,
width: "50%",
height: "90%",
minWidth: 780,
minWidth: 900,
minHeight: 300,
padding: 0,
}

@ -0,0 +1,91 @@
import { Icon, ITreeNode, TreeEventHandler } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import * as React from 'react';
export interface IActionTreeProps<T = {}>
{
nodes: ITreeNode[];
className?: string;
onNodeDoubleClick?: TreeEventHandler<T>;
onNodeClick?: TreeEventHandler<T>;
onNodeCollapse?: (node: ITreeNode) => void;
}
@observer
export default class ActionTree extends React.Component<IActionTreeProps> {
public render()
{
return (
<div className={"bp3-tree bp3-elevation-0 " + this.props.className}>
<ul className="bp3-tree-node-list bp3-tree-root">
{
this.props.nodes.map((node, i1) =>
{
return (
<li
className={`bp3-tree-node bp3-tree-node-expanded ${node.isSelected ? "bp3-tree-node-selected" : ""}`}
onDoubleClick={(e) => this.handleDbclick(node, [i1], e)}
onClick={e => this.handleclick(node, [i1], e)}
>
<div className="bp3-tree-node-content">
<Icon
icon="chevron-right"
className={`bp3-icon bp3-icon-chevron-right bp3-tree-node-caret bp3-tree-node-caret-${node.isExpanded ? "open" : "close"}`}
onClick={() => this.handleNodeCollapse(node)}
/>
<span className="bp3-tree-node-label">{node.label}</span>
</div>
<ul
className="bp3-tree-node-list"
style={{ display: node.isExpanded ? "block" : "none" }}>
{
node.childNodes && node.childNodes.map((n, i2) =>
{
return (
<li
className={`bp3-tree-node ${n.isSelected ? "bp3-tree-node-selected" : ""}`}
onDoubleClick={(e) => this.handleDbclick(n, [i1, i2], e)}
onClick={e => this.handleclick(n, [i1, i2], e)}
>
<div className="bp3-tree-node-content">
<span className="bp3-tree-node-caret-none bp3-icon-standard"></span>
<span className="bp3-tree-node-label">{n.label}</span>
</div>
</li>
)
})
}
</ul>
</li>
)
})
}
</ul>
</div>
);
}
private handleDbclick = (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement>) =>
{
if (this.props.onNodeDoubleClick)
{
this.props.onNodeDoubleClick(nodeData, _nodePath, e);
e.stopPropagation();
}
}
private handleclick = (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement>) =>
{
if (this.props.onNodeClick)
{
this.props.onNodeClick(nodeData, _nodePath, e);
e.stopPropagation();
}
}
private handleNodeCollapse = (nodeData: ITreeNode) =>
{
if (this.props.onNodeCollapse)
{
this.props.onNodeCollapse(nodeData);
}
};
}

@ -150,3 +150,149 @@
}
}
}
#commonModal .template-design {
width: 40vw;
height: 61vh;
min-width: 768px;
min-height: 590px;
.bp3-dialog-body {
overflow: hidden;
}
.bp3-dialog-body .bp3-label {
margin: 0;
}
.bp3-dialog-body .bp3-label>span {
width: auto;
}
&>.bp3-dialog-body>div:first-child {
input {
width: 100px;
height: 20px;
}
button {
height: 20px;
min-height: 20px;
padding: 2px 8px;
}
}
&>.bp3-dialog-body>div:last-child {
height: 100%;
&>div:first-child {
width: 60%;
}
&>div:last-child {
width: 40%;
}
}
}
@boxShadow: rgba(19, 124, 189, 0) 0px 0px 0px 0px,
rgba(19, 124, 189, 0) 0px 0px 0px 0px,
rgba(16, 22, 26, 0.15) 0px 0px 0px 1px inset,
rgba(16, 22, 26, 0.2) 0px 1px 1px inset;
.params-list {
list-style: none;
padding: 0;
text-align: center;
box-shadow: 1px 0 0 0 rgba(16, 22, 26, 0.15);
flex: 1;
overflow: auto;
&>li {
display: flex;
justify-content: space-between;
height: 25px;
align-items: center;
&>span {
line-height: 25px;
background: rgb(240, 240, 240);
box-shadow: @boxShadow;
}
&>label {
box-shadow: @boxShadow;
}
&>span,
input,
label {
width: 20% !important;
height: 100% !important;
overflow: hidden;
text-overflow: ellipsis;
}
&>input,
label {
background: rgb(255, 255, 224)
}
&>input:focus {
background: #fff;
}
}
}
.action-list {
overflow: auto;
flex: 1;
.bp3-tree-node-content {
height: 20px;
}
}
#modal .action-dialog {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 200px;
height: 200px;
z-index: 35;
display: flex;
flex-direction: column;
box-shadow: 0 0 0 1px rgba(16, 22, 26, 0.15),
0 0 0 rgba(16, 22, 26, 0),
0 0 0 rgba(16, 22, 26, 0);
background-color: #fff;
padding: 10px;
h4 {
font-size: 14px;
}
.bp3-dialog-body {
&>.bp3-label {
display: flex;
width: 100%;
justify-content: space-between;
margin: 5px 0 !important;
&>input,
&>.bp3-html-select {
width: 60%;
}
}
}
.bp3-dialog-footer {
padding: 0;
justify-content: flex-end;
}
}

@ -0,0 +1,353 @@
import { Button, Checkbox, Classes, Dialog, HTMLSelect, Intent, ITreeNode, Label } from '@blueprintjs/core';
import { IObservableValue, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { app } from '../../../ApplicationServices/Application';
import { KeyBoard } from '../../../Common/KeyEnum';
import { TemplateAction } from '../../../DatabaseServices/Template/Action/TemplateAction';
import { TemplateParam } from '../../../DatabaseServices/Template/Param/TemplateParam';
import { CommandWrap } from '../../../Editor/CommandMachine';
import { TempalteEditorStore } from '../../Store/TemplateEditorStore';
import { IActionParam } from './TemplateActionList';
import { INeedUpdateParams } from './TemplateComponent';
import { AppToaster } from '../Toaster';
import { AddStretchAction, AddFilletAction } from '../../../DatabaseServices/Template/TempateUtils';
export enum EEditorActionType
{
Add = 0,
Editor = 1,
AddFillet = 2,
AddParams = 3,
}
export interface ITempalteActionDialogProps
{
store: TempalteEditorStore;
type: EEditorActionType;
open: IObservableValue<boolean>;
currentAction?: TemplateAction;
currentNodePath?: number[];
currentActionInfo?: IActionParam;
}
@observer
export class TempalteActionDialog extends React.Component<ITempalteActionDialogProps> {
@observable pararmConfig: INeedUpdateParams = {
name: "",
value: "",
expr: "",
description: "",
isLock: false
};
private renderDialogBody = () =>
{
if (this.props.type === EEditorActionType.AddParams)
return this.renderParamsDialog();
else
return this.renderActionDialog();
}
private renderActionDialog = () =>
{
const { store, currentActionInfo } = this.props;
const options = store.params.map(par =>
{
return {
label: [par.name, par.value, par.description].join(","),
value: par.name
}
});
const isEditor = this.props.type === EEditorActionType.Editor;
return (
<>
{
!isEditor &&
<Label className={Classes.INLINE}>
<span>:</span>
<HTMLSelect
options={options}
value={currentActionInfo.paramName}
onChange={(e) =>
{
currentActionInfo.paramName = e.target.value;
currentActionInfo.expr = currentActionInfo.paramName;
}}
/>
</Label>
}
<Label className={Classes.INLINE}>
<span>:</span>
<input
autoFocus
className={Classes.INPUT}
value={currentActionInfo.actionName}
onChange={e => currentActionInfo.actionName = e.target.value}
/>
</Label>
<Label className={Classes.INLINE}>
<span>
:
</span>
<input className={Classes.INPUT}
value={currentActionInfo.expr}
onChange={e => currentActionInfo.expr = e.target.value}
/>
</Label>
</>
)
}
private renderParamsDialog = () =>
{
return (
<>
<Label className={Classes.INLINE}>
<span>:</span>
<input
autoFocus
className={Classes.INPUT}
value={this.pararmConfig.name}
onChange={e => this.pararmConfig.name = e.target.value.toUpperCase()}
/>
</Label>
<Label className={Classes.INLINE}>
<span>:</span>
<input
className={Classes.INPUT}
value={this.pararmConfig.value}
onChange={e => this.pararmConfig.value = e.target.value}
/>
</Label>
<Label className={Classes.INLINE}>
<span>:</span>
<input
className={Classes.INPUT}
value={this.pararmConfig.description}
onChange={e => this.pararmConfig.description = e.target.value}
/>
</Label>
<Checkbox
label="设置成锁定参数"
checked={this.pararmConfig.isLock}
onChange={() => this.pararmConfig.isLock = !this.pararmConfig.isLock}
/>
</>
)
}
componentWillUnmount()
{
document.getElementById("modal").focus();
}
public render()
{
let title = "";
switch (this.props.type)
{
case EEditorActionType.Add:
title = "增加动作";
break;
case EEditorActionType.Editor:
title = "编辑动作";
break;
case EEditorActionType.AddFillet:
title = "增加倒角动作";
break;
case EEditorActionType.AddParams:
title = "增加变量";
break;
default:
break;
}
return (
<Dialog
canEscapeKeyClose={true}
canOutsideClickClose={false}
className="action-dialog"
usePortal={false}
isOpen={true}
title={title}
onClose={this.handleCloseDialog}
onOpening={e =>
{
e.onkeydown = e =>
{
if (e.keyCode === KeyBoard.Escape)
this.handleCloseDialog();
e.stopPropagation()
};
}}
>
<div className={Classes.DIALOG_BODY}>
{
this.renderDialogBody()
}
</div>
<div className={Classes.DIALOG_FOOTER}>
<Button
text="确定"
intent={Intent.SUCCESS}
onClick={this.handleClick}
/>
<Button
text="取消"
intent={Intent.DANGER}
onClick={this.handleCloseDialog}
/>
</div>
</Dialog>
);
}
handleClick = async () =>
{
switch (this.props.type)
{
case EEditorActionType.Editor:
this.handleModifyAction();
break;
case EEditorActionType.Add:
this.handleCloseDialog();
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.Clear();
await CommandWrap(async () =>
{
await this.addAction(true);
}, "添加动作");
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.ShowMask();
break;
case EEditorActionType.AddFillet:
this.handleCloseDialog();
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.Clear();
await CommandWrap(async () =>
{
await this.addAction(false);
}, "添加圆角动作");
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.ShowMask();
break;
case EEditorActionType.AddParams:
if (!this.pararmConfig.name)
{
AppToaster.show({
message: "请输入变量名",
timeout: 1500,
intent: Intent.DANGER
});
return;
}
if (this.props.store.usedParamNames.has(this.pararmConfig.name))
{
AppToaster.show({
message: "变量名重复",
timeout: 1500,
intent: Intent.DANGER
});
return;
}
this.handleCloseDialog();
CommandWrap(() =>
{
this.addTemplateParam();
}, "增加变量")
break;
default:
break;
}
}
handleModifyAction = () =>
{
let { currentNodePath, currentAction, currentActionInfo } = this.props;
currentAction.Name = currentActionInfo.actionName;
currentAction.Expr = currentActionInfo.expr;
this.handleCloseDialog();
let nodes = this.props.store.actionNodes;
nodes[currentNodePath[0]].childNodes[currentNodePath[1]].label = this.props.currentActionInfo.actionName + " 表达式:" + this.props.currentActionInfo.expr;
}
private addAction = async (isStretchAction: boolean) =>
{
let act: TemplateAction;
if (isStretchAction)
{
let keyRes = await app.Editor.GetKeyWords({
Msg: "是否使用比例盒子?",
KeyWordList: [
{ key: "1", msg: "是" },
{ key: "2", msg: "否" },
],
Default: "1"
});
act = await AddStretchAction(this.props.store.Template, keyRes.StringResult === "1");
}
else
act = await AddFilletAction(this.props.store.Template);
if (act)
{
let info = this.props.currentActionInfo;
act.Name = info.actionName;
act.Expr = info.expr;
this.handleAddNode(info.paramName, act);
this.addActionToTemplate(info.paramName, act);
this.props.store.actionIndex++;
}
}
private addActionToTemplate = (parName: string, act: TemplateAction) =>
{
const template = this.props.store.Template;
let par = template.GetParam(parName);
par.actions.push(act);
}
private addTemplateParam = () =>
{
const template = this.props.store.Template;
let param = new TemplateParam();
this.pararmConfig.name = this.pararmConfig.name;
param.name = this.pararmConfig.name;
param.value = this.pararmConfig.value;
param.description = this.pararmConfig.description;
template.Params.push(param);
this.props.store.params.push(this.pararmConfig);
this.props.store.usedParamNames.add(param.name);
}
private handleAddNode = (parName: string, act: TemplateAction) =>
{
let nodes = this.props.store.actionNodes;
let node = nodes.find(node => (node.label as string).includes("<" + parName + ">"));
if (nodes.length === 0 || !node)
{
nodes.push({
id: 0,
label: `变量<${parName}>`,
hasCaret: true,
isExpanded: true,
nodeData: { name: parName },
childNodes: [
{
id: 0,
label: act.Name + " 表达式:" + act.Expr,
hasCaret: false,
isExpanded: true,
nodeData: { act },
}
]
})
}
else
node.childNodes.push({
id: node.childNodes.length,
label: act.Name + " 表达式:" + act.Expr,
hasCaret: false,
isExpanded: true,
nodeData: { act },
})
}
handleCloseDialog = () =>
{
this.props.open.set(false);
}
}

@ -0,0 +1,287 @@
import { Button, H5, ITreeNode } from '@blueprintjs/core';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { app } from '../../../ApplicationServices/Application';
import { TemplateAction } from '../../../DatabaseServices/Template/Action/TemplateAction';
import { InitTempateBoardThicknessActions, InitTempateSizeActions, UpdateTempateBoardThicknessAction } from '../../../DatabaseServices/Template/TempateUtils';
import { CommandWrap } from '../../../Editor/CommandMachine';
import { TempalteEditorStore, UNRENDERPARS } from '../../Store/TemplateEditorStore';
import ActionTree from './ActionTree';
import { EEditorActionType, TempalteActionDialog } from './TemplateActionDiglog';
export interface ITempalteActionListProps
{
store: TempalteEditorStore;
}
export interface IActionParam
{
paramName?: string;
actionName: string;
expr: string;
}
@observer
export default class TempalteActionList extends React.Component<ITempalteActionListProps, {}> {
private _tree: HTMLDivElement;
private index: number;
private _currentAction: TemplateAction;
private startEditorAction = observable.box(false);
@observable actionInfo: IActionParam = { actionName: "", expr: "" };
private _currentNodePath: number[];
private _editorActType = EEditorActionType.Editor;
constructor(props)
{
super(props);
}
componentWillMount()
{
this.parseUpdateNodes();
}
componentDidMount()
{
this._tree.addEventListener('click', this.handleCancelSelect);
}
componentWillUnmount()
{
this._tree.removeEventListener('click', this.handleCancelSelect);
}
public render()
{
return (
<div
className="flexCol"
ref={el => this._tree = el}>
<H5></H5>
<ActionTree
className="action-list"
nodes={this.props.store.actionNodes}
onNodeDoubleClick={this.handleDblick}
onNodeClick={this.handleNodeClick}
onNodeCollapse={(node) => this.handleNodeCollapse(node)}
/>
<div>
<Button
text="增加动作"
onClick={() => this.handleAddAction(EEditorActionType.Add)}
/>
<Button
text="增加圆角动作"
onClick={() => this.handleAddAction(EEditorActionType.AddFillet)}
/>
<Button
text="删除动作"
onClick={this.deleteAction}
/>
<Button
text="初始化模板大小动作"
onClick={this.InitAction}
/>
<Button
text="初始化板厚动作"
onClick={this.clickBrThicknessButton}
/>
<Button
text="添加板厚动作"
onClick={this.addBrThicknessButton}
/>
<Button
text="模板大小动作,板厚动作"
onClick={this.autoSetTemplate}
/>
</div>
{
this.startEditorAction.get() &&
<TempalteActionDialog
store={this.props.store}
type={this._editorActType}
open={this.startEditorAction}
currentAction={this._currentAction}
currentActionInfo={this.actionInfo}
currentNodePath={this._currentNodePath}
/>
}
</div>
);
}
private InitAction = () =>
{
InitTempateSizeActions(this.props.store.Template);
this.parseUpdateNodes();
}
private handleCancelSelect = (el: MouseEvent) =>
{
if ((el.target as HTMLElement).classList.contains('bp3-tree'))
{
let nodes = this.props.store.actionNodes;
this.forEachNode(nodes, n => (n.isSelected = false));
this._currentNodePath = undefined;
}
}
private handleDblick = (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
if (!nodeData.hasCaret)
{
let act = nodeData.nodeData["act"] as TemplateAction;
this._currentAction = act;
this._currentNodePath = _nodePath;
this._editorActType = EEditorActionType.Editor;
this.actionInfo.actionName = act.Name;
this.actionInfo.expr = act.Expr.toString();
this.startEditorAction.set(true);
}
}
//展开折叠目录
private handleNodeCollapse = (nodeData: ITreeNode) =>
{
nodeData.isExpanded = !nodeData.isExpanded;
};
//点击目录
private handleNodeClick = async (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
this._currentNodePath = _nodePath;
this.SelectNode(nodeData, e);
};
//选中目录高亮
private SelectNode = (nodeData: ITreeNode, e: React.MouseEvent<HTMLElement> | MouseEvent, isSelected?: boolean) =>
{
const originallySelected = nodeData.isSelected;
let nodes = this.props.store.actionNodes;
if (!e.shiftKey)
{
this.forEachNode(nodes, n => (n.isSelected = false));
}
if (isSelected)
nodeData.isSelected = isSelected;
else
nodeData.isSelected = originallySelected == null ? true : !originallySelected;
}
//去掉其他节点被选择状态
private forEachNode(nodes: ITreeNode[], callback: (node: ITreeNode) => void)
{
if (nodes == null)
return;
for (const node of nodes)
{
callback(node);
this.forEachNode(node.childNodes, callback);
}
}
private parseUpdateNodes = () =>
{
const template = this.props.store.Template;
let params = template.Params;
let newNodes: ITreeNode[] = [];
this.index = 0;
for (let par of params)
{
if (UNRENDERPARS.includes(par.name) || par.actions.length === 0) continue;
let node: ITreeNode = {
id: this.index++,
label: `变量<${par.name}>`,
hasCaret: true,
isExpanded: true,
isSelected: false,
nodeData: { name: par.name },
childNodes: par.actions.map((act, i) =>
{
return {
id: i,
label: act.Name + " 表达式:" + (act.Expr || par.name),
hasCaret: false,
isSelected: false,
nodeData: { act },
}
})
}
newNodes.push(node);
}
observable(this.props.store.actionNodes).replace(newNodes);
}
private handleAddAction = (type: EEditorActionType) =>
{
this._editorActType = type;
const { params, currentParamIndex } = this.props.store;
let par = currentParamIndex ? params[currentParamIndex] : params[0];
this.actionInfo.paramName = par.name;
this.actionInfo.actionName = "动作" + this.props.store.actionIndex;
this.actionInfo.expr = par.name.toString();
this.startEditorAction.set(true);
}
private deleteAction = () =>
{
const template = this.props.store.Template;
let nodes = this.props.store.actionNodes;
if (nodes.length === 0) return;
if (this._currentNodePath === undefined)
{
let node = nodes.shift();
let parName = node.nodeData["name"];
template.GetParam(parName).actions.length = 0;
}
else
{
let targetNodes = nodes;
let lastIndex = this._currentNodePath[0];
let node = nodes[lastIndex];
if (this._currentNodePath.length === 2)
{
lastIndex = this._currentNodePath[1];
targetNodes = node.childNodes;
}
targetNodes.splice(lastIndex, 1);
let parName = node.nodeData["name"];
if (this._currentNodePath.length === 2)
{
template.GetParam(parName).actions.splice(lastIndex, 1);
if (targetNodes.length === 0)
nodes.splice(this._currentNodePath[0], 1);
}
else
{
template.GetParam(parName).actions.length = 0;
}
this._currentNodePath = undefined;
}
}
private clickBrThicknessButton = async () =>
{
let isAuto = confirm("是否自动设置板厚的变化方向");
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.Clear();
await CommandWrap(async () =>
{
await InitTempateBoardThicknessActions(this.props.store.Template, isAuto);
this.parseUpdateNodes();
}, "初始化板厚");
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.ShowMask();
}
private addBrThicknessButton = async () =>
{
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.Clear();
await CommandWrap(async () =>
{
await UpdateTempateBoardThicknessAction(this.props.store.Template);
this.parseUpdateNodes();
}, "添加板厚动作");
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.ShowMask();
}
private autoSetTemplate = async () =>
{
let template = this.props.store.Template;
InitTempateSizeActions(template);
InitTempateBoardThicknessActions(template);
this.parseUpdateNodes();
}
}

@ -2,37 +2,40 @@ import { Button, Classes, Icon, Intent } from '@blueprintjs/core';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Box3, Vector3 } from 'three';
import { Vector3 } from 'three';
import { app } from '../../../ApplicationServices/Application';
import { EBoardKeyList } from '../../../Common/BoardKeyList';
import { TemplateUrls } from '../../../Common/HostUrl';
import { DirectoryId, PostJson, RequestStatus, uploadLogo } from '../../../Common/Request';
import { deflate, GetCurrentViewPreViewImage as GetCurrentViewPreviewImage, inflate, TemplateIn, TemplateOut, TemplateParamsOut } from '../../../Common/SerializeMaterial';
import { DirectoryId, PostJson, RequestStatus } from '../../../Common/Request';
import { inflate, TemplateIn } from '../../../Common/SerializeMaterial';
import { DuplicateRecordCloning } from '../../../Common/Status';
import { Board } from '../../../DatabaseServices/Entity/Board';
import { Entity } from '../../../DatabaseServices/Entity/Entity';
import { PositioningClampSpace } from '../../../DatabaseServices/Template/Positioning/PositioningClampSpace';
import { TemplateRecord } from '../../../DatabaseServices/Template/TemplateRecord';
import { commandMachine, CommandWrap } from '../../../Editor/CommandMachine';
import { JigUtils } from '../../../Editor/JigUtils';
import { PromptStatus } from '../../../Editor/PromptResult';
import { MoveMatrix } from '../../../Geometry/GeUtils';
import { MoveMatrix, ZeroVec } from '../../../Geometry/GeUtils';
import { ClampSpaceParse } from '../../../Geometry/SpaceParse/ClampSpaceParse';
import { PointSelectSpaceClamp } from '../../../Geometry/SpaceParse/PointSelectSpaceClamp';
import { TempalteEditorStore } from '../../Store/TemplateEditorStore';
import { MenuItem } from '../ContextMenu/MenuItem';
import { ModalPosition } from '../Modal/ModalsManage';
import { CommonPanel, IDirectoryProps } from '../SourceManage/CommonPanel';
import { HandleDirComponent } from '../SourceManage/HandleDirComponent';
import { AppToaster } from '../Toaster';
import { GetRoomCabName, IGetRoomInfo } from './GetRoomCabName';
import { TemplateList } from './TemplateList';
import { TempalteEditorStore } from '../../Store/TemplateEditorStore';
import { TemplateEditor } from './TemplateEditor';
import { TempEditor } from '../../../Editor/TempEditor';
export interface INeedUpdateParams
{
name: string;
value: string | number;
description: string;
expr: string | number;
expr?: string | number;
isLock?: boolean;
}
@observer
@ -137,35 +140,14 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore
let template = ens[0].Template.Object as TemplateRecord;
template = template.Root;
template.Name = name;
if (!template)
return;
ens = template.Objects.map(o => o.Object as Entity);
let box = new Box3();
for (let en of ens)
box.union(en.BoundingBox);
let blob = GetCurrentViewPreviewImage(box);
let logo = await uploadLogo(blob);
let json = TemplateOut(template);
let props = TemplateParamsOut(template.Params);
let data = await PostJson(TemplateUrls.create, {
name,
dir_id: currentDir.id,
logo,
props: deflate(props),
file: deflate(json),
zip_type: "gzip",
});
if (data.err_code === RequestStatus.Ok)
{
AppToaster.show({
message: "模板上传成功",
timeout: 1000
});
let status = await this.props.store.UploadTemplate(currentDir.id, template);
if (status)
await callback();
}
}
private handleRenameTemplate = async (name: string) =>
{
@ -220,23 +202,24 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore
app.Editor.MaskManage.ShowMask();
app.Editor.MaskManage.OnFocusEvent();
}
private handleInsertByBasePt = async () =>
private getBasePoint = (brs: Board[], template: TemplateRecord) =>
{
const getBasePoint = (brs: Board[]) =>
{
let br = brs[0] as Board;
template = br.Template.Object as TemplateRecord;
template = template.Root;
br = template.Objects[0].Object as Board;
return new Vector3().setFromMatrixPosition(br.SpaceOCS);
}
let br = brs[0] as Board;
template = br.Template.Object as TemplateRecord;
template = template.Root;
br = template.Objects[0].Object as Board;
return new Vector3().setFromMatrixPosition(br.SpaceOCS);
}
private handleInsertByBasePt = async () =>
{
let template = await this.GetTempalteAndUpdate(true);
if (!template)
return;
let ens = template.Db.ModelSpace.Entitys as Board[];
let nens = ens.map(e => JigUtils.Draw(e));
let pos = getBasePoint(ens);
let pos = new Vector3();
let ptRes = await app.Editor.GetPoint({
Msg: "点取位置",
Callback: (p: Vector3) =>
@ -248,7 +231,7 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore
if (ptRes.Status === PromptStatus.OK)
{
nens = app.Database.WblockCloneObejcts(ens, app.Database.ModelSpace, new Map(), DuplicateRecordCloning.Ignore) as Board[];
pos = getBasePoint(nens);
pos = new Vector3();
nens.forEach(en => en.ApplyMatrix(MoveMatrix(ptRes.Point.clone().sub(pos))));
}
}
@ -266,6 +249,8 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore
let parse = selectSpace.SpaceParse;
let template = await this.GetTempalteAndUpdate();
if (!template)
return;
//临时空间的板件
let ents = template.Objects.map(obj => obj.Object);
//图纸空间的板件
@ -330,6 +315,24 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore
await template.UpdateTemplateTree();
}
}
private handleEditor = async () =>
{
let template = await this.GetTempalteAndUpdate();
if (!template)
return;
TempEditor.Start();
app.Database.hm.lockIndex++;//禁止初始化动作被撤销
await CommandWrap(async () =>
{
let ens = template.Db.ModelSpace.Entitys as Board[];
let nents = app.Database.WblockCloneObejcts(ens, app.Database.ModelSpace, new Map(), DuplicateRecordCloning.Ignore) as Board[];
const store = this.props.store;
store.Template = (nents[0].Template.Object as TemplateRecord).Root;
store.InitParams();
app.Editor.ModalManage.RenderModeless(TemplateEditor, ModalPosition.Center, { store, tid: this.currentTemplateInfo.id });
}, "编辑模板")
}
public render()
{
return (
@ -373,6 +376,7 @@ export class TemplateManage extends React.Component<{ store: TempalteEditorStore
currentProps={this.currentProps}
info={this.currentTemplateInfo}
option={this.option}
editor={this.handleEditor}
/>
{
this.canCreateTemplate.get() && <HandleDirComponent

@ -1,73 +1,168 @@
import { Button, Classes, HTMLSelect, Icon, Label } from '@blueprintjs/core';
import { Button, Classes, Icon, Intent, Label } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import * as React from 'react';
import { app } from '../../../ApplicationServices/Application';
import { KeyBoard } from '../../../Common/KeyEnum';
import { DirectoryId, PostJson, RequestStatus, uploadLogo } from '../../../Common/Request';
import { commandMachine } from '../../../Editor/CommandMachine';
import { TempEditor } from '../../../Editor/TempEditor';
import { TempalteEditorStore } from '../../Store/TemplateEditorStore';
import { BoardModalType } from '../Board/BoardModal';
import { UserConfig } from '../Board/UserConfig';
import TempalteActionList from './TemplateActionList';
import TemplateParamList from './TemplateParamList';
import { TemplateOut, TemplateParamsOut, deflate, GetCurrentViewPreViewImage } from '../../../Common/SerializeMaterial';
import { TemplateUrls } from '../../../Common/HostUrl';
import { AppToaster } from '../Toaster';
import { TemplateSaveDir } from './TemplateSaveDir';
import { Box3 } from 'three';
import { Entity } from '../../../DatabaseServices/Entity/Entity';
export interface ITemplateEditorProps
{
store: TempalteEditorStore;
tid?: string;
}
@observer
export class TemplateEditor extends React.Component<ITemplateEditorProps, any> {
private _container: HTMLDivElement;
componentDidMount()
{
this._container.focus();
this._container.addEventListener('keydown', e =>
{
if (e.keyCode === KeyBoard.Escape)
{
this.handleClose();
e.stopPropagation();
}
});
this.props.store.currentParamIndex = undefined;
}
public render()
{
const template = this.props.store.Template;
return (
<div
className={Classes.DIALOG_CONTAINER}
id="commonModal"
ref={el => this._container = el}
tabIndex={-1}
>
<div className={Classes.DIALOG}>
<div className={Classes.DIALOG + " template-design"}>
<div
className={Classes.DIALOG_HEADER}
data-id="dragArea"
>
<Icon icon="bold" iconSize={18} />
<Icon icon="style" iconSize={18} />
<h4 className="bp3-heading"></h4>
<Button
aria-label="Close"
minimal
icon="cross"
className={Classes.DIALOG_CLOSE_BUTTON}
onClick={() => app.Editor.ModalManage.Clear()}
onClick={this.handleClose}
/>
</div>
<div
className={Classes.DIALOG_BODY}
className={Classes.DIALOG_BODY + " " + Classes.CARD}
>
<div className="flex">
<div>
<Label className={Classes.INLINE}>
<span></span>
<input type="text" className={Classes.INPUT} />
</Label>
<Label className={Classes.INLINE}>
<span></span>
<HTMLSelect />
</Label>
<Label className={Classes.INLINE}>
<span></span>
<input type="text" className={Classes.INPUT} disabled />
<input className={Classes.INPUT}
defaultValue={template.Name}
onChange={e => template.Name = e.target.value}
/>
</Label>
<Button text="选择" />
<Button text="保存" />
</div>
<div>content</div>
<div>editor</div>
<div className="flex">
<TemplateParamList
store={this.props.store}
/>
<TempalteActionList
store={this.props.store}
/>
</div>
</div>
<div className={Classes.DIALOG_FOOTER} >
<UserConfig
type={BoardModalType.TempDes}
store={this.props.store}
/>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button
className={Classes.INTENT_SUCCESS}
text="动态插入"
/>
<Button
className={Classes.INTENT_DANGER}
text="空间拾取"
onClick={() => app.Editor.ModalManage.Clear()}
/>
{
this.props.tid ?
<>
<Button
text="取消"
intent={Intent.DANGER}
onClick={this.handleClose} />
<Button
text="更新"
intent={Intent.SUCCESS}
onClick={this.handleUpdateTemplate}
/>
</> :
<TemplateSaveDir
upload={this.handleUploadTemplate}
/>
}
</div>
</div>
</div>
</div>
);
}
private handleClose = () =>
{
if (this.props.tid)
{
TempEditor.End();
commandMachine.ExecCommand("TEMPLATE");
}
else
app.Editor.ModalManage.Clear();
}
/**
* <> ,
*/
private handleUpdateTemplate = async () =>
{
const store = this.props.store;
await store.WriteParamsToTemplate();
let ens = store.Template.Objects.map(o => o.Object as Entity);
let box = new Box3();
for (let en of ens)
box.union(en.BoundingBox);
let blob = GetCurrentViewPreViewImage(box);
let logo = await uploadLogo(blob);
let json = TemplateOut(store.Template);
let props = TemplateParamsOut(store.Template.Params);
let data = await PostJson(TemplateUrls.update, {
name: store.Template.Name,
module_id: this.props.tid,
props: deflate(props),
file: deflate(json),
logo
});
if (data.err_code === RequestStatus.Ok)
{
AppToaster.show({
message: "更新模板成功",
timeout: 1000
});
}
this.handleClose();
}
private handleUploadTemplate = async (dirid: string) =>
{
await this.props.store.UploadTemplate(dirid || DirectoryId.TemplateDir);
this.handleClose();
}
}

@ -20,6 +20,7 @@ export interface ITemplateListProps
isRename: IObservableValue<boolean>;
info: { id: string, name: string };
option: IGetRoomInfo;
editor: () => void;
}
@observer
@ -135,7 +136,7 @@ export class TemplateList extends React.Component<ITemplateListProps> {
<MenuItem
icon="folder-new"
text="编辑"
// onClick={() => this.startEditorTopline(template)}
onClick={() => this.props.editor()}
/>
<MenuItem
icon="folder-new"

@ -0,0 +1,218 @@
import * as React from 'react';
import { Button, Classes, H5, Intent, Position } from '@blueprintjs/core';
import { TempalteEditorStore } from '../../Store/TemplateEditorStore';
import { observable } from 'mobx';
import { EEditorActionType, TempalteActionDialog } from './TemplateActionDiglog';
import { observer } from 'mobx-react';
import { AppToaster } from '../Toaster';
import { app } from '../../../ApplicationServices/Application';
import { PromptStatus } from '../../../Editor/PromptResult';
import { CommandWrap } from '../../../Editor/CommandMachine';
import { PopoverButton } from '../Common/PopoverButton';
import { arrayRemoveIf } from '../../../Common/ArrayExt';
import { SetTempateCoordinate, UpdateTemplateSizeOffBoards, GetTempateSize } from '../../../DatabaseServices/Template/TempateUtils';
import { FixedNotZero } from '../../../Common/Utils';
import { INeedUpdateParams } from './TemplateComponent';
export interface ITemplateParamListProps
{
store: TempalteEditorStore;
}
@observer
export default class TemplateParamList extends React.Component<ITemplateParamListProps> {
private startAddParam = observable.box(false);
public render()
{
const store = this.props.store;
const { params } = store;
return (
<div className="flexCol">
<H5></H5>
<ul
className={Classes.LIST_UNSTYLED + " params-list"}
onClick={() => store.currentParamIndex = undefined}
>
<li>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</li>
{
params.map((opt, index) =>
{
return (
<li
onClick={(e) =>
{
store.currentParamIndex = index;
e.stopPropagation();
}}
>
<span
style={{
background: store.currentParamIndex === index && "#ccc"
}}
>{opt.name}</span>
<input type="text"
className={Classes.INPUT}
value={opt.value}
onChange={e => opt.value = e.target.value}
onBlur={() => this.updateTempalteParam(opt)}
/>
<input type="text"
className={Classes.INPUT}
value={opt.description}
onChange={e => opt.description = e.target.value}
onBlur={() => this.updateTempalteParam(opt)}
/>
<input type="text"
className={Classes.INPUT}
value={opt.expr}
onChange={e => opt.expr = e.target.value}
onBlur={() => this.updateTempalteParam(opt)}
/>
<label>
<input
type="checkbox"
checked={opt.isLock}
onChange={() => opt.isLock = !opt.isLock}
/>
</label>
</li>
)
})
}
</ul>
<div>
<Button
text="增加变量"
onClick={() => this.startAddParam.set(true)}
/>
<PopoverButton
position={Position.TOP}
message="确定删除变量,以及该变量下的所有动作"
confirmCallback={this.deleteParam}
targetTitle="删除变量"
disabled={this.props.store.currentParamIndex === undefined}
/>
<Button
text="设置变量值"
onClick={() => this.setParamOrCoordinate(true)}
/>
<Button
text="设置模板坐标系"
onClick={() => this.setParamOrCoordinate(false)}
/>
<Button
text="从图纸更新模板大小"
onClick={this.updateSize}
/>
</div>
{
this.startAddParam.get() &&
<TempalteActionDialog
store={this.props.store}
type={EEditorActionType.AddParams}
open={this.startAddParam}
/>
}
</div>
);
}
private deleteParam = () =>
{
const store = this.props.store;
if (store.currentParamIndex === undefined)
{
AppToaster.show({
message: "未选择变量",
timeout: 1500,
intent: Intent.DANGER
});
return;
}
if (store.currentParamIndex <= 2)
{
AppToaster.show({
message: "不能删除默认变量",
timeout: 1500,
intent: Intent.DANGER
});
return;
}
let deletePar = store.params.splice(store.currentParamIndex, 1)[0];
store.usedParamNames.delete(deletePar.name);
store.Template.DeleteParam(deletePar.name);
arrayRemoveIf(store.actionNodes, (node) => node.nodeData["name"] === deletePar.name);
store.currentParamIndex = undefined;
}
private setParamOrCoordinate = async (isSetPar: boolean) =>
{
const store = this.props.store;
if (isSetPar && (store.currentParamIndex === undefined || store.params.length <= store.currentParamIndex))
{
AppToaster.show({
message: "未选择变量",
timeout: 1500,
});
return;
}
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.Clear();
if (isSetPar)
await this.SetParamValue();
else
await CommandWrap(async () =>
{
await this.setCoordinate();
}, "设置模板坐标系");
app.Editor.ModalManage.ToggleShow();
app.Editor.MaskManage.ShowMask();
}
/**
*
*/
private SetParamValue = async () =>
{
let distRes = await app.Editor.GetDistance({
Msg: "点取距离或者输入"
});
if (distRes.Status === PromptStatus.OK)
{
let dist = distRes.Distance;
const store = this.props.store;
store.params[store.currentParamIndex].value = dist.toFixed(2);
store.Template.Params[store.currentParamIndex].value = dist.toFixed(2);
await store.Template.UpdateTemplateTree();
}
}
private setCoordinate = async () =>
{
await SetTempateCoordinate(this.props.store.Template);
this.updateSize();
}
private updateSize = () =>
{
let template = this.props.store.Template;
UpdateTemplateSizeOffBoards(template);
let size = GetTempateSize(template);
let params = this.props.store.params;
params[0].value = FixedNotZero(size.x, 2);
params[1].value = FixedNotZero(size.y, 2);
params[2].value = FixedNotZero(size.z, 2);
}
private updateTempalteParam = (opt: INeedUpdateParams) =>
{
let temp = this.props.store.Template;
let par = temp.GetParam(opt.name);
par.value = opt.value;
par.expr = opt.expr;
par.description = opt.description;
}
}

@ -0,0 +1,72 @@
import * as React from 'react';
import { Popover, Position, Button, Intent, Classes, Card, IconName, MaybeElement, ITreeNode, Tree } from '@blueprintjs/core';
import { PostJson, DirectoryId, RequestStatus } from '../../../Common/Request';
import { DirUrl } from '../../../Common/HostUrl';
interface ITemplateSaveDirProps
{
upload: (dirid: React.ReactText) => void;
}
export class TemplateSaveDir extends React.Component<ITemplateSaveDirProps, { nodes: ITreeNode[] }> {
constructor(props)
{
super(props);
this.state = {
nodes: []
}
}
async componentWillMount()
{
//初始化目录
let data = await PostJson(DirUrl.query, { dir_type: DirectoryId.TemplateDir });
if (data.err_code === RequestStatus.Ok)
this.setState({ nodes: this.parseNodes(data.dirs) })
}
public render()
{
return (
<Popover
content={
<Tree
contents={this.state.nodes}
onNodeClick={this.handleNodeClick}
onNodeCollapse={(node) => this.handleNodeCollapse(node, true)}
onNodeExpand={(node) => this.handleNodeCollapse(node, false)}
className={Classes.ELEVATION_0}
/>
}
target={
<Button
text="保存到"
intent={Intent.SUCCESS}
/>}
/>
);
}
//分析目录转换为ui节点数
private parseNodes = (dirs: any) =>
{
let newNodes: ITreeNode[] = [];
for (let dir of dirs)
{
let node: ITreeNode = {
id: dir.dir_id,
label: dir.dir_name,
icon: "folder-close",
hasCaret: dir.childs.length > 0,
childNodes: this.parseNodes(dir.childs),
};
newNodes.push(node);
}
return newNodes;
}
private handleNodeCollapse = (nodeData: ITreeNode, isCollapse: boolean) =>
{
nodeData.isExpanded = !isCollapse;
this.setState(this.state);
};
private handleNodeClick = async (nodeData: ITreeNode, _nodePath: number[], e: React.MouseEvent<HTMLElement> | MouseEvent) =>
{
await this.props.upload(nodeData.id);
};
}

@ -565,9 +565,6 @@ div {
list-style: none;
padding: 0;
}
.flex-arround{
display: flex;
}
.flex-arround{
.flex();
justify-content: space-around;

@ -1,19 +1,134 @@
import { ITreeNode } from "@blueprintjs/core";
import { observable, toJS } from "mobx";
import { Box3 } from "three";
import { TemplateUrls } from "../../Common/HostUrl";
import { PostJson, RequestStatus, uploadLogo } from "../../Common/Request";
import { deflate, GetCurrentViewPreViewImage, TemplateOut, TemplateParamsOut } from "../../Common/SerializeMaterial";
import { Singleton } from "../../Common/Singleton";
import { Entity } from "../../DatabaseServices/Entity/Entity";
import { TemplateParam } from "../../DatabaseServices/Template/Param/TemplateParam";
import { TemplateRecord, TempateDefaultParamCount } from "../../DatabaseServices/Template/TemplateRecord";
import { IConfigOption } from "../Components/Board/UserConfig";
import { INeedUpdateParams } from "../Components/Template/TemplateComponent";
import { AppToaster } from "../Components/Toaster";
import { IConfigStore } from "./BoardStore";
import { FixedNotZero } from "../../Common/Utils";
export const UNRENDERPARS = ["RX", "RY", "RZ", "PX", "PY", "PZ"];
export class TempalteEditorStore extends Singleton implements IConfigStore
{
cabNameIndex = 0;
Template: TemplateRecord;
@observable params: INeedUpdateParams[] = [];
@observable currentParamIndex: number;
usedParamNames: Set<string> = new Set();
@observable actionNodes: ITreeNode[] = [];
actionIndex = 1;
InitParams()
{
this.usedParamNames.clear();
this.params.length = 0;
this.actionNodes.length = 0;
for (let par of this.Template.Params)
{
this.usedParamNames.add(par.name);
if (!UNRENDERPARS.includes(par.name))
this.params.push({
name: par.name,
value: FixedNotZero(par.value, 2),
description: par.description,
expr: par.expr,
isLock: false
});
}
}
UpdateOption(cof: IConfigOption)
{
let opts = cof.option as INeedUpdateParams[];
this.usedParamNames.clear();
for (let cof of opts)
this.usedParamNames.add(cof.name);
observable(this.params).replace(opts);
//删除模块中的非基本参数
this.Template.Params.length = TempateDefaultParamCount;
for (let par of this.params)
{
let tempPar = this.Template.GetParam(par.name);
if (!tempPar)
{
tempPar = new TemplateParam();
this.Template.Params.push(tempPar);
}
tempPar.value = par.value;
tempPar.expr = par.expr;
tempPar.description = par.description;
}
this.currentParamIndex = undefined;
}
SaveConfig()
{
//新的配置
let newConfig: IConfigOption = {};
newConfig.option = toJS(this.params);
return newConfig;
}
async WriteParamsToTemplate()
{
for (let par of this.params)
{
let tempPar = this.Template.GetParam(par.name);
if (!tempPar)
{
tempPar = new TemplateParam();
this.Template.Params.push(tempPar);
}
tempPar.value = par.value;
tempPar.description = par.description;
tempPar.expr = par.expr;
}
await this.Template.UpdateTemplateTree();
}
/**不传入template,则使用store里面的template */
async UploadTemplate(dirId: string, template?: TemplateRecord)
{
if (!template)
{
template = this.Template;
await this.WriteParamsToTemplate();
}
let ens = template.Objects.map(o => o.Object as Entity);
let box = new Box3();
for (let en of ens)
box.union(en.BoundingBox);
let blob = GetCurrentViewPreViewImage(box);
let logo = await uploadLogo(blob);
let json = TemplateOut(template);
let props = TemplateParamsOut(template.Params);
let data = await PostJson(TemplateUrls.create, {
name: template.Name,
dir_id: dirId,
logo,
props: deflate(props),
file: deflate(json),
zip_type: "gzip",
});
if (data.err_code === RequestStatus.Ok)
{
AppToaster.show({
message: "模板上传成功",
timeout: 1000
});
return true;
}
return false;
}
}

@ -14,6 +14,7 @@ import { DrillStore } from "./DrillStore";
import { IWineRackOption } from "./WineRackInterface";
import { WineRackStore } from "./WineRackStore";
import { appCache } from "../../Common/AppCache";
import { StoreageKeys } from "../../Common/KeyEnum";
type BehindConfigType = { option: BehindBoardOption, processData: BoardProcessOption, grooveData: IGrooveOption };
@ -86,7 +87,7 @@ export class UserConfigStore extends Singleton
message: "初始化配置成功",
timeout: 1000
});
localStorage.setItem("configName_" + type, "默认");
localStorage.setItem(StoreageKeys.ConfigName + type, "默认");
}
}
async InitDrillConfig()
@ -111,7 +112,7 @@ export class UserConfigStore extends Singleton
if (configs)
{
let confNames = [...Object.keys(configs)];
let curName = localStorage.getItem("configName_" + type);
let curName = localStorage.getItem(StoreageKeys.ConfigName + type);
if (!curName)
curName = arrayLast(confNames);
return configs[curName];
@ -190,7 +191,7 @@ export class UserConfigStore extends Singleton
message: isInit ? "初始化配置成功" : "配置保存成功",
timeout: 1000
});
localStorage.setItem("configName_" + type, name);
localStorage.setItem(StoreageKeys.ConfigName + type, name);
this.UpdateUserConfig(type, newConfig);
}
}
@ -227,7 +228,7 @@ export class UserConfigStore extends Singleton
let newName = this.configsNames[0];
this.configName = newName;
await this.UpdateBoardOption(newName, type, store);
localStorage.setItem("configName_" + type, newName);
localStorage.setItem(StoreageKeys.ConfigName + type, newName);
this.UpdateUserConfig(type, configs[newName]);
}
@ -247,7 +248,8 @@ export class UserConfigStore extends Singleton
if (configs && conf)
{
store.UpdateOption(conf);
localStorage.setItem("configName_" + type, k);
if (type !== BoardModalType.TempDes)
localStorage.setItem(StoreageKeys.ConfigName + type, k);
this.UpdateUserConfig(type, conf);
}
}

Loading…
Cancel
Save