How to divide multiple shapes in Paper.js like in Illustrator with Pathfinderpaper.js random triangle shapeHow to extend Shape class in paperjs to create new shapes like polygonHow to start with paper.js?Grouping shapes in paper.jsPaper.js not drawing shapesPaper.js doesn't draw multiple shapesIn Paper.js, when .subtract divides the shape into multiple regions, is it possible to separate them?Toggling multiple tools on Paper.jsHow to change default unit in Paper.js?How to create a hole on a Path in Paper.js?

Is future tense in English really a myth?

Do Sobolev spaces contain nowhere differentiable functions?

Where on Earth is it easiest to survive in the wilderness?

Can you pop microwave popcorn on a stove?

How can I hint that my character isn't real?

More than three domains hosted on the same IP address

How to best explain that you are taking pictures in a space for practice reasons?

At what point does a land become controlled?

Round away from zero

Can taking my 1-week-old on a 6-7 hours journey in the car lead to medical complications?

How do English-speaking kids loudly request something?

What quests do you need to stop at before you make an enemy of a faction for each faction?

How to make a pipe-divided tuple?

Bit floating sequence

Get a MPS file using NEOS/GAMS web interface

Relationship between speed and cadence?

Compiler optimization of bitwise not operation

Why has Marx's "Das Kapital" been translated to "Capital" in English and not "The Capital"

Why do we buy the Mazur Swindle in knot theory?

Contractor cut joist hangers to make them fit

How should Thaumaturgy's "three times as loud as normal" be interpreted?

Project Euler Problem 45

How many attacks exactly do I get combining Dual Wielder feat with Two-Weapon Fighting style?

pipe command output to convert?



How to divide multiple shapes in Paper.js like in Illustrator with Pathfinder


paper.js random triangle shapeHow to extend Shape class in paperjs to create new shapes like polygonHow to start with paper.js?Grouping shapes in paper.jsPaper.js not drawing shapesPaper.js doesn't draw multiple shapesIn Paper.js, when .subtract divides the shape into multiple regions, is it possible to separate them?Toggling multiple tools on Paper.jsHow to change default unit in Paper.js?How to create a hole on a Path in Paper.js?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








1















I have multiple overlapping squares in Paper.js, and I'd like to separate all the overlapping shapes into their own. You can do exactly this in Illustrator with the pathfinder divide. Before I attempt to just loop through all overlapping shapes and divide them with each other with what might have to be some nested loops I think, I'm wondering if there's a better way.



Example in Illustrator



I want to turn all these squares:
https://i.imgur.com/PPRi9M9.png



into pieces like this
https://i.imgur.com/xTFS8jP.png
(moved the pieces away from each other so you can see how they're separated)










share|improve this question






























    1















    I have multiple overlapping squares in Paper.js, and I'd like to separate all the overlapping shapes into their own. You can do exactly this in Illustrator with the pathfinder divide. Before I attempt to just loop through all overlapping shapes and divide them with each other with what might have to be some nested loops I think, I'm wondering if there's a better way.



    Example in Illustrator



    I want to turn all these squares:
    https://i.imgur.com/PPRi9M9.png



    into pieces like this
    https://i.imgur.com/xTFS8jP.png
    (moved the pieces away from each other so you can see how they're separated)










    share|improve this question


























      1












      1








      1








      I have multiple overlapping squares in Paper.js, and I'd like to separate all the overlapping shapes into their own. You can do exactly this in Illustrator with the pathfinder divide. Before I attempt to just loop through all overlapping shapes and divide them with each other with what might have to be some nested loops I think, I'm wondering if there's a better way.



      Example in Illustrator



      I want to turn all these squares:
      https://i.imgur.com/PPRi9M9.png



      into pieces like this
      https://i.imgur.com/xTFS8jP.png
      (moved the pieces away from each other so you can see how they're separated)










      share|improve this question














      I have multiple overlapping squares in Paper.js, and I'd like to separate all the overlapping shapes into their own. You can do exactly this in Illustrator with the pathfinder divide. Before I attempt to just loop through all overlapping shapes and divide them with each other with what might have to be some nested loops I think, I'm wondering if there's a better way.



      Example in Illustrator



      I want to turn all these squares:
      https://i.imgur.com/PPRi9M9.png



      into pieces like this
      https://i.imgur.com/xTFS8jP.png
      (moved the pieces away from each other so you can see how they're separated)







      paperjs






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 28 at 6:12









      jepjep

      313 bronze badges




      313 bronze badges

























          2 Answers
          2






          active

          oldest

          votes


















          2
















          I ended up going with my own solution which sounded more practical and simple than @arthur's answer. Not sure about which would be more performant though. To summarize, I map what blocks are overlapping with each other with a nested loop and Path.intersects(path), then do another nested loop to divide each block with its overlapping blocks with Path.divide(path) which will cut the original path with whatever path you're dividing it with.



          Here's my actual code I'm using in my project with comments.



           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




          My blocks set with random colors to differentiate each shape:



          Overlapping blocks before:
          https://i.imgur.com/j9ZSUC5.png



          Overlapping blocks separated into pieces:
          https://i.imgur.com/mc83IH6.png






          share|improve this answer

























          • Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

            – arthur.sw
            Mar 29 at 11:11






          • 1





            No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

            – jep
            Mar 29 at 21:59


















          1
















          Since you want to create shapes which did not exist before (according to your example, you want the operation to create the inner rectangle), I think you will have to loop over all overlapping shapes, compute intersections with Path.getIntersections(path[, include]), and re-create new paths from existing ones.



          Once you computed all intersections, you will have to loop through all vertices, always rotating in the same direction, and create the new paths.



          Take one (random) vertex, find the connected vertex "with the smallest angle" (it should work with currentVertex.getDirectedAngle(connectedVertex)) ; set the current vertex as visited and continue until you find the first vertex again. Create a shape, and redo this algorithm until you visited all vertices.



          You could also use Path.intersect(path[, options]) but I don't think it would help you.






          share|improve this answer



























            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );














            draft saved

            draft discarded
















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55391163%2fhow-to-divide-multiple-shapes-in-paper-js-like-in-illustrator-with-pathfinder%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2
















            I ended up going with my own solution which sounded more practical and simple than @arthur's answer. Not sure about which would be more performant though. To summarize, I map what blocks are overlapping with each other with a nested loop and Path.intersects(path), then do another nested loop to divide each block with its overlapping blocks with Path.divide(path) which will cut the original path with whatever path you're dividing it with.



            Here's my actual code I'm using in my project with comments.



             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




            My blocks set with random colors to differentiate each shape:



            Overlapping blocks before:
            https://i.imgur.com/j9ZSUC5.png



            Overlapping blocks separated into pieces:
            https://i.imgur.com/mc83IH6.png






            share|improve this answer

























            • Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

              – arthur.sw
              Mar 29 at 11:11






            • 1





              No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

              – jep
              Mar 29 at 21:59















            2
















            I ended up going with my own solution which sounded more practical and simple than @arthur's answer. Not sure about which would be more performant though. To summarize, I map what blocks are overlapping with each other with a nested loop and Path.intersects(path), then do another nested loop to divide each block with its overlapping blocks with Path.divide(path) which will cut the original path with whatever path you're dividing it with.



            Here's my actual code I'm using in my project with comments.



             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




            My blocks set with random colors to differentiate each shape:



            Overlapping blocks before:
            https://i.imgur.com/j9ZSUC5.png



            Overlapping blocks separated into pieces:
            https://i.imgur.com/mc83IH6.png






            share|improve this answer

























            • Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

              – arthur.sw
              Mar 29 at 11:11






            • 1





              No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

              – jep
              Mar 29 at 21:59













            2














            2










            2









            I ended up going with my own solution which sounded more practical and simple than @arthur's answer. Not sure about which would be more performant though. To summarize, I map what blocks are overlapping with each other with a nested loop and Path.intersects(path), then do another nested loop to divide each block with its overlapping blocks with Path.divide(path) which will cut the original path with whatever path you're dividing it with.



            Here's my actual code I'm using in my project with comments.



             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




            My blocks set with random colors to differentiate each shape:



            Overlapping blocks before:
            https://i.imgur.com/j9ZSUC5.png



            Overlapping blocks separated into pieces:
            https://i.imgur.com/mc83IH6.png






            share|improve this answer













            I ended up going with my own solution which sounded more practical and simple than @arthur's answer. Not sure about which would be more performant though. To summarize, I map what blocks are overlapping with each other with a nested loop and Path.intersects(path), then do another nested loop to divide each block with its overlapping blocks with Path.divide(path) which will cut the original path with whatever path you're dividing it with.



            Here's my actual code I'm using in my project with comments.



             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




            My blocks set with random colors to differentiate each shape:



            Overlapping blocks before:
            https://i.imgur.com/j9ZSUC5.png



            Overlapping blocks separated into pieces:
            https://i.imgur.com/mc83IH6.png







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Mar 29 at 1:30









            jepjep

            313 bronze badges




            313 bronze badges















            • Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

              – arthur.sw
              Mar 29 at 11:11






            • 1





              No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

              – jep
              Mar 29 at 21:59

















            • Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

              – arthur.sw
              Mar 29 at 11:11






            • 1





              No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

              – jep
              Mar 29 at 21:59
















            Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

            – arthur.sw
            Mar 29 at 11:11





            Did you check that your algorithm create the rectangle at the center of the 2nd image in your question ?

            – arthur.sw
            Mar 29 at 11:11




            1




            1





            No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

            – jep
            Mar 29 at 21:59





            No it doesn't, I skipped that feature for now since I don't really need it in my current block setup. Thank you for your answer though I might try out your solution at some point if I need to.

            – jep
            Mar 29 at 21:59













            1
















            Since you want to create shapes which did not exist before (according to your example, you want the operation to create the inner rectangle), I think you will have to loop over all overlapping shapes, compute intersections with Path.getIntersections(path[, include]), and re-create new paths from existing ones.



            Once you computed all intersections, you will have to loop through all vertices, always rotating in the same direction, and create the new paths.



            Take one (random) vertex, find the connected vertex "with the smallest angle" (it should work with currentVertex.getDirectedAngle(connectedVertex)) ; set the current vertex as visited and continue until you find the first vertex again. Create a shape, and redo this algorithm until you visited all vertices.



            You could also use Path.intersect(path[, options]) but I don't think it would help you.






            share|improve this answer





























              1
















              Since you want to create shapes which did not exist before (according to your example, you want the operation to create the inner rectangle), I think you will have to loop over all overlapping shapes, compute intersections with Path.getIntersections(path[, include]), and re-create new paths from existing ones.



              Once you computed all intersections, you will have to loop through all vertices, always rotating in the same direction, and create the new paths.



              Take one (random) vertex, find the connected vertex "with the smallest angle" (it should work with currentVertex.getDirectedAngle(connectedVertex)) ; set the current vertex as visited and continue until you find the first vertex again. Create a shape, and redo this algorithm until you visited all vertices.



              You could also use Path.intersect(path[, options]) but I don't think it would help you.






              share|improve this answer



























                1














                1










                1









                Since you want to create shapes which did not exist before (according to your example, you want the operation to create the inner rectangle), I think you will have to loop over all overlapping shapes, compute intersections with Path.getIntersections(path[, include]), and re-create new paths from existing ones.



                Once you computed all intersections, you will have to loop through all vertices, always rotating in the same direction, and create the new paths.



                Take one (random) vertex, find the connected vertex "with the smallest angle" (it should work with currentVertex.getDirectedAngle(connectedVertex)) ; set the current vertex as visited and continue until you find the first vertex again. Create a shape, and redo this algorithm until you visited all vertices.



                You could also use Path.intersect(path[, options]) but I don't think it would help you.






                share|improve this answer













                Since you want to create shapes which did not exist before (according to your example, you want the operation to create the inner rectangle), I think you will have to loop over all overlapping shapes, compute intersections with Path.getIntersections(path[, include]), and re-create new paths from existing ones.



                Once you computed all intersections, you will have to loop through all vertices, always rotating in the same direction, and create the new paths.



                Take one (random) vertex, find the connected vertex "with the smallest angle" (it should work with currentVertex.getDirectedAngle(connectedVertex)) ; set the current vertex as visited and continue until you find the first vertex again. Create a shape, and redo this algorithm until you visited all vertices.



                You could also use Path.intersect(path[, options]) but I don't think it would help you.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Mar 28 at 10:50









                arthur.swarthur.sw

                6,2415 gold badges29 silver badges66 bronze badges




                6,2415 gold badges29 silver badges66 bronze badges































                    draft saved

                    draft discarded















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55391163%2fhow-to-divide-multiple-shapes-in-paper-js-like-in-illustrator-with-pathfinder%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

                    Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

                    Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript