!1669 功能:添加相机控制操作面板(仅在透视相机下显示),模型控制面板

pull/1723/head
我是一条懒汉 3 years ago committed by ChenX
parent 93717dcf02
commit cb1f591b67

@ -1,9 +1,9 @@
import AddAssetHtmlPlugin from "add-asset-html-webpack-plugin";
import CleanTerminalPlugin from "clean-terminal-webpack-plugin";
import HtmlWebPackPlugin from "html-webpack-plugin";
import * as path from 'path';
import * as webpack from 'webpack';
import { outputDir } from "./outputPath";
import CleanTerminalPlugin from "clean-terminal-webpack-plugin";
const WebpackBar = require('webpackbar');
export const buildVersion = new Date().toLocaleString();
@ -80,7 +80,7 @@ const config: webpack.Configuration = {
},
//字体加载 blueprint
{
test: /\.(ttf|eot|svg)$/,
test: /\.(ttf|eot|svg|FBX)$/,
use: {
loader: 'file-loader',
options: { name: 'fonts/[hash].[ext]' }

@ -0,0 +1,63 @@
import { app } from "../ApplicationServices/Application";
import { GetCurrentViewPreViewImage } from "../Common/SerializeMaterial";
import { CameraSnapshootRecord } from "../DatabaseServices/CameraSnapshoot/CameraSnapshootRecord";
import { RestoreCameraSnapshootRecord, SaveCameraSnapshootRecord } from "../DatabaseServices/CameraSnapshoot/CameraSnapshootRecordUtil";
import { Command } from "../Editor/CommandMachine";
import { CameraSnapshootStore } from "../UI/Components/CameraControlButton/CameraState/CameraSnapshootPanel";
//保存相机状态
export class Command_CameraSnapshootSave implements Command
{
Transparency = true;
async exec()
{
const snapshot = GetCurrentViewPreViewImage(true, true) as string;
let record = new CameraSnapshootRecord();
SaveCameraSnapshootRecord(record);
app.Database.CameraSnapshoots.push(record);
CameraSnapshootStore.GetInstance().cameraSnapshootRecords.push({ snapshot, record });
app.Saved = false;
}
}
//保存相机状态(存放到指定的位置)
export class Command_CameraSnapshootSaveIndex implements Command
{
constructor(private _SaveIndex: number) { }
Transparency = true;
async exec()
{
const snapshot = GetCurrentViewPreViewImage(true, true) as string;
let record = new CameraSnapshootRecord();
SaveCameraSnapshootRecord(record);
let store = CameraSnapshootStore.GetInstance();
if (app.Database.CameraSnapshoots.length < this._SaveIndex)
for (let i = app.Database.CameraSnapshoots.length; i < this._SaveIndex; i++)
{
app.Database.CameraSnapshoots.push(record);
CameraSnapshootStore.GetInstance().cameraSnapshootRecords.push({ snapshot, record });
}
else
{
app.Database.CameraSnapshoots[this._SaveIndex] = record;
store.cameraSnapshootRecords[this._SaveIndex] = { snapshot, record };
}
app.Saved = false;
}
}
//还原相机状态
export class Command_CameraSnapshootRestore implements Command
{
constructor(private _Index: number) { }
async exec()
{
let record = app.Database.CameraSnapshoots[this._Index];
if (record)
RestoreCameraSnapshootRecord(record);
}
}

@ -62,6 +62,7 @@ export function Purge(db: Database): void
if (isErase) e.GoodBye();
return isErase;
});
arrayRemoveIf(db.ProcessingGroupTable.Objects, e =>
{
if (!e || e.IsErase) return true;

@ -1,6 +1,6 @@
import md5 from "blueimp-md5";
import jwt_decode from "jwt-decode";
import { DoubleSide, MeshPhongMaterial, MeshPhysicalMaterial, MirroredRepeatWrapping, Texture } from "three";
import { DoubleSide, MeshPhongMaterial, MeshPhysicalMaterial, MirroredRepeatWrapping, RepeatWrapping, Texture, Vector2 } from "three";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
import { CURRENT_HOST } from "../../Common/HostUrl";
import { userConfig } from "../../Editor/UserConfig";
@ -10,6 +10,23 @@ import { LoadImageFromUrl } from "../../Loader/ImageLoader";
export const UE_RES_URL = "http://192.168.1.251";
export const UE_FBX_LOADER = new FBXLoader();
export const USE_WORLD_UV = "USE_WORLD_UV";
export const U_WORLD_REP = "u_w_rep";
export const V_WORLD_REP = "v_w_rep";
export const U_WORLD_MOVE = "u_w_move";
export const V_WORLD_MOVE = "v_w_move";
export const U_WORLD_RO = "v_w_ro";
export const U_REP = "u_rep";
export const V_REP = "v_rep";
export const U_MOVE = "v_move";
export const V_MOVE = "v_move";
export const U_RO = "v_ro";
/**
* ,
* @param path '/Paks/Fbx/Data/ASSETS/DUAA_0004/LOD_DUAA_0004.FBX'
@ -124,9 +141,16 @@ export async function ConverMaterial2(m: MeshPhongMaterial, url: string)
metalness: Math.max(0.2, data.common_metallic),//至少给个比较小的金属性 保证它的反光,否则马桶会变成纯白
opacity: 1,
roughness: data.common_roughness,
bumpScale: 0.0005
bumpScale: 0.0005,
});
if (data.opacity_contrast)
{
mtl.metalness = 0.2;
mtl.transparent = true;
mtl.opacity = 0.5;
}
if (mtl.metalness > 0.8)
LoadMetalEnv().then(env =>
{
@ -144,15 +168,41 @@ export async function ConverMaterial2(m: MeshPhongMaterial, url: string)
if (!texturePath.includes("CT"))
{
let imgUrl = GenerateCdnUrl(`/Paks/Texture/ue_resource/Content${encodeURI(texturePath.substring(5, texturePath.length - 6))}.webp`);
// imgUrl = require("../../textures/UV_Grid_Sm.jpg").default;
let img = await LoadImageFromUrl(imgUrl);
let t = new Texture();
t.image = img;
t.needsUpdate = true;
t.wrapS = MirroredRepeatWrapping;
t.wrapT = MirroredRepeatWrapping;
mtl.map = t;
t.wrapS = RepeatWrapping;
t.wrapT = RepeatWrapping;
mtl.needsUpdate = true;
mtl.map = t;
//世界坐标系UV
mtl[USE_WORLD_UV] = !(data.uv_enable && data.uv_type === 0);
if (mtl[USE_WORLD_UV])
{
mtl[U_WORLD_REP] = data[U_WORLD_REP] ?? 1;
mtl[V_WORLD_REP] = data[V_WORLD_REP] ?? 1;
mtl[U_WORLD_RO] = data[U_WORLD_RO] ?? 0;
mtl[U_WORLD_MOVE] = data[U_WORLD_MOVE] ?? 0;
mtl[V_WORLD_MOVE] = data[V_WORLD_MOVE] ?? 0;
}
else
{
if (data[U_REP])
{
t.repeat.set(data[U_REP], data[V_REP]);
t.rotation = data[U_RO] ?? 0;
t.transformUv(new Vector2(data[U_MOVE] ?? 0, data[V_MOVE] ?? 0));
}
}
}
// else
{

@ -1,6 +1,6 @@
import { Intent } from '@blueprintjs/core';
import hotkeys from 'hotkeys-js-ext';
import { Matrix4, Object3D, PerspectiveCamera, Vector3 } from 'three';
import { MathUtils, Matrix4, Object3D, PerspectiveCamera, Vector3 } from 'three';
import { begin, end } from 'xaop';
import { HardwareCuttingReactor } from '../Add-on/BoardCutting/HardwareCuttingReactor';
import { DrillingReactor } from '../Add-on/DrawDrilling/DrillingReactor';
@ -42,6 +42,12 @@ import { WebSocketClientServer } from './WebSocketClientServer';
export let app: ApplicationService;
export enum CameraRoamType
{
Fly = 0, //飞行
Walk = 1,//漫游
}
/**
* webCAD.
*/
@ -65,6 +71,10 @@ export class ApplicationService
CameraControls: CameraControls;
Gesture: Gesture;
//漫游-飞行
CameraRoamType = CameraRoamType.Fly;
CameraFlySpeed = 3;
private _PerCameraUseSkyBox = false;//在透视相机中使用天空球
constructor()
{
@ -82,7 +92,7 @@ export class ApplicationService
end(this.Viewer.CameraCtrl, this.Viewer.CameraCtrl.UpdateCameraMatrix, () =>
{
if (this.Viewer.CameraControl.CameraType === CameraType.PerspectiveCamera)
this.WebSocket.Send(JSON.stringify({ type: "camera", p: this.Viewer.Camera.position.toArray(), r: [this.Viewer.CameraControl.Orbit.RoX, this.Viewer.CameraControl.Orbit.theta, 0] }));
this.SendCameraPosToRenderer();
});
end(this.Viewer, this.Viewer.OnSize, () =>
@ -299,6 +309,20 @@ export class ApplicationService
}
SendCameraPosToRenderer()
{
//threejs fov = (h/2) / x
//ue fov = (w/2) / x
//所以用下面的代码求ue的fov
let fov = app.Viewer.CameraControl.Fov;
let h = Math.tan(MathUtils.DEG2RAD * fov / 2) * 2;
let w = h * app.Viewer.CameraControl.Aspect;
let b = Math.atan(w / 2);
b = MathUtils.RAD2DEG * b * 2;
app.WebSocket.Send(JSON.stringify({ type: "camera", p: app.Viewer.Camera.position.toArray(), r: [app.Viewer.CameraControl.Orbit.RoX, app.Viewer.CameraControl.Orbit.theta, 0], fov: b, aspect: app.Viewer.CameraControl.Aspect }));
}
get PerCameraUseSkyBox() { return this._PerCameraUseSkyBox; }
set PerCameraUseSkyBox(b: boolean)
{

@ -29,6 +29,9 @@ export enum CommandNames
Sphere = "SPHERE",
SpliteTemplate = "SPLITETEMPLATE",
SwitchCamera = "SWITCHCAMERA",
CameraSnapshootSave = "CAMERASNAPSHOOTSAVE", //保存相机状态
CameraSnapshootSaveIndex = "CAMERASNAPSHOOTSAVEINDEX", //保存相机状态(存放到指定的位置)
CameraSnapshootRestore = "CAMERASNAPSHOOTRESTORE", //还原相机状态
Zoome = "ZOOME",
Erase = "ERASE",
EraseNoSelect = "ERASENOSELECT",

@ -5,15 +5,34 @@ export enum HotkeyList
CA = "Control+A",
CB = "Control+B",
CC = "Control+C",
CD = "Control+D",
CY = "Control+Y",
CV = "Control+V",
CM = "Control+M",
CS = "Control+S",
CZ = "Control+Z",
CP = "Control+P",
CA1 = "Control+Alt+1",
CA2 = "Control+Alt+2",
CA3 = "Control+Alt+3",
CA4 = "Control+Alt+4",
CA5 = "Control+Alt+5",
CA6 = "Control+Alt+6",
CA7 = "Control+Alt+7",
CA8 = "Control+Alt+8",
CA9 = "Control+Alt+9",
CAE = "Control+Alt+E",
CAP = "Control+Alt+P",
CSC = "Control+Shift+C",
A1 = "Alt+1",
A2 = "Alt+2",
A3 = "Alt+3",
A4 = "Alt+4",
A5 = "Alt+5",
A6 = "Alt+6",
A7 = "Alt+7",
A8 = "Alt+8",
A9 = "Alt+9",
AD = "Alt+D",
AS = "Alt+S",
AF = "Alt+F",

@ -14,4 +14,5 @@ export enum ZINDEX
SpeechBox = "27",
CamCtrlBtn = "21",//左上角渲染模式切换按钮
SelectMarquee = "32", //框选ui在模态框下
CameraState = '28', //相机控制,只在漫游显示
}

@ -1,11 +1,11 @@
import { end } from 'xaop';
import { Status } from '../Common/Status';
import { Factory } from './CADFactory';
import { CADFiler } from './CADFiler';
import { Database } from './Database';
import { Entity } from './Entity/Entity';
import { ObjectCollection } from './ObjectCollection';
import { SymbolTableRecord } from './SymbolTableRecord';
import { CADFiler } from './CADFiler';
import { Status } from '../Common/Status';
@Factory
export class BlockTableRecord extends SymbolTableRecord

@ -0,0 +1,34 @@
import { RenderType } from "../../GraphicsSystem/RenderType";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { CADObject } from "../CADObject";
@Factory
export class CameraSnapshootRecord extends CADObject
{
Name: string = "";
_CameraData = new CADFiler;
get RenderType(): RenderType
{
return this._CameraData.Data[7];
}
//#region -------------------------File-------------------------
//对象从文件中读取数据,初始化自身
ReadFile(file: CADFiler)
{
let ver = file.Read();
this._CameraData.Data = file.Read();
this.Name = file.Read();
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(1);
file.Write(this._CameraData.Data);
file.Write(this.Name);
}
//#endregion
}

@ -0,0 +1,25 @@
import { app } from "../../ApplicationServices/Application";
import { userConfig } from "../../Editor/UserConfig";
import { CameraSnapshootRecord } from "./CameraSnapshootRecord";
export function SaveCameraSnapshootRecord(record: CameraSnapshootRecord, name: string = new Date().toLocaleString("chinese", { hour12: false }))
{
record.WriteAllObjectRecord();
record._CameraData.Clear();
record._CameraData.Write(1);
app.Viewer.CameraCtrl.WriteFile(record._CameraData);
record._CameraData.Write(app.Editor.UCSMatrix.toArray());
record._CameraData.Write(userConfig._renderType);
record.Name = name;
}
export function RestoreCameraSnapshootRecord(record: CameraSnapshootRecord)
{
record._CameraData.Reset();
let ver = record._CameraData.Read();
app.Viewer.CameraCtrl.ReadFile(record._CameraData);
app.Editor.UCSMatrix.fromArray(record._CameraData.Read());
app.Editor.UCSMatrix = app.Editor.UCSMatrix;
userConfig.RenderType = record._CameraData.Read();
app.Viewer.UpdateRender();
}

@ -6,6 +6,7 @@ import { BlockTableRecord } from './BlockTableRecord';
import { Factory } from './CADFactory';
import { CADFiler } from './CADFiler';
import { CADObject } from './CADObject';
import { CameraSnapshootRecord } from './CameraSnapshoot/CameraSnapshootRecord';
import { DeepCloneFiler } from './DeepCloneFiler';
import { Entity } from './Entity/Entity';
import { GroupTable } from './GroupTable';
@ -47,6 +48,9 @@ export class Database
LayoutSpace: BlockTableRecord;
Lights: BlockTableRecord;
//相机快照记录
CameraSnapshoots: CameraSnapshootRecord[] = [];
AmbientLight: AmbientLight;
SunLight: DirectionalLight;
HemisphereLight: HemisphereLight;
@ -135,6 +139,7 @@ export class Database
this.Lights.Destroy();
this.ProcessingGroupTable.Destroy();
this.hm.Destroy();
this.CameraSnapshoots.length = 0;
this.hm.historyRecord.length = 0;
this.idIndex = 1;
@ -154,7 +159,7 @@ export class Database
FileWrite(file = new CADFiler): CADFiler
{
file.Write(6);//ver;
file.Write(7);//ver;
file.Write(this.idIndex);
this.ModelSpace.WriteFile(file);
this.TextureTable.WriteFile(file);
@ -167,6 +172,10 @@ export class Database
this.LayoutSpace.WriteFile(file);
file.Write(this.CameraSnapshoots.length);
for (let r of this.CameraSnapshoots)
r.WriteFile(file);
return file;
}
FileRead(file: CADFiler)
@ -206,6 +215,18 @@ export class Database
if (ver > 5)
this.LayoutSpace.ReadFile(file);
if (ver > 6)
{
let count = file.Read();
this.CameraSnapshoots.length = 0;
for (let i = 0; i < count; i++)
{
let r = new CameraSnapshootRecord;
r.ReadFile(file);
this.CameraSnapshoots.push(r);
}
}
this.SettingDefaultMaterial();
this.hm.doing = false;

@ -536,6 +536,10 @@ export class Entity extends CADObject
{
}
static _xa = new Vector3;
static _ya = new Vector3;
static _za = new Vector3;
/**
* 使.
* .
@ -544,15 +548,16 @@ export class Entity extends CADObject
{
this.WriteAllObjectRecord();
if (equaln(m.getMaxScaleOnAxis(), 1))
m.extractBasis(Entity._xa, Entity._ya, Entity._za);
if (
equaln(Entity._xa.lengthSq(), 1, 1e-4) &&
equaln(Entity._ya.lengthSq(), 1, 1e-4) &&
equaln(Entity._za.lengthSq(), 1, 1e-4)
)
{
let xA = new Vector3();
let yA = new Vector3();
let zA = new Vector3();
m.extractBasis(xA, yA, zA);
this._Matrix.multiplyMatrices(m, this._Matrix);
this._SpaceOCS.multiplyMatrices(m, this._SpaceOCS);
if (!equalv3(xA.clone().cross(yA).normalize(), zA))
if (!equalv3(Entity._xa.cross(Entity._ya).normalize(), Entity._za))
this.ApplyMirrorMatrix(m);
else
this.Update(UpdateDraw.Matrix);

@ -1,15 +1,17 @@
import { Box3, Matrix3, Mesh, MeshPhongMaterial, MeshPhysicalMaterial, Object3D, Vector3 } from "three";
import { Box3, Matrix3, Matrix4, Mesh, MeshPhongMaterial, MeshPhysicalMaterial, Object3D, Vector3 } from "three";
import { ConverMaterial2, ParseBoxUrl, ParseFBXUrl, UE_FBX_LOADER } from "../../Add-on/testEntity/ParseMaterialImage";
import { BoxLine } from "../../Add-on/testEntity/TestBoundaryBox";
import { ColorMaterial } from "../../Common/ColorPalette";
import { DisposeThreeObj, Object3DRemoveAll } from "../../Common/Dispose";
import { ObjectSnapMode } from "../../Editor/ObjectSnapMode";
import { equalv3 } from "../../Geometry/GeUtils";
import { RenderType } from "../../GraphicsSystem/RenderType";
import { IndexedDbStore, StoreName } from "../../IndexedDb/IndexedDbStore";
import { Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler";
import { GetBoxGeoBufferGeometry } from "./BoxSolid";
import { Entity } from "./Entity";
import { GenUVForWorld } from "./GenUVForWorld";
const TempBox = new Box3;
@ -20,6 +22,11 @@ const TempBox = new Box3;
export class EntityRef extends Entity
{
OnlyRenderType = true;
private _Size = new Vector3;//原始尺寸
private _ScaleSize = new Vector3;//缩放后的尺寸
private _Center = new Vector3;//盒子中心
// `/Data/ASSETS/DXAA_0001`
constructor(private _url?: string)
{
@ -28,34 +35,106 @@ export class EntityRef extends Entity
get Url() { return this._url; }
get CurSize() { return this.ScaleSize.x ? this.ScaleSize.clone() : this._Size.clone(); }
get ScaleSize() { return this._ScaleSize; }
set ScaleSize(size: Vector3)
{
if (!equalv3(size, this._ScaleSize))
{
this.WriteAllObjectRecord();
this._ScaleSize.copy(size);
this.Update();
}
}
ApplyScaleMatrix(m: Matrix4)
{
this.WriteAllObjectRecord();
let p = this.Position;
p.applyMatrix4(m);
m.extractBasis(Entity._xa, Entity._ya, Entity._za);
let scaleX = Entity._xa.length();
let scaleY = Entity._ya.length();
let scaleZ = Entity._za.length();
if (!this._ScaleSize.x) this._ScaleSize.copy(this._Size);
this._ScaleSize.x *= scaleX;
this._ScaleSize.y *= scaleY;
this._ScaleSize.z *= scaleZ;
Entity._xa.normalize();
Entity._ya.normalize();
Entity._za.normalize();
m = new Matrix4().makeBasis(Entity._xa, Entity._ya, Entity._za);
this.ApplyMatrix(m);
this.Position = p;
this.Update();
return this;
}
// //与网络相关,如果模型没请求下来 这个盒子数据也是错误的()
// // if (this._Size.x)//我们使用缓存的数据直接求盒子? 这样是不行的 因为旋转后的盒子似乎不对!
// // {
// // let size2 = (this._ScaleSize.x ? this._ScaleSize : this._Size).clone().multiplyScalar(0.5);
// // return new Box3(this._Center.clone().sub(size2), size2.add(this._Center));
// // }
//#region Draw
InitDrawObject(renderType: RenderType = RenderType.Wireframe)
{
let dObj = new Object3D();
let boxurl = ParseBoxUrl(this._url);
let boxUrl = ParseBoxUrl(this._url);
let fbxloaded = false;
let mesh = new Mesh(GetBoxGeoBufferGeometry(), ColorMaterial.GetConceptualMaterial(8));
mesh.position.set(0, 0, 150);
mesh.scale.set(300, 300, 300);
mesh.updateMatrix();
dObj.add(mesh);
mesh.updateMatrixWorld(false);//保证更新位置
fetch(boxurl).then(async (res) =>
let boxPromise: Promise<boolean>;
//显示预览盒子,顺便请求模型的原始尺寸,以便我们开图就能有预览效果
if (this._Size.x)
{
let buff = await res.arrayBuffer();
if (fbxloaded || res.status !== 200) return;
let dataview = new DataView(buff);
TempBox.min.set(dataview.getFloat32(0, true) * 10, dataview.getFloat32(4, true) * 10, dataview.getFloat32(8, true) * 10);
TempBox.max.set(dataview.getFloat32(12, true) * 10, dataview.getFloat32(16, true) * 10, dataview.getFloat32(20, true) * 10);
TempBox.getSize(mesh.scale);
TempBox.getCenter(mesh.position);
mesh.updateMatrixWorld(false);//保证更新位置
this.AsyncUpdated();//保证更新视图
});
mesh.scale.copy(this._ScaleSize.x ? this._ScaleSize : this._Size);
mesh.position.copy(this._Center);
}
else
{
mesh.position.set(0, 0, 150);
mesh.scale.set(300, 300, 300);
boxPromise = new Promise(async (res, rej) =>
{
let rp = await fetch(boxUrl);
let buff = await rp.arrayBuffer();
if (fbxloaded || rp.status !== 200)
{
res(false);
return;
};
let dataview = new DataView(buff);
TempBox.min.set(dataview.getFloat32(0, true) * 10, dataview.getFloat32(4, true) * 10, dataview.getFloat32(8, true) * 10);
TempBox.max.set(dataview.getFloat32(12, true) * 10, dataview.getFloat32(16, true) * 10, dataview.getFloat32(20, true) * 10);
TempBox.getSize(mesh.scale);
TempBox.getCenter(mesh.position);
this._Size.copy(mesh.scale);
this._Center.copy(mesh.position);
mesh.updateMatrixWorld(false);//保证更新位置
this.AsyncUpdated();//保证更新视图
res(true);
});
}
mesh.updateMatrix();
mesh.updateMatrixWorld(false);//保证更新位置
dObj.add(mesh);
IndexedDbStore.CADStore().then(async store =>
{
@ -69,9 +148,10 @@ export class EntityRef extends Entity
store.Put(StoreName.FBX, this.Url, array);
}
// let fbxUrl = require("./LOD_DEAA_0055.FBX").default;
// let res = await fetch(fbxUrl);
// array = await res.arrayBuffer();
let newObject = UE_FBX_LOADER.parse(array, UE_FBX_LOADER.path);
newObject.scale.set(10, 10, 10);//UE4缩放10 如果按米为单位的缩放1000
newObject.updateMatrix();//保证更新缩放
fbxloaded = true;
DisposeThreeObj(dObj);
@ -87,10 +167,15 @@ export class EntityRef extends Entity
return p;
};
let gen = new GenUVForWorld;
newObject.traverse(async o =>
{
if (o instanceof Mesh)
{
o.geometry["IsMesh"] = true;
o.castShadow = true;
o.receiveShadow = true;
@ -99,17 +184,53 @@ export class EntityRef extends Entity
else
o.material = await GenMaterial(o.material);
gen.GenUV(o);
this.AsyncUpdated();//保证更新视图
}
});
dObj.add(newObject);
if (boxPromise)
{
let ok = await boxPromise;
if (!ok)//如果请求不到盒子的数据 那么我们就用模型的原始数据读取盒子
{
let box = this.BoundingBox;
box.getSize(this._Size).multiplyScalar(10);//这个时候我们还没更新矩阵 所以乘以10
box.getCenter(this._Center).multiplyScalar(10);
}
}
//缩放尺寸(如果用户指定了这个缩放 我们就缩放它)
if (this._ScaleSize.x)
newObject.scale.copy(this._ScaleSize).divide(this._Size).multiplyScalar(10);
else
newObject.scale.set(10, 10, 10);//UE4缩放10 如果按米为单位的缩放1000
newObject.updateMatrix();//保证更新缩放
newObject.updateMatrixWorld(false);//保证更新位置
this.AsyncUpdated();//保证更新视图
});
return dObj;
}
UpdateDrawObject(type: RenderType, obj: Object3D)
{
let newObject = obj.children[0];
//缩放尺寸(如果用户指定了这个缩放 我们就缩放它)
if (this._ScaleSize.x && this._Size.x)
newObject.scale.copy(this._ScaleSize).divide(this._Size).multiplyScalar(10);
else
newObject.scale.set(10, 10, 10);//UE4缩放10 如果按米为单位的缩放1000
newObject.updateMatrix();//保证更新缩放
newObject.updateMatrixWorld(false);//保证更新位置
}
GetObjectSnapPoints(
snapMode: ObjectSnapMode,
pickPoint: Vector3,
@ -186,9 +307,6 @@ export class EntityRef extends Entity
this.Position = this.Position.add(vec);
}
}
UpdateDrawObject(type: RenderType, obj: Object3D)
{
}
//#endregion
//#region -------------------------File-------------------------
@ -199,13 +317,40 @@ export class EntityRef extends Entity
let ver = file.Read();
super._ReadFile(file);
this._url = file.Read();
if (ver > 1)
{
this._Size.x = file.Read();
this._Size.y = file.Read();
this._Size.z = file.Read();
this._Center.x = file.Read();
this._Center.y = file.Read();
this._Center.z = file.Read();
this._ScaleSize.x = file.Read();
this._ScaleSize.y = file.Read();
this._ScaleSize.z = file.Read();
}
}
//对象将自身数据写入到文件.
WriteFile(file: CADFiler)
{
file.Write(1);
file.Write(2);
super.WriteFile(file);
file.Write(this._url);
file.Write(this._Size.x);
file.Write(this._Size.y);
file.Write(this._Size.z);
file.Write(this._Center.x);
file.Write(this._Center.y);
file.Write(this._Center.z);
file.Write(this._ScaleSize.x);
file.Write(this._ScaleSize.y);
file.Write(this._ScaleSize.z);
}
//#endregion
}

@ -0,0 +1,135 @@
import { Box3, BufferAttribute, BufferGeometry, Material, Matrix4, Mesh, Vector3 } from "three";
import { USE_WORLD_UV, U_WORLD_MOVE, U_WORLD_REP, V_WORLD_MOVE, V_WORLD_REP } from "../../Add-on/testEntity/ParseMaterialImage";
import { XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZAxisN } from "../../Geometry/GeUtils";
import { Orbit } from "../../Geometry/Orbit";
const DIRS = [XAxis, YAxis, ZAxis, XAxisN, YAxisN, ZAxisN];
function GetFaceDir(direction: Vector3): Vector3
{
let absx = Math.abs(direction.x);
let absy = Math.abs(direction.y);
let absz = Math.abs(direction.z);
let face = - 1.0;
if (absx > absz)
{
if (absx > absy)
face = direction.x > 0 ? 0 : 3;
else
face = direction.y > 0 ? 1 : 4;
}
else
{
if (absz > absy)
face = direction.z > 0 ? 2 : 5;
else
face = direction.y > 0 ? 1 : 4;
}
return DIRS[face];
}
export class GenUVForWorld
{
InvMtxMap = new Map<Vector3, Matrix4>();
private _Z = new Vector3;
private _X = new Vector3;
private _Y = new Vector3;
private _Box = new Box3;
private _Box2 = new Box3;
GetMtxInv(normalX: number, normalY: number, normalZ: number)
{
this._Z.set(normalX, normalY, normalZ);
let n = GetFaceDir(this._Z);
let mtx = this.InvMtxMap.get(n);
if (mtx)
return mtx;
this._Z.copy(n);
Orbit.ComputUpDirection(this._Z, this._Y, this._X);
mtx = new Matrix4().makeBasis(this._X, this._Y, this._Z);
mtx.getInverse(mtx);
this.InvMtxMap.set(n, mtx);
return mtx;
}
GenUV(mesh: Mesh<BufferGeometry, Material[]>)
{
if (Array.isArray(mesh.material))
{
let geo = mesh.geometry;
if (!geo.boundingBox)
geo.computeBoundingBox();
let normals = geo.getAttribute("normal") as BufferAttribute;
let pos = geo.getAttribute("position") as BufferAttribute;
let uvs = geo.getAttribute("uv") as BufferAttribute;
for (let i = 0; i < mesh.material.length; i++)
{
let mtl = mesh.material[i];
if (mtl[USE_WORLD_UV])
{
this._Box.makeEmpty();
let g = mesh.geometry.groups[i];
for (let y = 0; y < g.count; y++)
{
let index = (y + g.start) * 3;
this._X.set(pos.array[index], pos.array[index + 1], pos.array[index + 2]);
this._Box.expandByPoint(this._X);
}
for (let y = 0; y < g.count; y++)
{
let index = (y + g.start) * 3;
let mtx = this.GetMtxInv(normals.array[index], normals.array[index + 1], normals.array[index + 2]);
this._X.set(pos.array[index], pos.array[index + 1], pos.array[index + 2]);
this._X.applyMatrix4(mtx);
this._Box2.copy(this._Box).applyMatrix4(mtx);
//@ts-ignore
uvs.array[(y + g.start) * 2] = (((this._X.x - (this._Box2.min.x + this._Box2.max.x) * 0.5)) * 1e-2 + mtl[U_WORLD_MOVE]) * mtl[U_WORLD_REP] + 0.5;
//@ts-ignore
uvs.array[(y + g.start) * 2 + 1] = (((this._X.y - (this._Box2.min.y + this._Box2.max.y) * 0.5)) * 1e-2 - mtl[V_WORLD_MOVE]) * mtl[V_WORLD_REP] + 0.5;
}
uvs.needsUpdate = true;
}
}
}
else
{
let mtl = mesh.material;
if (mtl[USE_WORLD_UV])
{
let geo = mesh.geometry;
if (!geo.boundingBox)
geo.computeBoundingBox();
let normals = geo.getAttribute("normal") as BufferAttribute;
let pos = geo.getAttribute("position") as BufferAttribute;
let uvs = geo.getAttribute("uv") as BufferAttribute;
for (let y = 0; y < pos.count; y++)
{
let index = y * 3;
let mtx = this.GetMtxInv(normals.array[index], normals.array[index + 1], normals.array[index + 2]);
this._X.set(pos.array[index], pos.array[index + 1], pos.array[index + 2]);
this._X.applyMatrix4(mtx);
this._Box.copy(geo.boundingBox);
this._Box.applyMatrix4(mtx);
//@ts-ignore
uvs.array[y * 2] = (((this._X.x - (this._Box.min.x + this._Box.max.x) * 0.5)) * 1e-2 + mtl[U_WORLD_MOVE]) * mtl[U_WORLD_REP] + 0.5;
//@ts-ignore
uvs.array[y * 2 + 1] = (((this._X.y - (this._Box.min.y + this._Box.max.y) * 0.5)) * 1e-2 + mtl[V_WORLD_MOVE]) * mtl[V_WORLD_REP] + 0.5;
}
uvs.needsUpdate = true;
}
}
}
}

@ -10,6 +10,12 @@ export class ObjectCollection<T extends CADObject> extends CADObject
{
Objects: T[] = [];
Destroy()
{
super.Destroy();
this.Objects.length = 0;
}
/**
* @param object
* @param isCheckObjectCleanly ,,.
@ -82,7 +88,6 @@ export class ObjectCollection<T extends CADObject> extends CADObject
this.Objects.length = 0;
super.ReadFile(file);
let cout = file.Read();
this.Objects = [];
for (let i = 0; i < cout; i++)
{
let obj = file.ReadObject() as T;

@ -24,6 +24,7 @@ import { UpdateBoardInfos } from "../Add-on/BoardEditor/UpdateBoardInfos";
import { BoardFindModify } from "../Add-on/BoardFindModify";
import { IntersectionOperation, SubsractOperation, UnionOperation } from "../Add-on/BoolOperation";
import { Command_Break } from "../Add-on/Break";
import { Command_CameraSnapshootRestore, Command_CameraSnapshootSave, Command_CameraSnapshootSaveIndex } from "../Add-on/CameraSnapshootCMD";
import { ChangeColor } from "../Add-on/ChangeColor";
import { ChangeColorByMaterial } from "../Add-on/ChangeColorByBoardMaterial";
import { CheckHoles } from "../Add-on/CheckHoles";
@ -307,6 +308,14 @@ export function registerCommand()
commandMachine.RegisterCommand("fl", new DrawFloor());
commandMachine.RegisterCommand(CommandNames.SwitchCamera, new Command_SwitchCamera());
commandMachine.RegisterCommand(CommandNames.CameraSnapshootSave, new Command_CameraSnapshootSave());
//保存和读取相机状态
for (let i = 1; i <= 9; i++)
{
commandMachine.RegisterCommand(CommandNames.CameraSnapshootSaveIndex + "-" + i, new Command_CameraSnapshootSaveIndex(i));
commandMachine.RegisterCommand(CommandNames.CameraSnapshootRestore + "-" + i, new Command_CameraSnapshootRestore(i));
}
commandMachine.RegisterCommand(CommandNames.Erase, new Command_Erase());
commandMachine.RegisterCommand("deletecurve", new DeleteCurve());
commandMachine.RegisterCommand("EraseLineArc", new Command_EraseLineAndArc());

@ -5,6 +5,7 @@ import { InputState } from '../Common/InputState';
import { Entity } from '../DatabaseServices/Entity/Entity';
import { angle } from '../Geometry/GeUtils';
import { Orbit } from '../Geometry/Orbit';
import CameraStateManage from '../UI/Components/CameraControlButton/CameraState/CameraStateManage';
import { CommandInputManage } from '../UI/Components/CommandInput/CommandInputManage';
import { MaskManage } from '../UI/Components/Modal/MaskManage';
import { ModalManage } from '../UI/Components/Modal/ModalsManage';
@ -47,6 +48,7 @@ export class Editor
ModalManage: ModalManage;
CommandInput: CommandInputManage;
SsgetServices: SsgetServiecs;
CameraState: CameraStateManage;
KeywordsServices: GetKeyWordsServices;
ContextMenuServices: ContextMenuServices;
@ -83,6 +85,7 @@ export class Editor
this.MaskManage = new MaskManage();
this.ModalManage = new ModalManage(this);
this.CommandInput = new CommandInputManage();
this.CameraState = new CameraStateManage();
// new SpeechBoxManage();
this.InteractiveServices = [

@ -44,12 +44,14 @@ export class CameraUpdate
//观察的轨道.
private _Orbit: Orbit = new Orbit();
DisableRotate = false;
constructor()
{
this._CameraArray.set(OrthographicCamera, new OrthographicCamera(-2, 2, 2, -2,
-ViewScopeSize, ViewScopeSize));
this._CameraArray.set(PerspectiveCamera, new PerspectiveCamera(50, 1, 0.01, ViewScopeSize));
this._CameraArray.set(PerspectiveCamera, new PerspectiveCamera(60, 1, 0.01, ViewScopeSize));
this._CurCamera = this._CameraArray.get(OrthographicCamera);
@ -102,6 +104,18 @@ export class CameraUpdate
return this._Height;
}
get Fov()
{
return (this._CameraArray.get(PerspectiveCamera) as PerspectiveCamera).fov;
}
set Fov(fov: number)
{
let camera = this._CameraArray.get(PerspectiveCamera) as PerspectiveCamera;
camera.fov = fov;
this.UpdateCameraMatrix();
}
/**
* .
* @param {Vector3} mouseMove
@ -122,6 +136,8 @@ export class CameraUpdate
this._Orbit.theta -= mouseMove.x * scale;
if (this.CameraType === CameraType.PerspectiveCamera && !target)//转头
{
if (this.DisableRotate) return;
this._Orbit.UpdateDirection(this._Direction);
this.UpdateUp();

@ -4,7 +4,7 @@ import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { begin, end } from 'xaop';
import { app } from '../ApplicationServices/Application';
import { app, CameraRoamType } from '../ApplicationServices/Application';
import { arrayRemoveOnce } from '../Common/ArrayExt';
import { ColorMaterial } from '../Common/ColorPalette';
import { DisposeThreeObj, Object3DRemoveAll } from '../Common/Dispose';
@ -21,7 +21,7 @@ import { ViewportEntity } from '../DatabaseServices/ViewportEntity';
import { CameraControlState } from '../Editor/CameraControls';
import { GenerateRaycaster } from '../Editor/PointPick';
import { userConfig } from '../Editor/UserConfig';
import { GetBox, GetBoxArr, isIntersect, isPerpendicularityTo, ZeroVec } from '../Geometry/GeUtils';
import { GetBox, GetBoxArr, isIntersect, isPerpendicularityTo, ZAxis, ZeroVec } from '../Geometry/GeUtils';
import { PlaneExt } from '../Geometry/Plane';
import { DownPanelStore } from '../UI/Store/DownPanelStore';
import { LightStore } from '../UI/Store/RightPanelStore/LightStore';
@ -266,13 +266,14 @@ export class Viewer
this.UpdateRender();
};
private _TempMove = new Vector3;
StartRender = () =>
{
requestAnimationFrame(this.StartRender);
if (this.CameraControl.CameraType === CameraType.PerspectiveCamera && app.CameraControls.State === CameraControlState.Rotate)
{
let move = new Vector3;
let move = this._TempMove.set(0, 0, 0);
let left = hotkeys.isPressed(KeyBoard.ArrowLeft) || hotkeys.isPressed(KeyBoard.KeyA);
let right = hotkeys.isPressed(KeyBoard.ArrowRight) || hotkeys.isPressed(KeyBoard.KeyD);
let up = hotkeys.isPressed(KeyBoard.ArrowUp) || hotkeys.isPressed(KeyBoard.KeyW);
@ -281,28 +282,50 @@ export class Viewer
let q = hotkeys.isPressed(KeyBoard.KeyQ);
let e = hotkeys.isPressed(KeyBoard.KeyE);
let speed = app.CameraFlySpeed * 10;
if (left) move.x -= 30;
if (right) move.x += 30;
if (up) move.z -= 30;
if (down) move.z += 30;
if (left) move.x -= speed;
if (right) move.x += speed;
if (up) move.z -= speed;
if (down) move.z += speed;
if (q) { this.Camera.position.z -= 30; this.CameraControl.Target.z -= 30; }
if (e) { this.Camera.position.z += 30; this.CameraControl.Target.z += 30; }
if (q) { this.Camera.position.z -= speed; this.CameraControl.Target.z -= speed; }
if (e) { this.Camera.position.z += speed; this.CameraControl.Target.z += speed; }
if (move.x || move.y || move.z || q || e)
{
if (hotkeys.shift) move.multiplyScalar(2);
if (app.CameraRoamType === CameraRoamType.Walk)
{
let forward = move.z;
let right = move.x;
move.set(0, 0, 0);
let dir = this.CameraControl.Direction.setZ(0).normalize();
if (forward)
move.copy(dir).multiplyScalar(-forward);
if (right)
{
dir.crossVectors(ZAxis, dir);
move.add(dir.multiplyScalar(-right));
}
}
else
{
move.applyQuaternion(this.Camera.quaternion);
}
this.NeedUpdate = true;
move.applyQuaternion(this.Camera.quaternion);
this.Camera.position.add(move);
this.CameraControl.Target.add(move);
this.CameraControl.UpdateCameraMatrix();
}
}
if (this.Scene && this.NeedUpdate && !this.DisableRenderer)
if (this.Scene && this.NeedUpdate)
{
this.Render();
this.NeedUpdate = false;
@ -321,6 +344,8 @@ export class Viewer
this._NeedUpdateEnts.clear();
if (this.DisableRenderer) return;
if (this.isLayout)
{
this.Renderer.clear();
@ -382,6 +407,7 @@ export class Viewer
for (let le of app.Database.Lights.Entitys)
this._RenderSelectScene.children.push(le.DrawObject);
this._RenderSelectScene.background = this.Scene.background;
this.Renderer.render(this._RenderSelectScene, this.Camera);
}
else
@ -602,6 +628,7 @@ export class Viewer
}
return [...ents];
}
//延时加载布局空间或者模型空间
private LazyRenderDatabase: () => void;
//TODO: 假设现在只渲染一个数据层.不渲染多个.
@ -743,29 +770,11 @@ export class Viewer
en.GoodBye();
});
begin(userConfig, userConfig.SetRenderTypeEvent, async () =>
begin(userConfig, userConfig.SetRenderTypeEvent, () =>
{
let i = 0;
let down = DownPanelStore.GetInstance() as DownPanelStore;
down.progress = 0.1;
for (let index = 0; index < db.ModelSpace.Entitys.length; index++)
{
let en = db.ModelSpace.Entitys[index];
if (en.Visible)
{
en.UpdateRenderType(userConfig.RenderType);
i++;
if (i === 50)
{
down.progress = 0.1 + index / db.ModelSpace.Entitys.length;
await Sleep(1);
i = 0;
}
}
}
down.progress = 1;
this.UpdateRender();
this.UpdateRenderType(db, userConfig._renderType);
});
begin(db, db.FileRead, () =>
{
//在文件读取的开始去销毁这些,而不是文件读取后,避免贴图被销毁
@ -790,6 +799,33 @@ export class Viewer
en.GoodBye();
});
}
async UpdateRenderType(db: Database, type: RenderType)
{
let i = 0;
let down = DownPanelStore.GetInstance() as DownPanelStore;
down.progress = 0.1;
for (let index = 0; index < db.ModelSpace.Entitys.length; index++)
{
let en = db.ModelSpace.Entitys[index];
if (en.Visible)
{
en.UpdateRenderType(type);
i++;
if (i === 50)
{
down.progress = 0.1 + index / db.ModelSpace.Entitys.length;
await Sleep(1);
i = 0;
}
}
}
down.progress = 1;
this.UpdateRender();
}
SwitchLayout()
{
this.Renderer.autoClear = !this.isLayout;

@ -129,7 +129,7 @@ export class WebRtcRenderer
this.webRtcPlayerObj.createOffer();
this.webRtcPlayerObj.video.play();
app.WebSocket.Send(JSON.stringify({ type: "camera", p: app.Viewer.Camera.position.toArray(), r: [app.Viewer.CameraControl.Orbit.RoX, app.Viewer.CameraControl.Orbit.theta, 0] }));
app.SendCameraPosToRenderer();
app.WebSocket.Send(JSON.stringify({ type: "ResSize", w: app.Viewer.Width, h: app.Viewer.Height }));
app.Viewer.DisableRenderer = true;

@ -0,0 +1,183 @@
import { Button, Icon, Label, NumericInput, Popover, Position, Radio, RadioGroup, Slider, Switch, Tooltip } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { app, CameraRoamType } from '../../../../ApplicationServices/Application';
import { CameraType } from '../../../../GraphicsSystem/CameraUpdate';
import CameraSettingStore, { CameraMode } from './CameraSettingStore';
import { CameraSettingIcon } from './CameraState';
@observer
export default class CameraSetting extends Component
{
CameraSettingStore: CameraSettingStore = CameraSettingStore.GetSingleInstance();
AlterCameraVision = (deg: number): void =>
{
this.CameraSettingStore.cameraFov = deg;
app.Viewer.CameraControl.Fov = deg;
app.Editor.UpdateScreen();
};
render()
{
const { CameraSettingStore } = this;
return (
<Popover
onOpening={() =>
{
CameraSettingStore.cameraType = app.Viewer.CameraControl.CameraType;
}}
interactionKind='click'
placement={Position.TOP}
minimal
content={
<div className='CameraSettingPanel'>
<div className='CameraSettingItem'>
<Label></Label>
<Switch size={30} disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
onChange={(): void =>
{
CameraSettingStore.isCameraRotateLock = !CameraSettingStore.isCameraRotateLock;
app.Viewer.CameraControl.DisableRotate = CameraSettingStore.isCameraRotateLock;
}} />
</div>
<div className='CameraSettingItem'>
<Label></Label>
<RadioGroup selectedValue={CameraSettingStore.cameraType} inline
onChange={(e: React.FormEvent<HTMLInputElement>) =>
{
CameraSettingStore.cameraType = (parseInt((e.target as HTMLInputElement).value));
app.Viewer.CameraCtrl.CameraType = CameraSettingStore.cameraType;
}} >
<Radio value={CameraType.PerspectiveCamera} label='透视' />
<Radio value={CameraType.OrthographicCamera} label='正交' />
</RadioGroup>
</div>
<div className='CameraSettingItem'>
<Label></Label>
<RadioGroup selectedValue={CameraSettingStore.cameraMode} inline
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
onChange={(e: React.FormEvent<HTMLInputElement>) =>
{
CameraSettingStore.cameraMode = (e.target as HTMLInputElement).value as CameraMode;
app.CameraRoamType = CameraSettingStore.cameraMode === "飞行" ? CameraRoamType.Fly : CameraRoamType.Walk;
}} >
<Radio value={CameraMode.walk} label='行走' />
<Radio value={CameraMode.fly} label='飞行' />
</RadioGroup>
</div>
<div className='CameraSettingItem'>
<Label></Label>
<div>
<Slider
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
max={5000}
min={0}
value={CameraSettingStore.cameraAltitude > 5000 ? 5000 : CameraSettingStore.cameraAltitude}
onChange={(e) =>
{
CameraSettingStore.cameraAltitude = e;
let dif = app.Viewer.Camera.position.z - e;
app.Viewer.Camera.position.z = e;
app.Viewer.CameraControl.Target.z -= dif;
app.Viewer.CameraControl.UpdateCameraMatrix();
app.Editor.UpdateScreen();
}} />
<NumericInput style={{ fontSize: '12px' }} value={CameraSettingStore.cameraAltitude}
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
onValueChange={(e) =>
{
if (e < 0) return;
CameraSettingStore.cameraAltitude = e;
}}
/>
</div>
</div>
<div className='CameraSettingItem'>
<Label></Label>
<div>
<div className='CameraVison'>
<Slider
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
value={CameraSettingStore.cameraFov < 30 ? 30 : CameraSettingStore.cameraFov}
max={120}
min={30}
onChange={(e: number) =>
{
if (e <= 35) e = 30;
if (e >= 55 && e <= 65) e = 60;
if (e >= 115) e = 120;
this.AlterCameraVision(e);
}}
/>
<div className='VisionMarker'
onClick={() => { this.AlterCameraVision(30); }}
>
<Icon icon='caret-up' />
</div>
<div className='VisionMarker'
onClick={() => { this.AlterCameraVision(60); }}
>
<Icon icon='caret-up' />
</div>
<div className='VisionMarker'
onClick={() => { this.AlterCameraVision(120); }}
>
<Icon icon='caret-up' />
广
</div>
</div>
<NumericInput allowNumericCharactersOnly={false}
value={CameraSettingStore.cameraFov}
min={0}
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
onValueChange={(e) =>
{
if (e === NaN) return;
if (e > 120) return;
this.AlterCameraVision(e);
}}
/>
</div>
</div>
<div className='CameraSettingItem'>
<Label></Label>
<div>
<Slider
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
max={5}
min={1}
value={CameraSettingStore.walkSpeed}
onChange={(e) =>
{
CameraSettingStore.walkSpeed = e;
app.CameraFlySpeed = e;
}} />
<NumericInput
max={5}
min={1}
allowNumericCharactersOnly={true}
disabled={app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera}
value={CameraSettingStore.walkSpeed} onValueChange={(e) =>
{
if (e > 5 || e < 1) return;
CameraSettingStore.walkSpeed = e;
app.CameraFlySpeed = e;
}} />
</div>
</div>
</div>
}
>
<Tooltip content='相机设置' minimal>
<Button
icon={<CameraSettingIcon subIcon='cog' />}
minimal
small
/>
</Tooltip>
</Popover>
);
}
}

@ -0,0 +1,71 @@
import { observable } from "mobx";
import { end } from "xaop";
import { app, CameraRoamType } from "../../../../ApplicationServices/Application";
import { CameraType } from "../../../../GraphicsSystem/CameraUpdate";
export enum CameraView
{
orthographic = '正交相机',
perspective = '透视相机',
}
export enum CameraMode
{
fly = '飞行',
walk = '行走',
}
export default class CameraSettingStore
{
/**
* @description
*/
@observable isCameraRotateLock: boolean = false;
/**
* @description
*/
@observable cameraAltitude: number = 0;
/**
* @description
*/
@observable cameraFov: number = 60;
/**
* @description
*/
@observable cameraType: CameraType = CameraType.PerspectiveCamera;
/**
* @description
*/
@observable cameraMode: CameraMode = CameraMode.walk;
/**
* @description
*/
@observable walkSpeed: number = 3;
private static _SingleInstance: CameraSettingStore;
static GetSingleInstance = (): CameraSettingStore =>
{
if (this._SingleInstance) return this._SingleInstance;
this._SingleInstance = new CameraSettingStore();
return this._SingleInstance;
};
private constructor()
{
this.cameraMode = app.CameraRoamType === CameraRoamType.Fly ? CameraMode.fly : CameraMode.walk;
this.cameraType = app.Viewer.CameraControl.CameraType;
end(app.Viewer.CameraControl, app.Viewer.CameraControl.SwitchCamera, () =>
{
this.cameraType = app.Viewer.CameraControl.CameraType;
});
end(app.Viewer.CameraControl, app.Viewer.CameraControl.UpdateCameraMatrix, () =>
{
this.cameraAltitude = app.Viewer.Camera.position.z;
});
end(app, app.OpenFile, () =>
{
this.cameraAltitude = app.Viewer.Camera.position.z;
});
}
}

@ -0,0 +1,216 @@
import { Button, EditableText, Icon, Intent, Popover, Position, Tooltip } from '@blueprintjs/core';
import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { end } from 'xaop';
import { app } from '../../../../ApplicationServices/Application';
import { GetCurrentViewPreViewImage } from '../../../../Common/SerializeMaterial';
import { CameraSnapshootRecord } from '../../../../DatabaseServices/CameraSnapshoot/CameraSnapshootRecord';
import { RestoreCameraSnapshootRecord, SaveCameraSnapshootRecord } from '../../../../DatabaseServices/CameraSnapshoot/CameraSnapshootRecordUtil';
import { userConfig } from '../../../../Editor/UserConfig';
import { equaln } from '../../../../Geometry/GeUtils';
import { RenderType } from '../../../../GraphicsSystem/RenderType';
import { AppToaster } from '../../Toaster';
import { CameraSettingIcon } from './CameraState';
declare interface CameraVison
{
snapshot: string; //base64
record: CameraSnapshootRecord;//记录
visionName?: string; //这个视图的名字,如果有的话
}
export class CameraSnapshootStore
{
@observable cameraSnapshootRecords: CameraVison[] = [];
private constructor()
{
let db = app.Database;
end(db, db.FileRead, () =>
{
action(() =>
{
this._Inited = false;
this.cameraSnapshootRecords.length = 0;
for (let record of db.CameraSnapshoots)
this.cameraSnapshootRecords.push({ snapshot: "", record, visionName: record.Name });
})();
});
}
private static _SingleInstance: CameraSnapshootStore;
static GetInstance(): CameraSnapshootStore
{
if (this._SingleInstance) return this._SingleInstance;
this._SingleInstance = new CameraSnapshootStore;
return this._SingleInstance;
}
private _Inited = false;
//初始化 如果有的话
async InitSnapshootImg()
{
if (this._Inited) return;
this._Inited = true;
let record = new CameraSnapshootRecord;
SaveCameraSnapshootRecord(record);
let map = new Map<RenderType, CameraVison[]>();
for (let r of this.cameraSnapshootRecords)
{
if (!r.snapshot)
{
let type = r.record.RenderType;
if (type === userConfig.RenderType)
{
RestoreCameraSnapshootRecord(r.record);
r.snapshot = GetCurrentViewPreViewImage(true, true) as string;
}
else
{
let arr = map.get(type);
if (!arr)
{
arr = [];
map.set(type, arr);
}
arr.push(r);
}
}
}
for (let [type, arr] of map)
{
await app.Viewer.UpdateRenderType(app.Database, type);
for (let r of arr)
{
RestoreCameraSnapshootRecord(r.record);
r.snapshot = GetCurrentViewPreViewImage(true, true) as string;
}
}
RestoreCameraSnapshootRecord(record);
}
}
@observer
export default class CameraSnapshootPanel extends Component<{}, {}>
{
store = CameraSnapshootStore.GetInstance();
GetCanvasSnapshot = (): void =>
{
const snapshot = GetCurrentViewPreViewImage(true, true) as string;
const total = (arr: number[]) => (arr.reduce((prev, curr) => prev + curr));
let record = new CameraSnapshootRecord();
SaveCameraSnapshootRecord(record);
for (let r of app.Database.CameraSnapshoots)
{
if (equaln(total(r._CameraData.Data.flat()), total(record._CameraData.Data.flat())))
{
AppToaster.show({
message: "该相机视角已保存",
timeout: 2000,
intent: Intent.WARNING,
});
return;
}
}
app.Database.CameraSnapshoots.push(record);
this.store.cameraSnapshootRecords.push({ snapshot, record, visionName: new Date().toLocaleString('chinese', { hour12: false }) });
app.Saved = false;
AppToaster.show({
message: "相机视角保存成功",
timeout: 2000,
intent: Intent.SUCCESS,
});
};
SetCameraVision = (record: CameraSnapshootRecord): void =>
{
RestoreCameraSnapshootRecord(record);
};
render()
{
let store = CameraSnapshootStore.GetInstance();
return (
<Popover
interactionKind='click'
position={Position.TOP}
minimal
onOpened={() =>
{
CameraSnapshootStore.GetInstance().InitSnapshootImg();
}}
content={
<div className='SaveCameraVision' >
<Button small minimal
icon='refresh'
onClick={() =>
{
//刷新按钮.
}}
/>
<div className='SaveCamera' onClick={this.GetCanvasSnapshot}>
<Icon icon='plus' />
</div>
{store.cameraSnapshootRecords.map((v: CameraVison, index) =>
{
return (
<div className='CameraVison' onClick={() => { this.SetCameraVision(v.record); }}>
<img alt={index + "snapshot"} src={v.snapshot} draggable={false} />
<Button
icon='trash'
intent={Intent.DANGER}
small minimal
onClick={(e: React.MouseEvent) =>
{
e.stopPropagation();
store.cameraSnapshootRecords.splice(index, 1);
app.Database.CameraSnapshoots.splice(index, 1);
app.Saved = false;
}}
/>
<div className='VisionName'
onClick={(e) =>
{
e.stopPropagation();
}}>
<EditableText
onChange={(e) =>
{
v.visionName = e;
}}
onConfirm={(e: string) =>
{
event.stopPropagation();
if (!e) return;
SaveCameraSnapshootRecord(app.Database.CameraSnapshoots[index], e);
app.Saved = false;
}}
value={v.visionName}
/>
</div>
<div className='VisionIndex'>
{index + 1}
</div>
</div>
);
})}
</div>
}
>
<Tooltip content='保存视角' minimal>
<Button
icon={<CameraSettingIcon subIcon='new-layers' />}
minimal
small
/>
</Tooltip>
</Popover>
);
}
}

@ -0,0 +1,259 @@
.CameraState
{
// width : 200px;
height : 40px;
position : absolute;
background-color: rgba(245, 248, 250, .9);
bottom : 10px;
right : 10px;
box-sizing : border-box;
padding : 10px;
display : flex;
justify-content : space-around;
align-items : center;
border-radius : 5px;
.BtnContainer
{
position : relative;
width : 30px;
height : 24px;
display : flex;
align-items : center;
justify-content: center;
flex-direction : column
}
.CameraSettingIcon
{
.BtnContainer();
>span
{
position: absolute;
}
>span:nth-child(1)
{
transform: rotate(180deg);
}
>span:nth-child(2)
{
left : 15px;
top : 10px;
// color: #CED9E0;
color: #293743;
}
}
.ResetCamera
{
width : 44px;
height: 24px;
>span
{
margin-top: 2px !important;
}
}
}
.CameraSettingPanel
{
width : 300px;
display : flex;
flex-direction : column;
box-sizing : border-box;
padding : 25px;
.CameraSettingItem
{
display : flex;
justify-content: space-between;
align-items : center;
.bp3-label{
font-size : 14px;
font-weight: bold;
color : #4e5257;
}
.bp3-radio
{
font-weight : bold;
color : #4e5257;
margin-right: 10px;
}
&:nth-child(4),&:nth-child(5),&:nth-child(6)
{
flex-direction: column;
align-items : flex-start;
>div
{
width : 100%;
box-sizing : border-box;
display : flex;
justify-content: space-between;
.bp3-input
{
width: 45px;
}
.bp3-button-group
{
height: 30px;
>button
{
width : 15px !important;
min-width: 10px;
}
}
.bp3-slider
{
min-width: 180px;
width : 10px;
.bp3-slider-handle
{
transform : scale(80%);
border-radius: 25px;
}
.bp3-slider-axis
{
display: none;
}
.bp3-slider-label
{
display: none;
}
}
}
}
&:nth-child(4)
{
.bp3-slider
{
margin-top: 8px;
}
.bp3-label
{
margin-bottom: 5px;
}
}
&:nth-child(6)
{
margin-top: 30px;
.bp3-slider
{
margin-top: 8px;
}
.bp3-label
{
margin-bottom: 5px;
}
}
.CameraVison
{
position: relative;
.VisionMarker
{
position : absolute;
display : flex;
flex-direction: column;
top : 20px;
user-select : none;
color : #4e5257;
font-weight : bold;
cursor : pointer;
&:hover
{
color: #1374bd;
}
&:nth-child(2)
{
left: -5px;
}
&:nth-child(3)
{
left: 54px;
}
&:nth-child(4)
{
width : 24px;
height: 31px;
top : 19px;
left : 170px;
}
}
}
}
}
.SaveCameraVision
{
box-sizing: border-box;
padding : 10px;
display : flex;
flex-wrap : wrap;
>button
{
align-self : flex-start;
margin-right: 10px;
}
.SaveCamera
{
box-sizing : border-box;
display : flex;
flex-direction : column;
justify-content: center;
align-items : center;
padding : 30px;
border : 1px dashed lightgray;
margin-right : 5px;
border-radius : 5px;
user-select : none;
cursor : pointer;
}
.CameraVison
{
position: relative;
>img
{
border : 1px solid #1374bd;
border-radius: 5px;
margin-right : 5px;
width : 134px;
height : 93px;
}
& >button:nth-child(2)
{
position: absolute;
top : 5px;
right : 10px;
}
.VisionName
{
position : absolute;
bottom : 5px;
left : 0;
width : 134px;
display : flex;
justify-content: center;
box-shadow : 0 -10px 5px rgba(1, 1, 1, .5) inset;
border-radius : 0 0 5px 5px;
.bp3-editable-text
{
text-align : center;
color : white;
font-weight : bold;
input
{
color : black;
}
}
}
.VisionIndex
{
position : absolute;
width : 20px;
height : 20px;
top : 5px;
left : 5px;
color : white;
font-weight : bold;
font-size : 14px;
// box-shadow : 0 0 10px rgba(255, 255, 255, .7) inset;
border-radius: 100%;
text-align : center;
line-height : 20px;
}
}
}

@ -0,0 +1,71 @@
import { Button, FocusStyleManager, Icon, IconName, Tooltip } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { app } from '../../../../ApplicationServices/Application';
import { GetBox } from '../../../../Geometry/GeUtils';
import { CameraType } from '../../../../GraphicsSystem/CameraUpdate';
import ModifyModelStore from '../../ToolBar/ModifyModel/ModifyModelStore';
import CameraSetting from './CameraSetting';
import CameraSnapshootPanel from './CameraSnapshootPanel';
import './CameraState.less';
@observer
export default class CameraState extends Component
{
ModifyModelStore: ModifyModelStore = ModifyModelStore.GetSingleInstance();
ResetCameraVisoin = async () =>
{
//重置视图
if (app.Viewer.CameraCtrl.CameraType === CameraType.OrthographicCamera)
app.Viewer.ZoomAll();
else
{
//尝试移动到中心
let box = GetBox(app.Viewer.Scene, true);
if (!box.isEmpty())
{
app.Viewer.CameraControl.Target.sub(app.Viewer.Camera.position);
box.getCenter(app.Viewer.Camera.position);
app.Viewer.CameraControl.Target.add(app.Viewer.Camera.position);
app.Viewer.CameraControl.UpdateCameraMatrix();
}
}
app.Viewer.UpdateRender();
};
componentDidMount()
{
FocusStyleManager.onlyShowFocusOnTabs();
}
render()
{
return (
<div className='CameraState'>
<CameraSnapshootPanel />
<CameraSetting />
<Tooltip content='重置视图' minimal>
<Button
className='ResetCamera'
icon={<Icon icon='fullscreen' size={14} />}
minimal
small
onClick={() =>
{
this.ResetCameraVisoin();
}}
/>
</Tooltip>
</div>
);
}
}
export function CameraSettingIcon(props: { subIcon: IconName; }): JSX.Element
{
return (
<div className='CameraSettingIcon'>
<Icon icon='mobile-video' size={20} />
<Icon icon={props.subIcon} size={12} />
</div>
);
}

@ -0,0 +1,21 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { ZINDEX } from '../../../../Common/ZIndex';
import CameraState from './CameraState';
export default class CameraStateManage
{
private _CameraStateContainer: HTMLElement;
constructor()
{
this._CameraStateContainer = document.createElement('div');
this._CameraStateContainer.id = 'CameraState';
this._CameraStateContainer.style.zIndex = ZINDEX.CameraState;
document.getElementById('Webgl').appendChild(this._CameraStateContainer);
}
RenderCameraState()
{
ReactDOM.render(<CameraState />, this._CameraStateContainer);
}
}

@ -1114,6 +1114,15 @@ export const CommandList: ICommand[] = [
chName: "爆炸图",
chDes: "爆炸图效果",
},
{
typeId: "view",
link: `#`,
defaultCustom: "ZE",
command: CommandNames.Zoome,
type: "视图",
chName: "缩放全部视图",
chDes: "缩放全部视图",
},
{
icon: IconEnum.Camera,
typeId: "view",
@ -1128,11 +1137,192 @@ export const CommandList: ICommand[] = [
{
typeId: "view",
link: `#`,
defaultCustom: "ZE",
command: CommandNames.Zoome,
defaultCustom: CommandNames.CameraSnapshootSave,
command: CommandNames.CameraSnapshootSave,
defaultHotkeys: HotkeyList.CD,
type: "视图",
chName: "缩放全部视图",
chDes: "缩放全部视图",
chName: "保存相机状态",
chDes: "保存相机状态",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-1",
command: CommandNames.CameraSnapshootSaveIndex + "-1",
defaultHotkeys: HotkeyList.CA1,
type: "视图",
chName: "保存相机状态一",
chDes: "保存相机状态(存放到相机一)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-2",
command: CommandNames.CameraSnapshootSaveIndex + "-2",
defaultHotkeys: HotkeyList.CA2,
type: "视图",
chName: "保存相机状态二",
chDes: "保存相机状态(存放到相机二)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-3",
command: CommandNames.CameraSnapshootSaveIndex + "-3",
defaultHotkeys: HotkeyList.CA3,
type: "视图",
chName: "保存相机状态三",
chDes: "保存相机状态(存放到相机三)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-4",
command: CommandNames.CameraSnapshootSaveIndex + "-4",
defaultHotkeys: HotkeyList.CA4,
type: "视图",
chName: "保存相机状态四",
chDes: "保存相机状态(存放到相机四)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-5",
command: CommandNames.CameraSnapshootSaveIndex + "-5",
defaultHotkeys: HotkeyList.CA5,
type: "视图",
chName: "保存相机状态五",
chDes: "保存相机状态(存放到相机五)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-6",
command: CommandNames.CameraSnapshootSaveIndex + "-6",
defaultHotkeys: HotkeyList.CA6,
type: "视图",
chName: "保存相机状态六",
chDes: "保存相机状态(存放到相机六)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-7",
command: CommandNames.CameraSnapshootSaveIndex + "-7",
defaultHotkeys: HotkeyList.CA7,
type: "视图",
chName: "保存相机状态七",
chDes: "保存相机状态(存放到相机七)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-8",
command: CommandNames.CameraSnapshootSaveIndex + "-8",
defaultHotkeys: HotkeyList.CA8,
type: "视图",
chName: "保存相机状态八",
chDes: "保存相机状态(存放到相机八)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootSaveIndex + "-9",
command: CommandNames.CameraSnapshootSaveIndex + "-9",
defaultHotkeys: HotkeyList.CA9,
type: "视图",
chName: "保存相机状态九",
chDes: "保存相机状态(存放到相机九)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-1",
command: CommandNames.CameraSnapshootRestore + "-1",
defaultHotkeys: HotkeyList.A1,
type: "视图",
chName: "还原相机状态一",
chDes: "还原相机状态(保存的相机状态一)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-2",
command: CommandNames.CameraSnapshootRestore + "-2",
defaultHotkeys: HotkeyList.A2,
type: "视图",
chName: "还原相机状态二",
chDes: "还原相机状态(保存的相机状态二)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-3",
command: CommandNames.CameraSnapshootRestore + "-3",
defaultHotkeys: HotkeyList.A3,
type: "视图",
chName: "还原相机状态三",
chDes: "还原相机状态(保存的相机状态三)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-4",
command: CommandNames.CameraSnapshootRestore + "-4",
defaultHotkeys: HotkeyList.A4,
type: "视图",
chName: "还原相机状态四",
chDes: "还原相机状态(保存的相机状态四)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-5",
command: CommandNames.CameraSnapshootRestore + "-5",
defaultHotkeys: HotkeyList.A5,
type: "视图",
chName: "还原相机状态五",
chDes: "还原相机状态(保存的相机状态五)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-6",
command: CommandNames.CameraSnapshootRestore + "-6",
defaultHotkeys: HotkeyList.A6,
type: "视图",
chName: "还原相机状态六",
chDes: "还原相机状态(保存的相机状态六)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-7",
command: CommandNames.CameraSnapshootRestore + "-7",
defaultHotkeys: HotkeyList.A7,
type: "视图",
chName: "还原相机状态七",
chDes: "还原相机状态(保存的相机状态七)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-8",
command: CommandNames.CameraSnapshootRestore + "-8",
defaultHotkeys: HotkeyList.A8,
type: "视图",
chName: "还原相机状态八",
chDes: "还原相机状态(保存的相机状态八)",
},
{
typeId: "view",
link: `#`,
defaultCustom: CommandNames.CameraSnapshootRestore + "-9",
command: CommandNames.CameraSnapshootRestore + "-9",
defaultHotkeys: HotkeyList.A9,
type: "视图",
chName: "还原相机状态九",
chDes: "还原相机状态(保存的相机状态九)",
},
{
typeId: "view",

@ -38,28 +38,26 @@ export class LightDataCom extends React.Component<ILightComponentProps, {}> {
this.target = dirTarge.ceil().toArray().toString();
};
ChangeSkyLightIntensity = (val: number, k?: string) =>
ChangeSkyLightIntensity = async (val: number, k?: string) =>
{
const KEY = (k === "IndirectLightingIntensity") ? "修改天光反弹" : "修改天光强度";
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法" + KEY + "!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
});
AppToaster.show({
message: "命令正在执行中!无法" + KEY + "!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
commandMachine.CommandStart(KEY);
}
}
else
} else
{
commandMachine.CommandStart(KEY);
}

@ -16,6 +16,7 @@ import { commandMachine, CommandWrap } from '../../Editor/CommandMachine';
import { CommandState } from '../../Editor/CommandState';
import { LightsMenu } from '../../Editor/LightsMenu';
import { SnapMenuFixed } from '../../Editor/SnapMenuFixed';
import { AxisSnapMode } from '../../Editor/SnapServices';
import { TempEditor } from '../../Editor/TempEditor';
import { userConfig } from '../../Editor/UserConfig';
import '../Css/PanelStyle.less';
@ -286,6 +287,29 @@ export class DownPanel extends React.Component<{ store?: DownPanelStore; }, {}>
e.currentTarget.blur();
return;
}
else if (key === 'useOrtho')
{
if (e.currentTarget.checked)
{
this.props.store.useAxis = false;
app.Editor.GetPointServices.snapServices.AxisSnapMode = AxisSnapMode.None;
}
else
{
this.props.store.useAxis = true;
}
}
else if (key === 'axisSnapMode')
{
this.props.store.useAxis = !this.props.store.useAxis;
if (this.props.store.useAxis)
{
app.Editor.GetPointServices.snapServices.AxisSnapMode = AxisSnapMode.Polar;
} else
{
app.Editor.GetPointServices.snapServices.AxisSnapMode = AxisSnapMode.None;
}
}
this.props.store[key] = e.currentTarget.checked;
if (!app.Viewer.isLayout)

@ -13,28 +13,26 @@ import { AppToaster } from "../Toaster";
@observer
export class ExposureUI extends React.Component<{ store: LightStore; }, {}>
{
SetExposureCompensation(val: number)
async SetExposureCompensation(val: number)
{
const KEY = '修改曝光补偿';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改曝光补偿!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
});
AppToaster.show({
message: "命令正在执行中!无法修改曝光补偿!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
commandMachine.CommandStart(KEY);
}
}
else
} else
{
commandMachine.CommandStart(KEY);
}

@ -5,6 +5,7 @@ import { end } from 'xaop';
import { app } from '../../../ApplicationServices/Application';
import { RightPanelStore } from '../../Store/RightPanelStore/RightPanelStore';
import { MaterialExplorer } from '../MaterialExplorer';
import ModifyModelPanel from '../ToolBar/ModifyModel/ModifyModelPanel';
import './BoardProps.less';
import { BoardPropsComponent } from './BoardPropsComponent';
import { DrillingComponent } from './DrillComponent';
@ -30,6 +31,7 @@ export enum RightTabId
Matals = "matals",
Model2 = "modeing2",
Model3 = "modeing3",
ModuelParams = 'moduleparams',
}
@inject('store')
@ -92,6 +94,7 @@ export class RightPanel extends React.Component<{ store?: RightPanelStore; }>
<Tab className="tab-unstyle" id={RightTabId.TemplateParam} title="模板参数" panel={<TemplateParamPanel />} />
<Tab className="tab-unstyle" id={RightTabId.Matals} title="五 金" panel={<MatalPanel />} />
{/* <Tab className="tab-unstyle" id={RightTabId.Template} title="模 板" panel={<BoardTemplatePanel />} /> */}
<Tab className='tab-unstyle' id={RightTabId.ModuelParams} title='模型' panel={<ModifyModelPanel />} />
</ Tabs>
</div>)
}

@ -124,31 +124,28 @@ export default class SunLightGui extends Component
};
};
SetSunLightIntensity = (val: number) =>
SetSunLightIntensity = async (val: number) =>
{
const KEY = '修改太阳光强度';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改太阳光强度!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
});
AppToaster.show({
message: "命令正在执行中!无法修改太阳光强度!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
commandMachine.CommandStart(KEY);
}
}
else
{
commandMachine.CommandStart(KEY);
}
app.Database.SunLight.Intensity = val;
app.Database.AmbientLight.Intensity = MathUtils.clamp(app.Database.SunLight.Intensity / 50 - app.Database.HemisphereLight.Intensity * 0.1, 0, 1.2);
this.store.sunLightIntensity = val;
@ -160,21 +157,19 @@ export default class SunLightGui extends Component
const KEY = '修改太阳间接光强度';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
await app.Editor.ModalManage.EndExecingCmd().then(() =>
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改太阳间接光强度!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
});
AppToaster.show({
message: "命令正在执行中!无法修改太阳间接光强度!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
commandMachine.CommandStart(KEY);
}
}
else

@ -0,0 +1,242 @@
.ModifyModelPanel
{
width : 100%;
min-height : 50px;
max-height : 700px;
overflow : auto;
display : flex;
flex-direction : column;
box-sizing : border-box;
// padding : 0 10px;
cursor : default;
.ModifyModelPanelWrapper
{
width : 100%;
height : 100%;
position: relative;
.ResizeBar
{
width : 100%;
height : 10px;
position: absolute;
cursor : s-resize;
&.AtTop
{
top: 0;
}
&.AtBottom
{
bottom : 0;
display : flex;
justify-content: center;
z-index : 99;
}
}
.ModifyModulePanelTitle
{
width : 100%;
display : flex;
flex-direction: column;
align-items : center;
.TitleInfo
{
display : flex;
width : 100%;
justify-content: space-between;
align-items : center;
font-size : 16px;
}
}
.ModuleBaseParams
{
width : 100%;
display : flex;
flex-direction: column;
padding-bottom: 10px;
.CollapseOpenTitle
{
width : 100%;
display : flex;
justify-content: space-between;
align-items : center;
margin-bottom : 10px;
font-weight : bold;
cursor : pointer;
}
.CollapseContent
{
display : flex;
flex-direction: column;
box-sizing : border-box;
padding : 0 10px;
.ParamsItem
{
display : flex;
flex-direction: column;
.bp3-button-group{
display: none;
}
.ParamsSlider
{
width : 100%;
height : 35px;
display : flex;
flex-direction : row;
justify-content: space-between;
>span
{
line-height: 35px;
}
.bp3-input
{
width : 50px;
font-size: 12px;
}
// .bp3-button-group
// {
// height: 30px;
// >button
// {
// width : 15px;
// min-width: 1px;
// }
// }
.bp3-slider
{
min-width : 10px;
width : 140px;
margin-top: 8px;
.bp3-slider-axis
{
display: none;
}
.bp3-slider-handle
{
transform : scale(80%);
border-radius: 50px;
}
.bp3-slider-label
{
display: none;
}
}
}
.bp3-checkbox
{
align-self: flex-end;
margin : 10px 0 0 0;
}
.ParamsRotate
{
display : flex;
flex-direction : row;
justify-content: space-between;
align-items : center;
margin-top : 10px;
>div
{
display : flex;
flex-direction: column;
align-items : center;
>div
{
padding : 2px;
display : flex;
flex-direction: row;
align-items : center;
border: 1px solid lightgray;
.RotateBox
{
width : 20px;
height : 20px;
box-sizing : border-box;
border : 1px solid lightgray;
border-radius : 100%;
position : relative;
transform : rotate(135deg);
background-color: rgba(92, 112, 128, 0.2);
>span
{
position : absolute;
pointer-events: none;
}
}
.bp3-input
{
min-width : 0px;
width : 30px;
font-size : 8px;
padding : 0;
margin-left: 6px;
//输入框边框不是border是box-shadow
box-shadow: none;
}
// .bp3-button-group
// {
// height : 20px;
// margin-left: -14px;
// z-index : 20;
// >button
// {
// min-width : 0px;
// width : 15px;
// }
// }
}
}
}
.ParamsPosition
{
display : flex;
flex-direction : row;
justify-content: space-between;
margin-top : 10px;
align-items : center;
>div
{
display : flex;
flex-direction: column;
align-items : center;
&:nth-child(2)
{
.bp3-input-group::before{
background-color: red;
}
}
&:nth-child(3)
{
.bp3-input-group::before{
background-color: #00ff00;
}
}
&:nth-child(4)
{
.bp3-input-group::before{
background-color: blue;
}
}
.bp3-input-group
{
display : flex;
position: relative;
&::before{
height : 100%;
width : 2px;
content : '';
position : absolute;
z-index : 23;
}
}
.bp3-input
{
min-width: 0px;
width : 59px;
font-size: 12px;
}
}
}
}
}
}
}
}

@ -0,0 +1,20 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { ZINDEX } from '../../../../Common/ZIndex';
import ModifyModelPanel from './ModifyModelPanel';
export default class ModifyModelManage
{
private _ModifyPanel: HTMLElement;
constructor()
{
this._ModifyPanel = document.createElement("div");
this._ModifyPanel.id = "ModifyModel";
this._ModifyPanel.style.zIndex = ZINDEX.CommandInput;
document.getElementById("Webgl").appendChild(this._ModifyPanel);
}
RenderModifyModelPanel()
{
ReactDOM.render(<ModifyModelPanel />, this._ModifyPanel);
}
}

@ -0,0 +1,31 @@
import { Divider } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component, RefObject } from 'react';
import './ModifyModel.less';
import ModifyModelStore from './ModifyModelStore';
import ModuleBaseParams from './ModuleBaseParams';
@observer
export default class ModifyModelPanel extends Component
{
ModifyModelPanelRef: RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>();
ModifyModelStore: ModifyModelStore = ModifyModelStore.GetSingleInstance();
render()
{
return (
<div className='ModifyModelPanel' id='ModifyModelPanel' ref={this.ModifyModelPanelRef}>
<main className='ModifyModelPanelWrapper'>
<div className='ModifyModulePanelTitle'>
<div className='TitleInfo'>
<div>
{this.ModifyModelStore.name}
</div>
</div>
</div>
<Divider />
<ModuleBaseParams />
</main>
</div>
);
}
}

@ -0,0 +1,279 @@
import { Intent } from "@blueprintjs/core";
import { action, observable } from "mobx";
import { Box3, Euler, MathUtils, Matrix4, Vector3 } from "three";
import { end } from "xaop";
import { app } from "../../../../ApplicationServices/Application";
import { UpdateDraw } from "../../../../Common/Status";
import { CommandHistoryRecord } from "../../../../DatabaseServices/CommandHistoryRecord";
import { CreateObjectData } from "../../../../DatabaseServices/CreateObjectData";
import { Board } from "../../../../DatabaseServices/Entity/Board";
import { Entity } from "../../../../DatabaseServices/Entity/Entity";
import { EntityRef } from "../../../../DatabaseServices/Entity/EntityRef";
import { commandMachine } from "../../../../Editor/CommandMachine";
import { CommandState } from "../../../../Editor/CommandState";
import { SelectSetBase } from "../../../../Editor/SelectBase";
import { AppToaster } from "../../Toaster";
import { ModuleAxis } from "./ModuleBaseParams";
export default class ModifyModelStore
{
@observable isCollapseOpened: boolean = true;
@observable isProportionalZoom: boolean = true;
@observable module_Length: number = 0;
@observable module_Width: number = 0;
@observable module_Height: number = 0;
@observable offGround: number = 0;//离地
@observable rotateX: number = 0;
@observable rotateY: number = 0;
@observable rotateZ: number = 0;
@observable positionX: number = 0;
@observable positionY: number = 0;
@observable positionZ: number = 0;
@observable name: string = "";
sliderMax: number = 5000;
@observable _EntityIds: number[] = [];
private constructor()
{
let selectCtrl = app.Editor.SelectCtrl;
end(selectCtrl, selectCtrl.AddSelect, (ss: SelectSetBase) =>
{
if (selectCtrl.SelectSet.SelectObjectCount > 50)
observable(this._EntityIds).replace([]);
else
observable(this._EntityIds).replace(selectCtrl.SelectSet.SelectEntityList.map(e => e.Id.Index));
this.UpdateUIData();
});
end(app.Database.hm, app.Database.hm.RedoEvent, (cmdName: string, historyRec: CommandHistoryRecord) =>
{
for (let [h, hs] of historyRec.HistoryList)
{
if (h === app.Database.ModelSpace.Id)
{
for (let h of hs)
{
if (h.redoData instanceof CreateObjectData)
{
if (this._EntityIds.includes(h.redoData.Object.Id.Index))
{
this.UpdateUIData();
return;
}
}
}
}
else if (this._EntityIds.includes(h.Index))
this.UpdateUIData();
}
});
end(app.Database.hm, app.Database.hm.UndoEvent, (cmdName: string, historyRec: CommandHistoryRecord) =>
{
//撤销时不会出现CreateObjectData.(因为我们使用标记删除的方式,所以不可能)
for (let [h, hs] of historyRec.HistoryList)
{
if (this._EntityIds.includes(h.Index))
this.UpdateUIData();
}
});
app.CommandReactor.OnCommandEnd((cmdName, changeObjects, createObjects) =>
{
let set = new Set(this._EntityIds);
for (let e of changeObjects)
{
if (set.has(e.Id.Index))
{
this.UpdateUIData();
return;
}
}
});
end(app.Database, app.Database.FileRead, () =>
{
observable(this._EntityIds).replace([]);
this.UpdateUIData();
});
}
@action
UpdateUIData()
{
let ents: Entity[] = this._EntityIds.map(id => app.Database.GetObjectId(id).Object).filter(en => en && en instanceof Entity) as Entity[];
if (!ents.length) return;
this.InitBox(ents);
this.offGround = this.__Box.min.z;
if (this._EntityIds.length === 1)
{
let ent = app.Database.GetObjectId(this._EntityIds[0])?.Object as Entity;
if (!ent) return;
if (ent instanceof Board)
{
this.name = "[板]" + ent.Name;
this.module_Length = ent.Height;
this.module_Width = ent.Width;
this.module_Height = ent.Thickness;
}
else if (ent instanceof EntityRef)
{
this.name = "[模型]" + ent.Url;
let size = ent.CurSize;
this.module_Length = size.x;
this.module_Width = size.y;
this.module_Height = size.z;
if (size.x > 2000 || size.y > 2000 || size.z > 2000)
this.sliderMax = 5000;
else if (size.x < 500 && size.y < 500 && size.z < 500)
this.sliderMax = 1000;
else
this.sliderMax = 2000;
}
let p = ent.Position;
this.positionX = p.x;
this.positionY = p.y;
this.positionZ = p.z;
let ocs = ent.OCS.setPosition(0, 0, 0);
let eu = new Euler().setFromRotationMatrix(ocs, "ZYX");
this.rotateX = eu.x * MathUtils.RAD2DEG;
this.rotateY = eu.y * MathUtils.RAD2DEG;
this.rotateZ = eu.z * MathUtils.RAD2DEG;
}
else
{
let size = this.__Box.getSize(new Vector3);
this.module_Length = size.x;
this.module_Width = size.y;
this.module_Height = size.z;
this.positionX = this.__Box.min.x;
this.positionY = this.__Box.min.y;
this.positionZ = this.__Box.min.z;
this.rotateX = 0;
this.rotateY = 0;
this.rotateZ = 0;
this.name = `[${ents.length}个模型]`;
}
}
UpdateModulePosition = async (ent: Entity, position: number, axis: ModuleAxis) =>
{
if (!ent) return;
let p = ent.Position;
switch (axis)
{
case (ModuleAxis.x):
{
p.x = position;
break;
}
case (ModuleAxis.y):
{
p.y = position;
break;
}
case (ModuleAxis.z):
{
p.z = position;
break;
}
default:
AppToaster.show({
message: "出错啦!",
timeout: 5000,
intent: Intent.DANGER,
});
break;
}
ent.Position = p;
app.Viewer.UpdateRender();
};
UpdateModuleRotate = (ent: Entity, x: number, y: number, z: number) =>
{
let eu = new Euler(x * MathUtils.DEG2RAD, y * MathUtils.DEG2RAD, z * MathUtils.DEG2RAD, 'ZYX');
ent.WriteAllObjectRecord();
ent.OCS = ent.OCS.makeRotationFromEuler(eu).setPosition(ent.Position);
ent.Update(UpdateDraw.Matrix);
app.Viewer.UpdateRender();
};
private __Box: Box3;
private InitBox(ens: Entity[])
{
this.__Box = new Box3;
for (let e of ens)
this.__Box.union(e.BoundingBox);
}
UpdateScaleModule = async (length: number, width: number, height: number) =>
{
let ents: Entity[] = this._EntityIds.map(id => app.Database.GetObjectId(id).Object).filter(en => en && en instanceof Entity) as Entity[];
if (ents.length === 0) return;
const Command_KEY = '修改模型尺寸';
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== Command_KEY)
{
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改模型尺寸!",
timeout: 5000,
intent: Intent.DANGER
});
return;
}
commandMachine.CommandStart(Command_KEY);
}
}
else
{
commandMachine.CommandStart(Command_KEY);
}
if (ents.length === 1)
{
let ent = ents[0];
if (ent instanceof EntityRef)
ent.ScaleSize = new Vector3(length, width, height);
else if (ent instanceof Board)
{
ent.Height = length;
ent.Width = width;
ent.Thickness = height;
}
}
else
{
let c = this.__Box.getCenter(new Vector3);
let size = this.__Box.getSize(new Vector3);
//不等比例缩放
let mtx = new Matrix4().makeScale(length / size.x, width / size.y, height / size.z).setPosition(c.x * (1 - (length / size.x)), c.y * ((1 - width / size.y)), c.z * (1 - height / size.z));
for (let e of ents)
e.ApplyMatrix(mtx);
this.__Box.applyMatrix4(mtx);
}
app.Viewer.UpdateRender();
};
private static _SingleInstance: ModifyModelStore;
static GetSingleInstance = (): ModifyModelStore =>
{
if (this._SingleInstance) return this._SingleInstance;
this._SingleInstance = new ModifyModelStore();
return this._SingleInstance;
};
}

@ -0,0 +1,677 @@
import { Button, Checkbox, Collapse, Divider, Icon, InputGroup, Intent, NumericInput, Slider, Tooltip } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import { MathUtils } from 'three';
import { app } from '../../../../ApplicationServices/Application';
import { FixedNotZero } from '../../../../Common/Utils';
import { Entity } from '../../../../DatabaseServices/Entity/Entity';
import { EntityRef } from '../../../../DatabaseServices/Entity/EntityRef';
import { commandMachine } from '../../../../Editor/CommandMachine';
import { CommandState } from '../../../../Editor/CommandState';
import { ZeroVec } from '../../../../Geometry/GeUtils';
import { AppToaster } from '../../Toaster';
import ModifyModelStore from './ModifyModelStore';
export enum ModuleAxis
{
x = 'x',
y = 'y',
z = 'z',
}
enum ModuleScale
{
LENGTH,
WIDTH,
HEIGHT,
}
const iClamp = (value: number, min: number, max: number) =>
{
if (value <= min) return min;
return Math.max(min, Math.min(max, value));
};
@observer
export default class ModuleBaseParams extends Component<{}, {}>
{
ModifyModelStore: ModifyModelStore = ModifyModelStore.GetSingleInstance();
tempNumberInputValue: number = 0;
LetsRotate = async (e: React.PointerEvent<HTMLDivElement>, axis: ModuleAxis) =>
{
if (!app.Editor.SelectCtrl.SelectSet.SelectEntityList.length) return;
if (CommandState.CommandIng)
{
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改模型角度!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
}
const Command_KEY = '修改模型角度';
commandMachine.CommandStart(Command_KEY);
const { ModifyModelStore } = this;
const targetEl = e.target as HTMLDivElement;
targetEl.setPointerCapture(e.pointerId);
const boxRect = targetEl.getBoundingClientRect();
const boxCenter = [boxRect.right - (boxRect.width / 2), boxRect.bottom - (boxRect.height / 2)];
targetEl.onmousemove = (ev: MouseEvent) =>
{
const angle = Math.atan2(-(ev.clientY - boxCenter[1]), ev.clientX - boxCenter[0]) * MathUtils.RAD2DEG;
switch (axis)
{
case ModuleAxis.x: {
ModifyModelStore.rotateX = Math.round(angle);
if (ModifyModelStore.rotateX < 0) ModifyModelStore.rotateX += 360;
ModifyModelStore.rotateX = this.StickyRotateDeg(ModifyModelStore.rotateX);
targetEl.style.transform = `rotate(${-ModifyModelStore.rotateX + 135}deg)`;
break;
}
case ModuleAxis.y: {
ModifyModelStore.rotateY = Math.round(angle);
if (ModifyModelStore.rotateY < 0) ModifyModelStore.rotateY += 360;
ModifyModelStore.rotateY = this.StickyRotateDeg(ModifyModelStore.rotateY);
targetEl.style.transform = `rotate(${-ModifyModelStore.rotateY + 135}deg)`;
break;
}
case ModuleAxis.z: {
ModifyModelStore.rotateZ = Math.round(angle);
if (ModifyModelStore.rotateZ < 0) ModifyModelStore.rotateZ += 360;
ModifyModelStore.rotateZ = this.StickyRotateDeg(ModifyModelStore.rotateZ);
targetEl.style.transform = `rotate(${-ModifyModelStore.rotateZ + 135}deg)`;
break;
}
default:
break;
}
for (let e of app.Editor.SelectCtrl.SelectSet.SelectEntityList)
{
ModifyModelStore.UpdateModuleRotate(e,
ModifyModelStore.rotateX,
ModifyModelStore.rotateY,
ModifyModelStore.rotateZ
);
}
};
targetEl.onmouseup = () =>
{
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
{
commandMachine.CommandEnd();
}
targetEl.onmouseup = null;
targetEl.onmousemove = null;
};
};
LetsMove = async (e: React.PointerEvent<HTMLElement>, axis: ModuleAxis) =>
{
if (!app.Editor.SelectCtrl.SelectSet.SelectEntityList.length) return;
const Command_KEY = '修改模型位置';
if (CommandState.CommandIng)
{
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改模型位置!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
commandMachine.CommandStart(Command_KEY);
} else
{
commandMachine.CommandStart(Command_KEY);
}
const { ModifyModelStore } = this;
const targetEl = e.target as HTMLInputElement;
targetEl.setPointerCapture(e.pointerId);
const downX = e.clientX;
let currPosition: number = 0;
let startPoint: number = Date.now();
const test: number[] = [];
for (let e of app.Editor.SelectCtrl.SelectSet.SelectEntityList)
{
switch (axis)
{
case ModuleAxis.x: {
test.push(e.Position.x);
break;
}
case ModuleAxis.y: {
test.push(e.Position.y);
break;
}
case ModuleAxis.z: {
test.push(e.Position.z);
break;
}
}
}
switch (axis)
{
case ModuleAxis.x: {
currPosition = ModifyModelStore.positionX;
break;
}
case ModuleAxis.y: {
currPosition = ModifyModelStore.positionY;
break;
}
case ModuleAxis.z: {
currPosition = ModifyModelStore.positionZ;
break;
}
}
targetEl.onmousemove = (ev: MouseEvent) =>
{
ev.preventDefault();
const endPoint = Date.now();
const move = ev.clientX - downX;
if (Math.abs(startPoint - endPoint) < 400) return;
for (let [e, index] of new Map(app.Editor.SelectCtrl.SelectSet.SelectEntityList.map((e: Entity, index) => [e, index])))
{
switch (axis)
{
case ModuleAxis.x: {
ModifyModelStore.positionX = currPosition + (-move);
ModifyModelStore.UpdateModulePosition(e, (test[index] + (-move)), ModuleAxis.x);
break;
}
case ModuleAxis.y: {
ModifyModelStore.positionY = currPosition + (-move);
ModifyModelStore.UpdateModulePosition(e, (test[index] + (-move)), ModuleAxis.y);
break;
}
case ModuleAxis.z: {
ModifyModelStore.positionZ = currPosition + (-move);
ModifyModelStore.UpdateModulePosition(e, (test[index] + (-move)), ModuleAxis.z);
break;
}
}
}
};
targetEl.onmouseup = () =>
{
targetEl.select();
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
{
commandMachine.CommandEnd();
}
targetEl.onmouseup = null;
targetEl.onmousemove = null;
};
};
ChangePosition = async (e: string, axis: ModuleAxis) =>
{
if (!app.Editor.SelectCtrl.SelectSet.SelectEntityList.length) return;
const ent = app.Editor.SelectCtrl.SelectSet.SelectEntityList[0];
const Command_KEY = '修改模型位置';
if (CommandState.CommandIng)
{
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改模型位置!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
commandMachine.CommandStart(Command_KEY);
} else
{
commandMachine.CommandStart(Command_KEY);
}
const { ModifyModelStore } = this;
let v = parseInt(e);
if (isNaN(v))
{
v = 0;
}
switch (axis)
{
case ModuleAxis.x: {
ModifyModelStore.positionX = v;
ModifyModelStore.UpdateModulePosition(ent, ModifyModelStore.positionX, ModuleAxis.x);
break;
}
case ModuleAxis.y: {
ModifyModelStore.positionY = v;
ModifyModelStore.UpdateModulePosition(ent, ModifyModelStore.positionY, ModuleAxis.y);
break;
}
case ModuleAxis.z: {
ModifyModelStore.positionZ = v;
ModifyModelStore.UpdateModulePosition(ent, ModifyModelStore.positionZ, ModuleAxis.z);
break;
}
default:
break;
}
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
{
commandMachine.CommandEnd();
}
};
StickyRotateDeg = (value: number): number =>
{
if (value <= 5) value = 0;
if (value >= 355) value = 0;
if (value >= 85 && value <= 95)
value = 90;
if (value >= 175 && value <= 185)
value = 180;
if (value >= 265 && value <= 275)
value = 270;
return value;
};
ChangeModuelScala = (e: React.KeyboardEvent, scale: ModuleScale) =>
{
const { ModifyModelStore } = this;
let percentage: number = 0;
if (e.key === 'Enter')
{
if (ModifyModelStore.isProportionalZoom)
{
switch (scale)
{
case ModuleScale.LENGTH:
percentage = ModifyModelStore.module_Length / this.tempNumberInputValue;
ModifyModelStore.module_Width = ModifyModelStore.module_Width * percentage;
ModifyModelStore.module_Height = ModifyModelStore.module_Height * percentage;
break;
case ModuleScale.WIDTH:
percentage = ModifyModelStore.module_Width / this.tempNumberInputValue;
ModifyModelStore.module_Length = ModifyModelStore.module_Length * percentage;
ModifyModelStore.module_Height = ModifyModelStore.module_Height * percentage;
break;
case ModuleScale.HEIGHT:
percentage = ModifyModelStore.module_Height / this.tempNumberInputValue;
ModifyModelStore.module_Width = ModifyModelStore.module_Width * percentage;
ModifyModelStore.module_Length = ModifyModelStore.module_Length * percentage;
break;
default: break;
}
}
ModifyModelStore.UpdateScaleModule(
ModifyModelStore.module_Length,
ModifyModelStore.module_Width,
ModifyModelStore.module_Height,
);
switch (scale)
{
case ModuleScale.LENGTH:
this.tempNumberInputValue = ModifyModelStore.module_Length;
break;
case ModuleScale.WIDTH:
this.tempNumberInputValue = ModifyModelStore.module_Width;
break;
case ModuleScale.HEIGHT:
this.tempNumberInputValue = ModifyModelStore.module_Height;
break;
default: break;
}
const Command_KEY = '修改模型尺寸';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
commandMachine.CommandEnd();
}
if (e.key === 'Escape')
{
switch (scale)
{
case ModuleScale.LENGTH:
ModifyModelStore.module_Length = this.tempNumberInputValue;
break;
case ModuleScale.WIDTH:
ModifyModelStore.module_Width = this.tempNumberInputValue;
break;
case ModuleScale.HEIGHT:
ModifyModelStore.module_Height = this.tempNumberInputValue;
break;
default: break;
}
}
if (e.ctrlKey && e.key === 'z')
{
app.Database.hm.Undo();
}
};
render()
{
const [min, max] = [0, 360];
const { ModifyModelStore } = this;
return (
<div className='ModuleBaseParams'>
<div className='CollapseOpenTitle'
style={{ display: ModifyModelStore._EntityIds.length < 1 ? 'none' : "block" }}
onClick={() =>
{
ModifyModelStore.isCollapseOpened = !ModifyModelStore.isCollapseOpened;
}}
>
<div >
<Icon icon={ModifyModelStore.isCollapseOpened ? 'chevron-up' : "chevron-down"} />
</div>
<Button small minimal intent='primary' text='恢复默认' style={{ fontSize: '12px' }}
onClick={async (e: React.MouseEvent) =>
{
e.stopPropagation();
if (!app.Editor.SelectCtrl.SelectSet.SelectEntityList.length) return;
if (CommandState.CommandIng)
{
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改模型尺寸!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
}
const Command_KEY = '修改模型尺寸';
commandMachine.CommandStart(Command_KEY);
for (let ent of app.Editor.SelectCtrl.SelectSet.SelectEntityList as EntityRef[])
{
ent.ScaleSize = ZeroVec;
app.Viewer.UpdateRender();
}
commandMachine.CommandEnd();
}}
/>
</div>
<Collapse isOpen={ModifyModelStore.isCollapseOpened}>
<div className='CollapseContent' style={{ display: ModifyModelStore._EntityIds.length < 1 ? 'none' : "block" }}>
<div >
<div className='ParamsItem'>
<div className='ParamsSlider'>
<span></span>
<Slider
min={1}
max={ModifyModelStore.sliderMax}
value={
iClamp(ModifyModelStore.module_Length, 0, ModifyModelStore.sliderMax)
}
onChange={(e) =>
{
const percentage = e / ModifyModelStore.module_Length;
ModifyModelStore.module_Length = e;
if (ModifyModelStore.isProportionalZoom)
{
ModifyModelStore.module_Width = ModifyModelStore.module_Width * percentage;
ModifyModelStore.module_Height = ModifyModelStore.module_Height * percentage;
}
ModifyModelStore.UpdateScaleModule(
ModifyModelStore.module_Length,
ModifyModelStore.module_Width,
ModifyModelStore.module_Height,
);
}}
onRelease={() =>
{
const Command_KEY = '修改模型尺寸';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
commandMachine.CommandEnd();
}}
/>
<NumericInput
value={iClamp(ModifyModelStore.module_Length, 0, Number.MAX_VALUE).toFixed(0)}
onValueChange={(e) =>
{
if (e === 0) return;
ModifyModelStore.module_Length = e;
}}
onFocus={(e) =>
{
this.tempNumberInputValue = parseInt(e.target.value);
}}
onKeyDown={(e) =>
{
e.stopPropagation();
this.ChangeModuelScala(e, ModuleScale.LENGTH);
}}
/>
</div>
</div>
<div className='ParamsItem'>
<div className='ParamsSlider'>
<span></span>
<Slider
min={1}
max={ModifyModelStore.sliderMax}
value={iClamp(ModifyModelStore.module_Width, 0, ModifyModelStore.sliderMax)}
onChange={(e) =>
{
const percentage = e / ModifyModelStore.module_Width;
ModifyModelStore.module_Width = e;
if (ModifyModelStore.isProportionalZoom)
{
ModifyModelStore.module_Length = ModifyModelStore.module_Length * percentage;
ModifyModelStore.module_Height = ModifyModelStore.module_Height * percentage;
}
ModifyModelStore.UpdateScaleModule(
ModifyModelStore.module_Length,
ModifyModelStore.module_Width,
ModifyModelStore.module_Height,
);
}}
onRelease={() =>
{
const Command_KEY = '修改模型尺寸';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
commandMachine.CommandEnd();
}} />
<NumericInput
value={iClamp(ModifyModelStore.module_Width, 0, Number.MAX_VALUE).toFixed(0)}
onValueChange={(e) =>
{
if (e === 0) return;
ModifyModelStore.module_Width = e;
}}
onFocus={(e) =>
{
this.tempNumberInputValue = parseInt(e.target.value);
}}
onKeyDown={(e) =>
{
e.stopPropagation();
this.ChangeModuelScala(e, ModuleScale.WIDTH);
}}
/>
</div>
</div>
<div className='ParamsItem'>
<div className='ParamsSlider'>
<span></span>
<Slider
min={1}
max={ModifyModelStore.sliderMax}
value={iClamp(ModifyModelStore.module_Height, 0, ModifyModelStore.sliderMax)}
onChange={(e: number) =>
{
const percentage = e / ModifyModelStore.module_Height;
ModifyModelStore.module_Height = e;
if (ModifyModelStore.isProportionalZoom)
{
ModifyModelStore.module_Length = ModifyModelStore.module_Length * percentage;;
ModifyModelStore.module_Width = ModifyModelStore.module_Width * percentage;
}
ModifyModelStore.UpdateScaleModule(
ModifyModelStore.module_Length,
ModifyModelStore.module_Width,
ModifyModelStore.module_Height,
);
}}
onRelease={() =>
{
const Command_KEY = '修改模型尺寸';
if (CommandState.CommandIng && app.Database.hm.UndoData.CommandName === Command_KEY)
commandMachine.CommandEnd();
}} />
<NumericInput
value={iClamp(ModifyModelStore.module_Height, 0, Number.MAX_VALUE).toFixed(0)}
onValueChange={(e) =>
{
if (e === 0) return;
ModifyModelStore.module_Height = e;
}}
onFocus={(e) =>
{
this.tempNumberInputValue = parseInt(e.target.value);
}}
onKeyDown={(e) =>
{
e.stopPropagation();
this.ChangeModuelScala(e, ModuleScale.HEIGHT);
}}
/>
</div>
</div>
</div>
{/* <div className='ParamsItem'>
<div className='ParamsSlider'>
<span></span>
<Slider
min={0}
max={5000}
value={MathUtils.clamp(ModifyModelStore.offGround, 0, 5000)}
onChange={(e) =>
{
ModifyModelStore.offGround = e;
for (let ent of app.Editor.SelectCtrl.SelectSet.SelectEntityList)
{
}
}} />
<NumericInput value={ModifyModelStore.offGround} />
</div>
</div> */}
<div className='ParamsItem'>
<Checkbox label='等比缩放' checked={ModifyModelStore.isProportionalZoom} onChange={() =>
{
ModifyModelStore.isProportionalZoom = !ModifyModelStore.isProportionalZoom;
}} />
</div>
<div className='ParamsItem'>
<div className='ParamsPosition'>
<span style={{ lineHeight: "24px" }}></span>
<div>
<InputGroup
value={FixedNotZero(ModifyModelStore.positionX.toString())}
onChange={(e) =>
{
this.ChangePosition(e.target.value, ModuleAxis.x);
}}
onPointerDown={(e) => { this.LetsMove(e, ModuleAxis.x); }}
/>
</div>
<div>
<InputGroup
value={FixedNotZero(ModifyModelStore.positionY.toString())}
onChange={(e) =>
{
this.ChangePosition(e.target.value, ModuleAxis.y);
}}
onPointerDown={(e) => { this.LetsMove(e, ModuleAxis.y); }}
/>
</div>
<div>
<InputGroup
value={FixedNotZero(ModifyModelStore.positionZ.toString())}
onChange={(e) =>
{
this.ChangePosition(e.target.value, ModuleAxis.z);
}}
onPointerDown={(e) => { this.LetsMove(e, ModuleAxis.z); }}
/>
</div>
<Tooltip minimal placement='top' content='重置'>
<Button minimal small intent={Intent.PRIMARY} icon='redo' />
</Tooltip>
</div>
</div>
<div className='ParamsItem' style={{ marginTop: "10px" }}>
<div className='ParamsRotate'>
<span style={{ lineHeight: "24px" }}></span>
<div className='RotateX'>
<div>
<div
className='RotateBox'
onPointerDown={(e) => { this.LetsRotate(e, ModuleAxis.x); }}
style={{ transform: `rotate(${-ModifyModelStore.rotateX + 135}deg)` }}
>
<Icon icon='record' size={8} style={{ color: "#FF0000" }} />
</div>
<NumericInput
min={min}
max={max}
value={ModifyModelStore.rotateX.toFixed(0)}
onValueChange={(e: number) =>
{
ModifyModelStore.rotateX = e;
}} />
</div>
</div>
<div className='RotateY'>
<div>
<div
className='RotateBox'
onPointerDown={(e) => { this.LetsRotate(e, ModuleAxis.y); }}
style={{ transform: `rotate(${-ModifyModelStore.rotateY + 135}deg)` }}
>
<Icon icon='record' size={8} style={{ color: "#00FF00" }} />
</div>
<NumericInput
min={min}
max={max}
value={ModifyModelStore.rotateY.toFixed(0)}
onValueChange={(e: number) =>
{
ModifyModelStore.rotateY = e;
}} />
</div>
</div>
<div className='RotateZ'>
<div>
<div
className='RotateBox'
onPointerDown={(e) => { this.LetsRotate(e, ModuleAxis.z); }}
style={{ transform: `rotate(${-ModifyModelStore.rotateZ + 135}deg)` }}
>
<Icon icon='record' size={8} style={{ color: "#0000FF" }} />
</div>
<NumericInput
min={min}
max={max}
value={ModifyModelStore.rotateZ.toFixed(0)}
onValueChange={(e: number) =>
{
ModifyModelStore.rotateZ = e;
}} />
</div>
</div>
<Tooltip minimal placement='top' content='重置'>
<Button minimal small intent={Intent.PRIMARY} icon='redo' />
</Tooltip>
</div>
</div>
</div>
</Collapse>
<Divider />
</div>
);
}
};

@ -51,6 +51,7 @@ export class WebCAD
this.renderRightPanel();
this.renderCommandInput();
this.renderCameraControlButton();
this.renderCameraState();
appUi = this;
@ -232,6 +233,10 @@ export class WebCAD
RenderComponent(ToolbarContainer, toolbarEl);
}
renderCameraState()
{
app.Editor.CameraState.RenderCameraState();
}
showMaterialEditor(props: MaterialContainerProps)
{

@ -153,6 +153,8 @@ export class DownPanelStore
},
];
@observable useAxis: boolean = true;
private timeId;
private constructor()
{
@ -266,7 +268,7 @@ export class DownPanelStore
this.snapData[i].enable = config.snapData[i];
}
if (config.lightsData)
for (let i = 0; i < config.lightsData.length; i++)
for (let i = 0; i < this.lightsData.length; i++)
{
this.lightsData[i].enable = config.lightsData[i];
}

@ -1,5 +1,5 @@
import { IOptionProps, TabId } from "@blueprintjs/core";
import { observable } from "mobx";
import { action, observable } from "mobx";
import { begin } from "xaop";
import { app } from "../../../ApplicationServices/Application";
import { Board } from "../../../DatabaseServices/Entity/Board";
@ -34,15 +34,19 @@ export class RightPanelStore
{
let ent = ss.SelectEntityList[0];
if (!ent) return;
if (ent instanceof Board)
this.currentBoard = ent;
//设置当前显示的模块节点
let store = TemplateParamPanelStore.GetInstance();
if (ent.Template)
store.DisplayTemplateId = ent.Template.Index;
else
store.DisplayTemplateId = undefined;
action(() =>
{
if (ent instanceof Board)
this.currentBoard = ent;
//设置当前显示的模块节点
let store = TemplateParamPanelStore.GetInstance();
if (ent.Template)
store.DisplayTemplateId = ent.Template.Index;
else
store.DisplayTemplateId = undefined;
})();
});
}

@ -221,7 +221,7 @@ export class SpotLightModel extends React.Component<{ store: LightStore; configS
content={
<SketchPicker
color={lightData.Color.toUpperCase()}
onChange={(e: ColorResult) =>
onChange={async (e: ColorResult) =>
{
if (!this.props.isNotModify)
{
@ -230,18 +230,19 @@ export class SpotLightModel extends React.Component<{ store: LightStore; configS
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改天光颜色!",
timeout: 5000,
intent: Intent.DANGER
});
});
return;
return;
}
commandMachine.CommandStart(KEY);
}
}
else
} else
{
commandMachine.CommandStart(KEY);
}
@ -439,28 +440,26 @@ export class InputAndSlider extends React.Component<{ pars: string[], store: Lig
{
OldData: number = 0;
SetValue(value: string)
async SetValue(value: string)
{
const KEY = "修改灯光" + this.props.pars[1];;
if (CommandState.CommandIng)
{
if (app.Database.hm.UndoData.CommandName !== KEY)
{
app.Editor.ModalManage.EndExecingCmd().then(() =>
await app.Editor.ModalManage.EndExecingCmd();
if (CommandState.CommandIng)
{
if (CommandState.CommandIng)
{
AppToaster.show({
message: "命令正在执行中!无法修改灯光" + this.props.pars[1] + "!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
});
AppToaster.show({
message: "命令正在执行中!无法修改灯光" + this.props.pars[1] + "!",
timeout: 5000,
intent: Intent.DANGER,
});
return;
}
commandMachine.CommandStart(KEY);
}
}
else
} else
{
commandMachine.CommandStart(KEY);
}

Loading…
Cancel
Save