This is a fix for bug #3038 which was investigated by @BenJamesBen who also proposed a fix in PR #3056 However, after discussing the matter, we agreed it would be better to have a generic method in core to guard against the issue of spurious drawing operations. This commit adds the `Path.clean()` method that does exactly that, as well as its documentation.
This commit is contained in:
parent
d9862326b2
commit
fab1e2f877
2 changed files with 90 additions and 0 deletions
61
markdown/dev/reference/api/path/clean/en.md
Normal file
61
markdown/dev/reference/api/path/clean/en.md
Normal file
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
title: Path.clean()
|
||||
---
|
||||
|
||||
The `Path.clean()` method removes spurious drawing operations from a path.
|
||||
|
||||
A _spurious_ drawing operation is one that has no effect, but can still cause
|
||||
problems if left in place. For example, a line from a given point to the same
|
||||
given point will not cause any problems as such, but can trip up things like
|
||||
path offset and other methods. For this reason, such drawing operations can be
|
||||
cleaned up with the `Path.clean()` method.
|
||||
|
||||
As this method is called under the hood to guard against various scenarios
|
||||
where spurious segments could cause an issue, you should have no need to call
|
||||
this method yourself explicitly, but it's there if you need it. path that you
|
||||
pass it.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.clean()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.clean() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(10, 10)
|
||||
points.B = new Point(10, 20)
|
||||
points.C = new Point(10, 30)
|
||||
points.D = new Point(90, 10)
|
||||
points.E = new Point(90, 20)
|
||||
points.F = new Point(90, 30)
|
||||
|
||||
paths.a = new Path()
|
||||
.move(points.A)
|
||||
.line(points.C)
|
||||
.line(points.B)
|
||||
.line(points.B) // spurious op
|
||||
.line(points.E)
|
||||
.line(points.F)
|
||||
.curve_(points.F, points.F) // another spurious op
|
||||
.line(points.D)
|
||||
.addClass('lining')
|
||||
|
||||
paths.b = paths.a
|
||||
.clone()
|
||||
.clean()
|
||||
.addClass('interfacing')
|
||||
|
||||
paths.a.addText(`${paths.a.ops.length} ops in a`, 'center fill-lining')
|
||||
paths.b.addText(`${paths.b.ops.length} ops in b`, 'center fill-note')
|
||||
.attr('data-text-dy', 7)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
|
@ -166,6 +166,34 @@ Path.prototype.bbox = function () {
|
|||
return __bbbbox(bbs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this after cleaning out in-place path operations
|
||||
*
|
||||
* Cleaned means that any in-place ops will be removed
|
||||
* An in-place op is when a drawing operation doesn't draw anything
|
||||
* like a line from the point to the same point
|
||||
*
|
||||
* @return {Path} this - This, but cleaned
|
||||
*/
|
||||
Path.prototype.clean = function () {
|
||||
const ops = []
|
||||
for (const i in this.ops) {
|
||||
const op = this.ops[i]
|
||||
if (['move', 'close', 'noop'].includes(op.type)) ops.push(op)
|
||||
else if (op.type === 'line') {
|
||||
if (!op.to.sitsRoughlyOn(cur)) ops.push(op)
|
||||
} else if (op.type === 'curve') {
|
||||
if (!(op.cp1.sitsRoughlyOn(cur) && op.cp2.sitsRoughlyOn(cur) && op.to.sitsRoughlyOn(cur)))
|
||||
ops.push(ops)
|
||||
}
|
||||
const cur = op?.to
|
||||
}
|
||||
|
||||
if (ops.length < this.ops.length) this.ops = ops
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deep copy of this path
|
||||
*
|
||||
|
@ -1117,6 +1145,7 @@ function __asPath(bezier, log = false) {
|
|||
new Point(bezier.points[2].x, bezier.points[2].y),
|
||||
new Point(bezier.points[3].x, bezier.points[3].y)
|
||||
)
|
||||
.clean()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue