mirror of
https://github.com/processing/processing4.git
synced 2026-02-03 21:59:20 +01:00
bezier work
This commit is contained in:
152
agg/agg_bezier_arc.java
Normal file
152
agg/agg_bezier_arc.java
Normal file
@@ -0,0 +1,152 @@
|
||||
import processing.core.*;
|
||||
|
||||
|
||||
public class agg_bezier_arc {
|
||||
|
||||
private int m_vertex; // un
|
||||
private m_num_vertices; // un
|
||||
private float m_vertices[] = new float[26];
|
||||
private int m_cmd; // un
|
||||
|
||||
/**
|
||||
* This epsilon is used to prevent us from adding degenerate curves
|
||||
* (converging to a single point).
|
||||
* The value isn't very critical. Function arc_to_bezier() has a limit
|
||||
* of the sweep_angle. If fabs(sweep_angle) exceeds pi/2 the curve
|
||||
* becomes inaccurate. But slight exceeding is quite appropriate.
|
||||
*/
|
||||
static final float bezier_arc_angle_epsilon = 0.01f;
|
||||
|
||||
|
||||
public agg_bezier_arc() {
|
||||
m_vertex = 26;
|
||||
m_num_vertices = 0;
|
||||
m_cmd = path_cmd_line_to;
|
||||
}
|
||||
|
||||
|
||||
public agg_bezier_arc(float x, float y,
|
||||
float rx, float ry,
|
||||
float start_angle,
|
||||
float sweep_angle) {
|
||||
init(x, y, rx, ry, start_angle, sweep_angle);
|
||||
}
|
||||
|
||||
|
||||
public void init(float x, float y,
|
||||
float rx, float ry,
|
||||
float start_angle,
|
||||
float sweep_angle) {
|
||||
start_angle = start_angle % PConstants.TWO_PI;
|
||||
if (sweep_angle >= 2.0 * pi) sweep_angle = PConstants.TWO_PI;
|
||||
if (sweep_angle <= -2.0 * pi) sweep_angle = -PConstants.TWO_PI;
|
||||
|
||||
if (Math.abs(sweep_angle) < 1e-10) {
|
||||
m_num_vertices = 4;
|
||||
m_cmd = path_cmd_line_to;
|
||||
m_vertices[0] = x + rx * (float)Math.cos(start_angle);
|
||||
m_vertices[1] = y + ry * (float)Math.sin(start_angle);
|
||||
m_vertices[2] = x + rx * (float)Math.cos(start_angle + sweep_angle);
|
||||
m_vertices[3] = y + ry * (float)Math.sin(start_angle + sweep_angle);
|
||||
return;
|
||||
}
|
||||
|
||||
float total_sweep = 0.0f;
|
||||
float local_sweep = 0.0f;
|
||||
float prev_sweep;
|
||||
m_num_vertices = 2;
|
||||
m_cmd = path_cmd_curve4;
|
||||
bool done = false;
|
||||
do {
|
||||
if (sweep_angle < 0.0f) {
|
||||
prev_sweep = total_sweep;
|
||||
local_sweep = -pi * 0.5f;
|
||||
total_sweep -= pi * 0.5f;
|
||||
if (total_sweep <= sweep_angle + bezier_arc_angle_epsilon) {
|
||||
local_sweep = sweep_angle - prev_sweep;
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
prev_sweep = total_sweep;
|
||||
local_sweep = pi * 0.5f;
|
||||
total_sweep += pi * 0.5f;
|
||||
if (total_sweep >= sweep_angle - bezier_arc_angle_epsilon) {
|
||||
local_sweep = sweep_angle - prev_sweep;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
arc_to_bezier(x, y, rx, ry,
|
||||
start_angle,
|
||||
local_sweep,
|
||||
m_vertices + m_num_vertices - 2);
|
||||
|
||||
m_num_vertices += 6;
|
||||
start_angle += local_sweep;
|
||||
}
|
||||
while (!done && m_num_vertices < 26);
|
||||
}
|
||||
|
||||
|
||||
public void rewind() {
|
||||
m_vertex = 0;
|
||||
}
|
||||
|
||||
|
||||
public int vertex(float x[], float y[], int offset) { // un
|
||||
if (m_vertex >= m_num_vertices) return path_cmd_stop;
|
||||
x[offset] = m_vertices[m_vertex];
|
||||
y[offset] = m_vertices[m_vertex + 1];
|
||||
m_vertex += 2;
|
||||
return (m_vertex == 2) ? path_cmd_move_to : m_cmd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Supplemantary functions. num_vertices() actually returns doubled
|
||||
* number of vertices. That is, for 1 vertex it returns 2.
|
||||
*/
|
||||
public int num_vertices() {
|
||||
return m_num_vertices;
|
||||
}
|
||||
|
||||
|
||||
public void float[] vertices() {
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
|
||||
public float[] vertices() {
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
|
||||
static public void arc_to_bezier(float cx, float cy, float rx, float ry,
|
||||
float start_angle, float sweep_angle,
|
||||
float* curve) {
|
||||
float x0 = (float) Math.cos(sweep_angle / 2.0f);
|
||||
float y0 = (float) Math.sin(sweep_angle / 2.0f);
|
||||
float tx = (1.0f - x0) * 4.0f / 3.0f;
|
||||
float ty = y0 - tx * x0 / y0;
|
||||
float px[] = new float[4];
|
||||
float py[] = new float[4];
|
||||
px[0] = x0;
|
||||
py[0] = -y0;
|
||||
px[1] = x0 + tx;
|
||||
py[1] = -ty;
|
||||
px[2] = x0 + tx;
|
||||
py[2] = ty;
|
||||
px[3] = x0;
|
||||
py[3] = y0;
|
||||
|
||||
float sn = (float) Math.sin(start_angle + sweep_angle / 2.0f);
|
||||
float cs = (float) Math.cos(start_angle + sweep_angle / 2.0f);
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
curve[i * 2] = cx + rx * (px[i] * cs - py[i] * sn);
|
||||
curve[i * 2 + 1] = cy + ry * (px[i] * sn + py[i] * cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
190
agg/agg_bezier_arc_svg.java
Normal file
190
agg/agg_bezier_arc_svg.java
Normal file
@@ -0,0 +1,190 @@
|
||||
import processing.core.*;
|
||||
|
||||
|
||||
/**
|
||||
* Compute an SVG-style bezier arc.
|
||||
*
|
||||
* Computes an elliptical arc from (x1, y1) to (x2, y2). The size and
|
||||
* orientation of the ellipse are defined by two radii (rx, ry)
|
||||
* and an x-axis-rotation, which indicates how the ellipse as a whole
|
||||
* is rotated relative to the current coordinate system. The center
|
||||
* (cx, cy) of the ellipse is calculated automatically to satisfy the
|
||||
* constraints imposed by the other parameters.
|
||||
* large-arc-flag and sweep-flag contribute to the automatic calculations
|
||||
* and help determine how the arc is drawn.
|
||||
*/
|
||||
public class agg_bezier_arc_svg {
|
||||
|
||||
public agg_bezier_arc_svg() : m_arc(), m_radii_ok(false) {}
|
||||
|
||||
bezier_arc_svg(float x1, float y1,
|
||||
float rx, float ry,
|
||||
float angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
float x2, float y2) {
|
||||
m_arc = new agg_bezier_arc();
|
||||
m_radii_ok = false;
|
||||
|
||||
init(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void init(float x1, float y1,
|
||||
float rx, float ry,
|
||||
float angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
float x2, float y2);
|
||||
|
||||
|
||||
public boolean radii_ok() {
|
||||
return m_radii_ok;
|
||||
}
|
||||
|
||||
|
||||
public void rewind() {
|
||||
m_arc.rewind(0);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int vertex(float x[], float y[], int offset) { // un
|
||||
return m_arc.vertex(x, y, offset);
|
||||
}
|
||||
|
||||
// Supplemantary functions. num_vertices() actually returns doubled
|
||||
// number of vertices. That is, for 1 vertex it returns 2.
|
||||
//--------------------------------------------------------------------
|
||||
unsigned num_vertices() const { return m_arc.num_vertices(); }
|
||||
const float* vertices() const { return m_arc.vertices(); }
|
||||
float* vertices() { return m_arc.vertices(); }
|
||||
|
||||
private agg_bezier_arc m_arc;
|
||||
private boolean m_radii_ok;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void bezier_arc_svg::init(float x0, float y0,
|
||||
float rx, float ry,
|
||||
float angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
float x2, float y2)
|
||||
{
|
||||
m_radii_ok = true;
|
||||
|
||||
if(rx < 0.0) rx = -rx;
|
||||
if(ry < 0.0) ry = -rx;
|
||||
|
||||
// Calculate the middle point between
|
||||
// the current and the final points
|
||||
//------------------------
|
||||
float dx2 = (x0 - x2) / 2.0;
|
||||
float dy2 = (y0 - y2) / 2.0;
|
||||
|
||||
float cos_a = cos(angle);
|
||||
float sin_a = sin(angle);
|
||||
|
||||
// Calculate (x1, y1)
|
||||
//------------------------
|
||||
float x1 = cos_a * dx2 + sin_a * dy2;
|
||||
float y1 = -sin_a * dx2 + cos_a * dy2;
|
||||
|
||||
// Ensure radii are large enough
|
||||
//------------------------
|
||||
float prx = rx * rx;
|
||||
float pry = ry * ry;
|
||||
float px1 = x1 * x1;
|
||||
float py1 = y1 * y1;
|
||||
|
||||
// Check that radii are large enough
|
||||
//------------------------
|
||||
float radii_check = px1/prx + py1/pry;
|
||||
if(radii_check > 1.0)
|
||||
{
|
||||
rx = sqrt(radii_check) * rx;
|
||||
ry = sqrt(radii_check) * ry;
|
||||
prx = rx * rx;
|
||||
pry = ry * ry;
|
||||
if(radii_check > 10.0) m_radii_ok = false;
|
||||
}
|
||||
|
||||
// Calculate (cx1, cy1)
|
||||
//------------------------
|
||||
float sign = (large_arc_flag == sweep_flag) ? -1.0 : 1.0;
|
||||
float sq = (prx*pry - prx*py1 - pry*px1) / (prx*py1 + pry*px1);
|
||||
float coef = sign * sqrt((sq < 0) ? 0 : sq);
|
||||
float cx1 = coef * ((rx * y1) / ry);
|
||||
float cy1 = coef * -((ry * x1) / rx);
|
||||
|
||||
//
|
||||
// Calculate (cx, cy) from (cx1, cy1)
|
||||
//------------------------
|
||||
float sx2 = (x0 + x2) / 2.0;
|
||||
float sy2 = (y0 + y2) / 2.0;
|
||||
float cx = sx2 + (cos_a * cx1 - sin_a * cy1);
|
||||
float cy = sy2 + (sin_a * cx1 + cos_a * cy1);
|
||||
|
||||
// Calculate the start_angle (angle1) and the sweep_angle (dangle)
|
||||
//------------------------
|
||||
float ux = (x1 - cx1) / rx;
|
||||
float uy = (y1 - cy1) / ry;
|
||||
float vx = (-x1 - cx1) / rx;
|
||||
float vy = (-y1 - cy1) / ry;
|
||||
float p, n;
|
||||
|
||||
// Calculate the angle start
|
||||
//------------------------
|
||||
n = sqrt(ux*ux + uy*uy);
|
||||
p = ux; // (1 * ux) + (0 * uy)
|
||||
sign = (uy < 0) ? -1.0 : 1.0;
|
||||
float v = p / n;
|
||||
if(v < -1.0) v = -1.0;
|
||||
if(v > 1.0) v = 1.0;
|
||||
float start_angle = sign * acos(v);
|
||||
|
||||
// Calculate the sweep angle
|
||||
//------------------------
|
||||
n = sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy));
|
||||
p = ux * vx + uy * vy;
|
||||
sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;
|
||||
v = p / n;
|
||||
if(v < -1.0) v = -1.0;
|
||||
if(v > 1.0) v = 1.0;
|
||||
float sweep_angle = sign * acos(v);
|
||||
if(!sweep_flag && sweep_angle > 0)
|
||||
{
|
||||
sweep_angle -= pi * 2.0;
|
||||
}
|
||||
else
|
||||
if (sweep_flag && sweep_angle < 0)
|
||||
{
|
||||
sweep_angle += pi * 2.0;
|
||||
}
|
||||
|
||||
// We can now build and transform the resulting arc
|
||||
//------------------------
|
||||
m_arc.init(0.0, 0.0, rx, ry, start_angle, sweep_angle);
|
||||
trans_affine mtx = trans_affine_rotation(angle);
|
||||
mtx *= trans_affine_translation(cx, cy);
|
||||
|
||||
for(unsigned i = 2; i < m_arc.num_vertices()-2; i += 2)
|
||||
{
|
||||
mtx.transform(m_arc.vertices() + i, m_arc.vertices() + i + 1);
|
||||
}
|
||||
|
||||
// We must make sure that the starting and ending points
|
||||
// exactly coincide with the initial (x0,y0) and (x2,y2)
|
||||
m_arc.vertices()[0] = x0;
|
||||
m_arc.vertices()[1] = y0;
|
||||
if(m_arc.num_vertices() > 2)
|
||||
{
|
||||
m_arc.vertices()[m_arc.num_vertices() - 2] = x2;
|
||||
m_arc.vertices()[m_arc.num_vertices() - 1] = y2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user