/*
* Copyright 2015 Brandon Borkholder
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jogamp.glg2d.impl;
import org.jogamp.glg2d.PathVisitor;
/**
* This is a fast Bézier curve implementation. I can't use OpenGL's
* built-in evaluators because subclasses need to do something with the points,
* not just pass them directly to glVertex2f. This algorithm uses forward
* differencing. Most of this is taken from <a
* href="http://www.niksula.hut.fi/~hkankaan/Homepages/bezierfast.html"
* >http://www.niksula.hut.fi/~hkankaan/Homepages/bezierfast.html</a>. I derived
* the implementation for the quadratic on my own, but it's simple.
*/
public abstract class SimplePathVisitor implements PathVisitor {
/**
* Just a guess. Would be nice to make a better guess based on what's visually
* acceptable.
*/
public static final int CURVE_STEPS = 30;
protected int steps = CURVE_STEPS;
/**
* Sets the number of steps to take in a quadratic or cubic curve spline.
*/
public void setNumCurveSteps(int steps) {
this.steps = steps;
}
/**
* Gets the number of steps to take in a quadratic or cubic curve spline.
*/
public int getNumCurveSteps() {
return steps;
}
@Override
public void quadTo(float[] previousVertex, float[] control) {
float[] p = new float[2];
float xd, xdd, xdd_per_2;
float yd, ydd, ydd_per_2;
float t = 1F / steps;
float tt = t * t;
// x
p[0] = previousVertex[0];
xd = 2 * (control[0] - previousVertex[0]) * t;
xdd_per_2 = 1 * (previousVertex[0] - 2 * control[0] + control[2]) * tt;
xdd = xdd_per_2 + xdd_per_2;
// y
p[1] = previousVertex[1];
yd = 2 * (control[1] - previousVertex[1]) * t;
ydd_per_2 = 1 * (previousVertex[1] - 2 * control[1] + control[3]) * tt;
ydd = ydd_per_2 + ydd_per_2;
for (int loop = 0; loop < steps; loop++) {
lineTo(p);
p[0] = p[0] + xd + xdd_per_2;
xd = xd + xdd;
p[1] = p[1] + yd + ydd_per_2;
yd = yd + ydd;
}
// use exactly the last point
p[0] = control[2];
p[1] = control[3];
lineTo(p);
}
@Override
public void cubicTo(float[] previousVertex, float[] control) {
float[] p = new float[2];
float xd, xdd, xddd, xdd_per_2, xddd_per_2, xddd_per_6;
float yd, ydd, yddd, ydd_per_2, yddd_per_2, yddd_per_6;
float t = 1F / steps;
float tt = t * t;
// x
p[0] = previousVertex[0];
xd = 3 * (control[0] - previousVertex[0]) * t;
xdd_per_2 = 3 * (previousVertex[0] - 2 * control[0] + control[2]) * tt;
xddd_per_2 = 3 * (3 * (control[0] - control[2]) + control[4] - previousVertex[0]) * tt * t;
xddd = xddd_per_2 + xddd_per_2;
xdd = xdd_per_2 + xdd_per_2;
xddd_per_6 = xddd_per_2 / 3;
// y
p[1] = previousVertex[1];
yd = 3 * (control[1] - previousVertex[1]) * t;
ydd_per_2 = 3 * (previousVertex[1] - 2 * control[1] + control[3]) * tt;
yddd_per_2 = 3 * (3 * (control[1] - control[3]) + control[5] - previousVertex[1]) * tt * t;
yddd = yddd_per_2 + yddd_per_2;
ydd = ydd_per_2 + ydd_per_2;
yddd_per_6 = yddd_per_2 / 3;
for (int loop = 0; loop < steps; loop++) {
lineTo(p);
p[0] = p[0] + xd + xdd_per_2 + xddd_per_6;
xd = xd + xdd + xddd_per_2;
xdd = xdd + xddd;
xdd_per_2 = xdd_per_2 + xddd_per_2;
p[1] = p[1] + yd + ydd_per_2 + yddd_per_6;
yd = yd + ydd + yddd_per_2;
ydd = ydd + yddd;
ydd_per_2 = ydd_per_2 + yddd_per_2;
}
// use exactly the last point
p[0] = control[4];
p[1] = control[5];
lineTo(p);
}
}