123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- import Render from '../renderer'
- import Point from '../../core/point'
- import WallLine from '../../core/wallline'
- import Casement from '../../architecture/casement'
- import Door from '../../architecture/door/index'
- import Column from '../../architecture/column'
- import { CADElementTS } from '../../core/element'
- import { ProcessingTS } from '.'
- export interface _Point { x: number, y:number, id: number }
- export interface _Line { p1: number, p2: number, id: number }
- export interface _window { pos: Array<number>, line: number, top: number, bottom: number }
- export interface _door { pos: Array<number>, line: number, top: number, bottom: number }
- export interface _column { pos: Array<number>, line: number }
- export interface _hole {pos: Array<number>, top: number}
- export type _Ground = Array<number>
- export interface _room { ground: _Ground, hole: Array<_hole>, top: number, bottom: number }
- export interface Data {vertex: Array<_Point>, surplus: Array<_Point>, wall: Array<_Line>, window: Array<_window>, door: Array<_door>, column: Array<_column>, room: Array<_room>}
- export interface StorageProps{ dom: HTMLElement }
- export interface CADState {elements: Array<Point>}
- export interface rhole extends _hole {bottom: number}
- type Walls = Array<{ id: number; ele: WallLine }>
- type Points = Array<{ id: number; ele: Point }>
- type Cases = Array<{ele: Casement}>
- type Doors = Array<{ele: Door}>
- type Columns = Array<{ele: Column}>
- const numRetain = (n: number, m = 2) => Number(n.toFixed(m))
- class Processing {
- data: Data
- render: Render
- points: Points
- lines: Walls
- cases: Cases
- doors: Doors
- columns: Columns
-
- constructor({dom}: StorageProps) {
- this.render = new Render({ layer: dom, processing: (this as unknown as ProcessingTS) })
- this.points = []
- this.lines = []
- this.cases = []
- this.doors = []
- this.columns = []
- WallLine.initLines(this.render)
- }
- getNewPointId = () => Math.max(...this.points.map(({id}) => id)) + 1
- getNewLineId = () => Math.max(...this.lines.map(({id}) => id)) + 1
- addPoint = ({id, x, y}: _Point) => {
- let ret = {id, ele: new Point({x, y, renderer: this.render})}
- this.points.push(ret)
- this.generateElement(ret.ele)
- return ret
- }
- addLine = ({id, p1, p2}: _Line) => {
- const rooms = this.data.room
- const isOut = rooms.some(({hole}) => hole.some(({pos: h}) => ~h.indexOf(p1) && ~h.indexOf(p2)))
- let ret = {
- id,
- ele: new WallLine({
- points: [
- this.points.find(p => p.id === p1).ele,
- this.points.find(p => p.id === p2).ele
- ],
- renderer: this.render,
- color: isOut ? 'red': void 0,
- isOut
- })
- }
- this.lines.push(ret)
- this.generateElement(ret.ele)
- return ret
- }
- addCase = ({pos, line, top = null, bottom = null}: _window) => {
- let ret = {
- ele: new Casement({
- renderer: this.render,
- attachment: this.lines.find(({id}) => id === line).ele,
- points: [{x: pos[0], y: pos[1]}, {x: pos[2], y: pos[3]}],
- top,
- bottom
- })
- }
- this.cases.push(ret)
- this.generateElement(ret.ele)
- return ret
- }
- addDoor = ({pos, line, top = null, bottom = null}: _door) => {
- let ret = {
- ele: new Door({
- renderer: this.render,
- attachment: this.lines.find(({id}) => id === line).ele,
- points: [{x: pos[0], y: pos[1]}, {x: pos[2], y: pos[3]}],
- top, bottom
- })
- }
- this.doors.push(ret)
- this.generateElement(ret.ele)
- return ret
- }
- addColumn = ({pos, line}: _column) => {
- let ret = {
- ele: new Column({
- renderer: this.render,
- attachment: this.lines.find(({ id }) => id === line).ele,
- points: [
- {x: pos[0], y: pos[1]},
- {x: pos[2], y: pos[3]},
- {x: pos[6], y: pos[7]},
- {x: pos[4], y: pos[5]}
- ]
- })
- }
- this.columns.push(ret)
- this.generateElement(ret.ele)
- return ret
- }
- // 获取与当前room有关联的所有room
- getJoinRooms(room: _room) {
- const checkRooms = []
- const queryRooms = (room: _room) => {
- if (~checkRooms.indexOf(room)) {
- return []
- } else {
- let rooms = this.data.room.filter(({ground}) => ground.some(id => ~room.ground.indexOf(id)))
- checkRooms.push(room)
- rooms.forEach(room => rooms.push(...queryRooms(room)))
- return rooms
- }
- }
- return Array.from(new Set(queryRooms(room)))
- }
- getPointsByRoom (room: _room) {
- room = this.data.room.find(r => r.ground.join('') === room.ground.join(''))
- if (room) {
- return room.ground.map(eid => this.points.find(({id}) => id === eid).ele)
- } else {
- return []
- }
- }
-
- getPointsByHole (rhole: rhole) {
- let rhids = rhole.pos.join('')
- let hole
- for (let i = 0; i < this.data.room.length; i++) {
- hole = this.data.room[i].hole.find(hole => hole.pos.join('') === rhids)
- if(hole) break
- }
- if (hole) {
- return hole.pos.map(eid => this.points.find(({id}) => id === eid).ele)
- } else {
- return []
- }
- }
- getLinesByRoom (room: _room) {
- room = this.data.room.find(r => r.ground.join('') === room.ground.join(''))
- if (room) {
- return this.lines.filter(({ele: line}) => {
- let p1 = this.points.find(({ele}) => ele === line.points[0]).id
- let p2 = this.points.find(({ele}) => ele === line.points[1]).id
- return ~room.ground.indexOf(p1) && ~room.ground.indexOf(p2)
- }).map(({ele}) => ele)
- } else {
- return []
- }
- }
- getLinesByHole (rhole: rhole) {
- let rhids = rhole.pos.join('')
- let hole
- for (let i = 0; i < this.data.room.length; i++) {
- hole = this.data.room[i].hole.find(hole => hole.pos.join('') === rhids)
- if(hole) break
- }
- if (hole) {
- return this.lines.filter(({ele: line}) => {
- let p1 = this.points.find(({ele}) => ele === line.points[0]).id
- let p2 = this.points.find(({ele}) => ele === line.points[1]).id
- return ~hole.pos.indexOf(p1) && ~hole.pos.indexOf(p2)
- }).map(({ele}) => ele)
- } else {
- return []
- }
- }
- getRoomsByPoint (point: Point) {
- let p = this.points.find(({ele}) => ele === point)
- if (p) {
- return this.data.room.filter(room => ~room.ground.indexOf(p.id))
- } else {
- return []
- }
- }
-
- getHolesByPoint (point: Point): Array<rhole> {
- let p = this.points.find(({ele}) => ele === point)
- let holes = []
- if (p) {
- this.data.room.find(room => {
- room.hole.forEach(hole => {
- if (~hole.pos.indexOf(p.id)) {
- holes.push(hole)
- }
- })
- })
- } else {
- console.error(point)
- }
- return holes
- }
- getRoomsByLine (line: WallLine) {
- let p1 = this.points.find(point => point.ele === line.points[0]).id
- let p2 = this.points.find(point => point.ele === line.points[1]).id
-
- return this.data.room.filter(room => ~room.ground.indexOf(p1) && ~room.ground.indexOf(p2))
- }
- getHolesByLine (line: WallLine): Array<_hole & {bottom: number}> {
- let p1 = this.points.find(point => point.ele === line.points[0]).id
- let p2 = this.points.find(point => point.ele === line.points[1]).id
- let holes = []
- this.data.room.forEach(room => {
- room.hole.forEach(hole => {
- if (~hole.pos.indexOf(p1) && ~hole.pos.indexOf(p2)) {
- holes.push(hole)
- }
- })
- })
- return holes
- }
- getLineId = (line: WallLine) => this.lines.find(({ele}) => ele === line).id
- getPointId = (point: Point) => this.points.find(({ele}) => ele === point).id
- // 将数据转换为ele
- toEles (data: Data) {
- let {vertex, wall, window, door, column} = data
- this.data = data
- vertex.forEach(this.addPoint)
- wall.forEach(this.addLine)
- window.forEach(this.addCase)
- door.forEach(this.addDoor)
- column.forEach(this.addColumn)
- this.data.room.forEach(room => {
- room.hole.forEach(hole => {
- Object.defineProperty(hole, 'bottom', {
- get: () => room.bottom
- })
- })
- })
- this.referElements()
- }
- // 将ele转换为data
- toData (): Data {
- let vertex = this.points.map(({ele, id}) => ({
- id, x: numRetain(ele.x), y: numRetain(ele.y)
- }))
- let wall = this.lines.map(({ele, id}) => ({
- id,
- p1: this.getPointId(ele.points[0]),
- p2: this.getPointId(ele.points[1])
- }))
- let column = this.columns.map(({ele}) => ({
- line: this.getLineId(ele.attachment),
- pos: [
- numRetain(ele.points[0].x), numRetain(ele.points[0].y),
- numRetain(ele.points[1].x), numRetain(ele.points[1].y),
- numRetain(ele.points[3].x), numRetain(ele.points[3].y),
- numRetain(ele.points[2].x), numRetain(ele.points[2].y)
- ]
- }))
- let window = this.cases.map(({ele}) =>({
- line: this.getLineId(ele.attachment),
- pos: [
- numRetain(ele.linePoints[0].x), numRetain(ele.linePoints[0].y),
- numRetain(ele.linePoints[1].x), numRetain(ele.linePoints[1].y)
- ],
- top: ele.top,
- bottom: ele.bottom
- }))
- let door = this.doors.map(({ele}) =>({
- line: this.getLineId(ele.attachment),
- pos: [
- numRetain(ele.linePoints[0].x), numRetain(ele.linePoints[0].y),
- numRetain(ele.linePoints[1].x), numRetain(ele.linePoints[1].y)
- ],
- top: ele.top,
- bottom: ele.bottom
- }))
- return {vertex, wall, window, door, column, room: this.data.room, surplus: this.data.surplus}
- }
- referElements() {
- let eles = [
- ...this.lines,
- ...this.points,
- ...this.cases,
- ...this.doors,
- ...this.columns
- ]
- eles.forEach(({ele}) => {
- this.render.g.removeChild(ele.real)
- this.render.elements.splice(this.render.elements.indexOf(ele), 1);
- })
- this.generateElements()
- }
- // 删除房间
- delRoom(cground: Array<number>) {
- let index = this.data.room.findIndex(({ground}) => cground === ground)
-
- if (~index) {
- let [room] = this.data.room.splice(index, 1)
- room.ground.forEach((p1Id, i) => {
- if (i > room.ground.length - 2) return;
- let p2Id = room.ground[i + 1]
- let arr = [p1Id, p2Id]
- let line = this.lines.find(({ele}) => {
- let p1 = this.points.find(({ele: p}) => p === ele.points[0])
- let p2 = this.points.find(({ele: p}) => p === ele.points[1])
- return p1 && p2 && ~arr.indexOf(p1.id) && ~arr.indexOf(p2.id)
- })
- line && line.ele.destroy()
- })
- return true
- } else {
- return false
- }
- }
- // 删除镂空区域
- delHole(cground: Array<number>) {
- let hIndex = -1;
- let rindex = this.data.room.findIndex(({hole}) => {
- hIndex = hole.findIndex(({pos}) => pos === cground)
- return ~hIndex
- })
- if (~rindex) {
- let [hole] = this.data.room[rindex].hole.splice(hIndex, 1)
- hole.pos.forEach((p1Id, i) => {
- if (i > hole.pos.length - 2) return;
- let p2Id = hole.pos[i + 1]
- let arr = [p1Id, p2Id]
- let line = this.lines.find(({ele}) => {
- let p1 = this.points.find(({ele: p}) => p === ele.points[0])
- let p2 = this.points.find(({ele: p}) => p === ele.points[1])
- return p1 && p2 && ~arr.indexOf(p1.id) && ~arr.indexOf(p2.id)
- })
- line && line.ele.destroy()
- })
- return true
- } else {
- return false
- }
- }
- // 构建所有ele
- generateElements() {
- let eles = [
- ...this.lines.map(line => line.ele),
- ...this.points.map(point => point.ele),
- ...this.cases.map(c => c.ele),
- ...this.doors.map(c => c.ele),
- ...this.columns.map(c => c.ele)
- ]
- eles.forEach(this.generateElement)
- }
- attrs = [ 'cases', 'doors', 'columns', 'lines', 'points']
-
- // Element加装Destroy方法
- retrofitElementDestroy (ele: CADElementTS) {
- let destroy = ele.destroy
- if (ele.__load_destroy) return;
- ele.__load_destroy = true
- ele.destroy = (...args) => {
- // rooms字段中删掉
- if (!(args as any)[1] && ele instanceof WallLine) {
-
- let p1 = this.points.find(pe => pe.ele === ele.points[0]).id
- let p2 = this.points.find(pe => pe.ele === ele.points[1]).id
-
- this.data.room.forEach(room => {
- if (~room.ground.indexOf(p1) && ~room.ground.indexOf(p2)) {
- room.ground.splice(room.ground.indexOf(p1), 1)
- // 如果一个房间或者镂空区域只剩两个点则销毁
- if (room.ground.length <= 2) {
- this.delHole(room.ground)
- }
- }
- room.hole.forEach(hole => {
- if (~hole.pos.indexOf(p1) && ~hole.pos.indexOf(p2)) {
- hole.pos.splice(hole.pos.indexOf(p1), 1)
- // 如果一个房间或者镂空区域只剩两个点则销毁
- if (hole.pos.length <= 2) {
- this.delHole(hole.pos)
- }
- }
- })
- })
- // let rooms = this.queryLineRoomPos(ele)
- // for (let i = 0; i < rooms.length; i++) {
- // let {pos, arr} = rooms[i]
- // arr.splice(pos, 1)
- // // 如果一个房间或者镂空区域只剩两个点则销毁
- // if (arr.length <= 2) {
- // this.delHole(arr) || this.delRoom(arr)
- // }
- // }
- }
- const rep = () => {
- // 帮自身缓存的数组删除
- this.attrs.forEach(attr => {
- let index = this[attr].findIndex(({ele: e}) => e === ele)
- if (~index) {
- this[attr].splice(index, 1)
- ele.__id = this[attr][index] && this[attr][index].id
- }
- })
- this.render.remove(ele)
- }
- // 需要同步删除还是更新完属性后删除
- if ((args as any)[0]) {
- rep()
- } else {
- ele.nextTick(rep)
- }
- destroy.call(ele, ...args)
- ele.__load_destroy = false
- }
- }
-
- // Element加装Destroy方法
- retrofitElementIntercept (ele: WallLine) {
- let intercept = ele.intercept
- if (ele.__load_intercept) return;
- ele.__load_intercept = true
- ele.intercept = (...args) => {
- let isPoints = Object.keys(args[1]).indexOf('points')
- // 如果更改了points点要同步到rooms
- if (~isPoints) {
- let oldIds = ele.points.map(p => this.points.find(({ele}) => ele === p).id)
- let rooms = this.queryLineRoomPos(ele)
- ele.nextTick(() => {
- let newIds = ele.points.map(p => this.points.find(({ele}) => ele === p).id)
- rooms.forEach(({arr: ground}) => {
- let oindex1 = ground.indexOf(oldIds[0])
- let oindex2 = ground.indexOf(oldIds[1])
- ~oindex1 && (ground[oindex1] = newIds[0])
- ~oindex2 && (ground[oindex2] = newIds[1])
- })
- })
- }
- return intercept.apply(ele, args)
- }
- }
- generateElement = (ele: CADElementTS) => {
- this.render.push(ele)
- this.retrofitElementDestroy(ele)
- ele instanceof WallLine &&
- this.retrofitElementIntercept(ele)
- }
- // 查找线段第一个点在rooms中的位置
- queryLineRoomPos (line: WallLine) {
- let rooms = this.data.room
- let p1 = this.points.find(pe => pe.ele === line.points[0])
- let p2 = this.points.find(pe => pe.ele === line.points[1])
- let hs = []
- rooms = rooms.filter((room, i) => {
- let i1 = room.ground.indexOf(p1.id)
- let i2 = room.ground.indexOf(p2.id)
- let j = Math.abs(i1 - i2)
- return ~i1 && ~i2 && (j === 1 || j === room.ground.length - 1)
- })
- if (!rooms.length || !p1) return hs
- let pointId = line.points[0].__id || p1.id
- if (line.isOut) {
- for (let i = 0; i < rooms.length; i++) {
- let index, hole = rooms[i].hole.find(({pos: h}) => ~(index = h.indexOf(pointId)))
- if (hole) hs.push({ pos: index, arr: hole.pos})
- }
- } else {
- for (let i = 0; i < rooms.length; i++) {
- let index = rooms[i].ground.indexOf(pointId)
- if (~index) hs.push({ pos: index, arr: rooms[i].ground })
- }
- }
- return hs
- }
- destroy() {
- let elesArr = this.attrs.map(attr => this[attr])
- this.data = {
- vertex: [],
- wall: [],
- room: [],
- window: [],
- column: [],
- door: [],
- surplus: []
- }
- elesArr.forEach(eles => {
- while (eles.length) {
- eles[0].ele.destroy(true)
- }
- })
- this.render.destroy()
- this.render = null
- }
- }
- export default Processing
|