Skip to content

Commit 575e022

Browse files
committed
Add CubicBezierCurve control point generation
1 parent 594f54d commit 575e022

File tree

3 files changed

+99
-4
lines changed

3 files changed

+99
-4
lines changed

modules/app/src/main/java/org/locationtech/jtstest/function/CreateShapeFunctions.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,22 @@ public static Geometry bezierCurveControl(Geometry geom, Geometry controlPoints)
364364
return CubicBezierCurve.bezierCurve(geom, controlPoints);
365365
}
366366

367+
@Metadata(description="Get the generated control points for a Bezier curve")
368+
public static Geometry bezierControl(Geometry geom,
369+
@Metadata(title="Alpha (curveness)")
370+
double alpha) {
371+
return CubicBezierCurve.controlPoints(geom, alpha);
372+
}
373+
374+
@Metadata(description="Get the generated control points for a Bezier curve with a skew")
375+
public static Geometry bezierControlSkew(Geometry geom,
376+
@Metadata(title="Alpha (curveness)")
377+
double alpha,
378+
@Metadata(title="Skew factor")
379+
double skew) {
380+
return CubicBezierCurve.controlPoints(geom, alpha, skew);
381+
}
382+
367383
public static Geometry nGon(Geometry g,
368384
@Metadata(title="Num sides")
369385
int sides) {

modules/core/src/main/java/org/locationtech/jts/shape/CubicBezierCurve.java

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,37 @@ public static Geometry bezierCurve(Geometry geom, double alpha, double skew) {
6868
return curve.getResult();
6969
}
7070

71+
/**
72+
* Gets a linear geometry containing the generated control points
73+
* for the Bezier curve defined by the segments of the input and a parameter
74+
* controlling how curved the result should be, with a skew factor
75+
* affecting the curve shape at each vertex.
76+
*
77+
* @param geom the geometry defining the curve
78+
* @param alpha curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved)
79+
* @return the line(s) containing the control points
80+
*/
81+
public static Geometry controlPoints(Geometry geom, double alpha) {
82+
CubicBezierCurve curve = new CubicBezierCurve(geom, alpha);
83+
return curve.getControlPoints();
84+
}
85+
86+
/**
87+
* Gets a linear geometry containing the generated control points
88+
* for the Bezier curve defined by the segments of the input and a parameter
89+
* controlling how curved the result should be, with a skew factor
90+
* affecting the curve shape at each vertex.
91+
*
92+
* @param geom the geometry defining the curve
93+
* @param alpha curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved)
94+
* @param skew the skew parameter (0 is none, positive skews towards longer side, negative towards shorter
95+
* @return the line(s) containing the control points
96+
*/
97+
public static Geometry controlPoints(Geometry geom, double alpha, double skew) {
98+
CubicBezierCurve curve = new CubicBezierCurve(geom, alpha, skew);
99+
return curve.getControlPoints();
100+
}
101+
71102
/**
72103
* Creates a geometry of linearized Cubic Bezier Curves
73104
* defined by the segments of the input
@@ -157,7 +188,7 @@ public static Geometry bezierCurve(Geometry geom, Geometry controlPoints) {
157188
*/
158189
public Geometry getResult() {
159190
bezierCurvePts = new Coordinate[numVerticesPerSegment];
160-
interpolationParam = computeIterpolationParameters(numVerticesPerSegment);
191+
interpolationParam = computeInterpolationParameters(numVerticesPerSegment);
161192

162193
return GeometryMapper.flatMap(inputGeom, 1, new GeometryMapper.MapOp() {
163194

@@ -175,6 +206,35 @@ public Geometry map(Geometry geom) {
175206
});
176207
}
177208

209+
/**
210+
* Gets the computed control points for the Bezier curve.
211+
*
212+
* @return a linear geometry holding the control points
213+
*/
214+
public Geometry getControlPoints() {
215+
bezierCurvePts = new Coordinate[numVerticesPerSegment];
216+
interpolationParam = computeInterpolationParameters(numVerticesPerSegment);
217+
218+
return GeometryMapper.flatMap(inputGeom, 1, new GeometryMapper.MapOp() {
219+
220+
@Override
221+
public Geometry map(Geometry geom) {
222+
if (geom instanceof LineString) {
223+
Coordinate[] control = controlPoints(geom.getCoordinates(), false);
224+
return geom.getFactory().createLineString(control);
225+
}
226+
if (geom instanceof Polygon ) {
227+
Polygon poly = (Polygon) geom;
228+
Coordinate[] control = controlPoints(poly.getExteriorRing().getCoordinates(), true);
229+
//TODO: include holes as well
230+
return geom.getFactory().createLineString(control);
231+
}
232+
//-- Points
233+
return geom.copy();
234+
}
235+
});
236+
}
237+
178238
private LineString bezierLine(LineString ls) {
179239
//-- can't curve a single segment
180240
if (ls.getNumPoints() <= 2)
@@ -278,7 +338,7 @@ private void addCurve(Coordinate p0, Coordinate p1,
278338
* @param alpha determines the curviness
279339
* @return the control point array
280340
*/
281-
private Coordinate[] controlPoints(Coordinate[] coords, boolean isRing, double alpha, double skew) {
341+
private static Coordinate[] controlPoints(Coordinate[] coords, boolean isRing, double alpha, double skew) {
282342
int N = coords.length;
283343
int start = 1;
284344
int end = N - 1;
@@ -351,7 +411,7 @@ private Coordinate[] controlPoints(Coordinate[] coords, boolean isRing, double a
351411
* @param coords
352412
* @param ctrl
353413
*/
354-
private void setLineEndControlPoints(Coordinate[] coords, Coordinate[] ctrl) {
414+
private static void setLineEndControlPoints(Coordinate[] coords, Coordinate[] ctrl) {
355415
int N = ctrl.length;
356416
ctrl[0] = mirrorControlPoint(ctrl[1], coords[1], coords[0]);
357417
ctrl[N - 1] = mirrorControlPoint(ctrl[N - 2],
@@ -436,7 +496,7 @@ private void cubicBezier(final Coordinate p0,
436496
* @param n number of vertices
437497
* @return array of double[4] holding the parameter values
438498
*/
439-
private static double[][] computeIterpolationParameters(int n) {
499+
private static double[][] computeInterpolationParameters(int n) {
440500
double[][] param = new double[n][4];
441501
for (int i = 0; i < n; i++) {
442502
double t = (double) i / (n - 1);

modules/core/src/test/java/org/locationtech/jts/shape/CubicBezierCurveTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ public void testAlphaRightAngle() {
4646
"LINESTRING (30 40, 30.1 41.1, 30.2 42.1, 30.5 43.1, 30.9 44, 31.4 44.9, 32 45.8, 32.7 46.6, 33.4 47.3, 34.2 48, 35.1 48.6, 36 49.1, 36.9 49.5, 37.9 49.8, 38.9 49.9, 40 50, 41.1 49.9, 42.1 49.8, 43.1 49.5, 44 49.1, 44.9 48.6, 45.8 48, 46.6 47.3, 47.3 46.6, 48 45.8, 48.6 44.9, 49.1 44, 49.5 43.1, 49.8 42.1, 49.9 41.1, 50 40)");
4747
}
4848

49+
public void testAlphaRightAngleControl() {
50+
checkControl("LINESTRING (30 40, 40 50, 50 40)", 1,
51+
"LINESTRING (30 45.3, 34.7 50, 45.3 50, 50 45.3)");
52+
}
53+
4954
public void testAlphaRightZigzag() {
5055
checkCurve("LINESTRING (10 10, 20 19, 30 10, 40 20)", 1,
5156
"LINESTRING (10 10, 10.2 11, 10.4 11.9, 10.8 12.9, 11.2 13.7, 11.7 14.6, 12.3 15.3, 13 16, 13.7 16.7, 14.5 17.3, 15.3 17.8, 16.2 18.2, 17.1 18.5, 18 18.8, 19 18.9, 20 19, 20.9 18.9, 21.8 18.6, 22.5 18.1, 23.1 17.4, 23.7 16.6, 24.2 15.8, 24.8 14.9, 25.2 14, 25.8 13.1, 26.3 12.3, 26.9 11.5, 27.5 10.9, 28.2 10.4, 29.1 10.1, 30 10, 31 10.1, 32 10.3, 33 10.6, 33.9 11, 34.8 11.5, 35.7 12.1, 36.5 12.8, 37.2 13.5, 37.9 14.3, 38.5 15.2, 39 16.1, 39.4 17, 39.7 18, 39.9 19, 40 20)");
@@ -69,6 +74,20 @@ private void checkCurve(String wkt, double alpha, String wktExpected) {
6974
checkEqual(expected, actual, 0.5);
7075
}
7176

77+
private void checkControl(String wkt, double alpha, String wktExpected) {
78+
Geometry geom = read(wkt);
79+
Geometry actual = CubicBezierCurve.controlPoints(geom, alpha);
80+
Geometry expected = read(wktExpected);
81+
checkEqual(expected, actual, 0.5);
82+
}
83+
84+
private void checkControl(String wkt, double alpha, double skew, String wktExpected) {
85+
Geometry geom = read(wkt);
86+
Geometry actual = CubicBezierCurve.controlPoints(geom, alpha, skew);
87+
Geometry expected = read(wktExpected);
88+
checkEqual(expected, actual, 0.5);
89+
}
90+
7291
private void checkCurve(String wkt, String wktCtrl, String wktExpected) {
7392
Geometry geom = read(wkt);
7493
Geometry ctrl = read(wktCtrl);

0 commit comments

Comments
 (0)