119 lines
4.1 KiB
JavaScript
119 lines
4.1 KiB
JavaScript
import cloneDeep from 'lodash/cloneDeep'
|
|
|
|
import logger from './util/logger'
|
|
|
|
export default (parseResult) => {
|
|
const blocksByName = parseResult.blocks.reduce((acc, b) => {
|
|
acc[b.name] = b
|
|
return acc
|
|
}, {})
|
|
|
|
const gatherEntities = (entities, transforms) => {
|
|
let current = []
|
|
entities.forEach((e) => {
|
|
if (e.type === 'INSERT') {
|
|
const insert = e
|
|
const block = blocksByName[insert.block]
|
|
if (!block) {
|
|
logger.error('no block found for insert. block:', insert.block)
|
|
return
|
|
}
|
|
|
|
const rowCount = insert.rowCount ?? 1
|
|
const columnCount = insert.columnCount ?? 1
|
|
const rowSpacing = insert.rowSpacing ?? 0
|
|
const columnSpacing = insert.columnSpacing ?? 0
|
|
const rotation = insert.rotation ?? 0
|
|
|
|
// It appears that the rectangular array is affected by rotation, but NOT by scale.
|
|
let rowVec, colVec
|
|
if (rowCount > 1 || columnCount > 1) {
|
|
const cos = Math.cos((rotation * Math.PI) / 180)
|
|
const sin = Math.sin((rotation * Math.PI) / 180)
|
|
rowVec = { x: -sin * rowSpacing, y: cos * rowSpacing }
|
|
colVec = { x: cos * columnSpacing, y: sin * columnSpacing }
|
|
} else {
|
|
rowVec = { x: 0, y: 0 }
|
|
colVec = { x: 0, y: 0 }
|
|
}
|
|
|
|
// For rectangular arrays, add the block entities for each location in the array
|
|
for (let r = 0; r < rowCount; r++) {
|
|
for (let c = 0; c < columnCount; c++) {
|
|
// Adjust insert transform by row and column for rectangular arrays
|
|
const t = {
|
|
x: insert.x + rowVec.x * r + colVec.x * c,
|
|
y: insert.y + rowVec.y * r + colVec.y * c,
|
|
scaleX: insert.scaleX,
|
|
scaleY: insert.scaleY,
|
|
scaleZ: insert.scaleZ,
|
|
extrusionX: insert.extrusionX,
|
|
extrusionY: insert.extrusionY,
|
|
extrusionZ: insert.extrusionZ,
|
|
rotation: insert.rotation,
|
|
}
|
|
// Add the insert transform and recursively add entities
|
|
const transforms2 = transforms.slice(0)
|
|
transforms2.push(t)
|
|
|
|
// Use the insert layer
|
|
const blockEntities = block.entities.map((be) => {
|
|
const be2 = cloneDeep(be)
|
|
be2.layer = insert.layer
|
|
// https://github.com/bjnortier/dxf/issues/52
|
|
// See Issue 52. If we don't modify the
|
|
// entity coordinates here it creates an issue with the
|
|
// transformation matrices (which are only applied AFTER
|
|
// block insertion modifications has been applied).
|
|
switch (be2.type) {
|
|
case 'LINE': {
|
|
be2.start.x -= block.x
|
|
be2.start.y -= block.y
|
|
be2.end.x -= block.x
|
|
be2.end.y -= block.y
|
|
break
|
|
}
|
|
case 'LWPOLYLINE':
|
|
case 'POLYLINE': {
|
|
be2.vertices.forEach((v) => {
|
|
v.x -= block.x
|
|
v.y -= block.y
|
|
})
|
|
break
|
|
}
|
|
case 'CIRCLE':
|
|
case 'ELLIPSE':
|
|
case 'ARC': {
|
|
be2.x -= block.x
|
|
be2.y -= block.y
|
|
break
|
|
}
|
|
case 'SPLINE': {
|
|
be2.controlPoints.forEach((cp) => {
|
|
cp.x -= block.x
|
|
cp.y -= block.y
|
|
})
|
|
break
|
|
}
|
|
}
|
|
return be2
|
|
})
|
|
current = current.concat(gatherEntities(blockEntities, transforms2))
|
|
}
|
|
}
|
|
} else {
|
|
// Top-level entity. Clone and add the transforms
|
|
// The transforms are reversed so they occur in
|
|
// order of application - i.e. the transform of the
|
|
// top-level insert is applied last
|
|
const e2 = cloneDeep(e)
|
|
e2.transforms = transforms.slice().reverse()
|
|
current.push(e2)
|
|
}
|
|
})
|
|
return current
|
|
}
|
|
|
|
return gatherEntities(parseResult.entities, [])
|
|
}
|