在Paper.js中,我有多个重叠的正方形,我想将所有重叠的形状分离为自己的形状。您可以在Illustrator中使用路径查找器划分来完全做到这一点。在我尝试遍历所有重叠的形状并将它们彼此分开(我认为可能是一些嵌套循环)之前,我想知道是否有更好的方法。
我想把所有这些正方形变成: https://i.imgur.com/PPRi9M9.png
分成这样的碎片 https://i.imgur.com/xTFS8jP.png (将各部分移开,以便您看到它们是如何分离的)
答案 0 :(得分:2)
我最终选择了自己的解决方案,该解决方案比@arthur's answer听起来更实用,更简单。虽然不确定哪个会更有表现。总而言之,我使用嵌套循环和Path.intersects(path)映射哪些块彼此重叠,然后执行另一个嵌套循环,用Path.divide(path)将每个块及其重叠块分开,这将剪切原始路径无论用什么路径分割它。
这是我在带注释的项目中使用的实际代码。
setupGrid() {
// Setup block row and column positions
for (let i = 0;i < this.total;i++) {
let x
let y
if (!odd(i)) {
x = firstColumnStartX + (this.size/2)
y = firstColumnStartY + ((i/2) * (this.size + this.gap)) + (this.size/2)
} else {
x = secondColumnStartX + (this.size/2)
y = secondColumnStartY + (Math.floor(i/2) * (this.size + this.gap)) + (this.size/2)
}
this.blocks.push(new paper.Path.Rectangle({
position: [x, y],
size: this.size,
strokeColor: '#ff000050'
}))
}
// Setup array to check what blocks are intersecting
const intersects = []
// Setup empty array with a nested array mapped to other blocks [5 x [5 x undefined]]
for (let i = 0;i < this.total;i++) {
intersects[i] = new Array(this.total).fill(undefined)
}
// Intersect checking
for (let i = 0;i < this.total;i++) {
const block = this.blocks[i]
for (let _i = 0;_i < this.total;_i++) {
const otherBlock = this.blocks[_i]
if (block !== otherBlock && intersects[i][_i] === undefined) {
intersects[_i][i] = intersects[i][_i] = block.intersects(otherBlock)
}
}
}
// First loop through all blocks
for (let i = 0;i < this.total;i++) {
let block = this.blocks[i]
// Then loop through other blocks only if they were intersected with the original block
for (let _i = 0;_i < this.total;_i++) {
const otherBlock = this.blocks[_i]
if (intersects[i][_i]) {
/* divide returns {
pieces: array of separated pieces that would be inside the original block's boundaries
leftoverBlock: what's leftover of the other block if the original block was subtracted from it
} */
const divide = this.divide(block, otherBlock)
block.remove()
otherBlock.remove()
// Override current block with the array of pieces
block = this.blocks[i] = divide.pieces
// Override other block with leftover
this.blocks[_i] = divide.leftoverBlock
// Don't let other block divide with original block since we already did it here
intersects[_i][i] = undefined
}
}
}
// Set random color for each piece to check if successful
for (let i = 0;i < this.blocks.length;i++) {
let block = this.blocks[i]
if (block instanceof Array) {
for (let _i = 0;_i < block.length;_i++) {
block[_i].fillColor = new paper.Color(Math.random(), Math.random(), Math.random(), 0.1)
}
} else {
block.fillColor = new paper.Color(Math.random(), Math.random(), Math.random(), 0.1)
}
}
}
// Divide blockA with blockB and expand
divideBlocks(blockA, blockB, pieces = []) {
const divideA = blockA.divide(blockB)
if (divideA instanceof paper.CompoundPath) {
for (let i = divideA.children.length;i--;) {
const child = divideA.children[i]
child.insertAbove(divideA)
pieces.push(child)
}
divideA.remove()
} else {
pieces.push(divideA)
}
return pieces
}
// Divide group (array of paths) with divider
divideGroup(children, divider, pieces = [], parent) {
for (let i = children.length;i--;) {
const child = children[i]
if (parent) {
child.insertAbove(parent)
}
if (child.intersects(divider)) {
this.divideBlocks(child, divider, pieces)
} else {
pieces.push(child)
}
}
}
// Subtract group (array of paths) from block
subtractGroupFromBlock(block, group) {
let oldBlock
let newBlock = block
for (let i = group.length;i--;) {
const child = group[i]
if (child.intersects(block)) {
newBlock = newBlock.subtract(child)
if (oldBlock) {
oldBlock.remove()
}
oldBlock = newBlock
}
}
return newBlock
}
// Check what kind of divide method to use
divide(blockA, blockB) {
const pieces = []
let leftoverBlock
if (blockA instanceof paper.Path) {
this.divideBlocks(blockA, blockB, pieces)
leftoverBlock = blockB.subtract(blockA)
} else if (blockA instanceof Array) {
this.divideGroup(blockA, blockB, pieces)
leftoverBlock = this.subtractGroupFromBlock(blockB, blockA)
}
return {
pieces,
leftoverBlock
}
}
我的积木设置了随机的颜色来区分每种形状:
之前的重叠块: https://i.imgur.com/j9ZSUC5.png
重叠的块分为几部分: https://i.imgur.com/mc83IH6.png
答案 1 :(得分:1)
由于您要创建以前不存在的形状(根据您的示例,您希望该操作创建内部矩形),我认为您将必须遍历所有重叠的形状,并使用{{3} },然后从现有路径重新创建新路径。
一旦计算了所有交点,就必须遍历所有顶点,并始终沿相同方向旋转,并创建新路径。
取一个(随机)顶点,找到“具有最小角度”的连接顶点(它应与currentVertex.getDirectedAngle(connectedVertex)
一起使用);将当前顶点设置为已访问,然后继续直到找到第一个顶点。创建一个形状,然后重做该算法,直到访问了所有顶点为止。
您也可以使用Path.intersect(path[, options])
,但我认为这不会帮助您。