Gathering detailed insights and metrics for @markroland/path-helper
Gathering detailed insights and metrics for @markroland/path-helper
Gathering detailed insights and metrics for @markroland/path-helper
Gathering detailed insights and metrics for @markroland/path-helper
Utility functions for working with points, paths and geometry.
npm install @markroland/path-helper
Typescript
Module System
Node Version
NPM Version
76.7
Supply Chain
99.5
Quality
88.8
Maintenance
100
Vulnerability
80.1
License
JavaScript (100%)
Total Downloads
7,404
Last Day
1
Last Week
86
Last Month
139
Last Year
1,380
20 Stars
200 Commits
1 Forks
4 Watching
1 Branches
2 Contributors
Minified
Minified + Gzipped
Latest Version
1.34.0
Package Id
@markroland/path-helper@1.34.0
Unpacked Size
1.61 MB
Size
477.77 kB
File Count
42
NPM Version
10.8.3
Node Version
20.15.0
Publised On
07 Dec 2024
Cumulative downloads
Total Downloads
Last day
-97.9%
1
Compared to previous day
Last week
83%
86
Compared to previous week
Last month
595%
139
Compared to previous month
Last year
-58.6%
1,380
Compared to previous year
The PathHelper class contains a variety of methods to assist with performing operations on multi-point paths (polylines).
Code is documented using JSDoc syntax and is compiled using the NPM jsdoc package.
Generate documentation:
1npm run docs
This is a new expiremental feature. This will start a local web server where class methods can be demonstrated.
1npm run demo
Open http://localhost:8000 in your browser.
Use ESLint to check code formatting. Run with:
1npm run lint
Unit Testing is being developed with Jest. Run with:
1npm run test
A point is an array of 2 or 3 elements representing either the point's X,Y or X,Y,Z position.
1let point = [0.0, 0.0];
A path is an array of one or more points.
1let path = [ 2 [-1, 0], 3 [ 1, 0] 4];
Paths represent one or more path.
1let paths = [ 2 [ 3 [-1, 0], 4 [ 1, 0] 5 ], 6 [ 7 [0, -1], 8 [0, 1] 9 ] 10];
The following methods are grouped and ordered loosely by their purpose and use.
Note: Some examples show rounded results in floating point numbers in order to keep the examples concise.
Types of Operations:
1let PH = new PathHelper();
Note: A custom Psuedo-Random Number Generator (PRNG) can be set as a class parameter. This is useful for creating consistent, deterministic results as required by most NFTs art.
The following methods provide general help with interacting with Path data in JavaScript
Get information about a 2D path
1let path = [ 2 [-1, 1], 3 [ 1, 1], 4 [ 1, -1], 5 [-1, -1] 6]; 7let i = PH.info(path);
Expected Output:
1{ 2 "min": [-1, -1], 3 "max": [1, 1], 4 "points": 4, 5 "range": [2, 2], 6 "center": [0, 0] 7}
Create a deep copy of a JavaScript array/object.
This is useful so that paths can be duplicated and then manipulated independently without any references.
Simplify the precision of floating point numbers in a Paths array.
1let path = [ 2 [ 3 [0.0001, 0.1501], 4 [1.1645, 1.5762] 5 ] 6]; 7let new_path = PH.pathsToFixed(path, 2);
Expected Output:
1[ 2 [ 3 [0, 0.15], 4 [1.16, 1.58] 5 ] 6]
Convert the points in a path from an array to an object
1PH.pathPointsArrayToObject([ 2 [0.0001, 0.1501], 3 [1.1645, 1.5762] 4]);
Expected Output:
1[ 2 {x: 0.0001, y: 0.1501}, 3 {x: 1.1645, y: 1.5762} 4]
Convert the points in a path from an object to an array
1PH.pathPointsObjectToArray([ 2 {x: 0.0001, y: 0.1501}, 3 {x: 1.1645, y: 1.5762} 4]);
Expected Output:
1[ 2 [0.0001, 0.1501], 3 [1.1645, 1.5762] 4]
Get the values from a single column in the input array
1PH.arrayColumn( 2 [ 3 [1, 2, 3], 4 [4, 5, 6], 5 [7, 8, 9] 6 ], 7 2 8); 9// Output is [3, 6, 9]
Get the minimum value from each coordinate compononent of a 2D or 3D path
1let path = [ 2 [-2, 1], 3 [ 4, 1], 4 [ 4, -3], 5 [-2, -3] 6]; 7PH.getMin(path); 8// Output is [-2, -3]
Get the minimum value from each coordinate compononent of a 2D or 3D path
1let path = [ 2 [-2, 1], 3 [ 4, 1], 4 [ 4, -3], 5 [-2, -3] 6]; 7PH.getMax(path); 8// Output is [4, 1]
Get the Bounding Box coordinates for a 2D or 3D path
This returns a multidimensional array with the minimum and maximum values for each dimension
1let path = [ 2 [-1, 0], 3 [ 0, -1], 4 [ 1, 0], 5 [ 0, 1] 6]; 7PH.boundingBox(path);
Expected Output:
1[ 2 [-1, 1], 3 [-1, 1], 4]
Get the smallest number from an array
1PH.arrayMin([10, 2, 4.5, 7, 2.3, -1.2, -2.7]); 2// Output is -2.7
Get the largest number from an array
1PH.arrayMax([10, 2, 4.5, 7, 2.3, -1.2, -2.7]); 2// Output is 10
Get a random Integer (whole number) between two values (inclusive). This can take an optional Psudeo-Random Number Generator (PRNG) function as a final parameter, which can help with the creation of deterministic results.
1PH.getRndInteger(1, 10);
2// Output is 5
Get a random Number between two values (inclusive). This can take an optional Psudeo-Random Number Generator (PRNG) function as a final parameter, which can help with the creation of deterministic results. This has a default range of 0 to 1 to match Math.random().
1PH.getRandom(1, 3); 2// Output is 1.3623930350489668
Get a random number between 0 and 1 within a Gaussian Distribution probability. This can take an optional Psudeo-Random Number Generator (PRNG) function as a final parameter, which can help with the creation of deterministic results.
1PH.getGaussianRandom();
2// Output is 0.5166768388415707
Map a value from one scale to another scale. This accepts an optional fifth boolean parameter to clamp the result to the output scale.
1PH.map(2, 0, 10, -5, 5); 2// Output is -3
Constrain a value within a range of numbers. If the input value is below the acceptable minimum, then the minimum value will be returned. If the input value is over the acceptable maximum, then the maximum value will be returned.
1PH.clamp(10, 0, 100); 2// Output is 10 3 4PH.clamp(-10, 0, 100); 5// Output is 0 6 7PH.clamp(110, 0, 100); 8// Output is 100
Perform a linear interpolation between two values
1PH.lerp(0, 20, 0.3); 2// Output is 6
Convert Degrees to Radians
1PH.degreesToRadians(135.0); 2// Output is 2.356194490192345
Convert Radians to Degrees
1PH.radiansToDegrees(0.5 * Math.PI);
2// Output is 90
Convert Polar coordinates to Rectangular (Cartesian) coordinates
1PH.polarToRect(1, 0.25 * Math.PI); 2// Output is [0.7071067811865476, 0.7071067811865475]
Convert Rectangular (Cartesian) coordinates to Polar coordinates
1PH.rectToPolar(0.7071, 0.7071); 2// Output is {radius: 0.99999, theta: 0.7854}
Get the Greatest Common Divisor of two numbers
1PH.greatestCommonDivisor(50, 30);
2// Output is 10
Get the sign of the number: +1 for positive, -1 for negative and 0 for zero.
1PH.sign(23)
2// Output is 1
3PH.sign(-12)
4// Output is -1
5PH.sign(0)
6// Output is 0
The following methods perform general mathematical operations
Calculate the cross product of two 3D vectors
1let a = [-2, 1, 1]; 2let b = [ 3, 2, 1]; 3PH.crossProduct(a, b); 4// Output is [-1, 5, -7]
Calculate the dot product of two matrices
1let a = [-2, 1, 1]; 2let b = [ 3, 2, 1]; 3PH.dotProduct(a, b); 4// Output is -3
Multiply two matrices
1let a = [[1, 2, 3]]; 2let b = [ 3 [2, 0, 0], 4 [0, 2, 0], 5 [0, 0, 2] 6]; 7PH.matrixMultiply(a, b); 8// Output is [ [ 2, 4, 6 ] ]
Calculate the slope and y-intercept of the line passing between two points.
In the return object, m
represents slope and b
represents the y-intercept.
1PH.lineSlopeIntercept([1, 2], [2, 3]); 2// Output is {m: 1, b: 1}
Solve the Quadratic Equation. For real values only. Standard Quadratic Equation: ax^2 + bx + c = 0
1PH.solveQuadratic(2, 4, -4); 2// Output is [0.7321, -2.7321]
Calculate the distance between two points in 2D or 3D space
1PH.distance([0, 0], [1, 1]); 2// Output is 1.4142135623730951 3 4PH.distance([0, 0, 0], [1, 1, 1]); 5// Output is 1.7320508075688772
Calculate the point equidistance from two points
1PH.midpoint([0, 0], [1, 1]); 2// Output is [0.5, 0.5]
Calculate the angle between 3 points
1PH.angle([1, 0], [0, 0], [1, 1]); 2// Output is 0.7853981633974483
Calculate the curvature of 3 points
1PH.curvature([1, 0], [0, 0], [1, 1]); 2// Output is 0.7071067811865476
The following methods help create basic shapes, curves, etc.
Create a regular polygon centered at the origin
1PH.polygon(4, 1.0, Math.PI/4);
Expected Output:
1[ 2 [ 3 0.7071067811865476, 4 0.7071067811865475 5 ], 6 [ 7 -0.7071067811865475, 8 0.7071067811865476 9 ], 10 [ 11 -0.7071067811865477, 12 -0.7071067811865475 13 ], 14 [ 15 0.7071067811865474, 16 -0.7071067811865477 17 ], 18 [ 19 0.7071067811865477, 20 0.7071067811865474 21 ] 22]
Create a rectangle centered at the origin. Specify the width and height.
1PH.rectangle(1, 0.5);
Create an ellipse (oval) centered at the origin. Specify the width, height, and number of segments.
1PH.ellipse(4, 2, 60);
Create a superellipse, also known as a Lamé curve, centered at the origin. Specify the width, height, and number of segments. A squircle is a special case when the width and height are the same.
1PH.superellipse(4, 2, 60);
Create a regular star polygon centered at the origin
1PH.star(4, 1.0, Math.PI/4);
Expected Output:
1[ 2 [ 3 1, 4 0 5 ], 6 [ 7 0.4045084971874737, 8 0.29389262614623657 9 ], 10 [ 11 0.30901699437494745, 12 0.9510565162951535 13 ], 14 [ 15 -0.15450849718747367, 16 0.4755282581475768 17 ], 18 [ 19 -0.8090169943749473, 20 0.5877852522924732 21 ], 22 [ 23 -0.5, 24 6.123233995736766e-17 25 ], 26 [ 27 -0.8090169943749475, 28 -0.587785252292473 29 ], 30 [ 31 -0.15450849718747378, 32 -0.47552825814757677 33 ], 34 [ 35 0.30901699437494723, 36 -0.9510565162951536 37 ], 38 [ 39 0.40450849718747367, 40 -0.2938926261462367 41 ], 42 [ 43 1, 44 0 45 ] 46]
Create a parabolic path centered at the origin
1PH.parabola(2.0, 1.0, 6);
Expected Output:
1[ 2 [ 3 -0.5, 4 0.5 5 ], 6 [ 7 -0.33333333333333337, 8 0.22222222222222227 9 ], 10 [ 11 -0.16666666666666669, 12 0.055555555555555566 13 ], 14 [ 15 0, 16 0 17 ], 18 [ 19 0.16666666666666663, 20 0.05555555555555553 21 ], 22 [ 23 0.33333333333333337, 24 0.22222222222222227 25 ], 26 [ 27 0.5, 28 0.5 29 ] 30]
Compose a circular arc between two points. The center of the circle on
which the arc lies is the midpoint between (x1, y1) and (x2, y2). The
arc starts at (x1, y1) and proceeds clockwise for theta
radians.
This method is most useful when you have two known points and wish to
connect them using a circular arc.
Compose a circular arc centered around a known point with a known radius
Create a Quadratic Bézier curve path.
1PH.quadraticBezierPath( 2 [0, 0], 3 [1, 1], 4 [0, 2], 5 5 6);
Expected Output:
1[ 2 [0, 0], 3 [0.32, 0.4], 4 [0.48, 0.8], 5 [0.48, 1.2], 6 [0.32, 1.6], 7 [0, 2], 8]
Create a Cubic Bézier curve path.
1PH.cubicBezierPath( 2 [0, 0], 3 [1, 0.5], 4 [1, 1.5], 5 [0, 2], 6 5 7);
Expected Output:
1[ 2 [0, 0], 3 [0.48, 0.35], 4 [0.72, 0.78], 5 [0.72, 1.2], 6 [0.48, 1.65], 7 [0, 2] 8]
The following methods perform standard linear transformations
Translate a group of paths to be centered around the origin
Scale a Path with respect to the origin. To scale "in place", translate
the path to be centered at the origin, apply scalePath
, and then re-translate
the path in the opposite direction.
1let path = [ 2 [-1, 0], 3 [ 0, -1], 4 [ 1, 0], 5 [ 0, 1] 6]; 7PH.scalePath(path, 0.5);
Expected Output:
1[ 2 [-0.5, 0], 3 [0, -0.5], 4 [0.5, 0], 5 [0, 0.5] 6]
Translate a Path in 2D Cartesian coordinates
1let path = [ 2 [-1, 0], 3 [ 0, -1], 4 [ 1, 0], 5 [ 0, 1] 6]; 7PH.translatePath(path, [0.5, 0.5]);
Expected Output:
1[ 2 [-0.5, 0.5], 3 [0.5, -0.5], 4 [1.5, 0.5], 5 [0.5, 1.5] 6]
Rotate a path around a point using the Rotation Matrix.
1let path = [ 2 [-1, 0], 3 [ 0, -1], 4 [ 1, 0], 5 [ 0, 1] 6]; 7PH.rotatePath(path, 0.5 * Math.PI);
Expected Output:
1[ 2 [ 0, -1], 3 [ 1, 0], 4 [ 0, 1], 5 [-1, 0] 6]
Rotate a point around another point using the Rotation Matrix.
1let a = [1, 0]; 2let b = [0.5, 0]; 3console.log(PH.rotatePoint(a, 0.5 * Math.PI, b));
Expected Output:
1[0.5, 0.5]
Reflect a Path vertically or horizontally about an axis (X or Y)
1PH.reflectPath([[1, 1], [2, 2]], "x", 0.0); 2// Expected output is [[-1, 1], [-2, 2]]
Shear (or skew) a Path in a direction, "horizontal" or "vertical", by a slope value.
1let path = [ 2 [0, 0], 3 [0, 1], 4 [1, 1], 5 [1, 0] 6]; 7PH.shearPath(path, "horizontal", 1);
Expected Output:
1[ 2 [0, 0], 3 [1, 1], 4 [2, 1], 5 [1, 0] 6]
Distort a path by mapping the corners of a rectangular bounding box to the respective corners of a manipulated quadrilateral. The path will be distorted using a linear interpolation of the transformation.
Bouding Box:
A -- B
| |
D -- C
Distortion:
A ------- B
\ /
\ /
D - C
The following methods perform standard Boolean operations on polygons
Perform a Boolean addition (union) of two closed paths
Remove segments of Shape A that are inside of Shape B.
This is a helper method for booleanAdd
.
Perform a Boolean subtraction (difference) of two closed paths
Remove segments of Shape B that are outside of Shape A.
This is a helper method for booleanSubtract
.
Perform a Boolean intersection of two closed paths
Remove segments of Shape B that are outside of Shape A.
This is a helper method for booleanIntersection
.
Calculate the intersection points of Shape A with Shape B, and insert these intersection points in Shape A (in order).
This is a helper method for the Boolean shape operations.
The following methods perform a wide variety of operations for manipulating paths
Calculate the total distance of a path of two or more points in 2D or 3D
1PH.pathLength([ 2 [0, 0], 3 [0, 1], 4 [1, 1], 5 [1, 0], 6 [0, 0] 7]); 8// Output is 4
Determine if two lines are equivalent by comparing their start and end points.
This supports an optional threshold
parameter that can be set to specify a
maximum distance that two points can be apart and still considered coincident.
This is very useful when dealing with floating point numbers.
1let AB = [ 2 [0, 0], 3 [0, 1] 4]; 5let CD = [ 6 [0.005, 0], 7 [0, 1.005] 8]; 9PH.lineEquals(AB, CD); 10// Output is False 11 12PH.lineEquals(AB, CD, 0.01); 13// Output is True
Determine if two points are coincident.
This supports an optional threshold
parameter that can be set to specify a
maximum distance that the points can be apart and still considered coincident.
This is very useful when dealing with floating point numbers.
1let A = [0.0, 0.0];
2let B = [0.005, 0];
3PH.pointEquals(A, B);
4// Output is False
5
6PH.pointEquals(A, B, 0.01);
7// Output is True
Determine if a Path is closed, meaning that the ending point coincides with
the starting point. This supports an optional threshold
parameter that
can be set to specify a maximum distance that the points can be apart and
still considered coincident.
1let path = [ 2 [0, 0], 3 [1, 0] 4]; 5PH.closedPath(path); 6// Output is False 7 8let path = [ 9 [0, 0], 10 [1, 0], 11 [1, 1], 12 [0, 1], 13 [0, 0] 14]; 15PH.closedPath(path); 16// Output is True
Determine if a path intersects, or overlaps, with itself.
Determine if a path represents a shape that is a simple polygon, meaning that the path is a closed shape that does not intersect itself.
Determine if a path represents a shape that is a complex polygon, meaning that the path is a closed shape that intersects itself.
Determine if a path represents a shape that is a convex polygon.
Determine if a path represents a shape that is a concave polygon.
Calculate the location where two lines intersect.
Note: Consider using getLineLineCollision instead
1PH.intersect_point( 2 [ 0, 0], 3 [ 0, 3], 4 [-1, 1], 5 [ 1, 1] 6);
Expected Output:
1[0, 1]
Calculate if and where two finite line segments intersect
Note: This method and intersect_point are very similar. This method is more robust because it detects non-intersection. Both methods were copied from other sources.
1PH.getLineLineCollision( 2 {x: 0, y: 0}, 3 {x: 0, y: 3}, 4 {x: -1, y: 1}, 5 {x: 1, y: 1} 6);
Expected Output:
1{x: 0, y: 1}
Calculate the intersection points between a line and a circle. The response is an array with 0, 1 or 2 Point array elements representing the locations of intersections.
1PH.lineCircleIntersect([-1, -1], [1, 1], [[0,0], 1]);
Expected Output:
1[ 2 [0.7071, 0.7071], 3 [-0.7071, -0.7071] 4]
Calculate the intersection point between two circles. This requires both
circles to be centered at the origin. A sign
parameter solves for one of
two possible solutions. This assumes the input circles do intersect and
does not solve for non-intersection.
Check if a Point is on a Line Segment (or within a threshold/buffer)
1PH.pointOnLineSegment( 2 [0.5, 0.01], 3 [[0, 0], [1, 0]], 4 0 5); 6// Output is false 7 8PH.pointOnLineSegment( 9 [0.5, 0.01], 10 [[0, 0], [1, 0]], 11 0.001 12); 13// Output is true
Determine if a point is inside of a polygon. This is taken from Jeffrey Thompson's excellent eBook on Collission Detection.
Create a line that runs parallel to the input points.
The side that the path runs parallel is determined by the cross product of BA and AC (BA X AC), where A = p1, B = p2 and C = the first point of the returned line. This follows the convention of the right hand rule.
(C) -------- (D) (Positive Offset)
p1 (A) -------- (B) p2
(C) -------- (D) (Negative Offset)
1PH.parallelPath([0, 0], [0, 1], 0.2);
Expected Output:
1[ 2 [-0.2, 0], 3 [-0.2, 1] 4]
Create two paths that run alongside the input path, either in parallel or in a taper. Optionally close the path with an end cap.
1PH.expandPath([[0, 0], [0, 1]], 0.2, 0.2, "open");
Vary the width (stroke) of a path. This works by applying a noisy offset to the path to create an envelope and then increasing the path offset incrementally to fill in the envelope.
1PathHelp.varyPath([[0, 0], [1, 0]], 0.003, 0.050, 0.010)
Create a path that runs parallel to the input path. This handles closed paths (end point coincident with start point) as well as open paths. The path must contain 3 or more points. An optional third parameter can be set to "true" in order to eliminate knots/kinks when the offset line overlaps with itself.
1PH.offsetPath([[0, 0], [0, 0.5], [0, 1]], 0.2);
Expected Output:
1[ 2 [-0.2, 0.0], 3 [-0.2, 0.5] 4]
A function can also be used as the second parameter. The functions's input value is a number betweeen 0 and 1 representing the current point's array index as a percentage. The output of the function is a numerical offset value. For example an offset function could be:
1/** 2 * Function returns an offset value describing a parabola 3 **/ 4function(val) { 5 const max_offset = 0.01; 6 return max_offset * (-Math.pow(2 * val - 1, 2) + 1); 7}
Remove parts of a path where it intersects with itself creating a loop/knot. This serves as a help function in offsetPath to support wide offset values.
Create a path offset from 3 points: A, B, C. A negative offset represents an "interior" offset for the acute angle ACB.
(A: p1)
/ /
/ /____ Negative Offset
/________
(C: p2) (B: p3)
This is used by the offsetPath
method and is currently intended
to be a private method of the class.
Extend the line segment between points A and B by an amount in either direction. This works for 2D and 3D points.
A B
In: ------------
Out: ----------------
1PH.extendLine([0, 0], [1, 1], 0.2, 0.2);
Extend a multi-point path by one point in the same direction and with the same distance as the previous two points. A second optional "factor" parameter can be set to either decrease or increase the curvature of the path.
Limit a path's length to a maximum distance
Superimpose a function onto a path. For example, add a Sine Wave function onto any input path.
Add random noise to a path. This can make lines appear more organic or hand-drawn. This accepts a number of parameters that impact the quality of the line:
max_segment_length
: Use a lower value to increase the resolutionmax_noise
: Set a maximum magnitude of the noise displacementgaussian
: Use a Gaussian distribution for the noise values instead of using
the native random
function. This should reduce the noise effectforce_close
: This is useful for closed paths. Since the first and last point
of a closed paths may receive different random noise they may or may not close
after the noise has been added. Depending on the desired effect this may or
may not be desirable, so this may be set to true
or false
to achieve either effectsmooth_window
: Set a smoothing window size to reduce the jaggedness of the
path after receiving noise. This creates smoother, wavier linessmooth_repeat
: Use this in conjunction with smooth_window
in order to repeat
the smooth_window
multiple times, making the line even smoother.anchor_start
: Set to true if you want the path's first point to keep its position.
Defaults to false to maintain legacy behavior.anchor_end
: Set to true if you want the path's last point to keep its position.
Defaults to true to maintain legacy behavior.Smooth a path by performing a one dimensional convolution on the X
and Y components of each point in the path. The size
parameter defines
the window size. A larger window size will produce a smoother, less
defined path. There are different boundary treatments supported:
preserve: This is like "trim", except the input path's end points are appended. This was the function's original behavior. This method can create relatively long segments toward the end of the line that can look out of place.
trim: This drops the points that are near the ends and don't have a full smoothing window. This method does not create or add additional path data. It will shorten the path.
weight: This duplicates the endpoints to accomodate the window size. It will shorten the path, but not as much as the trim method. It can result in some curling toward the endpoints since they are repeated.
extrapolate: This adds additional points that attempt to be at the same interval/distance as segments at the end of the path and point in the same direction as the opposite side of the window. This maintains the original length and solves the flat ending segemnts of the "preserve" method.
Smooth the corners on a Path in relation to other points on the path.
A sharpness
parameter controls the curvature on a scale from 0 to 1,
where 0 represents the maximum amount of curvature
between points and a value of 1 represents no curvature.
Smooth the corners on a Path by a set value. The curvature begins at the
radius
distance from the each point. This is useful for creating
uniform curvatures, like to round corners on polygon.
Shift and wrap the elements in the array. This is useful for changing the start/end point of a closed shape. Specifically, when using a pen plotter this can be used to break up undesired patterns created by a pen depositing extra ink when it starts/stops a path.
1let path = [ 2 [1, 1], 3 [2, 2], 4 [3, 3], 5 [4, 4] 6]; 7PH.shiftPath(path, 2);
Expected Output:
1[ 2 [3, 3], 3 [4, 4], 4 [1, 1], 5 [2, 2] 6]
Divide each segment of a multi-point Path array into two segments.
1let path = [ 2 [0, 0], 3 [0, 1], 4 [1, 1] 5]; 6PH.subdividePath(path);
Expected Output:
1[ 2 [0, 0], 3 [0, 0.5], 4 [0, 1], 5 [0.5, 1], 6 [1, 1] 7]
Divide a two-point Path array (line) into 2 or more segments
1let path = [ 2 [0, 0], 3 [0, 1] 4]; 5PH.dividePath(path, 5);
Expected Output:
1[ 2 [0, 0], 3 [0, 0.2], 4 [0, 0.4], 5 [0, 0.6], 6 [0, 0.8], 7 [0, 1] 8]
Refactor a Path array so that no segments of the path exceed a maximum distance. This can be used to "upsample" a path so that smoothing, adding noise, or other follow-up transformations may be applied in a more uniform manner.
Resample a path to contain a certain number of points. The new path will have points that are equidistant along the original path. This will result in a slightly different path than the origanl path - i.e. sharp corners will not be preserved unless the sampling value is sufficiently high.
Turn a solid line/path into a dashed line. A distance can be specified for the length of the dash and the length of the gap. An optional parameter can be set to return the gaps instead of the dashes.
Randomly remove portions of a path. This is controlled by an odds
parameter where a value of zero means that there is no chance any point
will be removed from the path and a value of one means that there is
a 100% chance that the point will be removed from the path.
To achieve this each point in the path is evaluated against a random number between 0 and 1 and if the number is less than the odds, then the point is removed from the path.
** Example of odds at 0.1 **
Here 2 out of the 20 segments have been removed as an example of what could happen if the odds of removal are 10%.
Input: --------------------
Output: -------- -------- --
This applies the same logic as decimatePath
to multiple Path arrays.
Create a new path that is a morphology of Paths A and B. Paths A and B are upsampled so that they are composed of an equal number of points and can interpolated.
Join Paths together when their endpoints are within a minimum distance of each other. This is a recursive algorithm that will keep consolidating paths until no paths are left within the threshold distance of each other.
A B C D
Input: ------------ -------------
Output: --------------------------
A B
Remove consecutive points if they are less than or equal to a threshold distance of the previous point.
This is useful to "downsample" a path if its spatial resolution is higher than required by the output device, such as a screen or pen plotter. This can help reduce file size or reduce plotting time without sacrificing image quality.
1let path = [ 2 [0, 0], 3 [0.1, 0], 4 [0.2, 0], 5 [0.21, 0], 6 [0.22, 0], 7 [0.25, 0], 8 [0.3, 0] 9]; 10PH.cleanPath(path, 0.05);
Expected Output:
1[ 2 [0, 0], 3 [0.1, 0], 4 [0.2, 0], 5 [0.3, 0] 6]
Sort Path arrays by start point from left to right, top to bottom. This is primarily useful for plotting optimization in order to reduce the distance traveled for non-drawing movements.
Note: This is a simple algorithm and could be improved for greater efficiency in the future. For example, rather than sorting every path by the starting point, the end point of the previous path could be used as the position by which to find the next closest path. This could be further optimized by optionally allowing paths to be plotted in reverse.
Randomly re-sort Path arrays. This is useful for plotting if the design has a repetitive pattern and it is undesirable for pen up/down artifacts to appear in a pattern that could negatively impact the desired image. This uses the Fisher-Yates algorithm for shuffling.
Remove any path from a Paths array if the distance (total length) of the path is below a certain distance. This can be useful if an algorithm produces many short segments that may not be necessary. It can be used to increase plotter efficiency and reduce stress on the servo motor.
Simplify a path by removing points that do not significantly alter
the path's shape. Like cleanPath
this is useful to reduce the complexity of
a path without sacrificing image quality.
This method takes a flat array of Points, and calculates the distance between each point. If the distance is below a threshold these points are considered to be part of a connected Path. Each Path will continue to grow until there are no points within the threshold distance. Once a Path terminates a new Point is selected for Path evaluation. This continues until no points remain to be evaluated.
This method was developed in order to convert raster/bitmap images into vector images. This works by performing edge detection on the image and then using this method to "connect the dots" of pixels determined to be edges.
This is the original recursive version of pointsToPaths2 and is known to cause a stack overflow. Consider using pointsToPaths2 instead.
Crop paths to a bounding shape. This supports a threshold value that can be used to handle points that are near the boundary of the crop shape. This should be able to handle concave and convex polygons.
Crop paths to a circle.
DEPRECATED: This has been replaced by the more generalized cropToShape
method
and will be removed in the future.
Crop paths to a rectangle.
DEPRECATED: This has been replaced by the more generalized cropToShape
method
and will be removed in the future.
Remove portions of paths that are inside of another shape. This may also be considered a Boolean Exclusive Or (XOR)
Fill a convex shape (polygon) with straight lines
Layer paths according to their stacking order The lowest index (0) of "paths" will be on the bottom of the stack. Subsequent paths (1, 2, 3...) will knock out (subtract) any portions of previous paths that they cover.
Important: Shapes that are knocked-out do not include the portion of the other shape that covers them. In other words, the cover section is removed from the original path and leaves a blank space, rather than incorporating the portion of the other shape
Subtract paths from one another. The lowest index The lowest index (0) of "paths" will be on the bottom of the stack. Subsequent paths (1, 2, 3...) will knock out (subtract) any portions of previous paths that they cover.
Important: This is very similar to layeredPaths, except that this method incorporates the path of the shape that is being subtracted from the original path (as opposed to removing it as in layeredPaths).
Take a line segment and a path of a closed shape and return the portion of that line that is not intersected by the shape
Take a line segment and multiple paths representing a closed convex polygon and return the portion of that line that is not intersected by any of the shapes (paths)
Determine the "shadow" of an input shape at a certain translation vector. This has been proven for closed-path convex regular polygons. This has not been tested for other shapes.
Add a "jot" or small mark near the end of the path. The offset distance from the end of the path, the length of the mark, and a rotation range can be set.
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
No vulnerabilities found.
No security vulnerabilities found.