Browse Source

版本更新 1.0.14.20210202b

master
徐振升 4 years ago
parent
commit
efce92f3a3
  1. 18
      package-lock.json
  2. 2
      package.json
  3. 80
      src/app/canvas-share-data.service.ts
  4. 112
      src/app/working-area/model/axGrid.ts
  5. 11
      src/app/working-area/model/axImageShapeTest.ts
  6. 1
      src/app/working-area/model/axLegend.ts
  7. 90
      src/app/working-area/model/axMessageSystem.ts
  8. 18
      src/app/working-area/model/axRectangleShape.ts
  9. 65
      src/app/working-area/model/axSelection.ts
  10. 104
      src/app/working-area/model/axShape.ts
  11. 164
      src/app/working-area/model/configuration.ts
  12. 145
      src/app/working-area/model/dimensioning.ts
  13. 67
      src/app/working-area/model/events.ts
  14. 87
      src/app/working-area/model/grid2D.ts
  15. 37
      src/app/working-area/model/messageSystem.ts
  16. 3
      src/app/working-area/working-area.component.html
  17. 944
      src/app/working-area/working-area.component.ts

18
package-lock.json generated

@ -12845,6 +12845,11 @@
"sha.js": "^2.4.8"
}
},
"penner": {
"version": "0.1.3",
"resolved": "https://registry.npm.taobao.org/penner/download/penner-0.1.3.tgz",
"integrity": "sha1-C4tILU6bOa8vPXw3WSIpuKzClwU="
},
"perfect-scrollbar": {
"version": "1.5.0",
"resolved": "https://registry.npm.taobao.org/perfect-scrollbar/download/perfect-scrollbar-1.5.0.tgz",
@ -12922,6 +12927,14 @@
"@pixi/filter-zoom-blur": "3.1.1"
}
},
"pixi-viewport": {
"version": "4.18.1",
"resolved": "https://registry.npm.taobao.org/pixi-viewport/download/pixi-viewport-4.18.1.tgz",
"integrity": "sha1-EP1/72igFjwcKhxvI83KVvzbRvM=",
"requires": {
"penner": "^0.1.3"
}
},
"pixi.js": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-5.3.2.tgz",
@ -15860,6 +15873,11 @@
}
}
},
"three": {
"version": "0.125.2",
"resolved": "https://registry.npm.taobao.org/three/download/three-0.125.2.tgz",
"integrity": "sha1-3LoSdJoutBUi4VISuRnNP79ymxI="
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz",

2
package.json

@ -37,9 +37,11 @@
"ngx-echarts": "^4.2.2",
"ngx-perfect-scrollbar": "^8.0.0",
"pixi-filters": "^3.1.1",
"pixi-viewport": "^4.18.1",
"pixi.js": "^5.3.2",
"rxjs": "~6.5.4",
"swiper": "^5.3.6",
"three": "^0.125.2",
"tslib": "^1.10.0",
"viewerjs": "^1.6.2",
"zone.js": "~0.10.2"

80
src/app/canvas-share-data.service.ts

@ -1,42 +1,41 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import {ReplaySubject} from 'rxjs';
import { Observable } from 'rxjs';
import { GameMode } from './working-area/model/gameMode';
@Injectable({
providedIn: 'root'
})
export class CanvasShareDataService {
constructor() { }
constructor(private http:HttpClient) { }
private _sendMessage: ReplaySubject<any> = new ReplaySubject<any>(1);
examDisposalNodesData; // 考生进入时获取当前试卷的处置节点
examFacilityAssetsData; // 考生进入时获取当前试卷要考察的消防设施
examOriginaleveryStoreyData: any; // 考生答卷 总平面图/楼层/区域 楼层数据
hiddenBasicInfoFacilities: any = []; // 考生答卷 当前楼层需要隐藏的基本信息素材
isChange = false; // 数据 是否改动
selectTemplateData: any; // 选择当前 模板数据
isChange:boolean = false; // 数据 是否改动
selectTemplateData:any; // 选择当前 模板数据
// 总平面图/建筑 楼层
selectStorey: any = {area: '', details: ''}; // 选择当前 楼层 数据
originalcompanyBuildingData: any; // 单位/建筑 数据
originaleveryStoreyData: any; // 总平面图/楼层/区域 楼层数据
examOriginaleveryStoreyData: any; // 考生答卷 总平面图/楼层/区域 楼层数据
hiddenBasicInfoFacilities: any = []; // 考生答卷 当前楼层需要隐藏的基本信息素材
// 总平面图/建筑 楼层
// 处置 节点
allDisposalNode: any = []; // 所有 处置节点
allNodeMarkers: any; // 灾情 标签信息
selectPanelPoint: DisposalNodeData = new DisposalNodeData();
selectPanelPointBaseData: any = {description: '', notes: '', weather: '', airTemperature: '', windDirection: '', windScale: ''}; // 当前 数据节点 所对应的 天气,详情 数据节点
allNodeMarkers: any = { highlightMarkers:{}, markers:{} }; // 灾情 标签信息
selectPanelPoint: DisposalNodeData = new DisposalNodeData(); // 当前数据节点
selectPanelPointBaseData: any = {description: '', notes: '', weather: '', airTemperature: '', windDirection: '', windScale: ''}; // 当前 数据节点 对应 父级节点
customizeDisposalNode:any; // 新建 自定义数据节点 底图+名称
// 处置 节点
/**
*
*/
@ -83,6 +82,49 @@ export class CanvasShareDataService {
return this._sendMessage.asObservable();
}
//分段上传
sectionUpload (companyId:string,file) {
let data = {filename: file.name}
return new Promise ((resolve, reject)=>{
this.http.post(`/api/NewMultipartUpload/PlanPlatform/${companyId}/DisposalNode`,{},{params:data}).subscribe(async (data:any)=>{ //初始化分段上传
let objectName = data.objectName
let uploadId = data.uploadId
let PartNumberETag = []; //每次返回需要保存的信息
//分块 处理
let fileSize = file.size || null //上传文件的总大小
let shardSize = 5 * 1024 * 1024 //5MB一个分片
let allSlice = Math.ceil(fileSize / shardSize) //总文件/5MB===共分多少段
for (let i = 0;i < allSlice;i++) { //循环分段上传
let start = i * shardSize //切割文件开始位置
let end = Math.min(fileSize, start + shardSize); //切割文件结束位置
let formData = new FormData()
formData.append("file",file.slice(start, end))
//同步写法实现异步调用
let result = await new Promise((resolve, reject) => {
// await 需要后面返回一个 promise 对象
this.http.post(`/api/MultipartUpload/PlanPlatform/${objectName}?uploadId=${uploadId}&partNumber=${i+1}`,formData).subscribe((data:any)=>{
let msg = { "partNumber":data.partNumber || null, "eTag": data.eTag || null }
resolve(msg) // 调用 promise 内置方法处理成功
})
});
PartNumberETag.push(result)
if (PartNumberETag.length === allSlice) { //分块上传完成
let data = PartNumberETag
let paramsData = {uploadId:uploadId}
this.http.post(`/api/CompleteMultipartUpload/PlanPlatform/${objectName}`,data,{params:paramsData}).subscribe(data=>{
resolve(objectName)
})
}
}//for循环
//分块 处理
})
})
}
// 处置节点 筛选出 匹配数据 匹配不到 return undefined
findDisposalNode(parentId: string= null, name: string= null) {
if (parentId && name) { // 匹配 父id, name
@ -588,6 +630,14 @@ export class DisposalNodeData {
*
*/
public Version: string;
/**
*
*/
public BackgroundImageUrl: string;
/**
*
*/
public BackgroundImageAngle: number;
/**
*
*/

112
src/app/working-area/model/axGrid.ts

@ -8,58 +8,38 @@ const DEFAULT_LINE_STYLE = {
native: true,
};
/**
* @description
* @extends PIXI.Graphics
*/
export class AxGrid extends PIXI.Graphics {
private _cellSize: number;
private _correctedWidth: number;
private _gridWidth: number;
private _useCorrectedWidth: boolean;
private _drawBoundaries: any;
private _amtLines: any;
/**
* @param {number} cellSize 默认值:网格边长的平方根
*/
private _cellSize: number;
private _correctedWidth: number;
private _gridWidth: number;
private _useCorrectedWidth: boolean;
private _drawBoundaries: any;
private _amtLines: any;
set cellSize(cellSize) {
this._cellSize = cellSize || Math.sqrt(this._correctedWidth);
}
get cellSize() {
return this._cellSize;
}
/**
* 线
*/
get amtLines() {
return Math.floor(this.gridWidth / this.cellSize);
}
/**
* ' width '
*/
get originalWidth() {
return this._gridWidth;
}
/**
*
*
*
*/
get correctedWidth() {
return this._correctedWidth;
}
get useCorrectedWidth() {
return this._useCorrectedWidth;
}
/**
*
* @returns {{ x1: number, y1: number, x2: number, y2: number}}
* (**x1**)(**y1**)(**x2**)(**y2**)
*/
get bounds() {
return {
@ -78,50 +58,11 @@ export class AxGrid extends PIXI.Graphics {
return this._drawBoundaries;
}
/**
*
* ' cellSize '
* ' width '
*/
get gridWidth() {
if (!this.useCorrectedWidth) { return this._gridWidth; }
return Math.abs(this.cellSize - Math.sqrt(this._correctedWidth)) <= 1e-6 ? this._correctedWidth : this._gridWidth;
}
/**
*
* @param {number} width number. Required.
*
* The target sidelength of the grid. It is best for `width` to be a perfect square (i.e., 2, 4, 9, 16, 25, etc.). If
* not and the parameter `useCorrectedWidth` is set to **false**, then the grid will use a corrected width,
* which is the smallest perfect square greater than `width`.
*
* @param {number} cellSize number, null. Optional, default: square root of corrected width
*
* The size of each cell in the grid.
* If the value is **null**, the grid will use the default value.
*
* @param {{ width: number, color: number, alpha: number, alignment: number, native: boolean }}. Object. Optional.
*
* default:
* **{
* width: 1,
* color: 0xffffff,
* alpha: 1,
* alignment: 0.5,
* native: true
* }**
*
* Configuration for the line style on the object. See documentation on `PIXI.Graphics` for more on the `LineStyle` class.
*
* @param {boolean} useCorrectedWidth boolean. Optional. default: **true**
* If **true**, the grid will use the smallest perfect square greater than `width`.
* Otherwise, the grid will use the exact value given by `width`.
*
* @param {boolean} drawBoundaries boolean. Optional. default: **true**
* If **true**, the grid will draw its boundaries.
* Otherwise, the grid will not draw its boundaries. Mouse pointer detection is not affected.
*/
constructor(
width,
cellSize= null,
@ -151,12 +92,9 @@ export class AxGrid extends PIXI.Graphics {
lConfig.alignment,
lConfig.native
);
// handle mouse move
this.interactive = true;
this.on('mousemove', (evt) => {
const mouseCoords = evt.data.getLocalPosition(evt.currentTarget.parent);
// 检查鼠标是否在此网格的范围内。如果不是,那就什么都不做。
if (
mouseCoords.x >= this.bounds.x1 &&
mouseCoords.x <= this.bounds.x2 &&
@ -192,11 +130,6 @@ export class AxGrid extends PIXI.Graphics {
/**
*
*
* @param {boolean} retainLineStyle true
*
* **true**线
* ' PIXI '
*/
clearGrid(retainLineStyle = true) {
const { width, alignment, color, alpha, native } = this.line;
@ -207,14 +140,10 @@ export class AxGrid extends PIXI.Graphics {
return this;
}
/**
* Transforms global coordinates to grid coordinates.
* @param {number} x
* The global X coordinate.
*
* @param {number} y
* The global Y coordinate.
*
* @param x x
* @param y y
*/
getCellCoordinates(x, y) {
return {
@ -222,22 +151,15 @@ export class AxGrid extends PIXI.Graphics {
y: Math.floor((y - this.bounds.y1) / this.cellSize),
};
}
/**
* mousemove事件后触发的回调
*
* @param {PIXI.InteractionData} evt
* 'PIXI.InteractionData '
*
* @param {{x: number, y: number}} gridCoords
*
*
* @param evt
* @param gridCoords
*/
onMousemove(evt, gridCoords) {
}
// 计算修正后的宽度。如果`useCorrectedWidth`构造函数参数设置为**false**,
// 然后,它简单地保持“width”的给定值作为修正后的宽度。
// 默认宽度
_correctWidth() {
if (!this._useCorrectedWidth) {
this._correctedWidth = this._gridWidth;
@ -245,9 +167,7 @@ export class AxGrid extends PIXI.Graphics {
this._correctedWidth = Math.ceil(Math.sqrt(this._gridWidth)) ** 2;
}
// 计算修正后的宽度。如果`useCorrectedWidth`构造函数参数设置为**false**,
// 然后,它简单地保持“width”的给定值作为修正后的宽度。
// 自定义宽度
correctWidth(width: number) {
if (!this._useCorrectedWidth) {
this._correctedWidth = width;

11
src/app/working-area/model/axImageShapeTest.ts

@ -1,11 +0,0 @@
import { AxRectangleShape } from "./axRectangleShape";
export class AxImageShapeTest extends AxRectangleShape{
/**
*
*/
constructor(x:number,y:number,width:number,height:number) {
super(x,y,width,height);
}
}

1
src/app/working-area/model/axLegend.ts

@ -429,7 +429,6 @@ export class AxLegend extends AxShape {
*/
public drawBorder(scale: number) {
const visible = this.upLeft.visible;
console.log(visible);
this.setPointVisiable(false);
super.drawBorder(scale);

90
src/app/working-area/model/axMessageSystem.ts

@ -0,0 +1,90 @@
/**
*
*/
export class AxMessageSystem {
/** 监听数组 */
private static listeners = {};
/**
*
* @param name
* @param callback
* @param context
*/
public static addListener(name: string, callback: () => void, context: any) {
const observers: Observer[] = AxMessageSystem.listeners[name];
if (!observers) {
AxMessageSystem.listeners[name] = [];
}
AxMessageSystem.listeners[name].push(new Observer(callback, context));
}
/**
*
* @param name
* @param callback
* @param context
*/
public static removeListener(name: string, callback: () => void, context: any) {
const observers: Observer[] = AxMessageSystem.listeners[name];
if (!observers) { return; }
const length = observers.length;
for (let i = 0; i < length; i++) {
const observer = observers[i];
if (observer.compar(context)) {
observers.splice(i, 1);
break;
}
}
if (observers.length === 0) {
delete AxMessageSystem.listeners[name];
}
}
/**
*
* @param name
*/
public static send(name: string, ...args: any[]) {
const observers: Observer[] = AxMessageSystem.listeners[name];
if (!observers) { return; }
const length = observers.length;
for (let i = 0; i < length; i++) {
const observer = observers[i];
observer.notify(name, ...args);
}
}
}
/**
*
*/
class Observer {
/** 回调函数 */
private callback: () => void;
/** 上下文 */
private context: any = null;
constructor(callback: () => void, context: any) {
const self = this;
self.callback = callback;
self.context = context;
}
/**
*
* @param args
*/
notify(...args: any[]): void {
const self = this;
self.callback.call(self.context, ...args);
}
/**
*
* @param context
*/
compar(context: any): boolean {
return context === this.context;
}
}

18
src/app/working-area/model/axRectangleShape.ts

@ -1,16 +1,16 @@
import { Sprite } from "pixi.js";
import { Graphics } from "pixi.js";
import { WorkingAreaComponent } from "../working-area.component";
import { AxShape } from "./axShape";
import { Sprite } from 'pixi.js';
import { Graphics } from 'pixi.js';
import { WorkingAreaComponent } from '../working-area.component';
import { AxShape } from './axShape';
export class AxRectangleShape extends AxShape{
export class AxRectangleShape extends AxShape {
/**
*
*/
constructor(x:number,y:number,width:number,height:number,assetData: any, workingArea: WorkingAreaComponent) {
super(assetData,workingArea);
this.beginFill(0x0000ff,1);
this.lineStyle(1, 0xff0000,1);
constructor(x: number, y: number, width: number, height: number, assetData: any, workingArea: WorkingAreaComponent) {
super(assetData, workingArea);
this.beginFill(0x0000ff, 1);
this.lineStyle(1, 0xff0000, 1);
this.drawRect(x, y, width, height);
this.endFill();

65
src/app/working-area/model/axSelection.ts

@ -0,0 +1,65 @@
import { allowedNodeEnvironmentFlags } from "process";
/**
*
*/
export class AxSelection {
constructor() {
}
private objects: Set<any> = new Set<any>();
// 获得第一个对象
public first(): any {
if (this.objects.size > 0) {
return [...this.objects][0];
} else {
return null;
}
}
// 是否已经选择了对象
public has(obj: any): boolean {
return this.objects.has(obj);
}
// 是否所有选择对象都允许编辑
public allowEdit(): boolean {
let allowEdit = true;
for (const item of this.objects) {
if (!item.allowEdit) {
allowEdit = false;
break;
}
}
return allowEdit;
}
// 获得所有对象
public all() {
return [...this.objects];
}
// 获取集合长度
public size(): number {
return this.objects.size;
}
// 添加对象
public add(obj: any) {
this.objects.add(obj);
}
// 添加集合
public addArray(array: any[]) {
array.forEach(item => {
this.objects.add(item);
});
}
// 移除对象
public delete(obj: any) {
this.objects.delete(obj);
}
// 移除集合
public deleteArray(array: any[]) {
array.forEach(item => {
this.objects.delete(item);
});
}
// 清空所有对象
public clear() {
this.objects.clear();
}
}

104
src/app/working-area/model/axShape.ts

@ -8,18 +8,20 @@ import { WorkingAreaComponent } from '../working-area.component';
*/
export class AxShape extends Graphics {
assetData: any;
pointTexture: PIXI.Texture = PIXI.Texture.from('assets/images/handle-main.png')
pointTexture: PIXI.Texture = PIXI.Texture.from('assets/images/handle-main.png');
workingArea: WorkingAreaComponent;
// 可以被移动的
moveable = true;
// 可以被选中的
selectable = true;
// 允许选择
allowSelect = true;
// 允许编辑
allowEdit = true;
// 是否显示名称
showName = true;
// 边框
border: PIXI.Graphics = new PIXI.Graphics();
// 鼠标位置
mousePosition: PIXI.Point;
// 鼠标拖动
mouseDragging: boolean;
constructor(assetData: any, workingArea: WorkingAreaComponent) {
super();
@ -34,51 +36,31 @@ export class AxShape extends Graphics {
this
.on('pointerdown', event => {
event.stopPropagation();
if (this.selectable) {
this.workingArea.selection.selectOne(this);
if (this.allowSelect) {
this.workingArea.select(this);
}
if (this.moveable) {
event.currentTarget.data = event.data;
event.currentTarget.alpha = 0.5;
event.currentTarget.dragging = true;
event.currentTarget.dragPoint = event.data.getLocalPosition(event.currentTarget.parent);
event.currentTarget.dragPoint.x -= event.currentTarget.x;
event.currentTarget.dragPoint.y -= event.currentTarget.y;
if (this.allowEdit) {
this.mouseDragging = true;
this.mousePosition = new PIXI.Point(event.data.global.x, event.data.global.y);
}
})
.on('pointerup', event => {
if (event.currentTarget.dragging) {
event.currentTarget.alpha = 1;
event.currentTarget.dragging = false;
event.currentTarget.data = null;
}
this.mouseDragging = false;
})
.on('pointerupoutside', event => {
if (event.currentTarget.dragging) {
event.currentTarget.alpha = 1;
event.currentTarget.dragging = false;
event.currentTarget.data = null;
}
this.mouseDragging = false;
})
.on('pointermove', event => {
if (event.currentTarget.dragging) {
const newPosition = event.currentTarget.data.getLocalPosition(event.currentTarget.parent);
// const offsetX = newPosition.x - event.currentTarget.dragPoint.x;
// const offsetY = newPosition.y - event.currentTarget.dragPoint.y;
// const offset = this.workingArea.backgroundImage.toLocal(new Point(offsetX, offsetY));
// event.currentTarget.position += offset;
// // this.workingArea.selection.objects.forEach(shpae => {
// // shpae.x = newPosition.x - event.currentTarget.dragPoint.x;
// // shpae.y = newPosition.y - event.currentTarget.dragPoint.y;
// // shpae.assetData.Point = new PIXI.Point(this.x, this.y);
// // this.workingArea.canvasData.isChange = true;
// // })
event.currentTarget.x = newPosition.x - event.currentTarget.dragPoint.x;
event.currentTarget.y = newPosition.y - event.currentTarget.dragPoint.y;
this.assetData.Point = new PIXI.Point(this.x, this.y);
this.workingArea.canvasData.isChange = true;
if (this.mouseDragging) {
this.workingArea.selection.all().forEach(item => {
const x = event.data.global.x - this.mousePosition.x;
const y = event.data.global.y - this.mousePosition.y;
item.x += x * (1 / this.workingArea.camera2D.scale.x);
item.y += y * (1 / this.workingArea.camera2D.scale.y);
item.assetData.Point = new PIXI.Point(item.x, item.y);
this.workingArea.canvasData.isChange = true;
});
this.mousePosition = new PIXI.Point(event.data.global.x, event.data.global.y);
}
})
.on('rightclick', event => {
@ -89,7 +71,7 @@ export class AxShape extends Graphics {
}
refresh(): void{
refresh(): void {
}
public setItemScale(scale: number) {
@ -127,13 +109,13 @@ export class AxShape extends Graphics {
this.border.lineStyle(scale * 1, 0x00a8ff);
var spaceLength = scale * 1;
var lineLenght = rect.width + 0.5 + 0.5;
var dashLength = scale*( lineLenght +spaceLength - Math.floor((rect.width + rect.height)/2 / 4.1))/Math.floor((rect.width + rect.height)/2 / 4.1);
this.drawDash(this.border, p1.x -0.5*scale, p1.y, p2.x + 0.5*scale, p2.y,dashLength,spaceLength);
this.drawDash(this.border, p2.x, p2.y -0.5*scale, p3.x, p3.y + 0.5*scale, dashLength, spaceLength);
this.drawDash(this.border, p3.x+0.5*scale, p3.y, p4.x - 0.5*scale, p4.y, dashLength, spaceLength);
this.drawDash(this.border, p4.x, p4.y + 0.5*scale, p1.x, p1.y - 0.5*scale, dashLength, spaceLength);
const spaceLength = scale * 1;
const lineLenght = rect.width + 0.5 + 0.5;
const dashLength = scale * ( lineLenght + spaceLength - Math.floor((rect.width + rect.height) / 2 / 4.1)) / Math.floor((rect.width + rect.height) / 2 / 4.1);
this.drawDash(this.border, p1.x - 0.5 * scale, p1.y, p2.x + 0.5 * scale, p2.y, dashLength, spaceLength);
this.drawDash(this.border, p2.x, p2.y - 0.5 * scale, p3.x, p3.y + 0.5 * scale, dashLength, spaceLength);
this.drawDash(this.border, p3.x + 0.5 * scale, p3.y, p4.x - 0.5 * scale, p4.y, dashLength, spaceLength);
this.drawDash(this.border, p4.x, p4.y + 0.5 * scale, p1.x, p1.y - 0.5 * scale, dashLength, spaceLength);
this.border.lineStyle(0, 0x0000ff);
// this.border.beginFill(0x00ff00,0.1);
@ -145,16 +127,16 @@ export class AxShape extends Graphics {
// this.border.endFill();
}
// 画虚线
drawDash(target, x1, y1, x2, y2,dashLength = 5, spaceLength = 1) {
let x = x2 - x1;
let y = y2 - y1;
drawDash(target, x1, y1, x2, y2, dashLength = 5, spaceLength = 1) {
const x = x2 - x1;
const y = y2 - y1;
let hyp = Math.sqrt((x) * (x) + (y) * (y));
let units = hyp / (dashLength + spaceLength);
let dashSpaceRatio = dashLength / (dashLength + spaceLength);
let dashX = (x / units) * dashSpaceRatio;
let spaceX = (x / units) - dashX;
let dashY = (y / units) * dashSpaceRatio;
let spaceY = (y / units) - dashY;
const units = hyp / (dashLength + spaceLength);
const dashSpaceRatio = dashLength / (dashLength + spaceLength);
const dashX = (x / units) * dashSpaceRatio;
const spaceX = (x / units) - dashX;
const dashY = (y / units) * dashSpaceRatio;
const spaceY = (y / units) - dashY;
target.moveTo(x1, y1);
@ -200,7 +182,7 @@ export class AxShape extends Graphics {
return new PIXI.Point(gravityLat, gravityLng);
}
// 计算线段中点坐标
public getLineCenter(point1:PIXI.Point,point2:PIXI.Point) {
return new PIXI.Point((point1.x+point2.x)/2,(point1.y+point2.y)/2)
public getLineCenter(point1: PIXI.Point, point2: PIXI.Point) {
return new PIXI.Point((point1.x + point2.x) / 2, (point1.y + point2.y) / 2);
}
}

164
src/app/working-area/model/configuration.ts

@ -0,0 +1,164 @@
import { EventDispatcher } from 'three';
import { EVENT_CHANGED } from './events';
// GENERAL:
/** The dimensioning unit for 2D floorplan measurements. */
export var configDimUnit = 'dimUnit';
// WALL:
/** The initial wall height in cm. */
export const configWallHeight = 'wallHeight';
/** The initial wall thickness in cm. */
export const configWallThickness = 'wallThickness';
export const configSystemUI = 'systemUI';
export const scale = 'scale';
export const gridSpacing = 'gridSpacing';
export const snapToGrid = 'snapToGrid';
export const directionalDrag = 'directionalDrag';
export const dragOnlyX = 'dragOnlyX';
export const dragOnlyY = 'dragOnlyY';
export const snapTolerance = 'snapTolerance'; //In CMS
export const boundsX = 'boundsX'; //In CMS
export const boundsY = 'boundsY'; //In CMS
export const viewBounds = 'viewBounds';//In CMS
export const dimInch = 'inch';
/** Dimensioning in Inch. */
export const dimFeetAndInch = 'feetAndInch';
/** Dimensioning in Meter. */
export const dimMeter = 'm';
/** Dimensioning in Centi Meter. */
export const dimCentiMeter = 'cm';
/** Dimensioning in Milli Meter. */
export const dimMilliMeter = 'mm';
export const VIEW_TOP = 'topview';
export const VIEW_FRONT = 'frontview';
export const VIEW_RIGHT = 'rightview';
export const VIEW_LEFT = 'leftview';
export const VIEW_ISOMETRY = 'isometryview';
export enum WallTypes{
STRAIGHT,
CURVED
}
export const TEXTURE_DEFAULT_REPEAT = 300;
export const defaultWallTexture =
{
color: '#FFFFFF', repeat: TEXTURE_DEFAULT_REPEAT, normalmap: 'textures/Wall/Brick_Wall_017_SD/Brick_Wall_017_normal.jpg', roughnessmap: 'textures/Wall/Brick_Wall_017_SD/Brick_Wall_017_roughness.jpg', colormap: 'textures/Wall/Brick_Wall_017_SD/Brick_Wall_017_basecolor.jpg', ambientmap: 'textures/Wall/Brick_Wall_017_SD/Brick_Wall_017_ambientOcclusion.jpg', bumpmap: 'textures/Wall/Brick_Wall_017_SD/Brick_Wall_017_height.png'
};
export const defaultFloorTexture =
{
color: '#FFFFFF', emissive: '#181818', repeat: TEXTURE_DEFAULT_REPEAT, ambientmap: 'textures/Floor/Marble_Tiles_001/Marble_Tiles_001_ambientOcclusion.jpg', colormap: 'textures/Floor/Marble_Tiles_001/Marble_Tiles_001_basecolor.jpg', roughnessmap: 'textures/Floor/Marble_Tiles_001/Marble_Tiles_001_roughness.jpg', normalmap: 'textures/Floor/Marble_Tiles_001/Marble_Tiles_001_normal.jpg'
};
export const TEXTURE_PROPERTY_COLOR = 'color';
export const TEXTURE_NO_PREVIEW = 'textures/NoPreview.jpg';
export var config = {
dimUnit: dimCentiMeter,
wallHeight: 250,
wallThickness: 20,
systemUI: false,
scale: 1,
snapToGrid: true,
dragOnlyX: false,
dragOnlyY: false,
snapTolerance: 50,
gridSpacing: 20, // 50,
directionalDrag: true,
boundsX: 500,
boundsY: 500,
viewBounds: 20000 };
export var wallInformation = { exterior: false, interior: false, midline: true, labels: true, exteriorlabel: 'e:', interiorlabel: 'i:', midlinelabel: 'm:' };
/**
* The tolerance in cms between corners, otherwise below this tolerance they will snap together as one corner*/
export const cornerTolerance = 20;
/** Global configuration to customize the whole system.
* This is a singleton instance;
*/
export class Configuration extends EventDispatcher {
private static instance = new Configuration();
constructor() {
/** Configuration data loaded from/stored to extern. */
// this.data = {dimUnit: dimCentiMeter, wallHeight: 250, wallThickness: 10};
super();
}
static getInstance() {
if (this.instance === undefined
|| this.instance === null) {
this.instance = new Configuration();
}
return this.instance;
}
static getData() {
// return {dimUnit: dimCentiMeter,wallHeight: 250, wallThickness: 10};
return config;
}
/** Set a configuration parameter. */
static setValue(key, value) {
// this.data[key] = value;
config[key] = value;
// if(key !== viewBounds){
Configuration.getInstance().dispatchEvent({ type: EVENT_CHANGED, item: Configuration.getInstance(), 'key': key, 'value': value });
// }
}
/** Get a string configuration parameter. */
static getStringValue(key) {
switch (key) {
case configDimUnit:
// return String(this.data[key]);
return String(Configuration.getData()[key]);
default:
throw new Error('Invalid string configuration parameter: ' + key);
}
}
/** Get a numeric configuration parameter. */
static getNumericValue(key) {
switch (key) {
case configSystemUI:
case configWallHeight:
case configWallThickness:
case scale:
case snapTolerance:
case gridSpacing:
case boundsX:
case boundsY:
case viewBounds:
// return Number(this.data[key]);
return Number(Configuration.getData()[key]);
default:
throw new Error('Invalid numeric configuration parameter: ' + key);
}
}
/** Get a numeric configuration parameter. */
static getBooleanValue(key) {
switch (key) {
case snapToGrid:
case directionalDrag:
case dragOnlyX:
case dragOnlyY:
return Boolean(Configuration.getData()[key]);
default:
throw new Error('Invalid Boolean configuration parameter: ' + key);
}
}
}

145
src/app/working-area/model/dimensioning.ts

@ -0,0 +1,145 @@
import { Vector2, Vector3 } from 'three';
import { Configuration, configDimUnit,dimInch, dimFeetAndInch, dimMeter, dimCentiMeter, dimMilliMeter } from './configuration';
export const decimals = 1000;
export const cmPerFoot = 30.48;
export const pixelsPerFoot = 5.0;
export const pixelsPerCm = 1; // 0.5;
export const cmPerPixel = (1.0 / pixelsPerCm);
export const dimensioningOptions = [dimInch, dimFeetAndInch, dimMeter, dimCentiMeter, dimMilliMeter];
/** Dimensioning functions. */
export class Dimensioning {
static cmToPixelVector2D(cmV2d) {
let pixelV2d = new Vector2(Dimensioning.cmToPixel(cmV2d.x), Dimensioning.cmToPixel(cmV2d.y));
return pixelV2d;
}
static cmToPixelVector3D(cmV3d) {
let pixelV2d = new Vector3(Dimensioning.cmToPixel(cmV3d.x), Dimensioning.cmToPixel(cmV3d.y), Dimensioning.cmToPixel(cmV3d.z));
return pixelV2d;
}
static pixelToCmVector2D(pixelV2d) {
let cmV2d = new Vector2(Dimensioning.cmToPixel(pixelV2d.x), Dimensioning.cmToPixel(pixelV2d.y));
return cmV2d;
}
static pixelToCmVector3D(pixel3d) {
let cmV2d = new Vector3(Dimensioning.cmToPixel(pixel3d.x), Dimensioning.cmToPixel(pixel3d.y), Dimensioning.cmToPixel(pixel3d.z));
return cmV2d;
}
static cmToPixel(cm, apply_scale = true) {
if (apply_scale) {
return cm * pixelsPerCm * Configuration.getNumericValue('scale');
}
return cm * pixelsPerCm;
}
static pixelToCm(pixel, apply_scale = true) {
if (apply_scale) {
return pixel * cmPerPixel * (1.0 / Configuration.getNumericValue('scale'));
}
return pixel * cmPerPixel;
}
static roundOff(value, decimals) {
return Math.round(decimals * value) / decimals;
}
/** Converts cm to dimensioning number.
* @param cm Centi meter value to be converted.
* @returns Number representation.
*/
static cmFromMeasureRaw(measure) {
switch (Configuration.getStringValue(configDimUnit)) {
case dimFeetAndInch:
return Math.round(decimals * (measure * 30.480016459203095991)) / decimals;
case dimInch:
return Math.round(decimals * (measure * 2.5400013716002578512)) / decimals;
case dimMilliMeter:
return Math.round(decimals * (measure * 0.10000005400001014955)) / decimals;
case dimCentiMeter:
return measure;
case dimMeter:
default:
return Math.round(decimals * 100 * measure) / decimals;
}
}
/** Converts cm to dimensioning string.
* @param cm Centi meter value to be converted.
* @returns String representation.
*/
static cmFromMeasure(measure) {
switch (Configuration.getStringValue(configDimUnit)) {
case dimFeetAndInch:
return Math.round(decimals * (measure * 30.480016459203095991)) / decimals + 'cm';
case dimInch:
return Math.round(decimals * (measure * 2.5400013716002578512)) / decimals + 'cm';
case dimMilliMeter:
return Math.round(decimals * (measure * 0.10000005400001014955)) / decimals + 'cm';
case dimCentiMeter:
return measure;
case dimMeter:
default:
return Math.round(decimals * 100 * measure) / decimals + 'cm';
}
}
/** Converts cm to dimensioning string.
* @param cm Centi meter value to be converted.
* @returns String representation.
*/
static cmToMeasureRaw(cm, power = 1) {
switch (Configuration.getStringValue(configDimUnit)) {
case dimFeetAndInch: // dimFeetAndInch returns only the feet
var allInFeet = (cm * Math.pow(0.032808416666669996953, power));
return allInFeet;
case dimInch:
var inches = Math.round(decimals * (cm * Math.pow(0.393700, power))) / decimals;
return inches;
case dimMilliMeter:
var mm = Math.round(decimals * (cm * Math.pow(10, power))) / decimals;
return mm;
case dimCentiMeter:
return Math.round(decimals * cm) / decimals;
case dimMeter:
default:
var m = Math.round(decimals * (cm * Math.pow(0.01, power))) / decimals;
return m;
}
}
/** Converts cm to dimensioning string.
* @param cm Centi meter value to be converted.
* @returns String representation.
*/
static cmToMeasure(cm, power = 1) {
switch (Configuration.getStringValue(configDimUnit)) {
case dimFeetAndInch:
var allInFeet = (cm * Math.pow(0.032808416666669996953, power));
var floorFeet = Math.floor(allInFeet);
var remainingFeet = allInFeet - floorFeet;
var remainingInches = Math.round(remainingFeet * 12);
return floorFeet + '\'' + remainingInches + '';
case dimInch:
var inches = Math.round(decimals * (cm * Math.pow(0.393700, power))) / decimals;
return inches + '\'';
case dimMilliMeter:
var mm = Math.round(decimals * (cm * Math.pow(10, power))) / decimals;
return '' + mm + 'mm';
case dimCentiMeter:
return '' + Math.round(decimals * cm) / decimals + 'cm';
case dimMeter:
default:
var m = Math.round(decimals * (cm * Math.pow(0.01, power))) / decimals;
return '' + m + 'm';
}
}
}

67
src/app/working-area/model/events.ts

@ -0,0 +1,67 @@
export const EVENT_ACTION = 'ACTION_EVENT';
export const EVENT_DELETED = 'DELETED_EVENT';
export const EVENT_MOVED = 'MOVED_EVENT';
export const EVENT_REDRAW = 'REDRAW_EVENT';
export const EVENT_NEW = 'NEW_EVENT';
export const EVENT_LOADED = 'LOADED_EVENT';
export const EVENT_LOADING = 'LOADING_EVENT';
export const EVENT_UPDATED = 'UPDATED_EVENT';
export const EVENT_SAVED = 'SAVED_EVENT';
export const EVENT_CHANGED = 'CHANGED_EVENT';
export const EVENT_GLTF_READY = 'GLTF_READY_EVENT';
export const EVENT_EXTERNAL_FLOORPLAN_LOADED = 'EXTERNAL_FLOORPLAN_LOADED_EVENT';
export const EVENT_NEW_PARAMETRIC_ITEM = 'NEW_PARAMETRIC_ITEM_EVENT';
export const EVENT_NEW_ITEM = 'NEW_ITEM_EVENT';
export const EVENT_ITEM_LOADING = 'ITEM_LOADING_EVENT';
export const EVENT_ITEM_LOADED = 'ITEM_LOADED_EVENT';
export const EVENT_ITEM_REMOVED = 'ITEM_REMOVED_EVENT';
export const EVENT_ITEM_SELECTED = 'ITEM_SELECTED_EVENT';
export const EVENT_ITEM_MOVE = 'ITEM_MOVED_EVENT';
export const EVENT_ITEM_MOVE_FINISH = 'ITEM_MOVED_FINISH_EVENT';
export const EVENT_ITEM_HOVERON = 'ITEM_HOVERON_EVENT';
export const EVENT_ITEM_HOVEROFF = 'ITEM_HOVEROFF_EVENT';
export const EVENT_NO_ITEM_SELECTED = 'ITEM_NO_SELECTED_EVENT';
export const EVENT_MODE_RESET = 'MODE_RESET_EVENT';
export const EVENT_CAMERA_MOVED = 'CAMERA_MOVED_EVENT';
export const EVENT_CAMERA_ACTIVE_STATUS = 'CAMERA_ACTIVE_STATUS_EVENT';
export const EVENT_CAMERA_VIEW_CHANGE = 'CAMERA_VIEW_CHANGE_EVENT';
export const EVENT_FPS_EXIT = 'CAMERA_FPS_EXIT_EVENT';
export const EVENT_WALL_CLICKED = 'WALL_CLICKED_EVENT';
export const EVENT_ROOM_CLICKED = 'ROOM_CLICKED_EVENT';
export const EVENT_FLOOR_CLICKED = 'FLOOR_CLICKED_EVENT';
export const EVENT_NOTHING_CLICKED = 'NOTHING_CLICKED_EVENT';
export const EVENT_ROOM_NAME_CHANGED = 'CHANGED_ROOM_NAME_EVENT';
export const EVENT_NEW_ROOMS_ADDED = 'ADDED_NEW_ROOMS_EVENT';
export const EVENT_CORNER_ATTRIBUTES_CHANGED = 'CORNER_ATTRIBUTES_CHANGED_EVENT';
export const EVENT_WALL_ATTRIBUTES_CHANGED = 'WALL_ATTRIBUTES_CHANGED_EVENT';
export const EVENT_ROOM_ATTRIBUTES_CHANGED = 'ROOM_ATTRIBUTES_CHANGED_EVENT';
export const EVENT_CORNER_2D_CLICKED = 'CORNER_CLICKED_2D_EVENT';
export const EVENT_WALL_2D_CLICKED = 'WALL_CLICKED_2D_EVENT';
export const EVENT_ROOM_2D_CLICKED = 'ROOM_CLICKED_2D_EVENT';
export const EVENT_2D_UNSELECTED = 'UNSELECTED_2D_EVENT';
export const EVENT_2D_SELECTED = 'SELECTED_2D_EVENT';
export const EVENT_NOTHING_2D_SELECTED = 'NOTHING_2D_SELECTED_EVENT';
export const EVENT_CORNER_2D_DOUBLE_CLICKED = 'CORNER_DOUBLE_CLICKED_2D_EVENT';
export const EVENT_WALL_2D_DOUBLE_CLICKED = 'WALL_DOUBLE_CLICKED_2D_EVENT';
export const EVENT_ROOM_2D_DOUBLE_CLICKED = 'ROOM_DOUBLE_CLICKED_2D_EVENT';
export const EVENT_CORNER_2D_HOVER = 'CORNER_HOVER_2D_EVENT';
export const EVENT_WALL_2D_HOVER = 'WALL_HOVER_2D_EVENT';
export const EVENT_ROOM_2D_HOVER = 'ROOM_HOVER_2D_EVENT';
export const EVENT_KEY_PRESSED = 'KEY_PRESSED_EVENT';
export const EVENT_KEY_RELEASED = 'KEY_RELEASED_EVENT';
export const EVENT_UPDATE_TEXTURES = 'UPDATE_TEXTURES_EVENT';
export const EVENT_MODIFY_TEXTURE_ATTRIBUTE = 'MODIFY_TEXTURE_ATTRIBUTE_EVENT';
export const EVENT_PARAMETRIC_GEOMETRY_UPATED = 'PARAMETRIC_GEOMETRY_UPATED_EVENT';

87
src/app/working-area/model/grid2D.ts

@ -0,0 +1,87 @@
import { Configuration, gridSpacing, viewBounds } from './configuration';
import { EVENT_CHANGED } from './events';
import { Graphics } from 'pixi.js';
import { Vector2 } from 'three';
import { Dimensioning } from './dimensioning';
const GRID_SIZE = 10000;
export class Grid2D extends Graphics {
canvas;
options;
size;
gridScale;
constructor(canvas, options) {
super();
// this.drawRect(0, 0, GRID_SIZE, GRID_SIZE);
this.canvas = canvas;
this.options = options;
this.size = new Vector2(GRID_SIZE, GRID_SIZE);
this.gridScale = 1.0;
this.width = this.size.x;
this.height = this.size.y;
this.drawRect(0, 0, GRID_SIZE, GRID_SIZE);
this.pivot.x = this.pivot.y = 0.5;
Configuration.getInstance().addEventListener(EVENT_CHANGED, (evt) => this.updateGrid());
this.updateGrid();
}
updateGrid() {
let gridSize = Dimensioning.cmToPixel(Configuration.getNumericValue(viewBounds) * 1);
let spacingCMS = Configuration.getNumericValue(gridSpacing);
let spacing = Dimensioning.cmToPixel(spacingCMS);
let totalLines = gridSize / spacing;
let halfSize = gridSize * 0.5;
let linewidth = Math.max(1.0 / this.gridScale, 1.0) * 1/this.canvas.scale.x;// 增加缩放系数
let highlightLineWidth = Math.max(1 / this.gridScale, 1.0) * 1/this.canvas.scale.x;// 增加缩放系数
let normalColor = 0xE0E0E0;
let highlightColor = 0xD0D0D0;
const cellSize = 5;
this.clear();
for (let i = 0; i <= totalLines; i++) {
let co = (i * spacing) - halfSize;
if (i % cellSize === 0) {
this.lineStyle(highlightLineWidth, highlightColor).moveTo(-halfSize, co).lineTo(halfSize, co);
this.lineStyle(highlightLineWidth, highlightColor).moveTo(co, -halfSize).lineTo(co, halfSize);
} else {
this.lineStyle(linewidth, normalColor).moveTo(-halfSize, co).lineTo(halfSize, co);
this.lineStyle(linewidth, normalColor).moveTo(co, -halfSize).lineTo(co, halfSize);
}
}
this.endFill();
this.beginFill(0xFF0000, 1.0);
this.drawCircle(-halfSize, -halfSize,5);
this.drawCircle(halfSize, -halfSize,5);
this.drawCircle(halfSize, halfSize,5);
this.drawCircle(-halfSize, halfSize,5);
this.drawCircle(0, 0, 5);
this.endFill();
}
getGridScale() {
return this.gridScale;
}
setGridScale(value) {
this.gridScale = value;
this.updateGrid();
}
configurationUpdate(evt) {
if (evt.key === gridSpacing) {
this.updateGrid();
}
}
getCellCoordinates(x, y) {
let gridSize = Dimensioning.cmToPixel(Configuration.getNumericValue(viewBounds) * 1);
let spacingCMS = Configuration.getNumericValue(gridSpacing);
let spacing = Dimensioning.cmToPixel(spacingCMS);
let halfSize = gridSize * 0.5;
return {
x: Math.floor((x - -halfSize) / spacing),
y: Math.floor((y - -halfSize) / spacing),
};
}
}

37
src/app/working-area/model/messageSystem.ts

@ -1,37 +0,0 @@
class MyEvent<T> extends CustomEvent<T> {
public static readonly CMD: string = "EVENT_NAME";
public constructor($type: string , $data: T ) {
super( $type , { detail: $data, bubbles: true, cancelable: true, composed: true });
}
}
class MyDispatch extends EventTarget {
private static _instance: MyDispatch;
public static get Instance(): MyDispatch {
if (!MyDispatch._instance) MyDispatch._instance = new MyDispatch();
return MyDispatch._instance;
}
public send<T>($data: T, $type: string = MyEvent.CMD): void {
const $event: CustomEvent = new MyEvent<T>($type, $data);
this.dispatchEvent($event);
}
}
class Test {
public constructor() {
MyDispatch.Instance.addEventListener(MyEvent.CMD, this.onEvent as EventListener);
}
private onEvent($e: MyEvent<ITest>): void {
console.log(`target ${$e.target}`);
console.log(`name: ${$e.detail._name} , occupation: ${$e.detail._occupation}`);
}
}
interface ITest {
_name: string;
_occupation: string;
}
let $test: Test = new Test();
MyDispatch.Instance.send<ITest>({ _name: `Aonaufly`, _occupation: `it` });

3
src/app/working-area/working-area.component.html

@ -1,2 +1 @@
<div #content style="width:100%;height:100%;" (mousewheel)='this.mouseWheelHandel($event)'
(DOMMouseScroll)='this.mouseWheelHandel($event)'></div>
<div #content style="width:100%;height:100%;"></div>

944
src/app/working-area/working-area.component.ts

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save