/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2017 Andreas Maschke
This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this software;
if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jwildfire.create.tina.variation;
import static org.jwildfire.base.mathlib.MathLib.M_PI;
import static org.jwildfire.base.mathlib.MathLib.sinAndCos;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jwildfire.base.Tools;
import org.jwildfire.base.mathlib.GfxMathLib;
import org.jwildfire.base.mathlib.MathLib;
import org.jwildfire.base.mathlib.VecMathLib.Matrix3D;
import org.jwildfire.base.mathlib.VecMathLib.VectorD;
import org.jwildfire.create.tina.base.Layer;
import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.base.XYZPoint;
import org.jwildfire.create.tina.random.AbstractRandomGenerator;
import org.jwildfire.create.tina.random.MarsagliaRandomGenerator;
import org.jwildfire.create.tina.variation.mesh.Face;
import org.jwildfire.create.tina.variation.mesh.OBJMeshUtil;
import org.jwildfire.create.tina.variation.mesh.SimpleMesh;
import org.jwildfire.create.tina.variation.mesh.SimpleMesh.BoundingBox;
import org.jwildfire.create.tina.variation.mesh.UVColorMapper;
import org.jwildfire.create.tina.variation.mesh.Vertex;
import org.jwildfire.create.tina.variation.mesh.VertexWithUV;
import odk.lang.DoubleWrapper;
public class DLA3DWFFunc extends VariationFunc {
private static final long serialVersionUID = 1L;
private static final String PARAM_MAX_ITER = "max_iter";
private static final String PARAM_SEED = "seed";
private static final String PARAM_INNER_BLUR_RADIUS = "inner_blur_radius";
private static final String PARAM_OUTER_BLUR_RADIUS = "outer_blur_radius";
private static final String PARAM_JUNCTION_SCALE = "junction_scale";
private static final String PARAM_DC_COLOR = "dc_color";
private static final String PARAM_GLUE_RADIUS = "glue_radius";
private static final String PARAM_FORCE_X = "force_x";
private static final String PARAM_FORCE_Y = "force_y";
private static final String PARAM_FORCE_Z = "force_z";
private static final String PARAM_DISPLAY_NODES = "display_nodes";
private static final String PARAM_DISPLAY_JUNCTIONS = "display_junctions";
private static final String PARAM_SINGLE_THREAD = "single_thread";
private static final String PARAM_NODE_SDIV_LEVEL = "node_sdiv_level";
private static final String PARAM_NODE_SDIV_SMOOTH_PASSES = "node_sdiv_smooth_passes";
private static final String PARAM_NODE_SDIV_SMOOTH_LAMBDA = "node_sdiv_smooth_lambda";
private static final String PARAM_NODE_SDIV_SMOOTH_MU = "node_sdiv_smooth_mu";
private static final String PARAM_NODE_BLEND_COLORMAP = "node_blend_colormap";
private static final String PARAM_NODE_MESH_SCALE = "node_mesh_scale";
private static final String PARAM_JUNCT_SDIV_LEVEL = "junct_sdiv_level";
private static final String PARAM_JUNCT_SDIV_SMOOTH_PASSES = "junct_sdiv_smooth_passes";
private static final String PARAM_JUNCT_SDIV_SMOOTH_LAMBDA = "junct_sdiv_smooth_lambda";
private static final String PARAM_JUNCT_SDIV_SMOOTH_MU = "junct_sdiv_smooth_mu";
private static final String PARAM_JUNCT_BLEND_COLORMAP = "junct_blend_colormap";
private static final String PARAM_JUNCT_MESH_SCALE = "junct_mesh_scale";
private static final String RESSOURCE_NODE_OBJ_FILENAME = "node_obj_filename";
private static final String RESSOURCE_NODE_COLORMAP_FILENAME = "node_colormap_filename";
private static final String RESSOURCE_JUNCT_OBJ_FILENAME = "junct_obj_filename";
private static final String RESSOURCE_JUNCT_COLORMAP_FILENAME = "junct_colormap_filename";
private static final String[] paramNames = { PARAM_MAX_ITER, PARAM_SEED, PARAM_INNER_BLUR_RADIUS, PARAM_OUTER_BLUR_RADIUS, PARAM_JUNCTION_SCALE,
PARAM_DC_COLOR, PARAM_GLUE_RADIUS, PARAM_FORCE_X, PARAM_FORCE_Y, PARAM_FORCE_Z, PARAM_DISPLAY_NODES,
PARAM_DISPLAY_JUNCTIONS, PARAM_SINGLE_THREAD,
PARAM_NODE_SDIV_LEVEL, PARAM_NODE_SDIV_SMOOTH_PASSES, PARAM_NODE_SDIV_SMOOTH_LAMBDA, PARAM_NODE_SDIV_SMOOTH_MU, PARAM_NODE_BLEND_COLORMAP, PARAM_NODE_MESH_SCALE,
PARAM_JUNCT_SDIV_LEVEL, PARAM_JUNCT_SDIV_SMOOTH_PASSES, PARAM_JUNCT_SDIV_SMOOTH_LAMBDA, PARAM_JUNCT_SDIV_SMOOTH_MU, PARAM_JUNCT_BLEND_COLORMAP, PARAM_JUNCT_MESH_SCALE };
private static final String[] ressourceNames = { RESSOURCE_NODE_OBJ_FILENAME, RESSOURCE_NODE_COLORMAP_FILENAME, RESSOURCE_JUNCT_OBJ_FILENAME, RESSOURCE_JUNCT_COLORMAP_FILENAME };
private int max_iter = 320;
private int seed = (int) (Math.random() * 10000);
private double inner_blur_radius = 0.5;
private double outer_blur_radius = 0.01;
private double junction_scale = 1.4;
private int dc_color = 1;
private double glue_radius = 1.0;
private double force_x = 0.0;
private double force_y = 0.0;
private double force_z = 0.0;
private int display_nodes = 1;
private int display_junctions = 1;
private int single_thread = 0;
protected int node_sdiv_level = 0;
protected int node_sdiv_smooth_passes = 12;
protected double node_sdiv_smooth_lambda = 0.42;
protected double node_sdiv_smooth_mu = -0.45;
protected double node_mesh_scale = 1.0;
protected int junct_sdiv_level = 0;
protected int junct_sdiv_smooth_passes = 12;
protected double junct_sdiv_smooth_lambda = 0.42;
protected double junct_sdiv_smooth_mu = -0.45;
protected double junct_mesh_scale = 1.0;
private SimpleMesh nodeMesh;
private String nodeObjFilename = null;
protected ColorMapHolder nodeColorMapHolder = new ColorMapHolder();
protected UVColorMapper nodeUVColorMapper = new UVColorMapper();
private SimpleMesh junctMesh;
private String junctObjFilename = null;
protected ColorMapHolder junctColorMapHolder = new ColorMapHolder();
protected UVColorMapper junctUVColorMapper = new UVColorMapper();
private class Sample {
double x, y, z;
double color;
}
@Override
public void transform(FlameTransformationContext pContext, XForm pXForm, XYZPoint pAffineTP, XYZPoint pVarTP, double pAmount) {
DLA3DWFFuncPoint point = getRandomPoint();
double rnd = _randGen.random();
boolean doBlur = outer_blur_radius > MathLib.EPSILON;
Sample sample = null;
if (point.parent == null) {
if (display_nodes > 0 && doBlur)
sample = displayCentreNode(point);
}
else {
if (doBlur) {
double minRadius, maxRadius;
{
double fromDepth = point.relDepth;
double toDepth = point.parent.relDepth;
double dRadius = outer_blur_radius - inner_blur_radius;
minRadius = inner_blur_radius + dRadius * fromDepth;
maxRadius = inner_blur_radius + dRadius * toDepth;
}
if (display_junctions > 0 && display_nodes > 0) {
double shape = _randGen.random();
if (shape < 0.333) {
sample = displayOuterNode(point, minRadius);
}
else {
sample = displayJunction(point, minRadius, maxRadius, rnd);
}
}
else if (display_junctions > 0) {
sample = displayJunction(point, minRadius, maxRadius, rnd);
}
else if (display_nodes > 0) {
sample = displayOuterNode(point, maxRadius);
}
}
else {
sample = displayUnblurredPart(point, rnd);
}
}
if (sample != null) {
pVarTP.doHide = false;
pVarTP.x += pAmount * sample.x;
pVarTP.y += pAmount * sample.y;
pVarTP.z += pAmount * sample.z;
if (dc_color > 0) {
pVarTP.color = Math.max(0.0, Math.min(1.0, sample.color));
}
}
else {
pVarTP.doHide = true;
}
}
private Sample displayJunction(DLA3DWFFuncPoint point, double minRadius, double maxRadius, double rnd) {
Sample sample = new Sample();
double radius = minRadius + (maxRadius - minRadius) * rnd;
double defaultColor = point.relDepth + (point.parent.relDepth - point.relDepth) * rnd;
if (junctMesh == null || junctMesh.getFaceCount() == 0) {
sample.x = point.x + (point.parent.x - point.x) * rnd;
sample.y = point.y + (point.parent.y - point.y) * rnd;
sample.z = point.z + (point.parent.z - point.z) * rnd;
sample.color = defaultColor;
double ax = (point.parent.x - point.x);
double ay = (point.parent.y - point.y);
double az = (point.parent.z - point.z);
int iter = 0;
while (true && iter++ < 10) {
double bx = 0.5 - _randGen.random();
double by = 0.5 - _randGen.random();
double bz = 0.5 - _randGen.random();
double cx = ay * bz - az * by;
double cy = az * bx - ax * bz;
double cz = ax * by - ay * bx;
double r = MathLib.sqrt(cx * cx + cy * cy + cz * cz);
if (r > 0.001) {
sample.x += cx / r * radius;
sample.y += cy / r * radius;
sample.z += cz / r * radius;
break;
}
}
}
else {
sample = getRawSampleFromJunctMesh(radius, defaultColor, point.rotation);
sample.x += point.x + (point.parent.x - point.x) * 0.5;
sample.y += point.y + (point.parent.y - point.y) * 0.5;
sample.z += point.z + (point.parent.z - point.z) * 0.5;
}
return sample;
}
private Sample displayCentreNode(DLA3DWFFuncPoint point) {
Sample sample = new Sample();
double radius = inner_blur_radius * junction_scale;
if (nodeMesh == null || nodeMesh.getFaceCount() == 0) {
double phi = _randGen.random() * (M_PI + M_PI);
sinAndCos(phi, sinPhi, cosPhi);
double theta = _randGen.random() * (M_PI + M_PI);
sinAndCos(theta, sinTheta, cosTheta);
sample.x = point.x + radius * sinTheta.value * cosPhi.value;
sample.y = point.y + radius * sinTheta.value * sinPhi.value;
sample.z = point.z + radius * cosTheta.value;
sample.color = 0.0;
}
else {
sample = getRawSampleFromNodeMesh(radius, 0.0, null);
sample.x += point.x;
sample.y += point.y;
sample.z += point.z;
}
return sample;
}
private Sample displayOuterNode(DLA3DWFFuncPoint point, double minRadius) {
Sample sample = new Sample();
double radius = minRadius * junction_scale;
if (nodeMesh == null || nodeMesh.getFaceCount() == 0) {
double phi = _randGen.random() * (M_PI + M_PI);
sinAndCos(phi, sinPhi, cosPhi);
double theta = _randGen.random() * (M_PI + M_PI);
sinAndCos(theta, sinTheta, cosTheta);
sample.x = point.x + radius * sinTheta.value * cosPhi.value;
sample.y = point.y + radius * sinTheta.value * sinPhi.value;
sample.z = point.z + radius * cosTheta.value;
sample.color = point.relDepth;
}
else {
sample = getRawSampleFromNodeMesh(radius, point.relDepth, point.rotation);
sample.x += point.x;
sample.y += point.y;
sample.z += point.z;
}
return sample;
}
private Sample getRawSampleFromNodeMesh(double scale, double defaultColor, Matrix3D rotation) {
Sample sample = new Sample();
Face f = nodeMesh.getFace(_randGen.random(nodeMesh.getFaceCount()));
Vertex rawP1 = nodeMesh.getVertex(f.v1);
Vertex rawP2 = nodeMesh.getVertex(f.v2);
Vertex rawP3 = nodeMesh.getVertex(f.v3);
if (nodeColorMapHolder.isActive() && rawP1 instanceof VertexWithUV) {
VertexWithUV p1 = nodeTransform((VertexWithUV) rawP1, node_mesh_scale, scale, nodeMesh.getBoundingBox(), rotation);
VertexWithUV p2 = nodeTransform((VertexWithUV) rawP2, node_mesh_scale, scale, nodeMesh.getBoundingBox(), rotation);
VertexWithUV p3 = nodeTransform((VertexWithUV) rawP3, node_mesh_scale, scale, nodeMesh.getBoundingBox(), rotation);
// uniform sampling: http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle
double sqrt_r1 = MathLib.sqrt(_randGen.random());
double r2 = _randGen.random();
double a = 1.0 - sqrt_r1;
double b = sqrt_r1 * (1.0 - r2);
double c = r2 * sqrt_r1;
double dx = a * p1.x + b * p2.x + c * p3.x;
double dy = a * p1.y + b * p2.y + c * p3.y;
double dz = a * p1.z + b * p2.z + c * p3.z;
sample.x = dx;
sample.y = dy;
sample.z = dz;
sample.color = defaultColor;
double u = a * p1.u + b * p2.u + c * p3.u;
double v = a * p1.v + b * p2.v + c * p3.v;
if (nodeColorMapHolder.isActive()) {
double iu = GfxMathLib.clamp(u * (nodeColorMapHolder.getColorMapWidth() - 1.0), 0.0, nodeColorMapHolder.getColorMapWidth() - 1.0);
double iv = GfxMathLib.clamp(nodeColorMapHolder.getColorMapHeight() - 1.0 - v * (nodeColorMapHolder.getColorMapHeight() - 1.0), 0, nodeColorMapHolder.getColorMapHeight() - 1.0);
int ix = (int) MathLib.trunc(iu);
int iy = (int) MathLib.trunc(iv);
XYZPoint colorHolder = new XYZPoint();
nodeColorMapHolder.applyImageColor(colorHolder, ix, iy, iu, iv);
sample.color = nodeUVColorMapper.getUVColorIdx(Tools.FTOI(colorHolder.redColor), Tools.FTOI(colorHolder.greenColor), Tools.FTOI(colorHolder.blueColor));
}
}
else {
Vertex p1 = nodeTransform(rawP1, node_mesh_scale, scale, nodeMesh.getBoundingBox(), rotation);
Vertex p2 = nodeTransform(rawP2, node_mesh_scale, scale, nodeMesh.getBoundingBox(), rotation);
Vertex p3 = nodeTransform(rawP3, node_mesh_scale, scale, nodeMesh.getBoundingBox(), rotation);
// uniform sampling: http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle
double sqrt_r1 = MathLib.sqrt(_randGen.random());
double r2 = _randGen.random();
double a = 1.0 - sqrt_r1;
double b = sqrt_r1 * (1.0 - r2);
double c = r2 * sqrt_r1;
double dx = a * p1.x + b * p2.x + c * p3.x;
double dy = a * p1.y + b * p2.y + c * p3.y;
double dz = a * p1.z + b * p2.z + c * p3.z;
sample.x = dx;
sample.y = dy;
sample.z = dz;
sample.color = defaultColor;
}
return sample;
}
private Sample getRawSampleFromJunctMesh(double scale, double defaultColor, Matrix3D rotation) {
Sample sample = new Sample();
Face f = junctMesh.getFace(_randGen.random(junctMesh.getFaceCount()));
Vertex rawP1 = junctMesh.getVertex(f.v1);
Vertex rawP2 = junctMesh.getVertex(f.v2);
Vertex rawP3 = junctMesh.getVertex(f.v3);
if (junctColorMapHolder.isActive() && rawP1 instanceof VertexWithUV) {
VertexWithUV p1 = nodeTransform((VertexWithUV) rawP1, junct_mesh_scale, scale, junctMesh.getBoundingBox(), rotation);
VertexWithUV p2 = nodeTransform((VertexWithUV) rawP2, junct_mesh_scale, scale, junctMesh.getBoundingBox(), rotation);
VertexWithUV p3 = nodeTransform((VertexWithUV) rawP3, junct_mesh_scale, scale, junctMesh.getBoundingBox(), rotation);
// uniform sampling: http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle
double sqrt_r1 = MathLib.sqrt(_randGen.random());
double r2 = _randGen.random();
double a = 1.0 - sqrt_r1;
double b = sqrt_r1 * (1.0 - r2);
double c = r2 * sqrt_r1;
double dx = a * p1.x + b * p2.x + c * p3.x;
double dy = a * p1.y + b * p2.y + c * p3.y;
double dz = a * p1.z + b * p2.z + c * p3.z;
sample.x = dx;
sample.y = dy;
sample.z = dz;
sample.color = defaultColor;
double u = a * p1.u + b * p2.u + c * p3.u;
double v = a * p1.v + b * p2.v + c * p3.v;
if (junctColorMapHolder.isActive()) {
double iu = GfxMathLib.clamp(u * (junctColorMapHolder.getColorMapWidth() - 1.0), 0.0, junctColorMapHolder.getColorMapWidth() - 1.0);
double iv = GfxMathLib.clamp(junctColorMapHolder.getColorMapHeight() - 1.0 - v * (junctColorMapHolder.getColorMapHeight() - 1.0), 0, junctColorMapHolder.getColorMapHeight() - 1.0);
int ix = (int) MathLib.trunc(iu);
int iy = (int) MathLib.trunc(iv);
XYZPoint colorHolder = new XYZPoint();
junctColorMapHolder.applyImageColor(colorHolder, ix, iy, iu, iv);
sample.color = junctUVColorMapper.getUVColorIdx(Tools.FTOI(colorHolder.redColor), Tools.FTOI(colorHolder.greenColor), Tools.FTOI(colorHolder.blueColor));
}
}
else {
Vertex p1 = nodeTransform(rawP1, junct_mesh_scale, scale, junctMesh.getBoundingBox(), rotation);
Vertex p2 = nodeTransform(rawP2, junct_mesh_scale, scale, junctMesh.getBoundingBox(), rotation);
Vertex p3 = nodeTransform(rawP3, junct_mesh_scale, scale, junctMesh.getBoundingBox(), rotation);
// uniform sampling: http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle
double sqrt_r1 = MathLib.sqrt(_randGen.random());
double r2 = _randGen.random();
double a = 1.0 - sqrt_r1;
double b = sqrt_r1 * (1.0 - r2);
double c = r2 * sqrt_r1;
double dx = a * p1.x + b * p2.x + c * p3.x;
double dy = a * p1.y + b * p2.y + c * p3.y;
double dz = a * p1.z + b * p2.z + c * p3.z;
sample.x = dx;
sample.y = dy;
sample.z = dz;
sample.color = defaultColor;
}
return sample;
}
private Vertex nodeTransform(Vertex p, double preScale, double relScale, BoundingBox boundingBox, Matrix3D rotation) {
Vertex res = new Vertex();
double px, py, pz;
if (rotation != null) {
VectorD d = new VectorD(p.x - boundingBox.getXcentre(), p.y - boundingBox.getYcentre(), p.z - boundingBox.getZcentre());
VectorD r = Matrix3D.multiply(rotation, d);
px = r.x;
py = r.y;
pz = r.z;
}
else {
px = p.x;
py = p.y;
pz = p.z;
}
res.x = (float) (px * preScale * relScale);
res.y = (float) (py * preScale * relScale);
res.z = (float) (pz * preScale * relScale);
return res;
}
private VertexWithUV nodeTransform(VertexWithUV p, double preScale, double relScale, BoundingBox boundingBox, Matrix3D rotation) {
VertexWithUV res = new VertexWithUV();
double px, py, pz;
if (rotation != null) {
VectorD d = new VectorD(p.x - boundingBox.getXcentre(), p.y - boundingBox.getYcentre(), p.z - boundingBox.getZcentre());
VectorD r = Matrix3D.multiply(rotation, d);
px = r.x;
py = r.y;
pz = r.z;
}
else {
px = p.x;
py = p.y;
pz = p.z;
}
res.x = (float) (px * preScale * relScale);
res.y = (float) (py * preScale * relScale);
res.z = (float) (pz * preScale * relScale);
res.u = p.u;
res.v = p.v;
return res;
}
private Sample displayUnblurredPart(DLA3DWFFuncPoint point, double rnd) {
Sample sample = new Sample();
sample.x = point.x + (point.parent.x - point.x) * rnd;
sample.y = point.y + (point.parent.y - point.y) * rnd;
sample.z = point.z + (point.parent.z - point.z) * rnd;
sample.color = point.relDepth + (point.parent.relDepth - point.relDepth) * rnd;
return sample;
}
@Override
public String[] getParameterNames() {
return paramNames;
}
@Override
public Object[] getParameterValues() {
return new Object[] { max_iter, seed, inner_blur_radius, outer_blur_radius, junction_scale, dc_color, glue_radius, force_x, force_y,
force_z, display_nodes, display_junctions, single_thread,
node_sdiv_level, node_sdiv_smooth_passes, node_sdiv_smooth_lambda, node_sdiv_smooth_mu, nodeColorMapHolder.getBlend_colormap(), node_mesh_scale,
junct_sdiv_level, junct_sdiv_smooth_passes, junct_sdiv_smooth_lambda, junct_sdiv_smooth_mu, junctColorMapHolder.getBlend_colormap(), junct_mesh_scale };
}
@Override
public String[] getRessourceNames() {
return ressourceNames;
}
@Override
public byte[][] getRessourceValues() {
return new byte[][] { (nodeObjFilename != null ? nodeObjFilename.getBytes() : null),
(nodeColorMapHolder.getColormap_filename() != null ? nodeColorMapHolder.getColormap_filename().getBytes() : null),
(junctObjFilename != null ? junctObjFilename.getBytes() : null),
(junctColorMapHolder.getColormap_filename() != null ? junctColorMapHolder.getColormap_filename().getBytes() : null) };
}
@Override
public void setRessource(String pName, byte[] pValue) {
if (RESSOURCE_NODE_OBJ_FILENAME.equalsIgnoreCase(pName)) {
nodeObjFilename = pValue != null ? new String(pValue) : "";
}
else if (RESSOURCE_NODE_COLORMAP_FILENAME.equalsIgnoreCase(pName)) {
nodeColorMapHolder.setColormap_filename(pValue != null ? new String(pValue) : "");
nodeColorMapHolder.clear();
nodeUVColorMapper.clear();
}
else if (RESSOURCE_JUNCT_OBJ_FILENAME.equalsIgnoreCase(pName)) {
junctObjFilename = pValue != null ? new String(pValue) : "";
}
else if (RESSOURCE_JUNCT_COLORMAP_FILENAME.equalsIgnoreCase(pName)) {
junctColorMapHolder.setColormap_filename(pValue != null ? new String(pValue) : "");
junctColorMapHolder.clear();
junctUVColorMapper.clear();
}
else
throw new IllegalArgumentException(pName);
}
@Override
public RessourceType getRessourceType(String pName) {
if (RESSOURCE_NODE_OBJ_FILENAME.equalsIgnoreCase(pName)) {
return RessourceType.OBJ_MESH;
}
else if (RESSOURCE_NODE_COLORMAP_FILENAME.equalsIgnoreCase(pName)) {
return RessourceType.IMAGE_FILENAME;
}
else if (RESSOURCE_JUNCT_OBJ_FILENAME.equalsIgnoreCase(pName)) {
return RessourceType.OBJ_MESH;
}
else if (RESSOURCE_JUNCT_COLORMAP_FILENAME.equalsIgnoreCase(pName)) {
return RessourceType.IMAGE_FILENAME;
}
else
throw new IllegalArgumentException(pName);
}
@Override
public void setParameter(String pName, double pValue) {
if (PARAM_JUNCTION_SCALE.equalsIgnoreCase(pName))
junction_scale = pValue;
else if (PARAM_MAX_ITER.equalsIgnoreCase(pName))
max_iter = Tools.FTOI(pValue);
else if (PARAM_DC_COLOR.equalsIgnoreCase(pName))
dc_color = Tools.FTOI(pValue);
else if (PARAM_SEED.equalsIgnoreCase(pName))
seed = Tools.FTOI(pValue);
else if (PARAM_INNER_BLUR_RADIUS.equalsIgnoreCase(pName))
inner_blur_radius = pValue;
else if (PARAM_OUTER_BLUR_RADIUS.equalsIgnoreCase(pName))
outer_blur_radius = pValue;
else if (PARAM_GLUE_RADIUS.equalsIgnoreCase(pName)) {
glue_radius = pValue;
if (glue_radius < 0.1) {
glue_radius = 0.1;
}
}
else if (PARAM_FORCE_X.equalsIgnoreCase(pName))
force_x = pValue;
else if (PARAM_FORCE_Y.equalsIgnoreCase(pName))
force_y = pValue;
else if (PARAM_FORCE_Z.equalsIgnoreCase(pName))
force_z = pValue;
else if (PARAM_SINGLE_THREAD.equalsIgnoreCase(pName))
single_thread = Tools.FTOI(pValue);
else if (PARAM_DISPLAY_NODES.equalsIgnoreCase(pName))
display_nodes = Tools.FTOI(pValue);
else if (PARAM_DISPLAY_JUNCTIONS.equalsIgnoreCase(pName))
display_junctions = Tools.FTOI(pValue);
else if (PARAM_NODE_SDIV_LEVEL.equalsIgnoreCase(pName))
node_sdiv_level = limitIntVal(Tools.FTOI(pValue), 0, 6);
else if (PARAM_NODE_SDIV_SMOOTH_PASSES.equalsIgnoreCase(pName))
node_sdiv_smooth_passes = limitIntVal(Tools.FTOI(pValue), 0, 24);
else if (PARAM_NODE_SDIV_SMOOTH_LAMBDA.equalsIgnoreCase(pName))
node_sdiv_smooth_lambda = pValue;
else if (PARAM_NODE_SDIV_SMOOTH_MU.equalsIgnoreCase(pName))
node_sdiv_smooth_mu = pValue;
else if (PARAM_NODE_BLEND_COLORMAP.equalsIgnoreCase(pName))
nodeColorMapHolder.setBlend_colormap(limitIntVal(Tools.FTOI(pValue), 0, 1));
else if (PARAM_NODE_MESH_SCALE.equalsIgnoreCase(pName))
node_mesh_scale = pValue;
else if (PARAM_JUNCT_SDIV_LEVEL.equalsIgnoreCase(pName))
junct_sdiv_level = limitIntVal(Tools.FTOI(pValue), 0, 6);
else if (PARAM_JUNCT_SDIV_SMOOTH_PASSES.equalsIgnoreCase(pName))
junct_sdiv_smooth_passes = limitIntVal(Tools.FTOI(pValue), 0, 24);
else if (PARAM_JUNCT_SDIV_SMOOTH_LAMBDA.equalsIgnoreCase(pName))
junct_sdiv_smooth_lambda = pValue;
else if (PARAM_JUNCT_SDIV_SMOOTH_MU.equalsIgnoreCase(pName))
junct_sdiv_smooth_mu = pValue;
else if (PARAM_JUNCT_BLEND_COLORMAP.equalsIgnoreCase(pName))
junctColorMapHolder.setBlend_colormap(limitIntVal(Tools.FTOI(pValue), 0, 1));
else if (PARAM_JUNCT_MESH_SCALE.equalsIgnoreCase(pName))
junct_mesh_scale = pValue;
else
throw new IllegalArgumentException(pName);
}
@Override
public String getName() {
return "dla3d_wf";
}
private String makeKey() {
return "dla3d#" + String.valueOf(_max_iter) + "#" + String.valueOf(seed) + "#" + String.valueOf(force_x) + "#" + String.valueOf(force_y) + "#" + String.valueOf(force_z) + "#" + String.valueOf(glue_radius) + "#" + (single_thread > 0 ? 1 : 0);
}
private static Map<String, List<DLA3DWFFuncPoint>> cache = new HashMap<>();
private static AtomicBoolean calculating = new AtomicBoolean(false);
private List<DLA3DWFFuncPoint> getPoints() {
String key = makeKey();
List<DLA3DWFFuncPoint> res = cache.get(key);
if (res == null && calculating.compareAndSet(false, true)) {
try {
long t0 = System.currentTimeMillis();
res = new DLA3DWFFuncIterator(_max_iter, seed, glue_radius, force_x, force_y, force_z, single_thread > 0).iterate();
long t1 = System.currentTimeMillis();
System.out.println("DLA3D(" + res.size() + "): " + (t1 - t0) + " ms");
cache.put(key, res);
}
finally {
calculating.set(false);
}
}
while (calculating.get() || res == null) {
try {
Thread.sleep(66);
}
catch (InterruptedException e) {
e.printStackTrace();
}
res = cache.get(key);
}
return res;
}
private DLA3DWFFuncPoint getRandomPoint() {
return _points.get(_randGen.random(_points.size()));
}
private int _max_iter;
private AbstractRandomGenerator _randGen;
private DoubleWrapper sinPhi = new DoubleWrapper();
private DoubleWrapper cosPhi = new DoubleWrapper();
private DoubleWrapper sinTheta = new DoubleWrapper();
private DoubleWrapper cosTheta = new DoubleWrapper();
private List<DLA3DWFFuncPoint> _points;
@Override
public void init(FlameTransformationContext pContext, Layer pLayer, XForm pXForm, double pAmount) {
_max_iter = pContext.isPreview() ? (max_iter < 1000) ? max_iter : 1000 : max_iter;
if (_max_iter < 0)
_max_iter = 0;
_randGen = new MarsagliaRandomGenerator();
_randGen.randomize(seed);
nodeColorMapHolder.init();
nodeUVColorMapper.initFromLayer(pContext, pLayer);
junctColorMapHolder.init();
junctUVColorMapper.initFromLayer(pContext, pLayer);
_points = getPoints();
if (nodeObjFilename != null && nodeObjFilename.length() > 0) {
try {
String meshKey = this.getClass().getName() + "_" + OBJMeshUtil.getMeshname(nodeObjFilename, node_sdiv_level, node_sdiv_smooth_passes, node_sdiv_smooth_lambda, node_sdiv_smooth_mu);
nodeMesh = (SimpleMesh) RessourceManager.getRessource(meshKey);
if (nodeMesh == null) {
nodeMesh = OBJMeshUtil.loadAndSmoothMeshFromFile(nodeObjFilename, node_sdiv_smooth_passes, node_sdiv_level, node_sdiv_smooth_lambda, node_sdiv_smooth_mu);
RessourceManager.putRessource(meshKey, nodeMesh);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
if (junctObjFilename != null && junctObjFilename.length() > 0) {
try {
String meshKey = this.getClass().getName() + "_" + OBJMeshUtil.getMeshname(junctObjFilename, junct_sdiv_level, junct_sdiv_smooth_passes, junct_sdiv_smooth_lambda, junct_sdiv_smooth_mu);
junctMesh = (SimpleMesh) RessourceManager.getRessource(meshKey);
if (junctMesh == null) {
junctMesh = OBJMeshUtil.loadAndSmoothMeshFromFile(junctObjFilename, junct_sdiv_smooth_passes, junct_sdiv_level, junct_sdiv_smooth_lambda, junct_sdiv_smooth_mu);
RessourceManager.putRessource(meshKey, junctMesh);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}