admin管理员组

文章数量:1326069

I need to 'slice' a big path into two smaller paths using a line. For example, you may have the following configuration:

After the operation, I should have two distinct closed paths. I probably should find two intersections and use Path.split function to split rectangle path, but I don't fully understand paper.js API and I am not sure about the best way to do that using exactly paper.js API.

For example, I split the original rectangle by doing the following mands:

 var starting_shape = new paper.Path.Rectangle([paper.view.center.x - 200, paper.view.center.y - 200], 400);
 starting_shape.strokeColor = "#aaa";
 starting_shape.strokeWidth = 2;
 starting_shape.fullySelected = true;

 var p1 = starting_shape.split(starting_shape.getNearestLocation([paper.view.center.x - 40, paper.view.center.y - 250]));
 var p2 = starting_shape.split(starting_shape.getNearestLocation([paper.view.center.x + 50, paper.view.center.y + 250]));

And I get the following:

I tried to do the following:

p1.closed = true;
p2.closed = true;

p1.position.x += 10;

I got the necessary result:

But is there a way to make it more clever?

I need to 'slice' a big path into two smaller paths using a line. For example, you may have the following configuration:

After the operation, I should have two distinct closed paths. I probably should find two intersections and use Path.split function to split rectangle path, but I don't fully understand paper.js API and I am not sure about the best way to do that using exactly paper.js API.

For example, I split the original rectangle by doing the following mands:

 var starting_shape = new paper.Path.Rectangle([paper.view.center.x - 200, paper.view.center.y - 200], 400);
 starting_shape.strokeColor = "#aaa";
 starting_shape.strokeWidth = 2;
 starting_shape.fullySelected = true;

 var p1 = starting_shape.split(starting_shape.getNearestLocation([paper.view.center.x - 40, paper.view.center.y - 250]));
 var p2 = starting_shape.split(starting_shape.getNearestLocation([paper.view.center.x + 50, paper.view.center.y + 250]));

And I get the following:

I tried to do the following:

p1.closed = true;
p2.closed = true;

p1.position.x += 10;

I got the necessary result:

But is there a way to make it more clever?

Share Improve this question edited Apr 24, 2014 at 1:33 Daniel O'Hara asked Apr 24, 2014 at 1:08 Daniel O'HaraDaniel O'Hara 13.4k3 gold badges48 silver badges70 bronze badges 2
  • taking a quick glance at the API, You can probably use path1.getIntersections(path2) to grab the intersections, then use those to create 2 new rectangles. – kennypu Commented Apr 24, 2014 at 1:14
  • yeah, I know how to get the intersections, I am not sure about using split, because it uses location. I can make up some obscure code, but I am sure it wouldn't be even close to optimised. – Daniel O'Hara Commented Apr 24, 2014 at 1:20
Add a ment  | 

3 Answers 3

Reset to default 4

Yes, you can use path.divide(path2) to perform a division boolean operation. If you clone the project from github, there's a test for all boolean functions in Examples > Scripts > BooleanOperations.html

I don't believe this currently works as you would like with just a line. It seems to be more stable with closed paths.

The splitUsingPath function here can split in two a plex shape using path, even one with a curve.

const rectangle = new Shape.Rectangle(new Point(200, 200), new Size(300, 300)).toPath();
const path = new Path([
    new Point(300, 150),
    new Segment(new Point(325, 350), new Point(-90, -90), new Point(90, 90)),
    new Point(400, 550)
])

rectangle.strokeColor = 'black'
path.strokeColor = 'black'

const splitUsingPath = (target, path) => {
    const paths = [path];
    const targets = [target];
    
    const originalTarget = target.clone({ insert: false })
    const intersections = target.getIntersections(path)

    intersections.forEach(location => {
      const newTarget = target.splitAt(location)
      const isNew = newTarget !== target
      
      if (isNew) targets.push(newTarget)
    
      paths.forEach(path => {
          const offset = path.getOffsetOf(location.point)
          const pathLocation = path.getLocationAt(offset)

          if (pathLocation) {
                paths.push(path.splitAt(pathLocation))
          }
      })
    })

    const innerPath = paths.find(p => 
        originalTarget.contains(p.bounds.center))

    paths
        .filter(path => path !== innerPath)
        .forEach(item => item.remove())

    targets.forEach((target, i) => {
        const isFirst = i === 0
        const innerPathCopy = isFirst ? innerPath : innerPath.clone()
        
        target.join(innerPathCopy, innerPathCopy.length)
        target.closed = true
    })

    return targets
}

const splitPaths = splitUsingPath(rectangle, path)

splitPaths.forEach((path, i) => {
    path.position.x += i * -10
})

This is a great answer that I've used many times. I noticed a little room for improvement though. Sometimes the resulting sliced path has segments (those originated from the slicing path) in wrong order. That causes segment handles pointing to the opposite directions than intended and results in path deformation.

I added a check and fix:

...

targets.forEach((target, i) => {
  const isFirst = i === 0
  const innerPathCopy = isFirst ? innerPath : innerPath.clone()

  // THE FIX -------------------------------
  // Check if the starting point of the slicing path and the ending point of the target path are at the same point (or very near). 
  // If so, reverse the slicing path direction and fix the segment handle directions.

  if (innerPathCopy.getPointAt(0).isClose(target.getPointAt(target.length), 0.1)) innerPathCopy.reverse()

  // THE FIX -------------------------------    

  target.join(innerPathCopy, innerPathCopy.length)
  target.closed = true

 ...

本文标签: javascriptSlice path into two separate paths using paperjsStack Overflow