JaRMoS  1.1
Java Reduced Model Simulations
 All Classes Namespaces Files Functions Variables Enumerator Groups Pages
GeometryData.java
Go to the documentation of this file.
1 package jarmos.geometry;
2 
3 import jarmos.Log;
4 import jarmos.ModelType;
7 
8 import java.io.BufferedReader;
9 import java.io.IOException;
10 import java.util.List;
11 
24 public class GeometryData {
25 
26  public float boxsize; // bounding box size
27 
28  // /**
29  // * Contains the number of nodes whose values are given by dirichlet values.
30  // */
31  // public short[] dir_nodes = null;
32  //
33  // /**
34  // * The dirichlet values for the dir_nodes. The first index is the number of the field the value is dirichlet for,
35  // * and the second index denotes x,y and z offsets from original positions defined in node.
36  // */
37  // public float[][] dir_values = null;
38 
42  private int[] domain_of_face;
43 
47  public short[] edges; // edge data
48 
52  public short[] faces; // face data
53 
60  public short[] faceWireframe;
61 
65  public float[][] fnormal;
66 
70  private boolean is2D = true;
71 
75  public float[] nminmax = { 1e9f, 1e9f, 1e9f, -1e9f, -1e9f, -1e9f };
76 
80  public float[][] normal;
81 
85  public int numFaces;
86 
90  private int numOrigVertices;
91 
96  public float[] originalVertices;
97 
101  @SuppressWarnings("unused")
102  private int subdomains;
103 
107  public int[] vertexLTFuncNr;
108 
112  private float[][] vertices = null; // vertex data
113 
123  public void addDisplacements(DisplacementField d, int parts) {
124  float scaling = 1f;// (d.getMax() - d.getMin()) / boxsize;
125  Log.d("GeoData", "Adding displacements from " + d.descriptor + ", numVertices=" + numOrigVertices
126  + ", vertices field length=" + vertices.length + ", displacement field size=" + d.getSize() + " (x3="
127  + d.getSize() * 3 + "), parts=" + parts);
128  for (int vset = 0; vset < parts; vset++) {
129  for (int nodenr = 0; nodenr < numOrigVertices; nodenr++) {
130  int idx = vset * numOrigVertices + nodenr;
131  vertices[vset][3 * nodenr] += d.getXDisplacements()[idx] / scaling;
132  vertices[vset][3 * nodenr + 1] += d.getYDisplacements()[idx] / scaling;
133  vertices[vset][3 * nodenr + 2] += d.getZDisplacements()[idx] / scaling;
134  }
135  }
136  compute3DNormalData();
137  centerModelGeometry();
138  }
139 
143  private void centerModelGeometry() {
144  computeBoundingBox();
145  float xcen = 0.5f * (nminmax[0] + nminmax[3]);
146  float ycen = 0.5f * (nminmax[1] + nminmax[4]);
147  float zcen = 0.5f * (nminmax[2] + nminmax[5]);
148  for (int vset = 0; vset < vertices.length; vset++) {
149  for (int i = 0; i < vertices[vset].length / 3; i++) {
150  vertices[vset][i * 3 + 0] -= xcen;
151  vertices[vset][i * 3 + 1] -= ycen;
152  vertices[vset][i * 3 + 2] -= zcen;
153  }
154  }
155  // recalculating minmax box
156  nminmax[0] -= xcen;
157  nminmax[3] += xcen;
158  nminmax[1] -= ycen;
159  nminmax[4] += ycen;
160  nminmax[2] -= zcen;
161  nminmax[5] += zcen;
162  }
163 
167  private void compute3DNormalData() {
168  normal = new float[vertices.length][];
169  fnormal = new float[vertices.length][];
170  for (int vset = 0; vset < vertices.length; vset++) {
171  float[] normal_ = new float[numOrigVertices * 3];
172  float[] fnormal_ = new float[numFaces * 3];
173  float[] vecAB = new float[3];
174  float[] vecAC = new float[3];
175  int i, j, k;
176  float length;
177  // Initialize normal data and contribution flag
178  int[] icount = new int[numOrigVertices];
179  for (i = 0; i < numOrigVertices; i++) {
180  normal_[i * 3 + 0] = 0.0f;
181  normal_[i * 3 + 1] = 0.0f;
182  normal_[i * 3 + 2] = 0.0f;
183  icount[i] = 0;
184  }
185  // calculate local face normal
186  for (i = 0; i < numFaces; i++) {
187  for (j = 0; j < 3; j++) {
188  vecAB[j] = vertices[vset][faces[i * 3 + 1] * 3 + j] - vertices[vset][faces[i * 3 + 0] * 3 + j];
189  vecAC[j] = vertices[vset][faces[i * 3 + 2] * 3 + j] - vertices[vset][faces[i * 3 + 0] * 3 + j];
190  }
191  // normal of the face is the cross product of AB and AC
192  fnormal_[i * 3 + 0] = vecAB[1] * vecAC[2] - vecAB[2] * vecAC[1];
193  fnormal_[i * 3 + 1] = vecAB[2] * vecAC[0] - vecAB[0] * vecAC[2];
194  fnormal_[i * 3 + 2] = vecAB[0] * vecAC[1] - vecAB[1] * vecAC[0];
195  // normalize
196  length = (float) Math.sqrt((fnormal_[i * 3 + 0] * fnormal_[i * 3 + 0] + fnormal_[i * 3 + 1]
197  * fnormal_[i * 3 + 1] + fnormal_[i * 3 + 2] * fnormal_[i * 3 + 2]));
198  for (j = 0; j < 3; j++)
199  fnormal_[i * 3 + j] = fnormal_[i * 3 + j] / length;
200  // add in contribution to all three vertices
201  for (j = 0; j < 3; j++) {
202  icount[faces[i * 3 + j]]++;
203  for (k = 0; k < 3; k++)
204  normal_[faces[i * 3 + j] * 3 + k] += fnormal_[i * 3 + k];
205  }
206  }
207  // average and normal_ize all normal_ vectors
208  for (i = 0; i < numOrigVertices; i++) {
209  for (j = 0; j < 3; j++)
210  normal_[i * 3 + j] = normal_[i * 3 + j] / icount[i];
211  length = (float) Math.sqrt((normal_[i * 3 + 0] * normal_[i * 3 + 0] + normal_[i * 3 + 1]
212  * normal_[i * 3 + 1] + normal_[i * 3 + 2] * normal_[i * 3 + 2]));
213  for (j = 0; j < 3; j++)
214  normal_[i * 3 + j] = normal_[i * 3 + j] / length;
215  }
216  normal[vset] = normal_;
217  fnormal[vset] = fnormal_;
218  }
219  }
220 
224  private void computeBoundingBox() {
225  nminmax[0] = 1e9f;
226  nminmax[1] = 1e9f;
227  nminmax[2] = 1e9f;
228  nminmax[3] = -1e9f;
229  nminmax[4] = -1e9f;
230  nminmax[5] = -1e9f;
231  for (int vset = 0; vset < vertices.length; vset++) {
232  for (int i = 0; i < vertices[vset].length / 3; i++) {
233  for (int j = 0; j < 3; j++) {
234  nminmax[0 + j] = (nminmax[0 + j] > vertices[vset][i * 3 + j]) ? vertices[vset][i * 3 + j]
235  : nminmax[0 + j];
236  nminmax[3 + j] = (nminmax[3 + j] < vertices[vset][i * 3 + j]) ? vertices[vset][i * 3 + j]
237  : nminmax[3 + j];
238  }
239  }
240  }
241 
242  boxsize = 0.0f;
243  boxsize = (nminmax[3] - nminmax[0]) > boxsize ? (nminmax[3] - nminmax[0]) : boxsize;
244  boxsize = (nminmax[4] - nminmax[1]) > boxsize ? (nminmax[4] - nminmax[1]) : boxsize;
245  boxsize = (nminmax[5] - nminmax[2]) > boxsize ? (nminmax[5] - nminmax[2]) : boxsize;
246  }
247 
254  public void createMesh(List<MeshTransform> transforms, boolean update) {
255  vertices = new float[transforms.size()][];
256  int cnt = 0;
257  // Log.d("GeoData", "Original : " + Log.subArr(originalVertices,100));
258  for (MeshTransform m : transforms) {
259  vertices[cnt++] = m.transformMesh(originalVertices);
260  // Log.d("GeoData", "Transform "+cnt+": " +
261  // Log.subArr(vertices[cnt-1],100)+" ("+m.getClass().getName()+")");
262  // float[] diff = new float[200];
263  // for (int i=0; i < 200;i++) {
264  // diff[i] = originalVertices[i] - vertices[cnt-1][i];
265  // }
266  // Log.d("GeoData", "Diff "+cnt+": " + Log.subArr(diff,200));
267  }
268  if (update) {
269  if (!is2D) {
270  compute3DNormalData();
271  }
272  centerModelGeometry();
273  }
274  }
275 
281  public int getNumVertices() {
282  return numOrigVertices;
283  }
284 
285  public float[][] getVertices() {
286  return vertices;
287  }
288 
292  public boolean is2D() {
293  return is2D;
294  }
295 
302  private void loadGeometry(AModelManager m) throws IOException {
303 
305  originalVertices = mr.readRawFloatVector(m.getInStream("vertices.bin"));
306  Log.d("GeoData", "Loaded " + originalVertices.length + " vertex values");
307 
308  /*
309  * Assume the vector to contain 3D data. If we have 2D data, we insert zeros at every 3rd position!
310  */
311  is2D = false;
312  if ("2".equals(m.getModelXMLTagValue("geometry.dimension"))) {
313  is2D = true;
314  float[] tmpnode = new float[originalVertices.length + originalVertices.length / 2];
315  for (int i = 0; i < originalVertices.length / 2; i++) {
316  tmpnode[3 * i] = originalVertices[2 * i];
317  tmpnode[3 * i + 1] = originalVertices[2 * i + 1];
318  tmpnode[3 * i + 2] = 0;
319  }
320  originalVertices = tmpnode;
321  tmpnode = null;
322  Log.d("GeoData", "2D geometry - extending vertex data to 3rd dimension (zeros) to total number of "
323  + originalVertices.length + " values");
324  }
325  // Three coordinates per node
326  numOrigVertices = originalVertices.length / 3;
327  Log.d("GeoData", "Loaded " + numOrigVertices + " vertices");
328  // Only one transformation function for JRB models if any
329  vertexLTFuncNr = new int[numOrigVertices];
330 
331  faces = null;
332  if (m.modelFileExists("faces.bin") // check included for backwards
333  // compatibility.
334  || m.xmlTagExists("geometry.hasFaces")
335  && Boolean.parseBoolean(m.getModelXMLTagValue("geometry.hasFaces"))) {
336  faces = mr.readRawShortVector(m.getInStream("faces.bin"));
337  // Subtract the indices, as the nodes are addressed with zero offset
338  // inside java arrays
339  for (int i = 0; i < faces.length; i++) {
340  faces[i] -= 1;
341  }
342  // Three edges per face
343  numFaces = faces.length / 3;
344  Log.d("GeoData", "Loaded " + numFaces + " faces");
345  domain_of_face = new int[numFaces];
346  }
347 
348  edges = null;
349  if (m.modelFileExists("edges.bin")) {
350  edges = mr.readRawShortVector(m.getInStream("edges.bin"));
351  }
352 
353  // dir_nodes = null;
354  // if (m.modelFileExists("dir_nodes.bin")) {
355  // dir_nodes = mr.readRawShortVector(m.getInStream("dir_nodes.bin"));
356  // }
357  }
358 
365  public boolean loadModelGeometry(AModelManager m) {
366 
367  try {
368  // rb model or rbappmit-type model with new geometry
369  if (m.getModelType() == ModelType.JRB || m.getModelType() == ModelType.JKerMor) {
370  loadGeometry(m);
371  } else if (m.getModelType() == ModelType.rbappmit) {
372  loadrbappmitGeometry(m);
373  } else {
374  Log.e("GeometryData", "Unknown model type '" + m.getModelType() + "' for use with GeometryData");
375  return false;
376  }
377  } catch (IOException e) {
378  Log.e("GeometryData", "Loading model geometry failed: " + e.getMessage(), e);
379  return false;
380  }
381 
382  /*
383  * Create a wireframe list (edge data)
384  */
385  faceWireframe = new short[numFaces * 3 * 2];
386  for (int i = 0; i < numFaces; i++) {
387  faceWireframe[i * 6 + 0 * 2 + 0] = faces[i * 3 + 0];
388  faceWireframe[i * 6 + 0 * 2 + 1] = faces[i * 3 + 1];
389  faceWireframe[i * 6 + 1 * 2 + 0] = faces[i * 3 + 1];
390  faceWireframe[i * 6 + 1 * 2 + 1] = faces[i * 3 + 2];
391  faceWireframe[i * 6 + 2 * 2 + 0] = faces[i * 3 + 2];
392  faceWireframe[i * 6 + 2 * 2 + 1] = faces[i * 3 + 0];
393  }
394  return true;
395  }
396 
403  private void loadrbappmitGeometry(AModelManager m) throws IOException {
404  String[] tokens = null;
405  BufferedReader reader = m.getBufReader("geometry.dat");
406  try {
407  tokens = reader.readLine().split(" ");
408  } finally {
409  reader.close();
410  }
411 
415  numOrigVertices = Integer.parseInt(tokens[0]);
416  int count = 1;
417  originalVertices = new float[numOrigVertices * 3];
418  for (int i = 0; i < numOrigVertices; i++) {
419  originalVertices[i * 3 + 0] = Float.parseFloat(tokens[count]);
420  originalVertices[i * 3 + 1] = Float.parseFloat(tokens[count + 1]);
421  originalVertices[i * 3 + 2] = Float.parseFloat(tokens[count + 2]);
422  count += 3;
423  }
424  // Manually check if geometry is 2D
425  is2D = true;
426  for (int i = 0; i < numOrigVertices; i++) {
427  is2D &= originalVertices[i * 3 + 2] == 0;
428  }
429 
433  subdomains = Integer.parseInt(tokens[count]);
434  numFaces = Integer.parseInt(tokens[count + 1]);
435  count += 2;
436  faces = new short[numFaces * 3];
437  for (int i = 0; i < numFaces; i++) {
438  faces[i * 3 + 0] = Short.parseShort(tokens[count]);
439  faces[i * 3 + 1] = Short.parseShort(tokens[count + 1]);
440  faces[i * 3 + 2] = Short.parseShort(tokens[count + 2]);
441  count += 3;
442  }
447  vertexLTFuncNr = new int[numOrigVertices];
448  for (int i = 0; i < numOrigVertices; i++) {
449  vertexLTFuncNr[i] = Integer.parseInt(tokens[count]);
450  count++;
451  }
452  domain_of_face = new int[numFaces];
453  for (int i = 0; i < numFaces; i++) {
454  domain_of_face[i] = Integer.parseInt(tokens[count]);
455  count++;
456  }
457  // No edges for rbappmit-models (new feature)
458  edges = null;
459  }
460 
461  // /**
462  // * Applies Affine Linear Transformation To Vertices
463  // *
464  // * @param afflinfuncs
465  // */
466  // public void applyAffLinVertexTransformation(float[][][] afflinfuncs) {
467  // Log.d("GeoData", "Applying affine linear transformation to nodes (" +
468  // afflinfuncs.length + " sets/frames)");
469  // vertices = new float[afflinfuncs.length * numVertices * 3];
470  // float baseX, baseY, baseZ;
471  // for (int funcSetNr = 0; funcSetNr < afflinfuncs.length; funcSetNr++) {
472  // float[][] funcSet = afflinfuncs[funcSetNr];
473  // /**
474  // * Affine-linear transformation of a node to a new position. Uses
475  // * the reference nodes and the LTfunc (linear transform function) to
476  // * move the nodes to the specified location.
477  // *
478  // * The crack in a pillar demo illustrates the use of this.
479  // *
480  // * func is of size [number of subdomain, 12] a row of LTfunc is the
481  // * rowwise flatten of the [3,3] transformation matrix and the [3,1]
482  // * translation vector
483  // *
484  // * Copies the current nodal data into vertex list (flattened out)
485  // */
486  // for (int vertexNr = 0; vertexNr < numVertices; vertexNr++) {
487  // baseX = originalVertices[vertexNr * 3 + 0];
488  // baseY = originalVertices[vertexNr * 3 + 1];
489  // baseZ = originalVertices[vertexNr * 3 + 2];
490  // /*
491  // * Get transformation function for this vertex (possibly due to
492  // * different functions on different subdomains)
493  // */
494  // float[] fun = funcSet[vertexLTFuncNr[vertexNr]];
495  // /*
496  // * Apply affine linear transformation
497  // */
498  // vertices[funcSetNr * numVertices * 3 + vertexNr * 3 + 0] = fun[0] * baseX
499  // + fun[1] * baseY + fun[2]
500  // * baseZ + fun[9];
501  // vertices[funcSetNr * numVertices * 3 + vertexNr * 3 + 1] = fun[3] * baseX
502  // + fun[4] * baseY + fun[5]
503  // * baseZ + fun[10];
504  // vertices[funcSetNr * numVertices * 3 + vertexNr * 3 + 2] = fun[6] * baseX
505  // + fun[7] * baseY + fun[8]
506  // * baseZ + fun[11];
507  //
508  // // float[] hlp = new float[3];
509  // // System.arraycopy(vertices, funcNr * numVertices * 3 + vertexNr * 3,
510  // hlp, 0, 3);
511  // // if (hlp[0] > 4 || hlp[1] > 4 || hlp[2] > 4) {
512  // // Log.d("GeoData", "Transformed node " + vertexNr + " from [" + baseX +
513  // "," + baseY + "," + baseZ
514  // // + "] to " + Arrays.toString(hlp));
515  // // }
516  // }
517  // }
518  // //System.arraycopy(originalVertices, 0, vertices, 0,
519  // originalVertices.length);
520  // //System.arraycopy(originalVertices, 0, vertices,
521  // originalVertices.length, originalVertices.length);
522  // // Center geometry using ALL possibly used nodes
523  // centerModelGeometry();
524  // }
525 
526 }
short[] faceWireframe
Faces edge/wireframe data.
The displacement field is a logical solution field describing displacements of geometry nodes/vertice...
float[][] fnormal
For 3D geometry this contains the face normal data (three coordinates (x,y,z) per face) ...
float[] nminmax
the bounding box (xyz range) of the model
An rbappmit-model of old data format, compatible with JRB models.
Definition: ModelType.java:28
Reading matrices and vectors with a bunch of convenient overloads for different sources and output fo...
boolean loadModelGeometry(AModelManager m)
Reads the geometry data for the current model using the ModelManager.
Known model types within the JaRMoSBase project.
Definition: ModelType.java:9
This class serves as base class for accessing various types of models at different locations...
JKerMor
A JKerMor model.
Definition: ModelType.java:23
int numFaces
Number of faces.
ModelType getModelType()
Returns the model type as given in the model.xml attribute &quot;type&quot; of the &quot;model&quot; tag.
Provides a Log class imitating the Android Log class when not used on android systems.
Definition: Log.java:11
short[] faces
Faces data.
short[] edges
Edges data.
This is a container class for all geometry-related data of a reduced model.
void addDisplacements(DisplacementField d, int parts)
Sets the displacement data for this geometry according to the DisplacementField provided.
float[] originalVertices
The reference nodes.
float[][] normal
For 3D geometry this contains the local node normal data (three coordinates (x,y,z) per node) ...
int[] vertexLTFuncNr
tell us which subdomain our vertices belong to
A common interface for classes providing a mesh transformation.
void createMesh(List< MeshTransform > transforms, boolean update)
Transforms the original vertices by all given MeshTransforms in the list and concatenates the results...
int getNumVertices()
The number of (original) vertices of the geometry.