add(core): Add Path.rotate(...) function analogue to Point.rotate(...)
This commit is contained in:
parent
7e694de977
commit
849563d1ec
4 changed files with 119 additions and 1 deletions
53
markdown/dev/reference/api/path/rotate/en.md
Normal file
53
markdown/dev/reference/api/path/rotate/en.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
title: Path.rotate()
|
||||||
|
---
|
||||||
|
|
||||||
|
The `Path.rotate()` returns a path that is a rotated copy of this path.
|
||||||
|
This method behaves like calling [Point.rotate](/reference/api/point/rotate) on all nodes of this path.
|
||||||
|
|
||||||
|
## Signature
|
||||||
|
|
||||||
|
```js
|
||||||
|
Path path.rotate(number deg, Point rotationOrigin, cloneAttributes = false)
|
||||||
|
```
|
||||||
|
|
||||||
|
If you pass a truthy value to the cloneAttributes parameter, it will return a deep clone of the
|
||||||
|
path, including its attributes. By default, it will return a shallow
|
||||||
|
copy, without the attributes.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
|
||||||
|
<Example caption="Example of the Path.rotate() method">
|
||||||
|
```js
|
||||||
|
({ Point, points, Path, Snippet, paths, snippets, part }) => {
|
||||||
|
|
||||||
|
points.B = new Point(10, 30)
|
||||||
|
points.BCp2 = new Point(40, 20)
|
||||||
|
points.C = new Point(90, 30)
|
||||||
|
points.CCp1 = new Point(50, -30)
|
||||||
|
points.origin = new Point(6, 34)
|
||||||
|
snippets.origin = new Snippet('notch', points.origin)
|
||||||
|
|
||||||
|
paths.example = new Path()
|
||||||
|
.move(points.B)
|
||||||
|
.curve(points.BCp2, points.CCp1, points.C)
|
||||||
|
.setText("FreeSewing rocks", "text-xs fill-note center")
|
||||||
|
|
||||||
|
paths.rotated = paths.example
|
||||||
|
.rotate(180, points.origin, true)
|
||||||
|
.attr("class", "dotted")
|
||||||
|
|
||||||
|
return part
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Example>
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The rotated path is a shallow copy.
|
||||||
|
It will in other words not inherit the attributes of the original path.
|
||||||
|
|
||||||
|
If you want a deep copy, including the attributes, set the third parameter to true:
|
||||||
|
|
||||||
|
`Path.rotate(deg, origin, true)`
|
|
@ -678,6 +678,42 @@ Path.prototype.reverse = function (cloneAttributes = false) {
|
||||||
return rev
|
return rev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a rotated version of this Path
|
||||||
|
* @param {number} deg Angle to rotate, see {@link Point#rotate}
|
||||||
|
* @param {Point} rotationOrigin point to use as rotation origin, see {@link Point#rotate}
|
||||||
|
* @param {boolean} cloneAttributes If the rotated path should receive a copy of the path attributes
|
||||||
|
*
|
||||||
|
* @return {Path} A Path instance that is a rotated copy of this Path
|
||||||
|
*/
|
||||||
|
Path.prototype.rotate = function (deg, rotationOrigin, cloneAttributes = false) {
|
||||||
|
deg = __asNumber(deg, 'deg', 'Path.rotate', this.log)
|
||||||
|
if (!(rotationOrigin instanceof Point))
|
||||||
|
this.log.warn('Called `Path.rotate(deg,that)` but `rotationOrigin` is not a `Point` object')
|
||||||
|
|
||||||
|
const rotatedPath = new Path().__withLog(this.log)
|
||||||
|
|
||||||
|
for (const op of this.ops) {
|
||||||
|
if (op.type === 'move') {
|
||||||
|
const to = op.to.rotate(deg, rotationOrigin)
|
||||||
|
rotatedPath.move(to)
|
||||||
|
} else if (op.type === 'line') {
|
||||||
|
const to = op.to.rotate(deg, rotationOrigin)
|
||||||
|
rotatedPath.line(to)
|
||||||
|
} else if (op.type === 'curve') {
|
||||||
|
const cp1 = op.cp1.rotate(deg, rotationOrigin)
|
||||||
|
const cp2 = op.cp2.rotate(deg, rotationOrigin)
|
||||||
|
const to = op.to.rotate(deg, rotationOrigin)
|
||||||
|
rotatedPath.curve(cp1, cp2, to)
|
||||||
|
} else if (op.type === 'close') {
|
||||||
|
rotatedPath.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cloneAttributes) rotatedPath.attributes = this.attributes.clone()
|
||||||
|
|
||||||
|
return rotatedPath
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a rough estimate of the length of this path
|
* Returns a rough estimate of the length of this path
|
||||||
*
|
*
|
||||||
|
|
|
@ -701,7 +701,7 @@ export function __addNonEnumProp(obj, name, value) {
|
||||||
* @param {string} param - The name of the parameter to use in the logs
|
* @param {string} param - The name of the parameter to use in the logs
|
||||||
* @param {string} method - The name of the method to use in the logs
|
* @param {string} method - The name of the method to use in the logs
|
||||||
* @param {object} log - A logging object
|
* @param {object} log - A logging object
|
||||||
* @return {bool} result - True if it is a valid coordinate, false when not
|
* @return {number} the given value parameter, converted to a number if possible
|
||||||
*/
|
*/
|
||||||
export function __asNumber(value, param, method, log) {
|
export function __asNumber(value, param, method, log) {
|
||||||
if (typeof value === 'number') return value
|
if (typeof value === 'number') return value
|
||||||
|
|
|
@ -371,6 +371,20 @@ describe('Path', () => {
|
||||||
expect(rev.ops[2].type).to.equal('line')
|
expect(rev.ops[2].type).to.equal('line')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should rotate a path', () => {
|
||||||
|
const test = new Path()
|
||||||
|
.move(new Point(123, 456))
|
||||||
|
.line(new Point(12, 23))
|
||||||
|
.curve(new Point(0, 40), new Point(123, 34), new Point(230, 4))
|
||||||
|
.close()
|
||||||
|
let deg = 60
|
||||||
|
let rotationOrigin = new Point(42, 100)
|
||||||
|
let rotated = test.rotate(deg, rotationOrigin, true)
|
||||||
|
expect(test.length()).to.equal(rotated.length())
|
||||||
|
expect(test.ops[0].to.rotate(deg, rotationOrigin).x).to.equal(rotated.ops[0].to.x)
|
||||||
|
expect(test.ops[0].to.rotate(deg, rotationOrigin).y).to.equal(rotated.ops[0].to.y)
|
||||||
|
})
|
||||||
|
|
||||||
it('Should find the edges of a path', () => {
|
it('Should find the edges of a path', () => {
|
||||||
const test = new Path()
|
const test = new Path()
|
||||||
.move(new Point(45, 60))
|
.move(new Point(45, 60))
|
||||||
|
@ -916,6 +930,21 @@ describe('Path', () => {
|
||||||
expect(invalid).to.equal(true)
|
expect(invalid).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should log a warning when calling rotate with an origin that is not a point', () => {
|
||||||
|
let invalid = false
|
||||||
|
const log = { warn: () => (invalid = true) }
|
||||||
|
const test = new Path().__withLog(log).move(new Point(123, 456)).line(new Point(12, 23))
|
||||||
|
|
||||||
|
expect(invalid).to.equal(false)
|
||||||
|
let deg = 60
|
||||||
|
try {
|
||||||
|
test.rotate(deg, 'someOrigin')
|
||||||
|
} catch (err) {
|
||||||
|
expect('' + err).to.contain('Cannot read properties of')
|
||||||
|
}
|
||||||
|
expect(invalid).to.equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
it('Should add a noop operation', () => {
|
it('Should add a noop operation', () => {
|
||||||
const p1 = new Path().noop()
|
const p1 = new Path().noop()
|
||||||
expect(p1.ops.length).to.equal(1)
|
expect(p1.ops.length).to.equal(1)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue