package org.reprap.geometry.polyhedra;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Vector3d;
public class Primitives
{
/**
* This should really be called cuboid, but let's not be pedantic...
* @param x
* @param y
* @param z
* @param centre
* @return
*/
public static CSG3D cube(double x, double y, double z, boolean centre)
{
CSG3D result;
if(centre)
{
x = 0.5*x;
y = 0.5*y;
z = 0.5*z;
result = new CSG3D(new HalfSpace(new Point3D(1, 0, 0), new Point3D(x, 0, 0)));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, 1, 0), new Point3D(0, y, 0))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, 0, 1), new Point3D(0, 0, z))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(-1, 0, 0), new Point3D(-x, 0, 0))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, -1, 0), new Point3D(0, -y, 0))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, 0, -1), new Point3D(0, 0, -z))));
} else
{
result = new CSG3D(new HalfSpace(new Point3D(1, 0, 0), new Point3D(x, 0, 0)));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, 1, 0), new Point3D(0, y, 0))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, 0, 1), new Point3D(0, 0, z))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(-1, 0, 0), new Point3D(0, 0, 0))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, -1, 0), new Point3D(0, 0, 0))));
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(new Point3D(0, 0, -1), new Point3D(0, 0, 0))));
}
return result;
}
/**
* See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features
*/
private static int getFragmentsFromR(double r, int fn, double fs, double fa)
{
if (fn > 0)
return fn;
return (int)Math.ceil(Math.max(Math.min(360.0 / fa, r*Math.PI / fs), 5));
}
/**
* A cylinder without the top and the bottom
* @param fn
* @param fa
* @param fs
* @param h
* @param r1
* @param r2
* @return
*/
private static CSG3D openCylinder(int fn, double fa, double fs, double h, double r1, double r2)
{
fn = getFragmentsFromR(Math.min(r1,r2), fn, fs, fa);
Point3D p1 = new Point3D(r1,0,0);
Point3D p2 = new Point3D(r1,10,0);
Point3D p3 = new Point3D(r2,0,h);
CSG3D s = new CSG3D(new HalfSpace(p1,p2,p3));
double a = 2.0*Math.PI/(double)fn;
Matrix4d m = new Matrix4d();
m.setIdentity();
m.set(new AxisAngle4d(0, 0, 1, a));
CSG3D result = CSG3D.universe();
for(int i = 0; i < fn; i++)
{
result = CSG3D.intersection(result, s);
s = s.transform(m);
}
return result;
}
/**
* Cylinder with ends
*
* @param fn is usually 0. When this variable has a value greater than zero, the other two variables are ignored
* and full circle is rendered using this number of fragments.
* @param fa is the minimum angle for a fragment.
* @param fs is the minimum size of a fragment.
* @param h length in Z
* @param r1 bottom (low Z) radius of frustum
* @param r2 top radius
* @param centre Z goes from -h/2 to + h/2; or 0 to h
* @return
*/
public static CSG3D cylinder(int fn, double fa, double fs, double h, double r1, double r2, boolean centre)
{
CSG3D result = openCylinder(fn, fa, fs, h, r1, r2);
Point3D p1 = new Point3D(0,0,h);
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(p1,p1)));
Point3D p2 = new Point3D(0,0,0);
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(p1.neg(),p2)));
if(centre)
{
Matrix4d m = new Matrix4d();
m.setIdentity();
m.setTranslation(new Vector3d(0, 0, -h/2));
result = result.transform(m);
}
return result;
}
/**
* Sphere. The f arguments do the same as for Cylinder
* @param fn
* @param fa
* @param fs
* @param r
* @return
*/
static CSG3D sphere(int fn, double fa, double fs, double r)
{
int fnl = getFragmentsFromR(r, fn, fs, fa);
double a = 2.0*Math.PI/(double)fnl;
Matrix4d m = new Matrix4d();
m.setIdentity();
CSG3D result = CSG3D.universe();
CSG3D cyl;
double ang = 0;
double angp = a;
for(int i = 0; i < fnl/4; i++)
{
cyl = openCylinder(fn, fa, fs, r*(Math.sin(angp) - Math.sin(ang)), r*Math.cos(ang), r*Math.cos(angp));
m.setTranslation(new Vector3d(0, 0, r*Math.sin(ang)));
cyl = cyl.transform(m);
result = CSG3D.intersection(result,cyl);
cyl = openCylinder(fn, fa, fs, r*(Math.sin(angp) - Math.sin(ang)), r*Math.cos(angp), r*Math.cos(ang));
m.setTranslation(new Vector3d(0, 0, -r*Math.sin(ang)));
cyl = cyl.transform(m);
result = CSG3D.intersection(result,cyl);
ang = angp;
angp += a;
}
Point3D p1 = new Point3D(0,0,r);
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(p1,p1)));
p1 = new Point3D(0,0,-r);
result = CSG3D.intersection(result, new CSG3D(new HalfSpace(p1,p1)));
return result;
}
}