BoolMesh.java (boolean operations on mesh)

EDIT: waste no more time, go straight to this !!!

Hi!



I was working on making unbboolean working with JME3, and it is working now, with a few bugs yet…

See Box-Sphere+Cylinder:



in this image, the green spot is from cast ray, and the yellow wire mesh is a light that should be a bit far from the green spot, so it is another bug I couldnt solve yet, the face normal got bugged…; another bug is that I cant create a physics working collision mesh from this, I have no idea why (the normals again?)…



I had also to add a few jars to the project:

  • j3dcore.jar
  • j3dutils.jar
  • rt.jar
  • vecmath.jar

I think also it is not very well integrated yet. It uses Solid.java (that I changed a bit), but I think it should use Mesh.java (from jme3) instead, what would let skip the Mesh->Solid, and backwards, conversion...

This is where I created the files, any tips?
./jme3test/unbboolean:
BoolMesh.java (new)
TestBoolMesh.java (new)
./jme3test/unbboolean/j3dbool:
BooleanModeller.java
Bound.java
Face.java
Line.java
Object3D.java
Segment.java
Solid.java (modified)
Vertex.java

Tho... I have a question about licenses:
I cant find unbboolean license, so is it public domain? the most I found was a reference in sourceforge saying it is GPL, but I couldnt find that together with the code, so would it be incompatible with jme3? I mean jme3 being "new BSD license" can accept this addition? I will contact the unbboolean author to check this thread also and give his approval before posting the code.

PS.: the forum insert/uploadImage doesnt work, after waiting a long time it didnt show me a link to my just uploaded image.
3 Likes

Hi again!



I have contacted the author Danilo Balby, it is his graduation work on public domain!

I am adding here the files I created to integrate it with JME3. Thx vm!



This is a very initial work. As I said, it is not deeply integrated with JME3 (mesh); but is something that works and you can play with :).


  1. First, download this package: j3dbool-1.1.zip


  2. Extract this folder “src/unbboolean/j3dbool” to “jme3test/unbboolean/j3dbool”

    I personally created that package on my project, not at jme3 sources as I update it frequently.

    After extracting you will have to go on each file and modify the package, or just extract it to “unbboolean/j3dbool”.


  3. now, copy this code over Solid.java, (I made a few simple changes to it, but not changing the way it works).

package jme3test.unbboolean.j3dbool;



import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.util.Arrays;

import java.util.StringTokenizer;

import javax.media.j3d.Shape3D;

import javax.vecmath.Color3f;

import javax.vecmath.Point3d;

import com.sun.j3d.utils.geometry.GeometryInfo;

import com.sun.j3d.utils.geometry.NormalGenerator;



/**

* Class representing a 3D solid.

*

* @author Danilo Balby Silva Castanheira (danbalby@yahoo.com)

* @author teique, added a few methods to rotate and position

*/

public class Solid extends Shape3D

{

// translation

private double dx = 0;

private double dy = 0;

private double dz = 0;



/** array of indices for the vertices from the 'vertices' attribute */

protected int[] indices;

/** array of points defining the solid's vertices */

protected Point3d[] vertices;

/** array of color defining the vertices colors */

protected Color3f[] colors;



//


CONSTRUCTORS

//



/** Constructs an empty solid. */

public Solid()

{

super();

setInitialFeatures();

}



/**

* Construct a solid based on data arrays. An exception may occur in the case of

* abnormal arrays (indices making references to inexistent vertices, there are less

* colors than vertices...)

*

* @param vertices array of points defining the solid vertices

* @param indices array of indices for a array of vertices

* @param colors array of colors defining the vertices colors

*/

public Solid(Point3d[] vertices, int[] indices, Color3f[] colors)

{

this();

setData(vertices, indices, colors);

}



/**

* Constructs a solid based on a coordinates file. It contains vertices and indices,

* and its format is like this:

*

* 

4

* 
0 -5.00000000000000E-0001 -5.00000000000000E-0001 -5.00000000000000E-0001

* 
1 5.00000000000000E-0001 -5.00000000000000E-0001 -5.00000000000000E-0001

* 
2 -5.00000000000000E-0001 5.00000000000000E-0001 -5.00000000000000E-0001

* 
3 5.00000000000000E-0001 5.00000000000000E-0001 -5.00000000000000E-0001

*

* 

2

* 
0 0 2 3

* 
1 3 1 0

*

* @param solidFile file containing the solid coordinates

* @param color solid color

*/

public Solid(File solidFile, Color3f color)

{

this();

loadCoordinateFile(solidFile, color);

}



/** Sets the initial features common to all constructors */

protected void setInitialFeatures()

{

vertices = new Point3d[0];

colors = new Color3f[0];

indices = new int[0];



setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);

setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);

setCapability(Shape3D.ALLOW_APPEARANCE_READ);

}



//

GETS

//



/**

* Gets the solid vertices

*

* @return solid vertices

*/

public Point3d[] getVertices()

{

Point3d[] newVertices = new Point3d[vertices.length];

for(int i=0;i
{

newVertices = (Point3d)vertices.clone();

}

return newVertices;

}



/** Gets the solid indices for its vertices

*

* @return solid indices for its vertices

*/

public int[] getIndices()

{

int[] newIndices = new int[indices.length];

System.arraycopy(indices,0,newIndices,0,indices.length);

return newIndices;

}



/** Gets the vertices colors

*

* @return vertices colors

*/

public Color3f[] getColors()

{

Color3f[] newColors = new Color3f[colors.length];

for(int i=0;i
{

newColors = colors;

}

return newColors;

}



/**

* Gets if the solid is empty (without any vertex)

*

* @return true if the solid is empty, false otherwise

*/

public boolean isEmpty()

{

if(indices.length==0)

{

return true;

}

else

{

return false;

}

}



//

SETS

//



/**

* Sets the solid data. Each vertex may have a different color. An exception may

* occur in the case of abnormal arrays (e.g., indices making references to

* inexistent vertices, there are less colors than vertices...)

*

* @param vertices array of points defining the solid vertices

* @param indices array of indices for a array of vertices

* @param colors array of colors defining the vertices colors

*/

public void setData(Point3d[] vertices, int[] indices, Color3f[] colors)

{

this.vertices = new Point3d[vertices.length];

this.colors = new Color3f[colors.length];

this.indices = new int[indices.length];

if(indices.length!=0)

{

for(int i=0;i
{

this.vertices = (Point3d)vertices.clone();

this.colors = colors;

}

System.arraycopy(indices, 0, this.indices, 0, indices.length);



defineGeometry();

}

}



/**

* Sets the solid data. Defines the same color to all the vertices. An exception may

* may occur in the case of abnormal arrays (e.g., indices making references to

* inexistent vertices...)

*

* @param vertices array of points defining the solid vertices

* @param indices array of indices for a array of vertices

* @param color the color of the vertices (the solid color)

*/

public void setData(Point3d[] vertices, int[] indices, Color3f color)

{

Color3f[] colors = new Color3f[vertices.length];

Arrays.fill(colors, color);

setData(vertices, indices, colors);

}



//

GEOMETRICAL_TRANSFORMATIONS

//



/**

* Applies a translation into a solid

*

* @param dx translation on the x axis

* @param dy translation on the y axis

*/

public void translate(double dx, double dy, double dz)

{

if(dx!=0||dy!=0||dz!=0)

{

for(int i=0;i
{

vertices.x += dx;

vertices.y += dy;

vertices.z += dz;

}



defineGeometry();



this.dx += dx;

this.dy += dy;

this.dz += dz;

}

}



/**

* set fixed (not relative) "world" position.

* @param dx

* @param dy

* @param dz

*/

public void setLocation(double dx, double dy, double dz){

double dResX = dx - this.dx;

double dResY = dy - this.dy;

double dResZ = dz - this.dz;

translate(dResX,dResY,dResZ);

}



public void rotateDegreesX(double d){

rotateDegrees(d,0,0);

}

public void rotateDegreesY(double d){

rotateDegrees(0,d,0);

}

public void rotateDegreesZ(double d){

rotateDegrees(0,0,d);

}



private void rotateDegrees(double dx, double dy, double dz){

// if 2 axis are set >= 90, application will freeze... keep visibility private...

rotate(Math.toRadians(dx),Math.toRadians(dy),Math.toRadians(dz));

}



/**

* Applies a rotation into a solid

*

* @param dx rotation on the x axis

* @param dy rotation on the y axis

* @param dz rotation on the z axis

*/

public void rotate(double dx, double dy, double dz)

{

double cosX = Math.cos(dx);

double cosY = Math.cos(dy);

double cosZ = Math.cos(dz);

double sinX = Math.sin(dx);

double sinY = Math.sin(dy);

double sinZ = Math.sin(dz);



if(dx!=0||dy!=0||dz!=0)

{

//get mean

Point3d mean = getMean();



double newX, newY, newZ;

for(int i=0;i
{

vertices.x -= mean.x;

vertices.y -= mean.y;

vertices.z -= mean.z;



//x rotation

if(dx!=0)

{

newY = vertices.y*cosX - vertices.z*sinX;

newZ = vertices.y*sinX + vertices.z*cosX;

vertices.y = newY;

vertices.z = newZ;

}



//y rotation

if(dy!=0)

{

newX = vertices.x*cosY + vertices.z*sinY;

newZ = -vertices.x*sinY + vertices.z*cosY;

vertices.x = newX;

vertices.z = newZ;

}



//z rotation

if(dz!=0)

{

newX = vertices.x*cosZ - vertices.y*sinZ;

newY = vertices.x*sinZ + vertices.y*cosZ;

vertices.x = newX;

vertices.y = newY;

}



vertices.x += mean.x;

vertices.y += mean.y;

vertices.z += mean.z;

}

}



defineGeometry();

}



/**

* Applies a zoom into a solid

*

* @param dz translation on the z axis

*/

public void zoom(double dz)

{

if(dz!=0)

{

for(int i=0;i
{

vertices.z += dz;

}



defineGeometry();

}

}



/**

* Applies a scale changing into the solid

*

* @param dx scale changing for the x axis

* @param dy scale changing for the y axis

* @param dz scale changing for the z axis

*/

public void scale(double dx, double dy, double dz)

{

for(int i=0;i
{

vertices.x*=dx;

vertices.y*=dy;

vertices.z*=dz;

}



defineGeometry();

}



//

PRIVATES

//



/** Creates a geometry based on the indexes and vertices set for the solid */

protected void defineGeometry()

{

GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);

gi.setCoordinateIndices(indices);

gi.setCoordinates(vertices);

NormalGenerator ng = new NormalGenerator();

ng.generateNormals(gi);



gi.setColors(colors);

gi.setColorIndices(indices);

gi.recomputeIndices();



setGeometry(gi.getIndexedGeometryArray());

}



/**

* Loads a coordinates file, setting vertices and indices

*

* @param solidFile file used to create the solid

* @param color solid color

*/

protected void loadCoordinateFile(File solidFile, Color3f color)

{

try

{

BufferedReader reader = new BufferedReader(new FileReader(solidFile));



String line = reader.readLine();

int numVertices = Integer.parseInt(line);

vertices = new Point3d[numVertices];



StringTokenizer tokens;

String token;



for(int i=0;i
{

line = reader.readLine();

tokens = new StringTokenizer(line);

tokens.nextToken();

vertices= new Point3d(Double.parseDouble(tokens.nextToken()), Double.parseDouble(tokens.nextToken()), Double.parseDouble(tokens.nextToken()));

}



reader.readLine();



line = reader.readLine();

int numTriangles = Integer.parseInt(line);

indices = new int[numTriangles*3];



for(int i=0,j=0;i
{

line = reader.readLine();

tokens = new StringTokenizer(line);

tokens.nextToken();

indices = Integer.parseInt(tokens.nextToken());

indices[i+1] = Integer.parseInt(tokens.nextToken());

indices[i+2] = Integer.parseInt(tokens.nextToken());

}



colors = new Color3f[vertices.length];

Arrays.fill(colors, color);



defineGeometry();

}



catch(IOException e)

{

System.out.println("invalid file!");

e.printStackTrace();

}

}



/**

* Gets the solid mean

*

* @return point representing the mean

*/

protected Point3d getMean()

{

Point3d mean = new Point3d();

for(int i=0;i
{

mean.x += vertices.x;

mean.y += vertices.y;

mean.z += vertices.z;

}

mean.x /= vertices.length;

mean.y /= vertices.length;

mean.z /= vertices.length;



return mean;

}

}

  1. at package jme3test/unbboolean add this file:

BoolMesh.java


package jme3test.unbboolean;

import java.nio.FloatBuffer;

import java.nio.IntBuffer;



import javax.vecmath.Color3f;

import javax.vecmath.Point3d;



import jme3test.unbboolean.j3dbool.BooleanModeller;

import jme3test.unbboolean.j3dbool.Solid;



import com.jme3.math.Triangle;

import com.jme3.math.Vector3f;

import com.jme3.scene.Mesh;

import com.jme3.scene.VertexBuffer.Type;

import com.jme3.scene.mesh.IndexBuffer;

import com.jme3.util.BufferUtils;



/**

* author: teique

*/

public class BoolMesh extends Mesh {

private Solid solid;



public enum eBoolMeshOperation {

Difference,

Intersection,

Union

}



public BoolMesh(){

}



public BoolMesh(Mesh initialMesh){

this(meshToSolid(initialMesh));

}



public BoolMesh(Solid initialSolid){

setInitialSolid(initialSolid);

}



public void setInitialSolid(Solid initialSolid){

this.solid = initialSolid;

solidToThisMesh(this.solid);

}



/**

* if initial solid is null, no matter the operation, solidToBool will be used to set initial solid...

* @param e

* @param solidToBool

* @return

*/

public BoolMesh applyBooleanOperation(eBoolMeshOperation e,Solid solidToBool){

Solid solidResult = null;

if(this.solid == null){

solidResult = solidToBool;

}else{

BooleanModeller bm = new BooleanModeller(this.solid,solidToBool);

switch(e){

case Difference: solidResult = bm.getDifference(); break;

case Intersection: solidResult = bm.getIntersection(); break;

case Union: solidResult = bm.getUnion(); break;

}

}



solidToThisMesh(solidResult);

this.solid = solidResult;



return this;

}



public Solid getSolid(){

return this.solid;

}



public static Vector3f p3dToV3f(Point3d p3d){

return new Vector3f((float)p3d.x,(float)p3d.y,(float)p3d.z);

}



public static Triangle createTriangle(Point3d p3dA,Point3d p3dB,Point3d p3dC){

return new Triangle(p3dToV3f(p3dA),p3dToV3f(p3dB),p3dToV3f(p3dC));

}



private void solidToThisMesh(Solid solid) {

solidToMesh(solid, this);

}



public static Mesh solidToMesh(Solid solid) {

return solidToMesh(solid, new Mesh());

}



private static Mesh solidToMesh(Solid solid, Mesh mesh) {

//vertices

{

Point3d[] vertices = solid.getVertices();

mesh.setVertexCount(vertices.length);

msg("this.v="+vertices.length);

float[] fb = new float[vertices.length*3];

for(int i=0; i
Point3d p3d = vertices[i/3];

fb = (float)p3d.x;

fb[i+1] = (float)p3d.y;

fb[i+2] = (float)p3d.z;

}



if(mesh.getBuffer(Type.Position) != null){

mesh.getBuffer(Type.Position).updateData(

BufferUtils.createFloatBuffer(fb));

}else{

mesh.setBuffer(Type.Position,3,fb);

}



mesh.updateBound();

}



//normals

{

Point3d[] vertices = solid.getVertices();

float[] fb = new float[vertices.length*3];

//Triangle[] triangles = new Triangle[vertices.length/3];

for(int i=0; i
Vector3f normal =

createTriangle(vertices,vertices[i+1],vertices[i+2])

.getNormal();

for(int j=0; j < 9; j+:3){

fb[j] = (float)normal.x;

fb[j+1] = (float)normal.y;

fb[j+2] = (float)normal.z;

}

}



if(mesh.getBuffer(Type.Normal) != null){

mesh.getBuffer(Type.Normal).updateData(

BufferUtils.createFloatBuffer(fb));

}else{

mesh.setBuffer(Type.Normal,3,fb);

}

}



//texture coordinates UV, faked on color3f at meshToSolid()

{

Color3f[] colors = solid.getColors();

msg("this.c="+colors.length);

float[] fb = new float[colors.length*2];

for(int i=0; i
Color3f c3f = colors[i/2];

fb = (float)c3f.x;

fb[i+1] = (float)c3f.y;

}



if(mesh.getBuffer(Type.TexCoord) != null){

mesh.getBuffer(Type.TexCoord).updateData(

BufferUtils.createFloatBuffer(fb));

}else{

mesh.setBuffer(Type.TexCoord,2,fb);

}

}



//index

msg("this.i="+solid.getIndices().length);

if(mesh.getBuffer(Type.Index) != null){

mesh.getBuffer(Type.Index).updateData(

BufferUtils.createIntBuffer(solid.getIndices()));

}else{

mesh.setBuffer(Type.Index,3,solid.getIndices());

}



//TODO: colors, whatchout here, using texturecoord data... needs better integration

{

Color3f[] colors = solid.getColors();

msg("this.c="+colors.length);

float[] fb = new float[colors.length*4];

for(int i=0; i
Color3f c3f = colors[i/4];

fb = (float)c3f.x;

fb[i+1] = (float)c3f.y;

fb[i+2] = (float)c3f.z;

fb[i+3] = 1.0f;

}



if(mesh.getBuffer(Type.Color) != null){

mesh.getBuffer(Type.Color).updateData(

BufferUtils.createFloatBuffer(fb));

}else{

mesh.setBuffer(Type.Color,3,fb);

}

}



//TangentBinormalGenerator.generate(mesh); //TODO enable this? any changes?



return mesh;

}



private static void msg(String str){

//System.out.println(str);

}



public static Solid meshToSolid(Mesh mesh){

FloatBuffer fbVertex = mesh.getFloatBuffer(Type.Position);

fbVertex.compact();

Point3d[] vertices = new Point3d[fbVertex.limit()/3];

msg("v="+vertices.length);

for(int i=0; i
vertices[i/3] = new Point3d(

fbVertex.get(i),fbVertex.get(i+1),fbVertex.get(i+2));

}



FloatBuffer fbTexCoord = mesh.getFloatBuffer(Type.TexCoord);

Color3f[] colors = new Color3f[vertices.length];

if(fbTexCoord != null){

//TODO improve (extend Solid) to allow color and texture coord?

// fake texture coords into colors to make compatible with Solid

// texturecoord has only UV, x,y two values; so the 3rd at color3f is ignored...

msg("t="+fbTexCoord.limit());

assert(colors.length*2 == fbTexCoord.limit());

for(int i=0; i
colors[i/2] = new Color3f(

fbTexCoord.get(i),fbTexCoord.get(i+1),0f);

}

}else{ // has texture!!!

FloatBuffer fbColor = mesh.getFloatBuffer(Type.Color);

if(fbColor == null){ //has nothing, so create something, useless?

colors = new Color3f[vertices.length];

for(int i=0; i
colors = new Color3f(0.3f,0.3f,0.6f); //arbitrary color

}

}else{

// has colors!

fbColor.compact();

colors = new Color3f[fbColor.limit()/3];

for(int i=0; i
colors[i/3] = new Color3f(

fbColor.get(i),fbColor.get(i+1),fbColor.get(i+2));

}

}

msg("c="+colors.length);

}



IndexBuffer index = mesh.getIndexBuffer();

msg("i="+index.size());

//IntBuffer ib = BufferUtils.createIntBuffer(index.size());

IntBuffer ib = IntBuffer.wrap(new int[index.size()]);

for(int i=0; i
ib.put(index.get(i));

}

int[] indices = ib.array();



return new Solid(vertices,indices,colors);

}

}

  1. at package jme3test/unbboolean add this file:

TestBoolMesh.java


package jme3test.unbboolean;



import jme3test.unbboolean.BoolMesh.eBoolMeshOperation;

import jme3test.unbboolean.j3dbool.Solid;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Cylinder;

import com.jme3.scene.shape.Sphere;

import com.jme3.system.AppSettings;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import com.jme3.util.TangentBinormalGenerator;



/**

* author: teique

*/

public class TestBoolMesh extends SimpleApplication {



public static void main(String[] args){

TestBoolMesh app = new TestBoolMesh();

//AppSettings as = new AppSettings(true);

//as.setResolution(800,600);

//app.setSettings(as);

//app.setShowSettings(false);

app.start();

}



@Override

public void simpleInitApp() {

flyCam.setMoveSpeed(10);

//inputManager.setCursorVisible(true);



Box b = new Box(Vector3f.ZERO, 0.5f,0.5f,0.5f);

BoolMesh bm = new BoolMesh(b);

Solid solidBox = bm.getSolid();

solidBox.rotateDegreesZ(45);



Sphere s = new Sphere(9,9,0.5f);

Solid solidSphere = BoolMesh.meshToSolid(s);

solidSphere.rotateDegreesY(90);

solidSphere.translate(0.25,0,0.25);

bm.applyBooleanOperation(eBoolMeshOperation.Difference,solidSphere);



Cylinder c = new Cylinder(6,6,0.25f,0.05f,2f,true,false);

Solid solidCylinder = BoolMesh.meshToSolid(c);

solidCylinder.rotateDegreesY(90);

solidCylinder.rotateDegreesZ(-30);

solidCylinder.rotateDegreesY(60);

solidCylinder.translate(0.1,0.2,0.1);

bm.applyBooleanOperation(eBoolMeshOperation.Union,solidCylinder);



Geometry geom = new Geometry("BoolMesh", bm);



//Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/WireColor.j3md");

//mat.setColor("m_Color", ColorRGBA.Blue.multLocal(0.75f));



//Material mat = new Material(assetManager, "Common/MatDefs/Misc/SimpleTextured.j3md");

//mat.setTexture("m_ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));



//Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");



Material mat = new Material(assetManager, "Common/MatDefs/Misc/ColoredTextured.j3md");

Texture tex = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg");

tex.setWrap(WrapMode.Repeat);

mat.setTexture("m_ColorMap", tex);



geom.setMaterial(mat);



TangentBinormalGenerator.generate(geom.getMesh()); //any changes with this?



rootNode.attachChild(geom);



}



}

  1. add these jars to the project
  • j3dcore.jar
  • j3dutils.jar
  • vecmath.jar

On Ubuntu they are from these packages:

  • libjava3d-java
  • libvecmath-java

EDIT: if you see this line in the code:

for(int i=0;i= 90, application will freeze… keep visibility private…

means the “displayed code” is truncated and it wont compile if you copy/paste, but it is stored perfectly in the forum. A workaround is to quote the post, so you will get all original text in the edit box below! Just dont save, dont post it :slight_smile:











I think something went wrong with my previous post, the Solid.java code got trunked while viewing the post (but the code is all there if I try to edit it).



So I will put here the diff I created with kompare, so you can apply the the patch to Solid.java

[patch]

— …/workspace/UnbBoolean/src/unbboolean/j3dbool/Solid.java 2009-09-19 16:48:54.000000000 -0300

+++ …/workspace/Test/src/jme3test/unbboolean/j3dbool/Solid.java 2010-10-04 15:44:38.606325844 -0300

@@ -1,4 +1,4 @@

-package unbboolean.j3dbool;

+package jme3test.unbboolean.j3dbool;



import java.io.BufferedReader;

import java.io.File;

@@ -16,9 +16,15 @@

  • Class representing a 3D solid.

    *
  • @author Danilo Balby Silva Castanheira (danbalby@yahoo.com)
    • @author teique, added a few methods to rotate and position

      */

      public class Solid extends Shape3D

      {
  • // translation
  • private double dx = 0;
  • private double dy = 0;
  • private double dz = 0;

    +

    /** array of indices for the vertices from the ‘vertices’ attribute /

    protected int[] indices;

    /
    * array of points defining the solid’s vertices */

    @@ -197,34 +203,70 @@
  • @param dx translation on the x axis
  • @param dy translation on the y axis

    */
  • public void translate(double dx, double dy)
  • public void translate(double dx, double dy, double dz)

    {
  •   if(dx!=0||dy!=0)<br />
    
  •   if(dx!=0||dy!=0||dz!=0)<br />
    

{

for(int i=0;i < vertices.length;i++)

{

vertices.x += dx;

  •   		vertices<i>.y += dy;<br />
    
  •    vertices<i>.y += dy;<br />
    
  •    vertices<i>.z += dz;<br />
    

}



defineGeometry();

+

  •  this.dx += dx;<br />
    
  •  this.dy += dy;<br />
    
  •  this.dz += dz;<br />
    

}

}



/**

    • set fixed (not relative) “world” position.
    • @param dx
    • @param dy
    • @param dz
  • */
  • public void setLocation(double dx, double dy, double dz){
  • double dResX = dx - this.dx;
  • double dResY = dy - this.dy;
  • double dResZ = dz - this.dz;
  • translate(dResX,dResY,dResZ);
  • }

    +
  • public void rotateDegreesX(double d){
  • rotateDegrees(d,0,0);
  • }
  • public void rotateDegreesY(double d){
  • rotateDegrees(0,d,0);
  • }
  • public void rotateDegreesZ(double d){
  • rotateDegrees(0,0,d);
  • }

    +
  • private void rotateDegrees(double dx, double dy, double dz){
  • // if 2 axis are set >= 90, application will freeze… keep visibility private…
  • rotate(Math.toRadians(dx),Math.toRadians(dy),Math.toRadians(dz));
  • }

    +
  • /**
  • Applies a rotation into a solid

    *
  • @param dx rotation on the x axis
    • @param dy rotation on the y axis
    • @param dy rotation on the y axis
    • @param dz rotation on the z axis

      */
  • public void rotate(double dx, double dy)
  • public void rotate(double dx, double dy, double dz)

    {

    double cosX = Math.cos(dx);

    double cosY = Math.cos(dy);
  • double cosZ = Math.cos(dz);

    double sinX = Math.sin(dx);

    double sinY = Math.sin(dy);
  • double sinZ = Math.sin(dz);


  •   if(dx!=0||dy!=0)<br />
    
  •   if(dx!=0||dy!=0||dz!=0)<br />
    

{

//get mean

Point3d mean = getMean();

@@ -248,12 +290,21 @@

//y rotation

if(dy!=0)

{

  •   			newX = vertices<i>.x*cosY + vertices<i>.z*sinY;<br />
    
  •   			newX =  vertices<i>.x*cosY + vertices<i>.z*sinY;<br />
    

newZ = -vertices.xsinY + vertices.zcosY;

vertices.x = newX;

vertices.z = newZ;

}

-

+

  •    //z rotation<br />
    
  •    if(dz!=0)<br />
    
  •    {<br />
    
  •      newX =  vertices<i>.x*cosZ - vertices<i>.y*sinZ;<br />
    
  •      newY =  vertices<i>.x*sinZ + vertices<i>.y*cosZ;<br />
    
  •      vertices<i>.x = newX;<br />
    
  •      vertices<i>.y = newY;<br />
    
  •    }<br />
    

+

vertices.x += mean.x;

vertices.y += mean.y;

vertices.z += mean.z;

[/patch]

Thanks for providing this starting point, I really needed something like this since I suck as a 3d designer and therefore need to generate my shapes procedurally.



It works! As you probably know, something really bad happens to the textures in this case though – I assume the texture indeces get screwed up. I’ll see if I can do something about that.



However, as far as I can see the additional j3d jars are unnecessary, if you drop a couple of lines from Solid.java – since it doesn’t need to be a Shape3D for JMonkey. And for some reason I already have vecmath on classpath (possibly either jmonkey or jbullet use it?). In any case, here the, ahem, “j3d-independant” version:



[java]

package unbboolean.j3dbool;





import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.util.Arrays;

import java.util.StringTokenizer;

// import javax.media.j3d.Shape3D;

// import com.sun.j3d.utils.geometry.GeometryInfo;

// import com.sun.j3d.utils.geometry.NormalGenerator;

import javax.vecmath.Color3f;

import javax.vecmath.Point3d;





/**

  • Class representing a 3D solid.

    *
  • @author Danilo Balby Silva Castanheira (danbalby@yahoo.com)
  • @author teique, added a few methods to rotate and position

    /

    public class Solid // extends Shape3D

    {

    // translation

    private double dx = 0;

    private double dy = 0;

    private double dz = 0;



    /
    * array of indices for the vertices from the ‘vertices’ attribute /

    protected int[] indices;

    /
    * array of points defining the solid’s vertices /

    protected Point3d[] vertices;

    /
    * array of color defining the vertices colors */

    protected Color3f[] colors;



    //

CONSTRUCTORS
//

/** Constructs an empty solid. */
public Solid()
{
super();
setInitialFeatures();
}

/**
* Construct a solid based on data arrays. An exception may occur in the case of
* abnormal arrays (indices making references to inexistent vertices, there are less
* colors than vertices...)
*
* @param vertices array of points defining the solid vertices
* @param indices array of indices for a array of vertices
* @param colors array of colors defining the vertices colors
*/
public Solid(Point3d[] vertices, int[] indices, Color3f[] colors)
{
this();
setData(vertices, indices, colors);
}

/**
* Constructs a solid based on a coordinates file. It contains vertices and indices,
* and its format is like this:
*
* <br><br>4
* <br>0 -5.00000000000000E-0001 -5.00000000000000E-0001 -5.00000000000000E-0001
* <br>1 5.00000000000000E-0001 -5.00000000000000E-0001 -5.00000000000000E-0001
* <br>2 -5.00000000000000E-0001 5.00000000000000E-0001 -5.00000000000000E-0001
* <br>3 5.00000000000000E-0001 5.00000000000000E-0001 -5.00000000000000E-0001
*
* <br><br>2
* <br>0 0 2 3
* <br>1 3 1 0
*
* @param solidFile file containing the solid coordinates
* @param color solid color
*/
public Solid(File solidFile, Color3f color)
{
this();
loadCoordinateFile(solidFile, color);
}

/** Sets the initial features common to all constructors */
protected void setInitialFeatures()
{
vertices = new Point3d[0];
colors = new Color3f[0];
indices = new int[0];

// setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
// setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
// setCapability(Shape3D.ALLOW_APPEARANCE_READ);
}

//
GETS
//

/**
* Gets the solid vertices
*
* @return solid vertices
*/
public Point3d[] getVertices()
{
Point3d[] newVertices = new Point3d[vertices.length];
for(int i=0;i<newVertices.length;i++)
{
newVertices = (Point3d)vertices.clone();
}
return newVertices;
}

/** Gets the solid indices for its vertices
*
* @return solid indices for its vertices
*/
public int[] getIndices()
{
int[] newIndices = new int[indices.length];
System.arraycopy(indices,0,newIndices,0,indices.length);
return newIndices;
}

/** Gets the vertices colors
*
* @return vertices colors
*/
public Color3f[] getColors()
{
Color3f[] newColors = new Color3f[colors.length];
for(int i=0;i<newColors.length;i++)
{
newColors = colors;
}
return newColors;
}

/**
* Gets if the solid is empty (without any vertex)
*
* @return true if the solid is empty, false otherwise
*/
public boolean isEmpty()
{
if(indices.length==0)
{
return true;
}
else
{
return false;
}
}

//

SETS
//

/**
* Sets the solid data. Each vertex may have a different color. An exception may
* occur in the case of abnormal arrays (e.g., indices making references to
* inexistent vertices, there are less colors than vertices...)
*
* @param vertices array of points defining the solid vertices
* @param indices array of indices for a array of vertices
* @param colors array of colors defining the vertices colors
*/
public void setData(Point3d[] vertices, int[] indices, Color3f[] colors)
{
this.vertices = new Point3d[vertices.length];
this.colors = new Color3f[colors.length];
this.indices = new int[indices.length];
if(indices.length!=0)
{
for(int i=0;i<vertices.length;i++)
{
this.vertices = (Point3d)vertices.clone();
this.colors = colors;
}
System.arraycopy(indices, 0, this.indices, 0, indices.length);

defineGeometry();
}
}

/**
* Sets the solid data. Defines the same color to all the vertices. An exception may
* may occur in the case of abnormal arrays (e.g., indices making references to
* inexistent vertices...)
*
* @param vertices array of points defining the solid vertices
* @param indices array of indices for a array of vertices
* @param color the color of the vertices (the solid color)
*/
public void setData(Point3d[] vertices, int[] indices, Color3f color)
{
Color3f[] colors = new Color3f[vertices.length];
Arrays.fill(colors, color);
setData(vertices, indices, colors);
}

//

GEOMETRICAL_TRANSFORMATIONS
//

/**
* Applies a translation into a solid
*
* @param dx translation on the x axis
* @param dy translation on the y axis
*/
public void translate(double dx, double dy, double dz)
{
if(dx!=0||dy!=0||dz!=0)
{
for(int i=0;i<vertices.length;i++)
{
vertices.x += dx;
vertices.y += dy;
vertices.z += dz;
}

defineGeometry();

this.dx += dx;
this.dy += dy;
this.dz += dz;
}
}

/**
* set fixed (not relative) "world" position.
* @param dx
* @param dy
* @param dz
*/
public void setLocation(double dx, double dy, double dz){
double dResX = dx - this.dx;
double dResY = dy - this.dy;
double dResZ = dz - this.dz;
translate(dResX,dResY,dResZ);
}

public void rotateDegreesX(double d){
rotateDegrees(d,0,0);
}
public void rotateDegreesY(double d){
rotateDegrees(0,d,0);
}
public void rotateDegreesZ(double d){
rotateDegrees(0,0,d);
}

private void rotateDegrees(double dx, double dy, double dz){
// if 2 axis are set >= 90, application will freeze... keep visibility private...
rotate(Math.toRadians(dx),Math.toRadians(dy),Math.toRadians(dz));
}

/**
* Applies a rotation into a solid
*
* @param dx rotation on the x axis
* @param dy rotation on the y axis
* @param dz rotation on the z axis
*/
public void rotate(double dx, double dy, double dz)
{
double cosX = Math.cos(dx);
double cosY = Math.cos(dy);
double cosZ = Math.cos(dz);
double sinX = Math.sin(dx);
double sinY = Math.sin(dy);
double sinZ = Math.sin(dz);

if(dx!=0||dy!=0||dz!=0)
{
//get mean
Point3d mean = getMean();

double newX, newY, newZ;
for(int i=0;i<vertices.length;i++)
{
vertices.x -= mean.x;
vertices.y -= mean.y;
vertices.z -= mean.z;

//x rotation
if(dx!=0)
{
newY = vertices.y*cosX - vertices.z*sinX;
newZ = vertices.y*sinX + vertices.z*cosX;
vertices.y = newY;
vertices.z = newZ;
}

//y rotation
if(dy!=0)
{
newX = vertices.x*cosY + vertices.z*sinY;
newZ = -vertices.x*sinY + vertices.z*cosY;
vertices.x = newX;
vertices.z = newZ;
}

//z rotation
if(dz!=0)
{
newX = vertices.x*cosZ - vertices.y*sinZ;
newY = vertices.x*sinZ + vertices.y*cosZ;
vertices.x = newX;
vertices.y = newY;
}

vertices.x += mean.x;
vertices.y += mean.y;
vertices.z += mean.z;
}
}

defineGeometry();
}

/**
* Applies a zoom into a solid
*
* @param dz translation on the z axis
*/
public void zoom(double dz)
{
if(dz!=0)
{
for(int i=0;i<vertices.length;i++)
{
vertices.z += dz;
}

defineGeometry();
}
}

/**
* Applies a scale changing into the solid
*
* @param dx scale changing for the x axis
* @param dy scale changing for the y axis
* @param dz scale changing for the z axis
*/
public void scale(double dx, double dy, double dz)
{
for(int i=0;i<vertices.length;i++)
{
vertices.x*=dx;
vertices.y*=dy;
vertices.z*=dz;
}

defineGeometry();
}

//

PRIVATES
//

/** Creates a geometry based on the indexes and vertices set for the solid */
protected void defineGeometry()
{
// GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
// gi.setCoordinateIndices(indices);
// gi.setCoordinates(vertices);
// NormalGenerator ng = new NormalGenerator();
// ng.generateNormals(gi);
//
// gi.setColors(colors);
// gi.setColorIndices(indices);
// gi.recomputeIndices();
//
// setGeometry(gi.getIndexedGeometryArray());
}

/**
* Loads a coordinates file, setting vertices and indices
*
* @param solidFile file used to create the solid
* @param color solid color
*/
protected void loadCoordinateFile(File solidFile, Color3f color)
{
try
{
BufferedReader reader = new BufferedReader(new FileReader(solidFile));

String line = reader.readLine();
int numVertices = Integer.parseInt(line);
vertices = new Point3d[numVertices];

StringTokenizer tokens;
String token;

for(int i=0;i<numVertices;i++)
{
line = reader.readLine();
tokens = new StringTokenizer(line);
tokens.nextToken();
vertices= new Point3d(Double.parseDouble(tokens.nextToken()), Double.parseDouble(tokens.nextToken()), Double.parseDouble(tokens.nextToken()));
}

reader.readLine();

line = reader.readLine();
int numTriangles = Integer.parseInt(line);
indices = new int[numTriangles*3];

for(int i=0,j=0;i<numTriangles*3;i=i+3,j++)
{
line = reader.readLine();
tokens = new StringTokenizer(line);
tokens.nextToken();
indices = Integer.parseInt(tokens.nextToken());
indices[i+1] = Integer.parseInt(tokens.nextToken());
indices[i+2] = Integer.parseInt(tokens.nextToken());
}

colors = new Color3f[vertices.length];
Arrays.fill(colors, color);

defineGeometry();
}

catch(IOException e)
{
System.out.println("invalid file!");
e.printStackTrace();
}
}

/**
* Gets the solid mean
*
* @return point representing the mean
*/
protected Point3d getMean()
{
Point3d mean = new Point3d();
for(int i=0;i<vertices.length;i++)
{
mean.x += vertices.x;
mean.y += vertices.y;
mean.z += vertices.z;
}
mean.x /= vertices.length;
mean.y /= vertices.length;
mean.z /= vertices.length;

return mean;
}
}[/java]

Hi @SpacedGuy,



I cant even imagine myself creating any terrain other than proceduraly :D… I even thought on trees spreading seeds to make the vegetation dynamic, and houses/towns connecting to others with paths and roads, and all other facilities… but as usual thats too far from what I can do right now :/.



Yep, the textures are messed and I had no idea how to fix it up; If you need, Danilo may have a clue on how to fix it, and also how to improve its performance! I, unfortunately, hadnt time to look at this yet, I am waiting my vacations D:



Cool that you could remove those j3d dependencies, thx! I didnt even saw that possibility.

Btw, feel free to add yourself in the credits lines :smiley:



Also, I must add that, the new jme terrain system is very cool; and I think a few tweaks on it may let us (as a player in a running game) change the terrain (ex. with explosions that open a hole in the floor, throw debris up, and after it falls, it reintegrates into the terrain, after it stops moving/become static); I hadnt time to try those tweaks either :frowning:



Also, seeing the slow performance of bool operations, and my lack of knowledge on how to make it work faster, I created a simple “mesh adder” code (also adding static collision units to it), that using the same geometry, adds cube meshes (or spheres etc) in a orderly manner (matrix) to the geometry mesh, and this works much faster but until you reach about 1000 cubes, then it begins to slow to a crawl :frowning: (on my 1.8GHz machine).



I would still use boolean operations for precise mesh changes, like bullets hitting a wall (on a background thread calculating several changes at once), or using a knife to slice an apple!!! But… there is a major problem on this; everything that is not static wont have precise physics collision with bullet, so we get limited to the basic shapes (cubes, spheres, cylinders) and that wouldnt be cool. I still wonder how Dynamic Molecular Matter works about these stuff, but I need to research more…



After all, I would like to have more time to look at all this subject… :frowning:

Hi teique,



I am interested to know more about your code and have read through it because I may used it for my next project. However I came across this comment in your code,



private void rotateDegrees(double dx, double dy, double dz){

// if 2 axis are set >= 90, application will freeze… keep visibility private…

rotate(Math.toRadians(dx),Math.toRadians(dy),Math.toRadians(dz));

}



What do you mean by keep visibility private?

Do you have any solutions to avoid the system from this freezing problem?



Thank you.



cheers,

afifi

Hi @afifiakib!

public void rotateDegreesX(double d){

rotateDegrees(d,0,0);

}

public void rotateDegreesY(double d){

rotateDegrees(0,d,0);

}

public void rotateDegreesZ(double d){

rotateDegrees(0,0,d);

}

private void rotateDegrees(double dx, double dy, double dz){

// if 2 axis are set >= 90, application will freeze… keep visibility private…

rotate(Math.toRadians(dx),Math.toRadians(dy),Math.toRadians(dz));

}



EDIT: the private visibility is about the method, should not be called directly, instead use the public ones



Note that, you must use the public ones, to avoid using the private one; because if you misuse it, by by setting two of its parameters to a value greater than 90, it will freeze the application. It just happened to me, I dont know why, and the workaround I found was to create the isolated rotation ones;

In other words, if you find a good workaround, I would like to see it.

And if you improve this code it would be cool if you post it back here :D.

I dont understand most of the code that was implemented for the bool operations, I just created the JME interface. I would really like to use an improved version of it some day! For now I have ideas of only using it for minor/simple mesh modifications, like precisely cutting a tree down (in background).

Also, the texture problem after you modify a mesh is still present. I have no idea how to fix it :>, and I would really like… and so on, you can guess :D.

Hi Teique,



I am glad to inform that we have managed to solve the above issue and one more problem that arise while we are working with this library. The problems are:

  1. Not only with 90 deg, but the same problem arise with 180 deg and 270 deg as well, the program will go to freeze (actually it is an infinite loop).
  2. When performing intersection method, for every intersection method called, the total number of vertices is increase in a newly produced solid that lead to Java heap space problem (memory constraint).



    Solutions for the problems above are:
  3. The problem is actually with the decimal places of vertex coordinate system. We need to somehow round it off to nearest decimal number because somehow this program cannot accept the decimal places. For eg. 17.33 round off become 17 and cast it back to double become 17.0. In this way, it should work.
  4. Java heap space need to be increase as well as the perm space. This can be done by configuring the setting of your Eclipse or NetBeans or etc.
  5. If there is any condition that possible for having the infinite loop, the ‘escape’ function is enable (unmask) in Object3D class as shown below.



    [java]//prevent from infinite loop (with a loss of faces…)

    if(numFacesStart*20 <getNumFaces())

    {

    return;

    }[[/java]





    cheers,

    afifiakib

    thasprabu r.



    Solid.java



    package newBoolean;



    [java]import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileReader;

    import java.io.IOException;

    import java.io.Serializable;

    import java.util.Arrays;

    import java.util.StringTokenizer;

    import javax.media.j3d.Shape3D;

    import javax.vecmath.Color3f;

    import javax.vecmath.Point3d;

    import com.sun.j3d.utils.geometry.GeometryInfo;

    import com.sun.j3d.utils.geometry.NormalGenerator;



    /**
  • Class representing a 3D solid.

    *
  • @author Danilo Balby Silva Castanheira (danbalby@yahoo.com)

    /

    public class Solid extends Shape3D implements Serializable

    {

    /
    * array of indices for the vertices from the ‘vertices’ attribute /

    protected int[] indices;

    /
    * array of points defining the solid’s vertices /

    protected Point3d[] vertices;

    /
    * array of color defining the vertices colors */

    protected Color3f[] colors;



    //

CONSTRUCTORS
xs
//

/** Constructs an empty solid. */
public Solid()
{
super();
setInitialFeatures();
}

/**
* Construct a solid based on data arrays. An exception may occur in the case of
* abnormal arrays (indices making references to inexistent vertices, there are less
* colors than vertices...)
*
* @param vertices array of points defining the solid vertices
* @param indices array of indices for a array of vertices
* @param colors array of colors defining the vertices colors
*/
public Solid(Point3d[] vertices, int[] indices, Color3f[] colors)
{
this();
setData(vertices, indices, colors);
}
public Solid(Point3d[] vertices, int[] indices, Color3f color)
{
this();
setDataSolid(vertices, indices, color);
}

/**
* Constructs a solid based on a coordinates file. It contains vertices and indices,
* and its format is like this:
*
* <br><br>4
* <br>0 -5.00000000000000E-0001 -5.00000000000000E-0001 -5.00000000000000E-0001
* <br>1 5.00000000000000E-0001 -5.00000000000000E-0001 -5.00000000000000E-0001
* <br>2 -5.00000000000000E-0001 5.00000000000000E-0001 -5.00000000000000E-0001
* <br>3 5.00000000000000E-0001 5.00000000000000E-0001 -5.00000000000000E-0001
*
* <br><br>2
* <br>0 0 2 3
* <br>1 3 1 0
*
* @param solidFile file containing the solid coordinates
* @param color solid color
*/
public Solid(File solidFile, Color3f color)
{
this();
loadCoordinateFile(solidFile, color);
}

/** Sets the initial features common to all constructors */
protected void setInitialFeatures()
{
vertices = new Point3d[0];
colors = new Color3f[0];
indices = new int[0];

setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
setCapability(Shape3D.ALLOW_APPEARANCE_READ);
}

//
GETS
//

/**
* Gets the solid vertices
*
* @return solid vertices
*/
public Point3d[] getVertices()
{
Point3d[] newVertices = new Point3d[vertices.length];
for(int i=0;i<newVertices.length;i++)
{
newVertices = (Point3d)vertices.clone();
}
return newVertices;
}

/** Gets the solid indices for its vertices
*
* @return solid indices for its vertices
*/
public int[] getIndices()
{
int[] newIndices = new int[indices.length];
System.arraycopy(indices,0,newIndices,0,indices.length);
return newIndices;
}

/** Gets the vertices colors
*
* @return vertices colors
*/
public Color3f[] getColors()
{
Color3f[] newColors = new Color3f[colors.length];
for(int i=0;i<newColors.length;i++)
{
newColors = colors;
}
return newColors;
}

/**
* Gets if the solid is empty (without any vertex)
*
* @return true if the solid is empty, false otherwise
*/
public boolean isEmpty()
{
if(indices.length==0)
{
return true;
}
else
{
return false;
}
}

//

SETS
//

/**
* Sets the solid data. Each vertex may have a different color. An exception may
* occur in the case of abnormal arrays (e.g., indices making references to
* inexistent vertices, there are less colors than vertices...)
*
* @param vertices array of points defining the solid vertices
* @param indices array of indices for a array of vertices
* @param colors array of colors defining the vertices colors
*/
public void setData(Point3d[] vertices, int[] indices, Color3f[] colors)
{
this.vertices = new Point3d[vertices.length];
this.colors = new Color3f[colors.length];
this.indices = new int[indices.length];
if(indices.length!=0)
{
for(int i=0;i<vertices.length;i++)
{
this.vertices = (Point3d)vertices.clone();
this.colors = colors;
}
System.arraycopy(indices, 0, this.indices, 0, indices.length);

defineGeometry();
}
}

/**
* Sets the solid data. Defines the same color to all the vertices. An exception may
* may occur in the case of abnormal arrays (e.g., indices making references to
* inexistent vertices...)
*
* @param vertices array of points defining the solid vertices
* @param indices array of indices for a array of vertices
* @param color the color of the vertices (the solid color)
*/
public void setDataSolid(Point3d[] vertices, int[] indices, Color3f color)
{
Color3f[] colors = new Color3f[vertices.length];
Arrays.fill(colors, color);
setData(vertices, indices, colors);
}

//

GEOMETRICAL_TRANSFORMATIONS
//

/**
* Applies a translation into a solid
*
* @param dx translation on the x axis
* @param dy translation on the y axis
*/
public void translate(double dx, double dy)
{
if(dx!=0||dy!=0)
{
for(int i=0;i<vertices.length;i++)
{
vertices.x += dx;
vertices.y += dy;
}

defineGeometry();
}
}

public void translate(double dx, double dy, double dz)
{
if(dx!=0||dy!=0)
{
for(int i=0;i<vertices.length;i++)
{
vertices.x += (double)Math.round(dx);
vertices.y += (double)Math.round(dy);
vertices.z += (double)Math.round(dz);
}

defineGeometry();
}


}

/**
* Applies a rotation into a solid
*
* @param dx rotation on the x axis
* @param dy rotation on the y axis
*/


public void rotate(double dx, double dy)
{

double cosX = Math.cos(dx);
double cosY = Math.cos(dy);
double sinX = Math.sin(dx);
double sinY = Math.sin(dy);

if(dx!=0||dy!=0)
{
//get mean
Point3d mean = getMean();

double newX, newY, newZ;
for(int i=0;i<vertices.length;i++)
{
vertices.x -= mean.x;
vertices.y -= mean.y;
vertices.z -= mean.z;

//x rotation
if(dx!=0)
{
newY = vertices.y*cosX - vertices.z*sinX;
newZ = vertices.y*sinX + vertices.z*cosX;
vertices.y = newY;
vertices.z = newZ;
}

//y rotation
if(dy!=0)
{
newX = vertices.x*cosY + vertices.z*sinY;
newZ = -vertices.x*sinY + vertices.z*cosY;
vertices.x = newX;
vertices.z = newZ;
}

vertices.x += mean.x;
vertices.y += mean.y;
vertices.z += mean.z;
}
}

defineGeometry();
}



public void rotate(double dx, double dy, double dz)
{



double cosX = Math.cos(dx);
double cosY = Math.cos(dy);
double cosZ = Math.cos(dz);

double sinX = Math.sin(dx);
double sinY = Math.sin(dy);
double sinZ = Math.sin(dz);


if(dx!=0||dy!=0 ||dz!=0)
{
//get mean
Point3d mean = getMean();

double newX, newY, newZ;
for(int i=0;i<vertices.length;i++)
{
vertices.x -= (double)Math.round( mean.x);
vertices.y -= (double)Math.round( mean.y);
vertices.z -= (double)Math.round( mean.z);

//x rotation
if(dx!=0)
{
newY = vertices.y*cosX - vertices.z*sinX;
newZ = vertices.y*sinX + vertices.z*cosX;
vertices.y = (double)Math.round(newY);
vertices.z = (double)Math.round(newZ);
}

//y rotation
if(dy!=0)
{
newX = vertices.x*cosY + vertices.z*sinY;
newZ = -vertices.x*sinY + vertices.z*cosY;
vertices.x = (double)Math.round(newX);
vertices.z = (double) Math.round(newZ);
}
//z rotation
if(dz!=0)
{
newX = vertices.x*cosZ + vertices.y*sinZ;
newY = -vertices.x*sinZ + vertices.y*cosZ;
vertices.x = (double)Math.round(newX);
vertices.y = (double)Math.round(newY);
}

vertices.x += mean.x;
vertices.y += mean.y;
vertices.z += mean.z;
}
}

defineGeometry();
}

/**
* Applies a zoom into a solid
*
* @param dz translation on the z axis
*/
public void zoom(double dz)
{
if(dz!=0)
{
for(int i=0;i<vertices.length;i++)
{
vertices.z += dz;
}

defineGeometry();
}
}

/**
* Applies a scale changing into the solid
*
* @param dx scale changing for the x axis
* @param dy scale changing for the y axis
* @param dz scale changing for the z axis
*/
public void scale(double dx, double dy, double dz)
{
for(int i=0;i<vertices.length;i++)
{
vertices.x*=(double)Math.round(dx);
vertices.y*=(double)Math.round(dy);
vertices.z*=(double)Math.round(dz);
}

defineGeometry();
}

//

PRIVATES
//

/** Creates a geometry based on the indexes and vertices set for the solid */
protected void defineGeometry()
{
GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
gi.setCoordinateIndices(indices);
gi.setCoordinates(vertices);
NormalGenerator ng = new NormalGenerator();
ng.generateNormals(gi);

gi.setColors(colors);
gi.setColorIndices(indices);
gi.recomputeIndices();

setGeometry(gi.getIndexedGeometryArray());
}



/**
* Loads a coordinates file, setting vertices and indices
*
* @param solidFile file used to create the solid
* @param color solid color
*/
protected void loadCoordinateFile(File solidFile, Color3f color)
{
try
{
BufferedReader reader = new BufferedReader(new FileReader(solidFile));

String line = reader.readLine();
int numVertices = Integer.parseInt(line);
vertices = new Point3d[numVertices];

StringTokenizer tokens;
String token;

for(int i=0;i<numVertices;i++)
{
line = reader.readLine();
tokens = new StringTokenizer(line);
tokens.nextToken();
vertices= new Point3d(Double.parseDouble(tokens.nextToken()), Double.parseDouble(tokens.nextToken()), Double.parseDouble(tokens.nextToken()));
}

reader.readLine();

line = reader.readLine();
int numTriangles = Integer.parseInt(line);
indices = new int[numTriangles*3];

for(int i=0,j=0;i<numTriangles*3;i=i+3,j++)
{
line = reader.readLine();
tokens = new StringTokenizer(line);
tokens.nextToken();
indices = Integer.parseInt(tokens.nextToken());
indices[i+1] = Integer.parseInt(tokens.nextToken());
indices[i+2] = Integer.parseInt(tokens.nextToken());
}

colors = new Color3f[vertices.length];
Arrays.fill(colors, color);

defineGeometry();
}

catch(IOException e)
{
e.printStackTrace();
}
}

/**
* Gets the solid mean
*
* @return point representing the mean
*/
protected Point3d getMean()
{
Point3d mean = new Point3d();
for(int i=0;i<vertices.length;i++)
{
mean.x += vertices.x;
mean.y += vertices.y;
mean.z += vertices.z;
}
mean.x /= vertices.length;
mean.y /= vertices.length;
mean.z /= vertices.length;

return mean;
}
}[/java]

Hi @afifiakib!

.

I would check again the original Solid.java created by Danilo.

I tested it again with this ex.:

solid.rotate(Math.toRadians(180),Math.toRadians(150),Math.toRadians(-30));

and many other tests, and nothing wrong happened!

I think the updated libraries that it uses, are working better than before, needing no workarounds!

.

Btw, have someone found a way to fix the textures? it is still messed :frowning:

Hi !

I am new on JME developpement, i have to creat a house from XML data. I would use the CSG to build wall with windows and door… I installed your Lib but i got an error when i try to use your test class :

[java]GRAVE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.UnsupportedOperationException: Deprecated

at com.jme3.scene.Mesh.setVertexCount(Mesh.java:429)

at unbboolean.j3dbool.BoolMesh.solidToMesh(BoolMesh.java:101)

at unbboolean.j3dbool.BoolMesh.solidToThisMesh(BoolMesh.java:89)

at unbboolean.j3dbool.BoolMesh.setInitialSolid(BoolMesh.java:48)

at unbboolean.j3dbool.BoolMesh.<init>(BoolMesh.java:43)

at unbboolean.j3dbool.BoolMesh.<init>(BoolMesh.java:39)

at unbboolean.j3dbool.TestBoolMesh.simpleInitApp(TestBoolMesh.java:43)

at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:218)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:138)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:206)

at java.lang.Thread.run(Thread.java:662)[/java]



Anyone can help me ? And what about the texture issue ?

Or exist it an other solution to do a boolean difference between to mesh ?



Guillaume

There have been changes to the mesh API since this was posted, so this would need to be updated before it could be made to work…



Commit in question: http://code.google.com/p/jmonkeyengine/source/detail?r=6893

Yes i saw the fonction is deprecated, but i dont understand how to replace it … It says to use updateCounts() after update of buffer. But what type of buffer we need to use? mesh.setBuffer(Type, components, null); arguments arent so comprehensible for me:x

Ty for your prompt answer

Just remove those calls and call updateCounts() after setting the buffers, you don’t need to change anything else

yes but i don’t know how to set this buffer ? and which buffer ?:confused:

the method mesh.setbuffer? with which arg ? i am sorry, i am totally lost, i searched about setbuffer(vertexbuffer vb) but it doesn’t work…

Step 1) Remove the calls setVertexCount(), setTriangleCount() from the code.

Step 2) Call updateCounts() on the same mesh object that the above calls were used on, but put it at the end of the method

Ok thanks, i havent found “setTriangleCount” method in the code, but it works with the call “mesh.updateCounts()” at the end of the method.

I confirm the last post of @teique the old methode rotateDegrees(x,y,z) works now even with 2+ axes increment of 90+ degrees. I fix a little issue about translation solid::translate(double dx, double dy, double dz), we need to edit the test if(dx!=0||dy!=0) to if(dx!=0||dy!=0||dz!=0) else the rotation of unique Z axe doesn’t work.



Does anyone looked the texture issue?

EDIT: ugh… UnBBoolean seems to be public domain now at sourceforge :slight_smile:

I have made a statement here http://hub.jmonkeyengine.org/forum/topic/boolmesh-java-boolean-operations-on-mesh/#post-114857
that is WRONG. The unbboolean it NOT public domain, it is GPL, therefore it CANNOT be used on a closed source proprietary project. I dont know if it is possible to ask the author to make it available for proprietary project or if he could only grant specific permissions for each project individually (if this is ever allowed anyway).

I am unable to fix that post, it is uneditable.

And… has anyone fixed the texture issue?

PS.: btw, I just found this other that is GPL too: http://sourceforge.net/projects/graxml/files/HEP3D/1.2.0/

I’ve actually already done an implementation of CSG in JMonkeyEngine. You can find it here:

1 Like

Just git cloned, cant wait to try it!

Btw, I am not sure but I believe it may be easy to create a JmonkeySDK plugin making it more popular like this one http://hub.jmonkeyengine.org/forum/topic/image-painter-plugin-available/

Cant wait for the upcoming features heh, thx!

PS.: I didnt even know what CSG was! www.leadwerks.com/files/csg.pdf, doom3 uses CSG too!!! and doom3 rocks! (TheDarkProject)

Offtopic.: haha this http://raptjs.com/play/#/rapt/Intro_1/ is very fun indeed (playing with my two hands haha)

@Fabian

based on your test, and using jmonkey testdata lib, I tried this:

(unable to use code tag…)

public void simpleInitApp() { float fHalfSize = 0.25f; CSG a = new CubeBrush(new Vector3f(-fHalfSize, -fHalfSize, -fHalfSize), new Vector3f(1f, 1f, 1f)); CSG b = new SphereBrush(new Vector3f(fHalfSize, fHalfSize, fHalfSize), 1.3f, 16, 8);
//CSG boxOut = a.subtract(b);
CSG boxOut = a.subtract(b.inverse());
//CSG boxOut = a.union(b);
//CSG boxOut = a.union(b.inverse());
		
Mesh mesh = boxOut.toMesh();
	
Geometry geom = new Geometry("CSG", mesh);

    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/splat/road.jpg"));
    geom.setMaterial(mat);

    rootNode.attachChild(geom);
}

but the sphere part did not show the texture (in any of the 4 tests I tried), any idea?