use of org.jwildfire.create.tina.base.XYZPoint in project JWildfire by thargor6.
the class CubicLattice3DFunc method transform.
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
/* cubicLattice_3D by Larry Berlin, http://aporev.deviantart.com/art/3D-Plugins-Collection-One-138514007?q=gallery%3Aaporev%2F8229210&qo=15 */
double fill, exnze, wynze, znxy;
if (fabs(this.xpand) <= 1.0) {
// values up to 0.5
fill = this.xpand * 0.5;
} else {
// values above 0.5
fill = sqrt(this.xpand) * 0.5;
}
if (_iStyle == 2) {
exnze = cos(atan2(pAffineTP.x, pAffineTP.z));
wynze = sin(atan2(pAffineTP.y, pAffineTP.z));
znxy = (exnze + wynze) / 2.0;
} else {
exnze = 1.0;
wynze = 1.0;
znxy = 1.0;
}
// optionally * 0.5;
double lattd = pAmount;
int useNode = 0;
int rchoice = (int) trunc(pContext.random() * 8.0);
useNode = rchoice;
if (useNode == 0) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze + lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze + lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy + lattd;
} else if (useNode == 1) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze + lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze - lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy + lattd;
} else if (useNode == 2) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze + lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze + lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy - lattd;
} else if (useNode == 3) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze + lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze - lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy - lattd;
} else if (useNode == 4) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze - lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze + lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy + lattd;
} else if (useNode == 5) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze - lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze - lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy + lattd;
} else if (useNode == 6) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze - lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze + lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy - lattd;
} else if (useNode == 7) {
pVarTP.x = (pVarTP.x + pAffineTP.x) * fill * exnze - lattd;
pVarTP.y = (pVarTP.y + pAffineTP.y) * fill * wynze - lattd;
pVarTP.z = (pVarTP.z + pAffineTP.z) * fill * znxy - lattd;
}
}
use of org.jwildfire.create.tina.base.XYZPoint in project JWildfire by thargor6.
the class Grid3DWFFunc method transform.
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
/* grid3d_wf by thargor6, inspired by dc_cube by Xyrus02 */
int cxn = (int) (pAffineTP.x / size);
int cyn = (int) (pAffineTP.y / size);
int czn = (int) (pAffineTP.z / size);
double sizeSpread = getSizeSpread(cxn, cyn, czn);
double sizescl = spacing * (size + sizeSpread * 0.1);
double dx = 0.0, dy = 0.0, dz = 0.0;
switch(pContext.random(3)) {
case 0:
boolean left = pContext.random() < 0.5;
dx = sizescl * (left ? -0.5 : 0.5);
dy = sizescl * (pContext.random() - 0.5);
dz = sizescl * (pContext.random() - 0.5);
pVarTP.color = left ? c1 : c2;
break;
case 1:
boolean top = pContext.random() < 0.5;
dx = sizescl * (pContext.random() - 0.5);
dy = sizescl * (top ? -0.5 : 0.5);
dz = sizescl * (pContext.random() - 0.5);
pVarTP.color = top ? c3 : c4;
break;
case 2:
boolean front = pContext.random() < 0.5;
dx = sizescl * (pContext.random() - 0.5);
dy = sizescl * (pContext.random() - 0.5);
dz = sizescl * (front ? -0.5 : 0.5);
pVarTP.color = front ? c5 : c6;
break;
default:
// nothing to do
break;
}
if (doRotate) {
double a = alpha + getAlphaSpread(cxn, cyn, czn);
double b = beta + getBetaSpread(cxn, cyn, czn);
double g = gamma + getGammaSpread(cxn, cyn, czn);
double sina = sin(a);
double cosa = cos(a);
double sinb = sin(b);
double cosb = cos(b);
double sing = sin(g);
double cosg = cos(g);
double dxr = dx * (cosb * cosg) + dy * (cosg * sina * sinb - cosa * sing) + dz * (cosa * cosg * sinb + sina * sing);
double dyr = dx * (cosb * sing) + dy * (cosa * cosg + sina * sinb * sing) + dz * (-cosg * sina + cosa * sinb * sing);
double dzr = dx * (-sinb) + dy * (cosb * sina) + dz * (cosa * cosb);
dx = dxr;
dy = dyr;
dz = dzr;
}
pVarTP.x += cxn * size + dx;
pVarTP.y += cyn * size + dy;
pVarTP.z += czn * size + dz;
}
use of org.jwildfire.create.tina.base.XYZPoint in project JWildfire by thargor6.
the class MandelbrotFunc method transform.
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
double x1 = _x0;
double x = _x0;
double y1 = _y0;
double y = _y0;
int currIter;
boolean inverted = randGen.random() < this.invert;
if (inverted) {
currIter = 0;
} else {
currIter = iter;
}
while ((inverted && (currIter < iter)) || ((!inverted) && ((currIter >= iter) || ((skin < 1) && (currIter < 0.1 * iter * (1 - skin)))))) {
if ((_x0 == 0) && (_y0 == 0)) {
// Choose a point at random
if (max_points > 0) {
if (xP.size() >= max_points) {
_x0 = xP.get(_pIdx);
_y0 = yP.get(_pIdx);
_z0 = zP.get(_pIdx++);
if (_pIdx >= max_points) {
_pIdx = 0;
}
} else {
_x0 = (xmax - xmin) * randGen.random() + xmin;
_y0 = (ymax - ymin) * randGen.random() + ymin;
_z0 = randGen.random() * rnd_z_range;
xP.add(_x0);
yP.add(_y0);
zP.add(_z0);
}
} else {
_x0 = (xmax - xmin) * randGen.random() + xmin;
_y0 = (ymax - ymin) * randGen.random() + ymin;
_z0 = randGen.random() * rnd_z_range;
}
} else {
// Choose a point close to previous point
_x0 = (skin + 0.001) * (randGen.random() - 0.5) + _x0;
_y0 = (skin + 0.001) * (randGen.random() - 0.5) + _y0;
// _z0 = (skin + 0.001) * (randGen.random() - 0.5) + _z0;
}
x1 = _x0;
y1 = _y0;
x = _x0;
y = _y0;
currIter = 0;
while (((x * x + y * y < 2 * 2) && (currIter < iter))) {
double xtemp = x * x - y * y + _x0;
y = 2.0 * x * y + _y0;
x = xtemp;
currIter++;
}
if ((currIter >= iter) || (skin == 1) || (currIter < 0.1 * (iter * (1 - skin)))) {
// Random point next time
_x0 = 0;
_y0 = 0;
}
}
// + FTx^;
pVarTP.x += pAmount * (x1 + cx * x);
// + FTy^;
pVarTP.y += pAmount * (y1 + cy * y);
pVarTP.z += _z0;
}
use of org.jwildfire.create.tina.base.XYZPoint in project JWildfire by thargor6.
the class MaurerLinesFunc method transform.
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
count++;
setValues();
double xin = pAffineTP.x;
double yin = pAffineTP.y;
// atan2 range is [-PI, PI], so tin covers 2PI, or 1 cycle (from -0.5 to 0.5 cycle)
double tin;
if (randomize) {
// tin = (Math.random() * M_2PI) - M_PI; // random angle, range [-Pi .. +Pi]
// random angle, range [0.. +2Pi]
tin = (Math.random() * M_2PI);
} else {
// polar coordinate angle (theta in radians) of incoming point [-Pi .. +Pi]
tin = atan2(yin, xin);
}
// theta parameter for curve calculation
double t = cycles * tin;
// reusing curve_point
// curve_point = getCurveCoords(t, curve_point);
curve.getCurvePoint(t, curve_point);
double x = curve_point.x;
double y = curve_point.y;
double r = sqrt(x * x + y * y);
double rinx, riny;
double rout;
double xout = 0, yout = 0, zout = 0;
double step_number, theta1, theta2;
double x1, y1, x2, y2;
// map to a Maurer Rose line
// find nearest step
step_number = floor(t / theta_step_radians);
// find distance along line??
// find radians per full line
// double line_fraction = (t % theta_step_radians)/radians_per_full_line
// find polar and cartesian coordinates for endpoints of Maure Rose line
theta1 = (step_number * theta_step_radians) + initial_theta_radians;
theta2 = theta1 + theta_step_radians;
// reusing end_point1
// end_point1 = getCurveCoords(theta1, end_point1);
curve.getCurvePoint(theta1, end_point1);
x1 = end_point1.x;
y1 = end_point1.y;
// reusing end_point2
// end_point2 = getCurveCoords(theta2, end_point2);
curve.getCurvePoint(theta2, end_point2);
x2 = end_point2.x;
y2 = end_point2.y;
/* if (DEBUG_COSETS && count % 50000 == 0) {
System.out.println("step_number: " + step_number + ", theta1: " + theta1 + ", theta2: " + theta2);
System.out.println("point1: " + x1 + ", " + y1 + " point2: " + x2 + ", " + y2 );
}
*/
// find the slope and length of the line
double ydiff = y2 - y1;
double xdiff = x2 - x1;
// slope of line (m in y=mx+b line equation)
double line_slope = ydiff / xdiff;
// y-intercept of line (b in y=mx+b line equation)
double line_intercept;
// special-casing for slope being NaN (xdiff = 0) ==> line_intercept set to NaN as well
if (Double.isNaN(line_slope)) {
line_intercept = Double.NaN;
} else {
line_intercept = y1 - (line_slope * x1);
}
double point_angle = getPointAngle(end_point1, end_point2);
// atan2 range is [-Pi..+Pi]
double raw_line_angle = atan2(ydiff, xdiff);
// if (raw_line_angle < 0) { raw_line_angle += M_2PI; } // map to range [0..+2Pi]
// delta_from_yaxis should be 0 if parallel to y-axis, and M_PI/2 if parallel to x-axis
double unscaled_line_angle = abs(abs(raw_line_angle) - (M_PI / 2.0));
// scale to range [0..1]; (0 parallel to y-axis, 1 parallel to x-axis)
double line_angle = unscaled_line_angle / (M_PI / 2.0);
double line_length = Math.sqrt((xdiff * xdiff) + (ydiff * ydiff));
// yoffset = [+-] line_slope * d / (sqrt(1 + line_slope^2))
// double xoffset=0, yoffset=0, zoffset = 0;
double line_delta = 0;
// use midlength of Maurer line as radius
double midlength = line_length / 2.0;
double xmid = (x1 + x2) / 2.0;
double ymid = (y1 + y2) / 2.0;
// double speed1 = curve.getSpeed(theta1, end_point1);
boolean use_render_mode = true;
if (show_points_param > 0 || show_curve_param > 0) {
double rnd = pContext.random();
/**
* overrides of rendering mode
*/
double xoffset = 0, yoffset = 0, zoffset = 0;
double rand2 = Math.random();
if (rand2 <= show_points_param) {
// drawing Maurer anchor points instead of specified render_mode
use_render_mode = false;
if (point_thickness != 0) {
double roffset = pContext.random() * point_thickness;
double rangle = (pContext.random() * M_2PI);
xoffset = roffset * cos(rangle);
yoffset = roffset * sin(rangle);
} else {
xoffset = 0;
yoffset = 0;
}
if (rnd <= (show_points_param / 2)) {
xout = x1 + xoffset;
yout = y1 + yoffset;
} else {
xout = x2 + xoffset;
yout = y2 + yoffset;
}
zout = 0;
} else if (rand2 <= (show_points_param + show_curve_param)) {
// drawing base curve instead of specified render_mode
use_render_mode = false;
if (curve_thickness != 0) {
xout = x + ((pContext.random() - 0.5) * curve_thickness);
yout = y + ((pContext.random() - 0.5) * curve_thickness);
} else {
xout = x;
yout = y;
}
zout = 0;
} else {
use_render_mode = true;
xout = 0;
yout = 0;
}
}
if (use_render_mode) {
double xoffset = 0, yoffset = 0, zoffset = 0;
// pick a random point along the Maurer line specified by P1 and P2 endpoints
// t1 ranges from [0..1] as line ranges from P1..P2
// calculate the corresponding point PML along the Maurer line
double t1 = Math.random();
mpoint.x = (x1 * (1 - t1)) + (x2 * t1);
// same as mpoint.x = x1 + (t1 * (x2-x1));
mpoint.y = (y1 * (1 - t1)) + (y2 * t1);
// same as mpoint.y = y1 + (t1 * (y2-y1));
line_delta = t1 * line_length;
/**
* RENDER MODES
*/
if (render_mode == LINES || render_mode == DEFAULT) {
// draw lines
xout = mpoint.x;
yout = mpoint.y;
} else if (render_mode == CIRCLES) {
// and use midlength of Maurer line as radius
if (render_submode == Z_STROKE) {
double ang = t1 * M_2PI;
double rad = midlength;
double mid_delta = rad * cos(ang);
zout = rad * sin(ang);
// move along line, out from midpoint by mid_delta
xout = xmid + (mid_delta * cos(raw_line_angle));
yout = ymid + (mid_delta * sin(raw_line_angle));
line_delta = sqrt(((x1 - xout) * (x1 - xout)) + ((y1 - yout) * (y1 - yout)));
} else {
double ang = t1 * M_2PI;
double rad = midlength;
xout = xmid + (rad * sin(ang));
yout = ymid + (rad * cos(ang));
// line_delta = ang;
line_delta = sqrt(((x1 - xout) * (x1 - xout)) + ((y1 - yout) * (y1 - yout)));
}
} else if (render_mode == QUADRATIC_BEZIER) {
// use origin (0,0) as control point, and endpoints of Maurer line as Bezier curve endpoints
// (since using origin as control point, can drop middle term of standard Bezier curve calc
// double bt = Math.random(); // want bt => [0:1]
double bt = t1;
double ax, ay;
// use full formula with control point
if (render_modifier1 != 1 || render_modifier2 != 1) {
// render_modifier1 controls relative radius of control point
// (fraction of distance from midpoint of line to origin,
// so as render_modifier range: [0=>1] then control point radius range: [midpoint_radius=>0]
// render_modifier2 controls relative angle of control point
// (angle from midpoint-origin line to control point)
// so if render_modifier = 1 then control point angle delta = 0
double midpoint_radius = sqrt(xmid * xmid + ymid * ymid);
double midpoint_angle = atan2(ymid, xmid);
double cradius = (1 - render_modifier1) * midpoint_radius;
double cangle = midpoint_angle + (M_2PI - (render_modifier2 * M_2PI));
// double cangle = midpoint_angle;
double cx = cradius * cos(cangle);
double cy = cradius * sin(cangle);
ax = ((1 - bt) * (1 - bt) * x1) + (2 * (1 - bt) * bt * cx) + (bt * bt * x2);
ay = ((1 - bt) * (1 - bt) * y1) + (2 * (1 - bt) * bt * cy) + (bt * bt * y2);
} else {
// control point is origin (0,0), so can drop control point term of quadratic Bezier
// and therefore skip midradius, midangle etc. control point calcs
ax = ((1 - bt) * (1 - bt) * x1) + (bt * bt * x2);
ay = ((1 - bt) * (1 - bt) * y1) + (bt * bt * y2);
}
// for now working on Z submodes here, but handling most submodes at end of transform() method...
if (render_submode == Z_STROKE) {
// not really working
zout = ay;
xoffset = line_delta / Math.sqrt(1 + line_slope * line_slope);
// determine sign based on p2
if (x2 < x1) {
xoffset = -1 * xoffset;
}
yoffset = Math.abs(line_slope * xoffset);
if (y2 < y1) {
yoffset = -1 * yoffset;
}
xout = x1 + xoffset;
yout = y1 + yoffset;
} else // hijacking Z_STROKE_BOTH while trying different approaches for Z-Beziers
if (render_submode == Z_BOTH_STROKE) {
// xout = x1 + (line_delta * cos(raw_line_angle));
// yout = y1 + (line_delta * sin(raw_line_angle));
// unrotate:
// oR.x = oP.x + (o.x - oP.x) * cos(theta) - (o.y - oP.y) * sin(theta)
// oR.y = oP.y + (o.x - oP.x) * sin(theta) + (o.y - oP.y) * cos(theta)
/* double newx = x1 + ((ax - x1) * cos(-raw_line_angle)) - ((ay - y1) * sin(-raw_line_angle));
double newy = y1 + ((ax - x1) * sin(-raw_line_angle)) + ((ay - y1) * cos(-raw_line_angle));
xout = ax;
yout = (line_slope * xout) + line_intercept;
zout = newy - y1;
*/
// xoffset = line_delta / Math.sqrt(1 + line_slope*line_slope);
// if (x2 < x1) { xoffset = -1 * xoffset; } // determine sign based on p2
// yoffset = Math.abs(line_slope * xoffset);
// if (y2 < y1) { yoffset = -1 * yoffset; }
xout = ax;
// yout = (line_slope * xout) + y1;
yout = (line_slope * xout) + line_intercept;
// yout = y1 + ()
zout = ((ax - x1) * sin(-raw_line_angle)) + ((ay - y1) * cos(-raw_line_angle));
} else {
xout = ax;
yout = ay;
}
} else if (render_mode == ELLIPSES) {
if (render_submode == Z_STROKE) {
// ang ==> [-Pi : +Pi] or [ 0 : 2Pi ] ?
// double ang = (Math.random() * M_2PI) - M_PI; // ==> [ -Pi : +Pi ]
// double ang = (Math.random() * M_2PI); // ==> [ 0 : 2Pi ]
double ang = t1 * M_2PI;
// offset along line (relative to start of line)
// if render_modifier1 == 1, then ranges are
// delta_from_midlength ==> [-midlength : +midlength]
// delta_from_start ==> [0 : line_length]
double delta_from_midlength = (midlength * render_modifier1) * cos(ang);
double delta_from_start = midlength - delta_from_midlength;
line_delta = delta_from_start;
// offset perpendicular to line:
// shift angle by -pi/2 get range=>[-1:1] as line_ofset=>[0=>line_length],
// then adding 1 to gets range=>[0:2],
// then scaling by line_length/2 * amplitude gets perp_offset: [0:(line_length*amplitude)]
double relative_perp_offset = (midlength * (render_modifier2 / 2)) * sin(ang);
// shift to make offsets relative to start point (x1, y1)
double line_offset = delta_from_midlength + x1 - midlength;
double perp_offset = relative_perp_offset + y1;
// then consider (line_offset, perp_offset) as point and rotate around start point (x1, y1) ?
// should already have angle (raw_line_angle)
// 2D rotation transformation of point B about a given fixed point A to give point C
// C.x = A.x + (B.x - A.x) * cos(theta) - (B.y - A.y) * sin(theta)
// C.y = A.y + (B.x - A.x) * sin(theta) + (B.y - A.y) * cos(theta)
// drop last term for xout and yout since y offset (perp_offset) = y1 [[ or B.y = A.y in above equation ]
// double newx = x1 + ((line_offset - x1) * cos(raw_line_angle)) - ((perp_offset - y1) * sin(raw_line_angle));
// double newy = y1 + ((line_offset - x1) * sin(raw_line_angle)) + ((perp_offset - y1) * cos(raw_line_angle));
xout = x1 + ((line_offset - x1) * cos(raw_line_angle + M_PI));
// drop last term since y offset (perp_offset) = 0
yout = y1 + ((line_offset - x1) * sin(raw_line_angle + M_PI));
zout = relative_perp_offset;
} else {
// double ang = Math.random() * M_2PI;
double ang = t1 * M_2PI;
// double ang = (Math.random() * M_2PI) - M_PI;
// offset along line (relative to start of line)
double relative_line_offset = (midlength * render_modifier1) * cos(ang);
line_delta = midlength * cos(ang);
// offset perpendicular to line:
// shift angle by -pi/2 get range=>[-1:1] as line_ofset=>[0=>line_length],
// then adding 1 to gets range=>[0:2],
// then scaling by line_length/2 * amplitude gets perp_offset: [0:(line_length*amplitude)]
double relative_perp_offset = (midlength * (render_modifier2 / 2)) * sin(ang);
// double relative_perp_offset = midlength * sin(ang);
// shift to make offsets relative to start point (x1, y1)
double line_offset = relative_line_offset + x1 - midlength;
double perp_offset = relative_perp_offset + y1;
// then consider (line_offset, perp_offset) as point and rotate around start point (x1, y1) ?
// should already have angle (raw_line_angle)
// 2D rotation transformation of point B about a given fixed point A to give point C
// C.x = A.x + (B.x - A.x) * cos(theta) - (B.y - A.y) * sin(theta)
// C.y = A.y + (B.x - A.x) * sin(theta) + (B.y - A.y) * cos(theta)
// double newx = x1 + ((line_offset - x1) * cos(raw_line_angle)) - ((perp_offset - y1) * sin(raw_line_angle));
// double newy = y1 + ((line_offset - x1) * sin(raw_line_angle)) + ((perp_offset - y1) * cos(raw_line_angle));
double newx = x1 + ((line_offset - x1) * cos(raw_line_angle + M_PI)) - ((perp_offset - y1) * sin(raw_line_angle + M_PI));
double newy = y1 + ((line_offset - x1) * sin(raw_line_angle + M_PI)) + ((perp_offset - y1) * cos(raw_line_angle + M_PI));
xout = newx;
yout = newy;
// xout = line_offset;
// yout = perp_offset;
}
} else if (render_mode == SINE_WAVES) {
// amplitude calculated such that when render_modifier = 1, relative_perp_offset range: [0 ==> line_length/2]
double amplitude = (line_length / 4) * render_modifier1;
double frequency = render_modifier2;
// range of [0 -> 2Pi ]
// double ang = Math.random() * M_2PI;
double ang = t1 * M_2PI;
// offset along line (relative to start of line) ==> [0=>line_length]
double relative_line_offset = ang * (line_length / M_2PI);
line_delta = relative_line_offset;
// offset perpendicular to line:
// shift angle by -pi to get cos range=>[-1:1] as ang => [0:2Pi],
// find perp offset for endpoints:
// since midpoint is always at middle of range (0), and using cos,
// endpoints should have same offset, so use either one
// endpoints are at [+/-](Pi*frequency)
// so at amp=1, freq=1, ==> -1
double endpoint_perp_offset = amplitude * cos(M_PI * frequency);
double relative_perp_offset = amplitude * (cos((ang - M_PI) * frequency));
// adjust relative_per_offset so endpoints are at 0
relative_perp_offset = relative_perp_offset - endpoint_perp_offset;
// shift to make offsets relative to start point (x1, y1)
double line_offset = relative_line_offset + x1;
double perp_offset = relative_perp_offset + y1;
// then consider (line_offset, perp_offset) as point and rotate around start point (x1, y1) ?
// should already have angle (raw_line_angle)
// 2D rotation about a given point
// oR.x = oP.x + (o.x - oP.x) * cos(theta) - (o.y - oP.y) * sin(theta)
// oR.y = oP.y + (o.x - oP.x) * sin(theta) + (o.y - oP.y) * cos(theta)
double newx = x1 + ((line_offset - x1) * cos(raw_line_angle)) - ((perp_offset - y1) * sin(raw_line_angle));
double newy = y1 + ((line_offset - x1) * sin(raw_line_angle)) + ((perp_offset - y1) * cos(raw_line_angle));
// for now working on Z submodes here, but handling most submodes at end of transform() method...
if (render_submode == Z_STROKE) {
xout = x1 + (relative_line_offset * cos(raw_line_angle));
// can save a sin() call by using slope-intercept once have xout
// yout = y1 + (relative_line_offset * sin(raw_line_angle));
yout = (line_slope * xout) + line_intercept;
// plus z1?
zout = relative_perp_offset;
} else if (render_submode == Z_BOTH_STROKE) {
xout = x1 + (relative_line_offset * cos(raw_line_angle));
// yout = y1 + (relative_line_offset * sin(raw_line_angle));
yout = (line_slope * xout) + line_intercept;
if (Math.random() < 0.5) {
// plus z1?
zout = relative_perp_offset;
} else {
zout = -relative_perp_offset;
}
} else {
xout = newx;
yout = newy;
}
} else if (render_mode == SEQUIN_CIRCLE_SPLINE) {
// Circle Splines with angle-based trionometric interpolation
// attempting to implement strategy described by Sequin, Lee, Yen in paper
// "Fair, G2- and C2-continuous circle splines for the interpolation of sparse data points", 2005
// Want to calculate interpolated point P(u) between P1 and P2, where u:[0=>1]
// Need P0, P1, P2, P3
// already have P1, P2, endpoints of current Maurer line
// calculate P0 and P3, from t=(theta1-theta_offset) and t=(theta2+that_offset) respectively
double theta0 = theta1 - this.theta_step_radians;
double theta3 = theta2 + this.theta_step_radians;
curve.getCurvePoint(theta0, end_point0);
curve.getCurvePoint(theta3, end_point3);
double x0 = end_point0.x;
double y0 = end_point0.y;
double x3 = end_point3.x;
double y3 = end_point3.y;
// then calculate unit direction vectors:
// A = (P1-P0)/|P1-P0|
// B = (P2-P1)/|P2-P1|
// C = (P2-P0)/|P2-P0|
// D = (P3-P2)/|P3-P2|
// E = (P3-P1)/|P3-P1|
// where |Pk - Pj| = norm(Pk-Pi) = sqrt((xk-xi)^2 + (yk-yi)^2)
double norm10 = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
double norm21 = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
double norm20 = sqrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0));
double norm32 = sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2));
double norm31 = sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1));
vecA.x = (x1 - x0) / norm10;
vecA.y = (y1 - y0) / norm10;
vecB.x = (x2 - x1) / norm21;
vecB.y = (y2 - y1) / norm21;
vecC.x = (x2 - x0) / norm20;
vecC.y = (y2 - y0) / norm20;
vecD.x = (x3 - x2) / norm32;
vecD.y = (y3 - y2) / norm32;
vecE.x = (x3 - x1) / norm31;
vecE.y = (y3 - y1) / norm31;
// calculate tangent angles at P1 and P2:
// (hmm, wonder if could substitute exact tangent calculation for base curve here?? not sure if it's the same angle though...)
// a1 = arccos(A @ C) ==> @ is vector dot product
// a2 = arccos(E @ D)
double a1 = Math.acos((vecA.x * vecC.x) + (vecA.y * vecC.y));
double a2 = Math.acos((vecE.x * vecD.x) + (vecE.y * vecD.y));
// trigonometric angle blending function between P0 and P1:
// a(u) = (a1 * cos^2(u*Pi/2)) + (a2 * sin^2(u*Pi/2))
// already have t1:[0=>1]
double u = t1;
double cu = cos(u * M_PI / 2);
double su = sin(u * M_PI / 2);
double au = (a1 * cu * cu) + (a2 * su * su);
// now can calculate distance of P(u), d(P(u)) from P1:
// b = |P2-P1| ==> should already have this as line length for current Maurer line
// d(P(u)) = b * sin(u * a(u)) / sin(a(u))
// same as line_length?
double bp = norm21;
double pd = bp * sin(u * au) / sin(au);
// and deviation angle from Maurer line is
// dangle(u) = (1-u) * a(u)
double pa = (1 - u) * au;
// ???
pa = -pa;
// then place point along Maurer line P1P2 at distance d(P(u)) from endpoint P1,
// http://math.stackexchange.com/questions/409689/how-do-i-find-a-point-a-given-distance-from-another-point-along-a-line
double linex = x1 + ((x2 - x1) * pd / norm21);
double liney = y1 + ((y2 - y1) * pd / norm21);
// and rotate by deviation angle dangle(u) around P1
// to get final position position of P(u)
// 2D rotation transformation of point B about a given fixed point A to give point C
// C.x = A.x + (B.x - A.x) * cos(theta) - (B.y - A.y) * sin(theta)
// C.y = A.y + (B.x - A.x) * sin(theta) + (B.y - A.y) * cos(theta)
xout = x1 + ((linex - x1) * cos(pa)) - ((liney - y1) * sin(pa));
yout = y1 + ((linex - x1) * sin(pa)) + ((liney - y1) * cos(pa));
} else if (render_mode == CARDINAL_SPLINE || render_mode == UNIFORM_CATMULL_ROM_SPLINE || render_mode == CARDINAL_SPLINE_SWIZZLE1 || render_mode == CARDINAL_SPLINE_SWIZZLE2 || render_mode == CARDINAL_SPLINE_SWIZZLE3) {
// cobbled together from:
// https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline
// http://paulbourke.net/miscellaneous/interpolation/
// http://cubic.org/docs/hermite.htm
//
// Hermite Basis Functions:
// range from [0:1] along [0..line_length]
// already have t1, randome [0:1]
double t2 = t1 * t1;
double t3 = t1 * t1 * t1;
double h00 = 2 * t3 - 3 * t2 + 1;
double h10 = t3 - 2 * t2 + t1;
double h01 = -2 * t3 + 3 * t2;
double h11 = t3 - t2;
// have points p1 and p2, get p0 and p3 (previous point and next point)
double theta0 = theta1 - theta_step_radians;
double theta3 = theta2 + theta_step_radians;
curve.getCurvePoint(theta0, end_point0);
curve.getCurvePoint(theta3, end_point3);
double x0, y0, x3, y3;
if (render_mode == CARDINAL_SPLINE_SWIZZLE1) {
x0 = end_point0.y;
y0 = end_point0.x;
x3 = end_point3.y;
y3 = end_point3.x;
} else if (render_mode == CARDINAL_SPLINE_SWIZZLE2) {
x0 = end_point3.x;
y0 = end_point3.y;
x3 = end_point0.x;
y3 = end_point0.y;
} else if (render_mode == CARDINAL_SPLINE_SWIZZLE3) {
x0 = end_point3.y;
y0 = end_point3.x;
x3 = end_point0.y;
y3 = end_point0.x;
} else {
// render_mode == CARDINAL_SPLINE or UNIFORM_CATMULL_ROM_SPLINE
x0 = end_point0.x;
y0 = end_point0.y;
x3 = end_point3.x;
y3 = end_point3.y;
}
// m1 ==> cardinal spline calculated tangent for end_point1
// m2 ==> cardinal spline calculated tangent for end_point1
// M1 = (P2 - P0) / (t2 - t0)
// M2 = (P3 - P1) / (t3 - t1)
// for now assuming t(i+1) = t(i) + 1, or in other words (t2-t0) = 2 and (t3-t1) = 2
// (I think this is a standard assumption for baseline Catmull-Rom, see for example http://cubic.org/docs/hermite.htm)
// so
// M1 = (P2 - PO)/2
// M2 = (P3 - P1)/2
double m1x = 0.5 * (x2 - x0);
double m2x = 0.5 * (x3 - x1);
double m1y = 0.5 * (y2 - y0);
double m2y = 0.5 * (y3 - y1);
// also trying addition of a tightness parameter
// for the case where tanscale = 1 (render_modifier1 = 0),
// get the uniform Catmull-Rom spline as a special case of cardinal splines
// for the case where transcale = 0 (render_modifier1 = 1), tangents have no effect
double tanscale;
if (render_mode == UNIFORM_CATMULL_ROM_SPLINE) {
tanscale = 1;
} else {
tanscale = (1 - render_modifier1);
}
m1x = m1x * tanscale;
m1y = m1y * tanscale;
m2x = m2x * tanscale;
m2y = m2y * tanscale;
double xnew = (h00 * x1) + (h10 * m1x) + (h01 * x2) + (h11 * m2x);
double ynew = (h00 * y1) + (h10 * m1y) + (h01 * y2) + (h11 * m2y);
// line_delta = t1 * line_length;
xout = xnew;
yout = ynew;
} else if (render_mode == NONUNIFORM_CATMULL_ROM_SPLINE || render_mode == CENTRIPETAL_CATMULL_ROM_SPLINE || render_mode == CHORDAL_CATMULL_ROM_SPLINE) {
// cobbled together from:
// https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
// https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline
// most helpful for actual implementation:
// http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/19283471#19283471
//
// Original Paper: "A Recursive Evaluation Algorithm for a Class of Catmull-Rom Splines", Barry and Goldman
// Hermite Basis Functions:
// range from [0:1] along [0..line_length]
// already have t1, random [0:1]
double t2 = t1 * t1;
double t3 = t1 * t1 * t1;
double h00 = 2 * t3 - 3 * t2 + 1;
double h10 = t3 - 2 * t2 + t1;
double h01 = -2 * t3 + 3 * t2;
double h11 = t3 - t2;
// have points p1 and p2, get p0 and p3 (previous point and next point)
double theta0 = theta1 - theta_step_radians;
double theta3 = theta2 + theta_step_radians;
curve.getCurvePoint(theta0, end_point0);
curve.getCurvePoint(theta3, end_point3);
double x0 = end_point0.x;
double y0 = end_point0.y;
double x3 = end_point3.x;
double y3 = end_point3.y;
double alpha = 0;
if (render_mode == CENTRIPETAL_CATMULL_ROM_SPLINE) {
alpha = 0.5;
} else if (render_mode == CHORDAL_CATMULL_ROM_SPLINE) {
alpha = 1.0;
} else {
// render_mode == NONUNIFORM_CATMULL_ROM_SPLINE
// nonuniform Catmull-Rom spline, with special cases:
// rm = 0 ==> uniform Catmull-Rom spline (essentially same as cardinal spline)
// rm = 0.5 ==> centripetal Catmull-Rom spline
// rm = 1.0 ==> chordal Catmull-Rom spline
alpha = render_modifier2;
}
// centripetal/chordal Catmull-Rom tangent caclulations
// M1 = (P1 - P0) / (t1 - t0) - (P2 - P0) / (t2 - t0) + (P2 - P1) / (t2 - t1)
// M2 = (P2 - P1) / (t2 - t1) - (P3 - P1) / (t3 - t1) + (P3 - P2) / (t3 - t2)
// and t[i+1] = (((x[i+1]-x[i])^2 + (y[i+1]-y[i])^2)^0.5)^a + t[i]
// t[i+1] = (((x[i+1]-x[i])^2 + (y[i+1]-y[i])^2))^(a/2) + t[i]
// rewrite in terms of deltas, then can drop the last term
// dt0 = t1-t0 = (((x1-x0)^2 + (y1-y0)^2)) ^(a/2)
// dt1 = t2-t1
// dt2 = t3-t2
// M1 = ((P1-P0)/dt0) - ((P2-P0)/(dt0+dt1)) + ((P2-P1)/dt1)
// M2 = ((P2-P1)/dt1) - ((P3-P1)/(dt1+dt2)) + ((P3-P2)/dt2)
// also need to rescale by dt1 (so can parameterize t from [0:1]) ??
// do scaling when combining terms?
double dt0 = Math.pow(((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)), (alpha / 2));
double dt1 = Math.pow(((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)), (alpha / 2));
double dt2 = Math.pow(((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2)), (alpha / 2));
double m1x = ((x1 - x0) / dt0) - ((x2 - x0) / (dt0 + dt1)) + ((x2 - x1) / dt1);
double m1y = ((y1 - y0) / dt0) - ((y2 - y0) / (dt0 + dt1)) + ((y2 - y1) / dt1);
double m2x = ((x2 - x1) / dt1) - ((x3 - x1) / (dt1 + dt2)) + ((x3 - x2) / dt2);
double m2y = ((y2 - y1) / dt1) - ((y3 - y1) / (dt1 + dt2)) + ((y3 - y2) / dt2);
// scaling tangents (analagous to normalizing to the unit tangent?)
// double tanscale = dt1;
// also trying addition of a tightness parameter
double tanscale = dt1 * (1 - render_modifier1);
m1x = m1x * tanscale;
m1y = m1y * tanscale;
m2x = m2x * tanscale;
m2y = m2y * tanscale;
double xnew = (h00 * x1) + (h10 * m1x) + (h01 * x2) + (h11 * m2x);
double ynew = (h00 * y1) + (h10 * m1y) + (h01 * y2) + (h11 * m2y);
// line_delta = t1 * line_length;
xout = xnew;
yout = ynew;
} else if (render_mode == KOCHANEK_BARTELS_SPLINE || render_mode == KOCHANEK_BARTELS_SPLINE_SWIZZLE1 || render_mode == KOCHANEK_BARTELS_SPLINE_SWIZZLE2 || render_mode == KOCHANEK_BARTELS_SPLINE_SWIZZLE3) {
// cobbled together from:
// Online:
// https://en.wikipedia.org/wiki/Kochanek%E2%80%93Bartels_spline
// https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline
// http://paulbourke.net/miscellaneous/interpolation/
// http://cubic.org/docs/hermite.htm
// Original Paper: "Interpolating splines with local tension, continuity, and bias control", Kochanek & Bartels
// Reference Book: "Curves and Surfaces for Computer Graphics", David Saloman
// GDC2012 Presentation: "Interpolation and Splines", Squirrel Eiserloh
//
// Hermite Basis Functions:
// range from [0:1] along [0..line_length]
// double t1 = Math.random();
double t2 = t1 * t1;
double t3 = t1 * t1 * t1;
double h00 = 2 * t3 - 3 * t2 + 1;
double h10 = t3 - 2 * t2 + t1;
double h01 = -2 * t3 + 3 * t2;
double h11 = t3 - t2;
// have points p1 and p2, get p0 and p3 (previous point and next point)
double theta0 = theta1 - theta_step_radians;
double theta3 = theta2 + theta_step_radians;
curve.getCurvePoint(theta0, end_point0);
curve.getCurvePoint(theta3, end_point3);
double x0, y0, x3, y3;
if (render_mode == KOCHANEK_BARTELS_SPLINE_SWIZZLE1) {
x0 = end_point0.y;
y0 = end_point0.x;
x3 = end_point3.y;
y3 = end_point3.x;
} else if (render_mode == KOCHANEK_BARTELS_SPLINE_SWIZZLE2) {
x0 = end_point3.x;
y0 = end_point3.y;
x3 = end_point0.x;
y3 = end_point0.y;
} else if (render_mode == KOCHANEK_BARTELS_SPLINE_SWIZZLE3) {
x0 = end_point3.y;
y0 = end_point3.x;
x3 = end_point0.y;
y3 = end_point0.x;
} else {
// KOCHANEK_BARTELS_SPLINE
x0 = end_point0.x;
y0 = end_point0.y;
x3 = end_point3.x;
y3 = end_point3.y;
}
// but want defaults for tension, bias, continuity to be 0?
double tension = render_modifier1;
double continuity = render_modifier2;
double bias = render_modifier3;
// m2 ==> KB-calculated tangent for end_point2
double c110 = (1 - tension) * (1 + bias) * (1 + continuity) / 2;
double c121 = (1 - tension) * (1 - bias) * (1 - continuity) / 2;
double c221 = (1 - tension) * (1 + bias) * (1 - continuity) / 2;
double c232 = (1 - tension) * (1 - bias) * (1 + continuity) / 2;
// m1 ==> KB-calculated tangent for end_point1
// m2 ==> KB-calculated tangent for end_point1
// note that when tension = bias = continuity = 0, all coefficients become 0.5,
// and thus this reduces to Catmull-Rom spline, for example:
// m1x = (c110 * (x1-x0)) + (c121 * (x2-x1))
// = (0.5 * (x1-x0)) + (0.5 *(x2-x1))
// = 0.5 * (x1 - x0 + x2 - x1)
// = 0.5 * (x2 - x1)
//
double m1x = (c110 * (x1 - x0)) + (c121 * (x2 - x1));
double m2x = (c221 * (x2 - x1)) + (c232 * (x3 - x2));
double m1y = (c110 * (y1 - y0)) + (c121 * (y2 - y1));
double m2y = (c221 * (y2 - y1)) + (c232 * (y3 - y2));
double xnew = (h00 * x1) + (h10 * m1x) + (h01 * x2) + (h11 * m2x);
double ynew = (h00 * y1) + (h10 * m1y) + (h01 * y2) + (h11 * m2y);
// line_delta = t1 * line_length; // already calculated at start of use_render_mode loop
xout = xnew;
yout = ynew;
} else if (render_mode == CUBIC_HERMITE_SPLINE || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT1 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT2 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT3 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT4 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT5) {
// using general cubic hermite spline, with tangent vectors determined by derivative of underlying curve
// using formulation for interpolation on an arbitrary interval:
// https://en.wikipedia.org/wiki/Cubic_Hermite_spline
// w is random theta between theta1 and theta2
// double w = theta1 + (Math.random() * (theta2 - theta1));
// double t1 = (w-theta1)/(theta2-theta1);
// but the above w & t1 calcs are equivalent to t1 randomly ranging from [0:1], so just use that instead...
// t1 ranges from [0:1]
// double t1 = Math.random();
double t2 = t1 * t1;
double t3 = t1 * t1 * t1;
// Hermite Basis Functions:
double h00 = 2 * t3 - 3 * t2 + 1;
double h10 = t3 - 2 * t2 + t1;
double h01 = -2 * t3 + 3 * t2;
double h11 = t3 - t2;
double dt1, dt2;
// use render_modifier2 as theta offset (- for dt1, + for dt2) to find points to determine tangent vectors
if (tangent_submode == THETA_TANGENT) {
dt1 = theta1 - ((render_modifier2 / 360) * M_2PI);
dt2 = theta2 + ((render_modifier2 / 360) * M_2PI);
} else // (-rm2*theta_step_radians for dt1, +rm2*theta_line_offset for dt2)
if (tangent_submode == INDEX_TANGENT) {
dt1 = theta1 - (render_modifier2 * this.theta_step_radians);
dt2 = theta2 + (render_modifier2 * this.theta_step_radians);
} else {
dt1 = theta1;
dt2 = theta2;
}
double tan1x, tan1y, tan2x, tan2y;
if (render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT1 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT2 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT3 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT4 || render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT5) {
// using wrong (but interesting) calculations for first derivative
double k = a / b;
first_derivative_point1.x = -(cos(k * dt1) + c) * sin(dt1);
first_derivative_point1.y = (cos(k * dt1) + c) * cos(dt1);
first_derivative_point2.x = -(cos(k * dt2) + c) * sin(dt2);
first_derivative_point2.y = (cos(k * dt2) + c) * cos(dt2);
if (render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT2) {
// flip signs for x of tangents
first_derivative_point1.x = -1 * first_derivative_point1.x;
first_derivative_point2.x = -1 * first_derivative_point2.x;
} else if (render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT3) {
// flip signs for y of tangents
first_derivative_point1.y = -1 * first_derivative_point1.y;
first_derivative_point2.y = -1 * first_derivative_point2.y;
} else if (render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT4) {
// flip signs for both x and y of tangents
first_derivative_point1.x = -1 * first_derivative_point1.x;
first_derivative_point2.x = -1 * first_derivative_point2.x;
first_derivative_point1.y = -1 * first_derivative_point1.y;
first_derivative_point2.y = -1 * first_derivative_point2.y;
} else if (render_mode == CUBIC_HERMITE_HAPPY_ACCIDENT5) {
// flip tangent points
DoublePoint2D ptmp = first_derivative_point1;
first_derivative_point1 = first_derivative_point2;
first_derivative_point2 = ptmp;
}
} else {
// CUBIC_HERMITE
// calculating tangent vectors
// use first derivative of curve (currently using rhodonea) at each endpoint for tangent vectors
// tangent = f'(t)
curve.getFirstDerivative(dt1, first_derivative_point1);
curve.getFirstDerivative(dt2, first_derivative_point2);
}
tan1x = first_derivative_point1.x;
tan1y = first_derivative_point1.y;
tan2x = first_derivative_point2.x;
tan2y = first_derivative_point2.y;
if (Double.isNaN(tan1x) || Double.isNaN(tan1y) || Double.isNaN(tan2x) || Double.isNaN(tan2y)) {
// if can't find first derivative, bailout with point unchanged
xout = xin;
yout = yin;
} else {
double tanscale;
// if *_UNSCALED_* then don't apply scaling adjustment to vectors
if (tangent_submode == UNSCALED_TANGENT || tangent_submode == UNSCALED_UNIT_TANGENT || tangent_submode == UNSCALED_NORMAL || tangent_submode == UNSCALED_UNIT_NORMAL) {
tanscale = 1;
} else {
// apply standard Hermite non-unit-interval scaling to vectors
// TANGENT (or NORMAL?)
tanscale = theta2 - theta1;
}
double dx1, dx2, dy1, dy2;
// if *_NORMAL_* then set (dx1, dy1) and (dx2, dy2) to normal vectors instead of tangent vectors
if (tangent_submode == NORMAL_VECTOR || tangent_submode == UNIT_NORMAL || tangent_submode == UNSCALED_NORMAL || tangent_submode == UNSCALED_UNIT_NORMAL) {
// rotate tangent vector around point to get normal vector?
// 2D rotation transformation of point B about a given fixed point A to give point C
// C.x = A.x + (B.x - A.x) * cos(theta) - (B.y - A.y) * sin(theta)
// C.y = A.y + (B.x - A.x) * sin(theta) + (B.y - A.y) * cos(theta)
double rota = -M_PI / 2.0;
dx1 = x1 + ((tan1x - x1) * cos(rota)) - ((tan1y - y1) * sin(rota));
dy1 = y1 + ((tan1x - x1) * sin(rota)) + ((tan1y - y1) * cos(rota));
dx2 = x2 + ((tan2x - x2) * cos(rota)) - ((tan2y - y2) * sin(rota));
dy2 = y2 + ((tan2x - x2) * sin(rota)) + ((tan2y - y2) * cos(rota));
} else if (tangent_submode == ROTATION_TANGENT) {
// user render_modifier2 to determine angle (in degrees) to rotate tangent1
// user render_modifier3 to determine angle (in degrees) to rotate tangent2
// (or maybe should only use one modifier, and rotates both tangents?)
// (or one to modify x of both tangents, one to modify y of both tangents? ==> like happy_accident modes?)
double rota1 = (render_modifier2 / 360) * M_2PI;
dx1 = x1 + ((tan1x - x1) * cos(rota1)) - ((tan1y - y1) * sin(rota1));
dy1 = y1 + ((tan1x - x1) * sin(rota1)) + ((tan1y - y1) * cos(rota1));
double rota2 = (render_modifier3 / 360) * M_2PI;
dx2 = x2 + ((tan2x - x2) * cos(rota2)) - ((tan2y - y2) * sin(rota2));
dy2 = y2 + ((tan2x - x2) * sin(rota2)) + ((tan2y - y2) * cos(rota2));
} else // scale y of tangent by render_modifier3 param
if (tangent_submode == XY_SCALE_TANGENT) {
dx1 = tan1x * render_modifier2;
dx2 = tan2x * render_modifier2;
dy1 = tan1y * render_modifier3;
dy2 = tan2y * render_modifier3;
} else {
// otherwise set (dx1,dy1) and (dx2,dy2) to tangent vectors
dx1 = tan1x;
dy1 = tan1y;
dx2 = tan2x;
dy2 = tan2y;
}
// if *_UNIT_* then normalize to unit vectors
if (tangent_submode == UNIT_TANGENT || tangent_submode == UNIT_NORMAL || tangent_submode == UNSCALED_UNIT_TANGENT || tangent_submode == UNSCALED_UNIT_NORMAL) {
// normalizing the vectors
double sr1 = sqrt(dx1 * dx1 + dy1 * dy1);
double sr2 = sqrt(dx2 * dx2 + dy2 * dy2);
dx1 = dx1 / sr1;
dy1 = dy1 / sr1;
dx2 = dx2 / sr2;
dy2 = dy2 / sr2;
} else {
// otherwise leave unnormalized
}
// apply tension -- use render_modifier1 as tension parameter for cubic Hermite interpolation
// by applying a (1 - tension) scaling factor to the tangent vector Hermite terms
// thus if tension = 1, tangent terms will drop out and cubic Hermite interpolation will
// reduce to linear interoplation ==> Maurer lines
tanscale = (1 - render_modifier1) * tanscale;
// trying to add parameter similar to Kochanek-Bartels "bias"
// at tension = -1, first tangent term (h10) will be factored out
// at tension = +1, second tangnt term (h11) will be factored out
// double tanscale10 = (1 + render_modifier2) * tanscale;
// double tanscale11 = (1 - render_modifier2) * tanscale;
// double xnew = (h00 * x1) + (h10 * dx1 * tanscale10 ) + (h01 * x2) + (h11 * dx2 * tanscale11);
// double ynew = (h00 * y1) + (h10 * dy1 * tanscale10 ) + (h01 * y2) + (h11 * dy2 * tanscale11);
double xnew = (h00 * x1) + (h10 * dx1 * tanscale) + (h01 * x2) + (h11 * dx2 * tanscale);
double ynew = (h00 * y1) + (h10 * dy1 * tanscale) + (h01 * y2) + (h11 * dy2 * tanscale);
xout = xnew;
yout = ynew;
}
} else if (render_mode == CUBIC_HERMITE_TANGENT_FORM2) {
// using general cubic hermite spline, with tangent vectors determined by derivative of underlying curve
// trying long-form 3rd degree hermite polynomial equation from http://www3.nd.edu/~zxu2/acms40390F12/Lec-3.4-5.pdf
// for SPLINE6, attempting to introduce render modifier parameters (somewhat analogous to KB tension, continuity, bias?)
double w0 = theta1;
curve.getFirstDerivative(w0, first_derivative_point1);
double ffw0 = first_derivative_point1.x;
double ggw0 = first_derivative_point1.y;
// double ffw0 = (-k * sin(k*w0) * cos(w0)) - ((cos(k*w0)+c) * sin(w0)); // first x derivative at P0 (of rhodonea)
// double ggw0 = (-k * sin(k*w0) * sin(w0)) + ((cos(k*w0)+c) * cos(w0)); // first y derivative at P0 (of rhodonea)
double w1 = theta2;
curve.getFirstDerivative(w1, first_derivative_point2);
double ffw1 = first_derivative_point2.x;
double ggw1 = first_derivative_point2.y;
// double ffw1 = (-k * sin(k*w1) * cos(w1)) - ((cos(k*w1)+c) * sin(w1)); // first x derivative at P1 (of rhodonea)
// double ggw1 = (-k * sin(k*w1) * sin(w1)) + ((cos(k*w1)+c) * cos(w1)); // first y derivative at P1 (of rhodonea)
double fw0 = x1;
double gw0 = y1;
double fw1 = x2;
double gw1 = y2;
if (Double.isNaN(ffw0) || Double.isNaN(ggw0) || Double.isNaN(ffw1) || Double.isNaN(ggw1)) {
// if can't find first derivatives, bailout with point unchanged
xout = xin;
yout = yin;
} else {
// w (standing in for x from above hermite equation) ranges from [theta1:theta2]
double w = theta1 + (t1 * (theta2 - theta1));
if (DEBUG_TANGENTS && Math.random() < 0.01) {
double point_threshold = Math.random();
if (point_threshold < 0.5) {
// linear interp between point and tangent(point)
double fraction_of_line = 2 * point_threshold;
xout = (fw0 * (1 - fraction_of_line)) + (ffw0 * fraction_of_line);
yout = (gw0 * (1 - fraction_of_line)) + (ggw0 * fraction_of_line);
} else {
double fraction_of_line = 2 * (point_threshold - 0.5);
xout = (fw1 * (1 - fraction_of_line)) + (ffw1 * fraction_of_line);
yout = (gw1 * (1 - fraction_of_line)) + (ggw1 * fraction_of_line);
}
} else {
double tw = (w - w0) / (w1 - w0);
double tw1 = ((w1 - w) / (w1 - w0));
double tw0 = ((w0 - w) / (w0 - w1));
double hf0 = (1 + (2 * tw)) * tw1 * tw1 * fw0;
double hff0 = (w - w0) * tw1 * tw1 * ffw0;
double hf1 = (1 + (2 * tw1)) * tw0 * tw0 * fw1;
double hff1 = (w - w1) * tw0 * tw0 * ffw1;
double fw = hf0 + hff0 + hf1 + hff1;
double hg0 = (1 + (2 * tw)) * tw1 * tw1 * gw0;
double hgg0 = (w - w0) * tw1 * tw1 * ggw0;
double hg1 = (1 + (2 * tw1)) * tw0 * tw0 * gw1;
double hgg1 = (w - w1) * tw0 * tw0 * ggw1;
double gw = hg0 + hgg0 + hg1 + hgg1;
xout = fw;
yout = gw;
}
}
} else // end CUBIC_HERMITE_TANGENT_FORM2
{
// default to Maurer lines
xout = mpoint.x;
yout = mpoint.y;
}
//
if (render_submode == STROKE || render_submode == DEFAULT) {
// do nothing
} else if (render_submode == REFLECTED_STROKE) {
double bc = (((x2 - x1) * (xout - x1)) + ((y2 - y1) * (yout - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
xout = (2 * (x1 + ((x2 - x1) * bc))) - xout;
yout = (2 * (y1 + ((y2 - y1) * bc))) - yout;
} else if (render_submode == BOTH_STROKE) {
if (Math.random() < 0.5) {
// reflect half the points, leave other half unaltered
double bc = (((x2 - x1) * (xout - x1)) + ((y2 - y1) * (yout - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
xout = (2 * (x1 + ((x2 - x1) * bc))) - xout;
yout = (2 * (y1 + ((y2 - y1) * bc))) - yout;
}
} else if (render_submode == ALTERNATING_STROKE) {
if (step_number % 2 != 0) {
// reflect odd steps, leave even steps unaltered
double bc = (((x2 - x1) * (xout - x1)) + ((y2 - y1) * (yout - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
xout = (2 * (x1 + ((x2 - x1) * bc))) - xout;
yout = (2 * (y1 + ((y2 - y1) * bc))) - yout;
}
} else if (render_submode == FILL_TO_LINE || render_submode == FILL_TO_CURVE) {
DoublePoint2D opoint;
if (render_submode == FILL_TO_CURVE) {
opoint = curve_point;
} else {
opoint = mpoint;
}
// randomly place point on line from outpoint to mpoint
double rfill = Math.random();
xout = (xout * (1 - rfill)) + (opoint.x * rfill);
yout = (yout * (1 - rfill)) + (opoint.y * rfill);
} else if (render_submode == FILL_BETWEEN_LINE_CURVE) {
// ignores render mode
double rfill = Math.random();
xout = (mpoint.x * (1 - rfill)) + (curve_point.x * rfill);
yout = (mpoint.y * (1 - rfill)) + (curve_point.y * rfill);
} else if (render_submode == FILL_BETWEEN_LINE_CURVE_SWIZZLE) {
// ignores render mode
double rfill = Math.random();
xout = (mpoint.x * (1 - rfill)) + (curve_point.y * rfill);
yout = (mpoint.y * (1 - rfill)) + (curve_point.x * rfill);
} else if (render_submode == REFLECTED_FILL_TO_LINE || render_submode == REFLECTED_FILL_TO_CURVE) {
DoublePoint2D opoint;
if (render_submode == REFLECTED_FILL_TO_CURVE) {
opoint = curve_point;
} else {
opoint = mpoint;
}
double bc = (((x2 - x1) * (xout - x1)) + ((y2 - y1) * (yout - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
xout = (2 * (x1 + ((x2 - x1) * bc))) - xout;
yout = (2 * (y1 + ((y2 - y1) * bc))) - yout;
double rfill = Math.random();
xout = (xout * (1 - rfill)) + (opoint.x * rfill);
yout = (yout * (1 - rfill)) + (opoint.y * rfill);
} else if (render_submode == BOTH_FILL_TO_LINE || render_submode == BOTH_FILL_TO_CURVE) {
DoublePoint2D opoint;
if (render_submode == BOTH_FILL_TO_CURVE) {
opoint = curve_point;
} else {
opoint = mpoint;
}
if (Math.random() < 0.5) {
// reflect half the points, leave other half unaltered
double bc = (((x2 - x1) * (xout - x1)) + ((y2 - y1) * (yout - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
xout = (2 * (x1 + ((x2 - x1) * bc))) - xout;
yout = (2 * (y1 + ((y2 - y1) * bc))) - yout;
}
double rfill = Math.random();
xout = (xout * (1 - rfill)) + (opoint.x * rfill);
yout = (yout * (1 - rfill)) + (opoint.y * rfill);
} else if (render_submode == ALTERNATING_FILL_TO_LINE || render_submode == ALTERNATING_FILL_TO_CURVE) {
DoublePoint2D opoint;
if (render_submode == ALTERNATING_FILL_TO_CURVE) {
opoint = curve_point;
} else {
opoint = mpoint;
}
if (step_number % 2 != 0) {
// reflect odd steps, leave even steps unaltered
double bc = (((x2 - x1) * (xout - x1)) + ((y2 - y1) * (yout - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
xout = (2 * (x1 + ((x2 - x1) * bc))) - xout;
yout = (2 * (y1 + ((y2 - y1) * bc))) - yout;
}
double rfill = Math.random();
xout = (xout * (1 - rfill)) + (opoint.x * rfill);
yout = (yout * (1 - rfill)) + (opoint.y * rfill);
}
// handling thickness
if (line_thickness != 0) {
if (line_thickness_strategy == RANDOM) {
// previous simple random offset from center of line
xout += ((pContext.random() - 0.5) * line_thickness);
yout += ((pContext.random() - 0.5) * line_thickness);
} else if (line_thickness_strategy == PERPENDICULAR) {
// random distance _perpendicular_ to unmodified Maurer line;
double xnorm = xdiff / line_length;
double ynorm = ydiff / line_length;
double xperpnorm = -ynorm;
double yperpnorm = xnorm;
double perp_offset = (pContext.random() - 0.5) * line_thickness;
double xperp = perp_offset * xperpnorm;
double yperp = perp_offset * yperpnorm;
xout += xperp;
yout += yperp;
} else if (line_thickness_strategy == ROUNDED_CAPS) {
// random distance _perpendicular_ to unmodified Maurer line, but with rounded caps
if (line_delta < line_thickness || ((line_length - line_delta) < line_thickness)) {
xout += ((pContext.random() - 0.5) * line_thickness);
yout += ((pContext.random() - 0.5) * line_thickness);
} else {
double xnorm = xdiff / line_length;
double ynorm = ydiff / line_length;
double xperpnorm = -ynorm;
double yperpnorm = xnorm;
double perp_offset = (pContext.random() - 0.5) * line_thickness;
double xperp = perp_offset * xperpnorm;
double yperp = perp_offset * yperpnorm;
xout += xperp;
yout += yperp;
}
}
}
}
//
// FILTERING
//
pVarTP.doHide = false;
boolean cumulative_pass = true;
for (int findex = 0; findex < filter_count; findex++) {
MaurerFilter mfilter = (MaurerFilter) filters.get(findex);
int fmode = mfilter.mode;
// if filter mode is OFF, then skip this filter
if (fmode != OFF) {
int measure = mfilter.measure;
int op = mfilter.operator;
double low_thresh, high_thresh;
double val;
double[] sampled_vals;
if (measure == LINE_LENGTH_LINES) {
val = line_length;
sampled_vals = sampled_line_lengths;
} else if (measure == LINE_ANGLE_LINES) {
val = line_angle;
sampled_vals = sampled_line_angles;
} else if (measure == POINT_ANGLE_LINES) {
val = point_angle;
sampled_vals = sampled_point_angles;
} else if (measure == DISTANCE_ALONG_LINE_POINTS) {
val = line_delta;
// percentiles calculated directly for DISTANCE_ALONG_LINE_POINTS
sampled_vals = null;
} else if (measure == DISTANCE_FROM_MIDLINE_POINTS) {
val = abs(line_delta - midlength);
// percentiles calculated directly for DISTANCE_FROM_MIDLINE_POINTS
sampled_vals = null;
} else if (measure == DISTANCE_FROM_NEAREST_END_POINTS) {
val = Math.min(line_delta, line_length - line_delta);
// percentiles calculated directly for DISTANCE_FROM_NEAREST_END_POINTS
sampled_vals = null;
} else if (measure == Z_MINMAX_POINTS) {
// min/max zout should be +/- radius of circle ==> +/-(line_length/2)
// val = abs(zout*2); // min/max zout should be
// range of val should be 0 to line_length;
val = zout + (line_length / 2);
sampled_vals = sampled_line_lengths;
} else if (measure == Z_ABSOLUTE_MINMAX_POINTS) {
// min/max zout should be +/- radius of circle ==> +/-(line_length/2)
// range of val should be 0 to line_length
val = abs(zout) * 2;
sampled_vals = sampled_line_lengths;
} else {
// default to line length
val = line_length;
sampled_vals = sampled_line_lengths;
}
if (fmode == BAND_PASS_VALUE || fmode == BAND_STOP_VALUE) {
low_thresh = mfilter.low_thresh;
high_thresh = mfilter.high_thresh;
} else if (fmode == BAND_PASS_PERCENT || fmode == BAND_STOP_PERCENT) {
if (measure == DISTANCE_ALONG_LINE_POINTS) {
low_thresh = mfilter.low_thresh * line_length;
high_thresh = mfilter.high_thresh * line_length;
} else if (measure == DISTANCE_FROM_MIDLINE_POINTS || measure == DISTANCE_FROM_NEAREST_END_POINTS) {
// low_thresh and high_thresh for DISTANCE_FROM_MIDLINE_POINTS and DISTANCE_FROM_NEAREST_END_POINTS
// can behave differently when thresholding by value, but act the same when thresholding by percentile
low_thresh = mfilter.low_thresh * midlength;
high_thresh = mfilter.high_thresh * midlength;
} else {
int low_index, high_index;
// should probably round here instead of flooring with (int) cast?
if (mfilter.low_thresh <= 0 || mfilter.low_thresh >= 1) {
low_index = 0;
} else {
low_index = (int) (mfilter.low_thresh * sampled_vals.length);
}
// if high_thresh not in (0 -> 1.0) exclusive range, clamp at 100%
if (mfilter.high_thresh >= 1 || mfilter.high_thresh <= 0) {
high_index = (sampled_vals.length - 1);
} else {
high_index = (int) (mfilter.high_thresh * sampled_vals.length);
}
low_thresh = sampled_vals[low_index];
high_thresh = sampled_vals[high_index];
}
} else {
// default to values
low_thresh = mfilter.low_thresh;
high_thresh = mfilter.high_thresh;
}
boolean inband = (val >= low_thresh && val <= high_thresh);
boolean current_pass;
if (fmode == BAND_PASS_VALUE || fmode == BAND_PASS_PERCENT) {
current_pass = inband;
} else if (fmode == BAND_STOP_VALUE || fmode == BAND_STOP_PERCENT) {
// effectively the same as additional NOT operation on this filter
current_pass = !inband;
} else {
// default to bandpass: passing values that are within filter band
current_pass = inband;
}
if (findex == 0) {
// no combo operator for first filter
cumulative_pass = current_pass;
} else {
if (op == AND) {
cumulative_pass = cumulative_pass && current_pass;
} else if (op == OR) {
cumulative_pass = cumulative_pass || current_pass;
} else if (op == XOR) {
cumulative_pass = (cumulative_pass && !current_pass) || (!cumulative_pass && current_pass);
} else if (op == ANOTB) {
cumulative_pass = cumulative_pass && !current_pass;
} else if (op == BNOTA) {
cumulative_pass = !cumulative_pass && current_pass;
} else {
// default to AND
cumulative_pass = cumulative_pass && current_pass;
}
}
}
}
pVarTP.doHide = !cumulative_pass;
// Add final values in to variations totals
if (diff_mode) {
pVarTP.x = pAffineTP.x + (pAmount * (xout - pAffineTP.x));
pVarTP.y = pAffineTP.y + (pAmount * (yout - pAffineTP.y));
pVarTP.z = pAffineTP.z + (pAmount * (zout - pAffineTP.z));
} else {
pVarTP.x += pAmount * xout;
pVarTP.y += pAmount * yout;
pVarTP.z += pAmount * zout;
}
//
if (direct_color_measure != NONE && direct_color_gradient != OFF) {
double val;
double[] sampled_vals;
if (direct_color_measure == LINE_LENGTH_LINES) {
val = line_length;
sampled_vals = sampled_line_lengths;
} else if (direct_color_measure == SPEED_AT_ENDPOINT1) {
// val = speed1;
val = curve.getSpeed(theta1, end_point1);
sampled_vals = sampled_speeds;
} else if (direct_color_measure == CURRENT_THETA) {
val = theta1 / M_2PI;
sampled_vals = sampled_thetas;
} else if (direct_color_measure == LINE_ANGLE_LINES) {
val = line_angle;
sampled_vals = sampled_line_angles;
} else if (direct_color_measure == POINT_ANGLE_LINES) {
val = point_angle;
sampled_vals = sampled_point_angles;
} else if (direct_color_measure == DISTANCE_ALONG_LINE_POINTS) {
val = line_delta;
sampled_vals = null;
} else if (direct_color_measure == DISTANCE_FROM_MIDLINE_POINTS) {
val = abs(line_delta - midlength);
sampled_vals = null;
} else if (direct_color_measure == META_INDEX && meta_mode != OFF) {
val = current_meta_step;
sampled_vals = null;
} else if (direct_color_measure == Z_MINMAX_POINTS) {
// min/max zout should be +/- radius of circle ==> +/-(line_length/2)
// val = abs(zout*2); // min/max zout should be
// range of val should be 0 to line_length;
val = zout + (line_length / 2);
sampled_vals = sampled_line_lengths;
} else if (direct_color_measure == Z_ABSOLUTE_MINMAX_POINTS) {
// min/max zout should be +/- radius of circle ==> +/-(line_length/2)
// range of val should be 0 to line_length
val = abs(zout) * 2;
sampled_vals = sampled_line_lengths;
} else if (direct_color_measure == DISTANCE_FROM_NEAREST_END_POINTS) {
val = Math.min(line_delta, line_length - line_delta);
// percentiles calculated directly for DISTANCE_FROM_NEAREST_END_POINTS
sampled_vals = null;
} else {
// default to LINE_LENGTH_LINES
val = line_length;
sampled_vals = sampled_line_lengths;
}
double baseColor = 0;
double low_value, high_value;
// ignore percentile option and direct_color_thesholding if using META_INDEX mode??
if (direct_color_measure == META_INDEX && meta_mode != OFF) {
low_value = 0;
high_value = meta_steps;
} else {
if (direct_color_thesholding == PERCENT) {
if (direct_color_measure == DISTANCE_ALONG_LINE_POINTS) {
low_value = color_low_thresh * line_length;
high_value = color_high_thresh * line_length;
} else if (direct_color_measure == DISTANCE_FROM_MIDLINE_POINTS) {
low_value = color_low_thresh * midlength;
high_value = color_high_thresh * midlength;
} else if (direct_color_measure == DISTANCE_FROM_MIDLINE_POINTS || direct_color_measure == DISTANCE_FROM_NEAREST_END_POINTS) {
// low_thresh and high_thresh for DISTANCE_FROM_MIDLINE_POINTS and DISTANCE_FROM_NEAREST_END_POINTS
// can behave differently when thresholding by value, but act the same when thresholding by percentile
low_value = color_low_thresh * midlength;
high_value = color_high_thresh * midlength;
} else {
int low_index, high_index;
if (color_low_thresh < 0 || color_low_thresh >= 1) {
low_index = 0;
} else {
low_index = (int) (color_low_thresh * sample_size);
}
if (color_high_thresh >= 1 || color_high_thresh < 0) {
high_index = sample_size - 1;
} else {
high_index = (int) (color_high_thresh * (sample_size - 1));
}
low_value = sampled_vals[low_index];
high_value = sampled_vals[high_index];
}
} else {
// default is by value
low_value = color_low_thresh;
high_value = color_high_thresh;
}
if (low_value > high_value) {
double temp = low_value;
low_value = high_value;
high_value = temp;
}
}
if (val < low_value) {
baseColor = 0;
} else if (val >= high_value) {
baseColor = 255;
} else {
baseColor = ((val - low_value) / (high_value - low_value)) * 255;
}
if (direct_color_gradient == COLORMAP_CLAMP) {
pVarTP.rgbColor = false;
pVarTP.color = baseColor / 255.0;
if (pVarTP.color < 0) {
pVarTP.color = 0;
}
if (pVarTP.color > 1.0) {
pVarTP.color = 1.0;
}
} else if (direct_color_gradient == COLORMAP_WRAP) {
pVarTP.rgbColor = false;
// if val is outside range, wrap it around (cylce) to keep within range
if (val < low_value) {
val = high_value - ((low_value - val) % (high_value - low_value));
} else if (val > high_value) {
val = low_value + ((val - low_value) % (high_value - low_value));
}
baseColor = ((val - low_value) / (high_value - low_value)) * 255;
pVarTP.color = baseColor / 255.0;
if (pVarTP.color < 0) {
pVarTP.color = 0;
}
if (pVarTP.color > 1.0) {
pVarTP.color = 1.0;
}
} else if (direct_color_gradient == RED_GREEN) {
//
pVarTP.rgbColor = true;
pVarTP.redColor = baseColor;
pVarTP.greenColor = 255 - baseColor;
pVarTP.blueColor = 0;
} else if (direct_color_gradient == RED_BLUE) {
pVarTP.rgbColor = true;
pVarTP.redColor = baseColor;
pVarTP.greenColor = 0;
pVarTP.blueColor = 255 - baseColor;
} else if (direct_color_gradient == BLUE_GREEN) {
pVarTP.rgbColor = true;
pVarTP.redColor = 0;
pVarTP.greenColor = 255 - baseColor;
pVarTP.blueColor = baseColor;
}
}
// END color_mode != normal
}
use of org.jwildfire.create.tina.base.XYZPoint in project JWildfire by thargor6.
the class Hexaplay3DFunc method transform.
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
/* hexaplay3D by Larry Berlin, http://aporev.deviantart.com/art/3D-Plugins-Collection-One-138514007?q=gallery%3Aaporev%2F8229210&qo=15 */
if (this._fcycle > 5) {
this._fcycle = 0;
// Chooses new 6 or 3 nodes
this._rswtch = (int) trunc(pContext.random() * 3.0);
}
if (this._bcycle > 2) {
this._bcycle = 0;
// Chooses new 6 or 3 nodes
this._rswtch = (int) trunc(pContext.random() * 3.0);
}
// Sets hexagon length radius - major plane
double lrmaj = pAmount;
// Boost is the separation distance between the two planes
double boost = 0;
int posNeg = 1;
int loc60;
int loc120;
double scale = this.scale * 0.5;
if (pContext.random() < 0.5) {
posNeg = -1;
}
// Determine whether one or two major planes
int majplane = 1;
double abmajp = fabs(this.majp);
if (abmajp <= 1.0) {
// Want either 1 or 2
majplane = 1;
} else {
majplane = 2;
// distance above and below XY plane
boost = (abmajp - 1.0) * 0.5;
}
// Creating Z factors relative to the planes
if (majplane == 2) {
pVarTP.z += pAffineTP.z * 0.5 * this.zlift + (posNeg * boost);
} else {
pVarTP.z += pAffineTP.z * 0.5 * this.zlift;
}
// Work out the segments and hexagonal nodes
if (this._rswtch <= 1) {
// Occasion to build using 60 degree segments
// loc60 = trunc(pContext.random()*6.0); // random nodes selection
// sequential nodes selection
loc60 = this._fcycle;
pVarTP.x = ((pVarTP.x + pAffineTP.x) * scale) + (lrmaj * _seg60x[loc60]);
pVarTP.y = ((pVarTP.y + pAffineTP.y) * scale) + (lrmaj * _seg60y[loc60]);
this._fcycle += 1;
} else {
// Occasion to build on 120 degree segments
// loc120 = trunc(pContext.random()*3.0); // random nodes selection
// sequential nodes selection
loc120 = this._bcycle;
pVarTP.x = ((pVarTP.x + pAffineTP.x) * scale) + (lrmaj * _seg120x[loc120]);
pVarTP.y = ((pVarTP.y + pAffineTP.y) * scale) + (lrmaj * _seg120y[loc120]);
this._bcycle += 1;
}
}
Aggregations