Skip to content

Commit fd39484

Browse files
authored
Merge pull request #7471 from processing/splineProperty
Implement splineProperty
2 parents 92da914 + e8e2c28 commit fd39484

File tree

11 files changed

+73
-135
lines changed

11 files changed

+73
-135
lines changed

src/core/constants.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1347,7 +1347,7 @@ export const FLOAT = 'float';
13471347
export const HALF_FLOAT = 'half-float';
13481348

13491349
/**
1350-
* The `splineEnds` mode where splines curve through
1350+
* The `splineProperty('ends')` mode where splines curve through
13511351
* their first and last points.
13521352
* @typedef {unique symbol} INCLUDE
13531353
* @property {INCLUDE} INCLUDE
@@ -1356,7 +1356,7 @@ export const HALF_FLOAT = 'half-float';
13561356
export const INCLUDE = Symbol('include');
13571357

13581358
/**
1359-
* The `splineEnds` mode where the first and last points in a spline
1359+
* The `splineProperty('ends')` mode where the first and last points in a spline
13601360
* affect the direction of the curve, but are not rendered.
13611361
* @typedef {unique symbol} EXCLUDE
13621362
* @property {EXCLUDE} EXCLUDE
@@ -1365,7 +1365,7 @@ export const INCLUDE = Symbol('include');
13651365
export const EXCLUDE = Symbol('exclude');
13661366

13671367
/**
1368-
* The `splineEnds` mode where the spline loops back to its first point.
1368+
* The `splineProperty('ends')` mode where the spline loops back to its first point.
13691369
* Only used internally.
13701370
* @typedef {unique symbol} JOIN
13711371
* @property {JOIN} JOIN

src/core/p5.Renderer.js

+19-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ import { Image } from '../image/p5.Image';
1010
import { Vector } from '../math/p5.Vector';
1111
import { Shape } from '../shape/custom_shapes';
1212

13+
class ClonableObject {
14+
constructor(obj = {}) {
15+
for (const key in obj) {
16+
this[key] = obj[key];
17+
}
18+
}
19+
20+
clone() {
21+
return new ClonableObject(this);
22+
}
23+
};
24+
1325
class Renderer {
1426
static states = {
1527
strokeColor: null,
@@ -30,7 +42,7 @@ class Renderer {
3042
textAlign: constants.LEFT,
3143
textBaseline: constants.BASELINE,
3244
bezierOrder: 3,
33-
splineEnds: constants.INCLUDE,
45+
splineProperties: new ClonableObject({ ends: constants.INCLUDE, tightness: 0 }),
3446
textWrap: constants.WORD,
3547

3648
// added v2.0
@@ -77,7 +89,6 @@ class Renderer {
7789

7890
this._clipping = false;
7991
this._clipInvert = false;
80-
this._curveTightness = 0;
8192

8293
this._currentShape = undefined; // Lazily generate current shape
8394
}
@@ -150,11 +161,11 @@ class Renderer {
150161
this.currentShape.bezierVertex(position, textureCoordinates);
151162
}
152163

153-
splineEnds(mode) {
154-
if (mode === undefined) {
155-
return this.states.splineEnds;
164+
splineProperty(key, value) {
165+
if (value === undefined) {
166+
return this.states.splineProperties[key];
156167
} else {
157-
this.states.splineEnds = mode;
168+
this.states.splineProperties[key] = value;
158169
}
159170
this.updateShapeProperties();
160171
}
@@ -305,7 +316,8 @@ class Renderer {
305316

306317
updateShapeProperties() {
307318
this.currentShape.bezierOrder(this.states.bezierOrder);
308-
this.currentShape.splineEnds(this.states.splineEnds);
319+
this.currentShape.splineProperty('ends', this.states.splineProperties.ends);
320+
this.currentShape.splineProperty('tightness', this.states.splineProperties.tightness);
309321
}
310322

311323
updateShapeVertexProperties() {

src/shape/curves.js

+2-57
Original file line numberDiff line numberDiff line change
@@ -765,61 +765,6 @@ function curves(p5, fn){
765765
return this;
766766
};
767767

768-
/**
769-
* Adjusts the way <a href="#/p5/curve">curve()</a> and
770-
* <a href="#/p5/curveVertex">splineVertex()</a> draw.
771-
*
772-
* Spline curves are like cables that are attached to a set of points.
773-
* `curveTightness()` adjusts how tightly the cable is attached to the points.
774-
*
775-
* The parameter, `tightness`, determines how the curve fits to the vertex
776-
* points. By default, `tightness` is set to 0. Setting tightness to 1,
777-
* as in `curveTightness(1)`, connects the curve's points using straight
778-
* lines. Values in the range from –5 to 5 deform curves while leaving them
779-
* recognizable.
780-
*
781-
* @method curveTightness
782-
* @param {Number} amount amount of tightness.
783-
* @chainable
784-
*
785-
* @example
786-
* <div>
787-
* <code>
788-
* // Move the mouse left and right to see the curve change.
789-
*
790-
* function setup() {
791-
* createCanvas(100, 100);
792-
*
793-
* describe('A black curve forms a sideways U shape. The curve deforms as the user moves the mouse from left to right');
794-
* }
795-
*
796-
* function draw() {
797-
* background(200);
798-
*
799-
* // Set the curve's tightness using the mouse.
800-
* let t = map(mouseX, 0, 100, -5, 5, true);
801-
* curveTightness(t);
802-
*
803-
* // Draw the curve.
804-
* noFill();
805-
* beginShape();
806-
* splineVertex(10, 26);
807-
* splineVertex(10, 26);
808-
* splineVertex(83, 24);
809-
* splineVertex(83, 61);
810-
* splineVertex(25, 65);
811-
* splineVertex(25, 65);
812-
* endShape();
813-
* }
814-
* </code>
815-
* </div>
816-
*/
817-
fn.curveTightness = function(t) {
818-
// p5._validateParameters('curveTightness', arguments);
819-
this._renderer._curveTightness = t;
820-
return this;
821-
};
822-
823768
/**
824769
* Calculates coordinates along a spline curve using interpolation.
825770
*
@@ -934,7 +879,7 @@ function curves(p5, fn){
934879
*/
935880
fn.curvePoint = function(a, b, c, d, t) {
936881
// p5._validateParameters('curvePoint', arguments);
937-
const s = this._renderer._curveTightness,
882+
const s = this._renderer.states.splineProperties.tightness,
938883
t3 = t * t * t,
939884
t2 = t * t,
940885
f1 = (s - 1) / 2 * t3 + (1 - s) * t2 + (s - 1) / 2 * t,
@@ -1051,7 +996,7 @@ function curves(p5, fn){
1051996
fn.curveTangent = function(a, b, c, d, t) {
1052997
// p5._validateParameters('curveTangent', arguments);
1053998

1054-
const s = this._renderer._curveTightness,
999+
const s = this._renderer.states.splineProperties.tightness,
10551000
tt3 = t * t * 3,
10561001
t2 = t * 2,
10571002
f1 = (s - 1) / 2 * tt3 + (1 - s) * t2 + (s - 1) / 2,

src/shape/custom_shapes.js

+27-26
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,10 @@ to interpolated endpoints (a breaking change)
280280
*/
281281
class SplineSegment extends Segment {
282282
#vertexCapacity = Infinity;
283-
_splineEnds = constants.INCLUDE;
284-
_splineTightness = 0;
283+
_splineProperties = {
284+
ends: constants.INCLUDE,
285+
tightness: 0
286+
};
285287

286288
get vertexCapacity() {
287289
return this.#vertexCapacity;
@@ -296,15 +298,15 @@ class SplineSegment extends Segment {
296298
}
297299

298300
get canOverrideAnchor() {
299-
return this._splineEnds === constants.EXCLUDE;
301+
return this._splineProperties.ends === constants.EXCLUDE;
300302
}
301303

302304
// assuming for now that the first interpolated vertex is always
303305
// the second vertex passed to splineVertex()
304306
// if this spline segment doesn't follow another segment,
305307
// the first vertex is in an anchor
306308
get _firstInterpolatedVertex() {
307-
if (this._splineEnds === constants.EXCLUDE) {
309+
if (this._splineProperties.ends === constants.EXCLUDE) {
308310
return this._comesAfterSegment ?
309311
this.vertices[1] :
310312
this.vertices[0];
@@ -328,10 +330,10 @@ class SplineSegment extends Segment {
328330
// doesn't line up with end of last segment
329331
addToShape(shape) {
330332
const added = super.addToShape(shape);
331-
this._splineEnds = shape._splineEnds;
332-
this._splineTightness = shape._splineTightness;
333+
this._splineProperties.ends = shape._splineProperties.ends;
334+
this._splineProperties.tightness = shape._splineProperties.tightness;
333335

334-
if (this._splineEnds !== constants.EXCLUDE) return added;
336+
if (this._splineProperties.ends !== constants.EXCLUDE) return added;
335337

336338
let verticesPushed = !this._belongsToShape;
337339
let lastPrimitive = shape.at(-1, -1);
@@ -367,9 +369,9 @@ class SplineSegment extends Segment {
367369

368370
// override method on base class
369371
getEndVertex() {
370-
if (this._splineEnds === constants.INCLUDE) {
372+
if (this._splineProperties.ends === constants.INCLUDE) {
371373
return super.getEndVertex();
372-
} else if (this._splineEnds === constants.EXCLUDE) {
374+
} else if (this._splineProperties.ends === constants.EXCLUDE) {
373375
return this.vertices.at(-2);
374376
} else {
375377
return this.getStartVertex();
@@ -389,10 +391,10 @@ class SplineSegment extends Segment {
389391
}
390392

391393
const prevVertex = this.getStartVertex();
392-
if (this._splineEnds === constants.INCLUDE) {
394+
if (this._splineProperties.ends === constants.INCLUDE) {
393395
points.unshift(prevVertex);
394396
points.push(this.vertices.at(-1));
395-
} else if (this._splineEnds === constants.JOIN) {
397+
} else if (this._splineProperties.ends === constants.JOIN) {
396398
points.unshift(this.vertices.at(-1), prevVertex);
397399
points.push(prevVertex, this.vertices.at(0));
398400
}
@@ -410,7 +412,7 @@ class SplineSegment extends Segment {
410412
}
411413

412414
close() {
413-
this._splineEnds = constants.JOIN;
415+
this._splineProperties.ends = constants.JOIN;
414416
}
415417
}
416418

@@ -581,10 +583,12 @@ class Shape {
581583
#initialVertexProperties;
582584
#primitiveShapeCreators;
583585
#bezierOrder = 3;
584-
_splineTightness = 0;
585586
kind = null;
586587
contours = [];
587-
_splineEnds = constants.INCLUDE;
588+
_splineProperties = {
589+
tightness: 0,
590+
ends: constants.INCLUDE
591+
};
588592
userVertexProperties = null;
589593

590594
constructor(
@@ -828,12 +832,8 @@ class Shape {
828832
this.#bezierOrder = order;
829833
}
830834

831-
splineEnds(mode) {
832-
this._splineEnds = mode;
833-
}
834-
835-
splineTightness(tightness) {
836-
this._splineTightness = tightness;
835+
splineProperty(key, value) {
836+
this._splineProperties[key] = value;
837837
}
838838

839839
/*
@@ -1076,7 +1076,7 @@ class PrimitiveToPath2DConverter extends PrimitiveVisitor {
10761076
const shape = splineSegment._shape;
10771077

10781078
if (
1079-
splineSegment._splineEnds === constants.EXCLUDE &&
1079+
splineSegment._splineProperties.ends === constants.EXCLUDE &&
10801080
!splineSegment._comesAfterSegment
10811081
) {
10821082
let startVertex = splineSegment._firstInterpolatedVertex;
@@ -1088,7 +1088,7 @@ class PrimitiveToPath2DConverter extends PrimitiveVisitor {
10881088
);
10891089
let bezierArrays = shape.catmullRomToBezier(
10901090
arrayVertices,
1091-
splineSegment._splineTightness
1091+
splineSegment._splineProperties.tightness
10921092
).map(arr => arr.map(vertArr => shape.arrayToVertex(vertArr)));
10931093
for (const array of bezierArrays) {
10941094
const points = array.flatMap(vert => [vert.position.x, vert.position.y]);
@@ -1217,7 +1217,7 @@ class PrimitiveToVerticesConverter extends PrimitiveVisitor {
12171217
);
12181218
let bezierArrays = shape.catmullRomToBezier(
12191219
arrayVertices,
1220-
splineSegment._splineTightness
1220+
splineSegment._splineProperties.tightness
12211221
);
12221222
let startVertex = shape.vertexToArray(splineSegment._firstInterpolatedVertex);
12231223
for (const array of bezierArrays) {
@@ -1596,10 +1596,11 @@ function customShapes(p5, fn) {
15961596

15971597
/**
15981598
* TODO: documentation
1599-
* @param {SHOW|HIDE} mode
1599+
* @param {String} key
1600+
* @param value
16001601
*/
1601-
fn.splineEnds = function(mode) {
1602-
return this._renderer.splineEnds(mode);
1602+
fn.splineProperty = function(key, value) {
1603+
return this._renderer.splineProperty(key, value);
16031604
};
16041605

16051606
/**

src/webgl/p5.RendererGL.js

-30
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,6 @@ class RendererGL extends Renderer {
407407
this.filterLayerTemp = undefined;
408408
this.defaultFilterShaders = {};
409409

410-
this._curveTightness = 6;
411-
412410
this.fontInfos = {};
413411

414412
this._curShader = undefined;
@@ -2424,34 +2422,6 @@ class RendererGL extends Renderer {
24242422
_vToNArray(arr) {
24252423
return arr.flatMap((item) => [item.x, item.y, item.z]);
24262424
}
2427-
2428-
// function to calculate BezierVertex Coefficients
2429-
_bezierCoefficients(t) {
2430-
const t2 = t * t;
2431-
const t3 = t2 * t;
2432-
const mt = 1 - t;
2433-
const mt2 = mt * mt;
2434-
const mt3 = mt2 * mt;
2435-
return [mt3, 3 * mt2 * t, 3 * mt * t2, t3];
2436-
}
2437-
2438-
// function to calculate QuadraticVertex Coefficients
2439-
_quadraticCoefficients(t) {
2440-
const t2 = t * t;
2441-
const mt = 1 - t;
2442-
const mt2 = mt * mt;
2443-
return [mt2, 2 * mt * t, t2];
2444-
}
2445-
2446-
// function to convert Bezier coordinates to Catmull Rom Splines
2447-
_bezierToCatmull(w) {
2448-
const p1 = w[1];
2449-
const p2 = w[1] + (w[2] - w[0]) / this._curveTightness;
2450-
const p3 = w[2] - (w[3] - w[1]) / this._curveTightness;
2451-
const p4 = w[2];
2452-
const p = [p1, p2, p3, p4];
2453-
return p;
2454-
}
24552425
}
24562426

24572427
function rendererGL(p5, fn) {

test/unit/core/curves.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import curves from '../../../src/shape/curves';
44
suite('Curves', function() {
55
beforeAll(function() {
66
mockP5Prototype._renderer = {
7-
_curveTightness: 0
7+
states: {
8+
splineProperties: {
9+
tightness: 0
10+
}
11+
}
812
};
913
curves(mockP5, mockP5Prototype);
1014
});

0 commit comments

Comments
 (0)