From 5ddd1bc9a87c48893aa650172f7e57968474bb03 Mon Sep 17 00:00:00 2001 From: ChenX Date: Thu, 2 Aug 2018 11:42:26 +0800 Subject: [PATCH] =?UTF-8?q?!92=20scale=E5=91=BD=E4=BB=A4,offset=E5=91=BD?= =?UTF-8?q?=E4=BB=A4,GetDistance=E6=9C=8D=E5=8A=A1=E6=9B=B4=E6=96=B0=20Mer?= =?UTF-8?q?ge=20pull=20request=20!92=20from=20ChenX/scale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 20 ++-- package.json | 6 +- src/Add-on/Offset.ts | 150 +++++++++++++++++++++++------- src/Add-on/Scale.ts | 40 ++++++-- src/Common/InputState.ts | 9 +- src/Common/Matrix4Utils.ts | 9 ++ src/DatabaseServices/Circle.ts | 15 ++- src/DatabaseServices/Entity.ts | 30 ++++-- src/Editor/Editor.ts | 7 +- src/Editor/GetDistanceServices.ts | 26 +++++- src/Editor/GetEntityServices.ts | 3 +- src/Editor/GetPointServices.ts | 2 + src/Editor/PromptResult.ts | 11 +++ 13 files changed, 247 insertions(+), 81 deletions(-) diff --git a/package-lock.json b/package-lock.json index ea8d2cbc0..30b9a5ae4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -218,9 +218,9 @@ "dev": true }, "@types/node": { - "version": "10.5.3", - "resolved": "http://r.cnpmjs.org/@types/node/download/@types/node-10.5.3.tgz", - "integrity": "sha1-W8+vCIrReJQjIBKHdmljTAayDMU=", + "version": "10.5.5", + "resolved": "http://r.cnpmjs.org/@types/node/download/@types/node-10.5.5.tgz", + "integrity": "sha1-joTSTols13sNT3PfJ0An4xSewro=", "dev": true }, "@types/range-parser": { @@ -2864,7 +2864,7 @@ }, "detect-indent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "resolved": "http://r.cnpmjs.org/detect-indent/download/detect-indent-5.0.0.tgz", "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", "dev": true }, @@ -5166,9 +5166,9 @@ } }, "hard-source-webpack-plugin": { - "version": "0.11.2", - "resolved": "http://r.cnpmjs.org/hard-source-webpack-plugin/download/hard-source-webpack-plugin-0.11.2.tgz", - "integrity": "sha1-ezHE+RkqMZ37BHQaEFBmmSiQUDo=", + "version": "0.12.0", + "resolved": "http://r.cnpmjs.org/hard-source-webpack-plugin/download/hard-source-webpack-plugin-0.12.0.tgz", + "integrity": "sha1-6iHwQHU4/LYvaZU3FUG6qwpfZ54=", "dev": true, "requires": { "chalk": "^2.4.1", @@ -11155,9 +11155,9 @@ "dev": true }, "three": { - "version": "0.94.0", - "resolved": "http://r.cnpmjs.org/three/download/three-0.94.0.tgz", - "integrity": "sha1-TObbfyv795wtc0RKpuPPwIoy12I=" + "version": "0.95.0", + "resolved": "http://r.cnpmjs.org/three/download/three-0.95.0.tgz", + "integrity": "sha1-tg6gdroX35+rqehVuGqz9UEomr8=" }, "through": { "version": "2.3.8", diff --git a/package.json b/package.json index c99dbf63f..38a3b31c0 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@types/hard-source-webpack-plugin": "^0.9.0", "@types/html-webpack-plugin": "^3.2.0", "@types/jest": "^23.3.0", - "@types/node": "^10.5.3", + "@types/node": "^10.5.5", "@types/react": "^16.4.7", "@types/react-dom": "^16.0.6", "@types/stats.js": "^0.17.0", @@ -39,7 +39,7 @@ "file-loader": "^1.1.11", "fork-ts-checker-webpack-plugin": "^0.4.3", "git-revision-webpack-plugin": "^3.0.3", - "hard-source-webpack-plugin": "^0.11.2", + "hard-source-webpack-plugin": "^0.12.0", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "jest": "^23.4.1", @@ -75,7 +75,7 @@ "react-color": "^2.14.1", "react-dom": "^16.4.1", "stats.js": "^0.17.0", - "three": "^0.94.0", + "three": "^0.95.0", "xaop": "^1.3.2" }, "jest": { diff --git a/src/Add-on/Offset.ts b/src/Add-on/Offset.ts index 79f39b917..2d62f30d5 100644 --- a/src/Add-on/Offset.ts +++ b/src/Add-on/Offset.ts @@ -1,11 +1,16 @@ +import { Vector3 } from 'three'; import { app } from '../ApplicationServices/Application'; import { GetPointAtCurveDir } from '../Common/CurveUtils'; import { Curve } from '../DatabaseServices/Curve'; import { Command } from '../Editor/CommandMachine'; -import { PromptStatus } from '../Editor/PromptResult'; -import { Vector3 } from 'three'; import { Jig } from '../Editor/Jig'; +import { PromptStatus } from '../Editor/PromptResult'; +import { RenderType } from '../GraphicsSystem/Enum'; +//获取偏移距离的返回状态. +type GetOffsetStatus = { Status: PromptStatus, offsetDist?: number }; + +//曲线偏移 export class Command_Offset implements Command { offsetDis: number = 1; @@ -13,59 +18,132 @@ export class Command_Offset implements Command { let disRes = await app.m_Editor.GetDistance({ Msg: "指定偏移距离:", - KeyWordList: [{ msg: "通过", key: "T" }], + KeyWordList: [{ msg: "通过:", key: "T" }], Default: this.offsetDis }); - let dyn = false; - if (disRes.Status === PromptStatus.Keyword && disRes.StringResult === "T") - dyn = true; - else if (disRes.Status != PromptStatus.OK) - return; - else + let isDyn = false;//动态偏移. + if (disRes.StringResult === "T") + isDyn = true; + else if (disRes.Status === PromptStatus.OK) this.offsetDis = disRes.Value; + else + return; while (true) { let enRes = await app.m_Editor.GetEntity({ Msg: "选择要偏移的对象:" }); - if (enRes.Status === PromptStatus.Cancel) - break; - else if (enRes.Status !== PromptStatus.OK) + if (enRes.Status === PromptStatus.OK) + { + } + else if (enRes.Status === PromptStatus.None) continue; + else + break; let cu = enRes.Entity as Curve; if (cu instanceof Curve) { - let ptRes = await app.m_Editor.GetPoint({ - Msg: "指定要偏移的那一侧的点", - Callback: dyn ? (p: Vector3) => - { - Jig.Destroy(); - let dir = GetPointAtCurveDir(cu, p) ? 1 : -1 - cu.GetOffsetCurves(p.distanceTo(cu.GetClosestPointTo(p, false)) * dir) - .forEach(c => Jig.Draw(c)); - } : undefined - }); + app.m_Viewer.m_OutlinePass.selectedObjects = [cu.Draw(RenderType.Wireframe)]; + let state: GetOffsetStatus; + if (isDyn) + state = await this.GetDynOffsetDist(cu); + else + state = await this.GetOffsetDir(cu); Jig.End(); - if (ptRes.Status === PromptStatus.OK) + if (state.Status === PromptStatus.OK) + this.DrawOffset(cu, state.offsetDist); + else if (state.Status === PromptStatus.None) + continue; + else + break; + } + } + }//end exec + + //绘制偏移的对象 + DrawOffset(cu: Curve, offsetDist: number) + { + cu.GetOffsetCurves(offsetDist).forEach(c => + { + app.m_Database.ModelSpace.Append(c); + }); + } + + //单一对象,已经确定偏移距离的时候,用户选择偏移方向. + async GetOffsetDir(cu: Curve): Promise + { + let oldDir = 0; + let ptRes = await app.m_Editor.GetPoint({ + Msg: "指定要偏移的那一侧的点", + Callback: (p: Vector3) => + { + let dir = GetPointAtCurveDir(cu, p) ? 1 : -1; + if (dir !== oldDir) { - let p = ptRes.Value; - let dir = GetPointAtCurveDir(cu, p) ? 1 : -1; - let offCus: Curve[]; - if (dyn) - offCus = cu.GetOffsetCurves(p.distanceTo(cu.GetClosestPointTo(p, false)) * dir); - else - offCus = cu.GetOffsetCurves(this.offsetDis * dir); - offCus.forEach((offCur) => - { - app.m_Database.ModelSpace.Append(offCur); - }) - app.m_Viewer.m_bNeedUpdate = true; + Jig.Destroy(); + let offCus = cu.GetOffsetCurves(this.offsetDis * dir); + offCus.forEach(c => { Jig.Draw(c) }); + oldDir = dir; } + } + }); + let status = { Status: ptRes.Status, offsetDist: 0 }; + if (ptRes.Status === PromptStatus.OK) + { + let dir = GetPointAtCurveDir(cu, ptRes.Value) ? 1 : -1; + status.offsetDist = this.offsetDis * dir; + } + return status; + } + + //动态偏移用户点到哪里偏移到哪里. + async GetDynOffsetDist(cu: Curve): Promise + { + let basePoint: Vector3 = new Vector3(); + + let isMulti = false; + while (true) + { + let dir: number = 0; + let distRes = await app.m_Editor.GetDistance( + { + Msg: "指定通过点或输入偏移距离:", + KeyWordList: [{ key: "D", msg: isMulti ? "单个" : "多个" }], + BasePoint: basePoint, + CalcDistance: (p: Vector3) => + { + basePoint.copy(cu.GetClosestPointTo(p, false)); + dir = GetPointAtCurveDir(cu, p) ? 1 : -1; + return p.distanceTo(basePoint) * dir; + }, + Callback: (dis: number) => + { + Jig.Destroy(); + cu.GetOffsetCurves(dis).forEach(c => Jig.Draw(c)); + } + }); + + if (distRes.Status === PromptStatus.OK) + { + let offsetDist = distRes.Value; + if (dir !== Math.sign(offsetDist)) + offsetDist = -offsetDist; + this.DrawOffset(cu, offsetDist); + + if (isMulti) + continue; else - return; + return { Status: PromptStatus.None, offsetDist: distRes.Value }; + } + else if (distRes.StringResult === "D") + { + isMulti = !isMulti; + app.m_Editor.Prompt(`切换成功,当前<${isMulti ? "多个" : "单个"}>`); } + else + return { Status: distRes.Status, offsetDist: distRes.Value }; } } } diff --git a/src/Add-on/Scale.ts b/src/Add-on/Scale.ts index d66360d99..4d463c5b5 100644 --- a/src/Add-on/Scale.ts +++ b/src/Add-on/Scale.ts @@ -1,6 +1,8 @@ -import { Matrix4 } from "three"; +import { Box3, Vector3 } from "three"; import { app } from "../ApplicationServices/Application"; +import { matrixScale } from "../Common/Matrix4Utils"; import { Command } from "../Editor/CommandMachine"; +import { Jig } from "../Editor/Jig"; import { PromptStatus } from "../Editor/PromptResult"; export class Command_Scale implements Command @@ -16,18 +18,38 @@ export class Command_Scale implements Command if (ptRes.Status != PromptStatus.OK) return; - let scaleRes = await app.m_Editor.GetDistance({ Msg: "请输入缩放比例:" }); + let allBox = new Box3(); + let allEns = ssRes.SelectSet.SelectEntityList; + let jigEns = allEns.map(e => + { + allBox.union(e.BoundingBox); + return Jig.Draw(e) + }); + let maxSize = Math.max(...allBox.getSize(new Vector3()).toArray()) / 2; + + let scaleRes = await app.m_Editor.GetDistance({ + BasePoint: ptRes.Value, + Msg: "请输入缩放比例:", + Callback: (sc) => + { + Jig.Restore(); + let scMat = matrixScale(sc, ptRes.Value); + for (let en of jigEns) + { + en.ApplyMatrix(scMat); + } + }, + CalcDistance: (p) => p.distanceTo(ptRes.Value) / maxSize + }); + + Jig.End(); if (scaleRes.Status != PromptStatus.OK) return; - let scMat4 = new Matrix4(); - let sc = scaleRes.Value; - scMat4.makeScale(sc, sc, sc, ); - scMat4.setPosition(ptRes.Value); - - for (let en of ssRes.SelectSet.SelectEntityList) + let scMat = matrixScale(scaleRes.Value, ptRes.Value); + for (let en of allEns) { - en.ApplyMatrix(scMat4); + en.ApplyMatrix(scMat); } } } diff --git a/src/Common/InputState.ts b/src/Common/InputState.ts index a7f09aa9e..aaf835baa 100644 --- a/src/Common/InputState.ts +++ b/src/Common/InputState.ts @@ -45,7 +45,7 @@ export interface GetPointPrompt extends GetAnyPrompt //基点 BasePoint?: Vector3; //当鼠标移动时,回调该函数. - Callback?: (pt: THREE.Vector3) => void + Callback?: (pt: Vector3) => void; //绘制橡皮筋(必须指定基点) AllowDrawRubberBand?: Boolean; //不显示动态提示 @@ -56,9 +56,10 @@ export interface GetPointPrompt extends GetAnyPrompt export interface GetDistendPrompt extends GetAnyPrompt { - BasePoint?: Vector3 - Callback?: (pt: number) => void - Default?: number + BasePoint?: Vector3; + Callback?: (dist: number, pt?: Vector3) => void; + CalcDistance?: (pt: Vector3) => number; + Default?: number; } export interface GetEntityPrompt extends GetAnyPrompt diff --git a/src/Common/Matrix4Utils.ts b/src/Common/Matrix4Utils.ts index 5f2bd5733..b5947787c 100644 --- a/src/Common/Matrix4Utils.ts +++ b/src/Common/Matrix4Utils.ts @@ -57,3 +57,12 @@ export function matrixIsCoplane(matrixFrom: Matrix4, matrixTo: Matrix4): boolean return equaln(pt.z, 0); } + +//构造缩放矩阵 +export function matrixScale(scale: number, center?: Vector3) +{ + let scaleMat = new Matrix4().makeScale(scale, scale, scale); + if (center) + scaleMat.setPosition(center.clone().multiplyScalar(1 - scale)); + return scaleMat; +} diff --git a/src/DatabaseServices/Circle.ts b/src/DatabaseServices/Circle.ts index 8d8caddc7..f317eb64f 100644 --- a/src/DatabaseServices/Circle.ts +++ b/src/DatabaseServices/Circle.ts @@ -1,12 +1,12 @@ import * as THREE from 'three'; -import { Box3, EllipseCurve, Geometry, Object3D, Vector3, Shape, Quaternion } from 'three'; +import { Box3, EllipseCurve, Geometry, Matrix4, Object3D, Shape, Vector3 } from 'three'; import { arrayLast, arrayRemoveDuplicateBySort } from '../Common/ArrayExt'; import { ColorMaterial } from '../Common/ColorPalette'; import { clamp } from '../Common/Utils'; -import { Arc } from './Arc'; -import { MoveMatrix, angle, equaln, polar } from '../Geometry/GeUtils'; +import { angle, equaln, MoveMatrix, polar } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; import { IntersectCircleAndArc, IntersectCircleAndCircle, IntersectLineAndCircle, IntersectOption, IntersectPolylineAndCurve, reverseIntersectOption } from '../GraphicsSystem/IntersectWith'; +import { Arc } from './Arc'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; import { Curve } from './Curve'; @@ -51,6 +51,15 @@ export class Circle extends Curve this.m_Radius = clamp(v, 1e-9, 1e19); this.Update(); } + + protected ApplyScaleMatrix(m: Matrix4): this + { + this.WriteAllObjectRecord(); + this.Center = this.Center.applyMatrix4(m); + this.Radius = this.Radius * m.getMaxScaleOnAxis(); + return this; + } + //******************** Curve function start*****************// get StartPoint(): Vector3 diff --git a/src/DatabaseServices/Entity.ts b/src/DatabaseServices/Entity.ts index 40f8df73c..7f5ece366 100644 --- a/src/DatabaseServices/Entity.ts +++ b/src/DatabaseServices/Entity.ts @@ -1,13 +1,14 @@ import * as THREE from 'three'; import { Box3, Geometry, Matrix4, Object3D, Vector3 } from 'three'; +import { DisposeThreeObj } from '../Common/Dispose'; import { matrixIsCoplane } from '../Common/Matrix4Utils'; +import { equaln } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; import { IntersectOption } from '../GraphicsSystem/IntersectWith'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; import { CADObject } from './CADObject'; import { ObjectId } from './ObjectId'; -import { DisposeThreeObj } from '../Common/Dispose'; /** * Entity 是所有图元的基类,绘制的实体都集成该类. @@ -238,17 +239,28 @@ export class Entity extends CADObject } /** - * 使用统一的方法设置对象的矩阵. - * 需要对缩放矩形进行重载.避免对象矩阵不是单位矩阵 - * - * @param {Matrix4} m - * @memberof Entity - */ + * 使用统一的方法设置对象的矩阵. + * 需要对缩放矩形进行重载.避免对象矩阵不是单位矩阵 + * + * @param {Matrix4} m + * @memberof Entity + */ ApplyMatrix(m: Matrix4): this { this.WriteAllObjectRecord(); - this.m_Matrix.multiplyMatrices(m, this.m_Matrix); - this.Update(); + if (equaln(m.getMaxScaleOnAxis(), 1)) + { + this.m_Matrix.multiplyMatrices(m, this.m_Matrix); + this.Update(); + } + else + { + this.ApplyScaleMatrix(m); + } + return this; + } + protected ApplyScaleMatrix(m: Matrix4): this + { return this; } diff --git a/src/Editor/Editor.ts b/src/Editor/Editor.ts index 8ed2ec822..d3a820363 100644 --- a/src/Editor/Editor.ts +++ b/src/Editor/Editor.ts @@ -122,11 +122,16 @@ export class Editor return null; } + /** + * 进入用户鼠标交互,提示用户选择一个图元 + * @returns {Promise} Ok:选择到实体 None:点击却没选到 Other:空格和右键 Canel:Esc. + * @memberof Editor + */ GetEntity(prompt?: GetEntityPrompt): Promise { return this.m_GetEntitytServices.Start(prompt); } - async GetSelection(prompt?: GetSelectionPrompt): Promise + GetSelection(prompt?: GetSelectionPrompt): Promise { return this.m_SsgetServices.Start(prompt); } diff --git a/src/Editor/GetDistanceServices.ts b/src/Editor/GetDistanceServices.ts index bc7ba2aa2..d8f547848 100644 --- a/src/Editor/GetDistanceServices.ts +++ b/src/Editor/GetDistanceServices.ts @@ -66,14 +66,21 @@ export class GetDistanceServices dynInput.SetPostion(app.m_Editor.m_MouseCtrl.m_CurMousePointVCS); dynInput.ValuePostion = midp; - dynInput.Value = p1.distanceTo(p); + + if (prompt.CalcDistance) + dynInput.Value = prompt.CalcDistance(p); + else + dynInput.Value = p1.distanceTo(p); if (prompt.Callback) prompt.Callback(dynInput.Value); } }); - if (ptRes.Status == PromptStatus.OK) - this._return(p1.distanceTo(ptRes.Value)); + if (ptRes.Status === PromptStatus.OK) + if (prompt.CalcDistance) + this._return(prompt.CalcDistance(ptRes.Value)) + else + this._return(p1.distanceTo(ptRes.Value)); else if (ptRes.Status === PromptStatus.Keyword) { this._return(ptRes.StringResult); @@ -105,6 +112,13 @@ export class GetDistanceServices this._return(cmd); return; } + else if (cmd === "") + { + if (prompt.Default) + this._return(prompt.Default); + else + this._return(cmd); + } } let v = dynInput.Value; if (!isNaN(v)) @@ -157,11 +171,15 @@ export class GetDistanceServices res.Value = v as number; res.Status = PromptStatus.OK; } - else + else if (v !== "") { res.Status = PromptStatus.Keyword; res.StringResult = v; } + else + { + res.Status = PromptStatus.None; + } let promisResFunc = this.promisResolve; this.promisResolve = undefined; //先将回调函数设置为空,避免对GetPoint取消时重复触发本函数 diff --git a/src/Editor/GetEntityServices.ts b/src/Editor/GetEntityServices.ts index f8ee829d0..918f8f220 100644 --- a/src/Editor/GetEntityServices.ts +++ b/src/Editor/GetEntityServices.ts @@ -1,5 +1,4 @@ -import { begin, end } from 'xaop'; - +import { end } from 'xaop'; import { GetEntityPrompt, InputState } from '../Common/InputState'; import { KeyBoard, MouseKey } from '../Common/KeyEnum'; import { Entity } from '../DatabaseServices/Entity'; diff --git a/src/Editor/GetPointServices.ts b/src/Editor/GetPointServices.ts index a3aa27f3f..3aadcb100 100644 --- a/src/Editor/GetPointServices.ts +++ b/src/Editor/GetPointServices.ts @@ -3,6 +3,7 @@ import { Vector3 } from 'three'; import * as xaop from 'xaop'; import { end } from 'xaop'; import { app } from '../ApplicationServices/Application'; +import { DisposeThreeObj } from '../Common/Dispose'; import { GetPointPrompt, InputState } from '../Common/InputState'; import { KeyBoard, MouseKey } from '../Common/KeyEnum'; import { DynamicInputManage } from '../UI/DynamicPrompt/DynamicInputManage'; @@ -170,6 +171,7 @@ export class GetPointServices implements EditorService this.removeCalls.push( () => { + DisposeThreeObj(line); preView.Scene.remove(line); }, xaop.end(this, this.UpdateCurPointEvent, () => diff --git a/src/Editor/PromptResult.ts b/src/Editor/PromptResult.ts index 9e04bb1d8..e47269af3 100644 --- a/src/Editor/PromptResult.ts +++ b/src/Editor/PromptResult.ts @@ -15,11 +15,22 @@ export enum PromptStatus Error = -2 } +// export enum Errno 未来某一天我们可能需要这个东西 +// { +// Space = 0, +// Enter = 1, +// Esc = 2, +// Left = 3, +// Right = 4, +// } + export class PromptResult { Status: PromptStatus = PromptStatus.None; StringResult?: string; + //当用户选择失败的时候,提供当前选择失败的原因 + // Errno?: Errno; } export class PromptPointResult extends PromptResult