Model.java
Go to the documentation of this file.
00001 /*******************************************************************************
00002  * Copyright (c) 2012 Stefan Profanter. All rights reserved. This program and the accompanying
00003  * materials are made available under the terms of the GNU Public License v3.0 which accompanies
00004  * this distribution, and is available at http://www.gnu.org/licenses/gpl.html
00005  * 
00006  * Contributors: Stefan Profanter - initial API and implementation, Year: 2012
00007  ******************************************************************************/
00008 package edu.tum.cs.vis.model;
00009 
00010 import java.io.BufferedWriter;
00011 import java.io.File;
00012 import java.io.FileWriter;
00013 import java.io.IOException;
00014 import java.text.DecimalFormat;
00015 import java.text.NumberFormat;
00016 import java.util.ArrayList;
00017 import java.util.Arrays;
00018 import java.util.Collections;
00019 import java.util.HashSet;
00020 import java.util.LinkedList;
00021 import java.util.List;
00022 import java.util.Set;
00023 import java.util.concurrent.Callable;
00024 
00025 import javax.vecmath.Point3f;
00026 import javax.vecmath.Tuple3f;
00027 import javax.vecmath.Vector3f;
00028 
00029 import org.apache.log4j.Logger;
00030 
00031 import processing.core.PGraphics;
00032 import edu.tum.cs.ias.knowrob.utils.ThreadPool;
00033 import edu.tum.cs.vis.model.util.BSphere;
00034 import edu.tum.cs.vis.model.util.DrawSettings;
00035 import edu.tum.cs.vis.model.util.Group;
00036 import edu.tum.cs.vis.model.util.Line;
00037 import edu.tum.cs.vis.model.util.Triangle;
00038 import edu.tum.cs.vis.model.util.Vertex;
00039 import edu.tum.cs.vis.model.util.algorithm.Miniball;
00040 
00050 public class Model {
00051 
00055         private static Logger                   logger                          = Logger.getLogger(Model.class);
00056 
00060         private String                                  textureBasePath         = null;
00061 
00065         private Group                                   group;
00066 
00070         private final List<Vertex>              vertices                        = new ArrayList<Vertex>();
00071 
00075         private final List<Triangle>    triangles                       = new ArrayList<Triangle>();
00076 
00080         private final List<Line>                lines                           = new ArrayList<Line>();
00081 
00087         private BSphere                                 boundingSphere          = null;
00088 
00093         private float                                   scale                           = 1;
00094 
00098         private boolean                                 normalsInitialized      = false;
00099 
00107         public void draw(PGraphics g, DrawSettings drawSettings) {
00108                 if (group != null)
00109                         group.draw(g, drawSettings);
00110         }
00111 
00119         public BSphere getBoundingSphere() {
00120                 if (boundingSphere == null)
00121                         calculateBoundingsphere();
00122                 return boundingSphere;
00123         }
00124 
00130         public Group getGroup() {
00131                 return group;
00132         }
00133 
00139         public List<Line> getLines() {
00140                 return lines;
00141         }
00142 
00149         public float getScale() {
00150                 return scale;
00151         }
00152 
00158         public String getTextureBasePath() {
00159                 return textureBasePath;
00160         }
00161 
00167         public List<Triangle> getTriangles() {
00168                 return triangles;
00169         }
00170 
00178         public float getUnscaled(float scaled) {
00179                 return scaled * 1f / scale;
00180         }
00181 
00190         public Tuple3f[] getUnscaled(Point3f[] corner) {
00191                 Tuple3f[] ret = new Point3f[corner.length];
00192                 for (int i = 0; i < corner.length; i++) {
00193                         ret[i] = getUnscaled(corner[i]);
00194                 }
00195                 return ret;
00196         }
00197 
00205         public Tuple3f getUnscaled(Tuple3f t) {
00206                 Tuple3f tr = new Point3f(t);
00207                 tr.scale(1f / scale);
00208                 return tr;
00209         }
00210 
00218         public Vector3f getUnscaled(Vector3f t) {
00219                 Vector3f tr = new Vector3f(t);
00220                 tr.scale(1f / scale);
00221                 return tr;
00222         }
00223 
00229         public List<Vertex> getVertices() {
00230                 return vertices;
00231         }
00232 
00236         public void mirrorX() {
00237                 for (Vertex v : vertices) {
00238                         v.x *= (-1);
00239                 }
00240                 group.resetMinMaxValues();
00241 
00242         }
00243 
00248         public void normalize() {
00249                 reloadVertexList();
00250                 float x = group.getMaxX() - group.getMinX();
00251                 float y = group.getMaxY() - group.getMinY();
00252                 float z = group.getMaxZ() - group.getMinZ();
00253 
00254                 float max = Math.max(x, Math.max(y, z));
00255 
00256                 scale(1f / max);
00257 
00258                 scale = 1f / max;
00259         }
00260 
00268         public void scale(float factor) {
00269 
00270                 for (Vertex v : vertices) {
00271                         v.scale(factor);
00272                 }
00273                 for (Triangle t : triangles)
00274                         t.updateCentroid();
00275                 for (Line l : lines)
00276                         l.updateCentroid();
00277                 group.resetMinMaxValues();
00278         }
00279 
00286         public void setGroup(Group group) {
00287                 this.group = group;
00288         }
00289 
00296         public void setTextureBasePath(String textureBasePath) {
00297                 this.textureBasePath = textureBasePath;
00298         }
00299 
00306         public int removeDoubleSidedTriangles() {
00307                 final Set<Triangle> toRemove = new HashSet<Triangle>();
00308 
00309                 final int interval = 1000;
00310                 List<Callable<Void>> threads = new LinkedList<Callable<Void>>();
00311                 for (int start = 0; start < triangles.size(); start += interval) {
00312                         final int st = start;
00313                         threads.add(new Callable<Void>() {
00314 
00315                                 @Override
00316                                 public Void call() throws Exception {
00317                                         int end = Math.min(st + interval, triangles.size());
00318                                         for (int i = st; i < end; i++) {
00319                                                 Triangle t1 = triangles.get(i);
00320                                                 if (toRemove.contains(t1))
00321                                                         continue;
00322                                                 for (int j = i + 1; j < triangles.size(); j++) {
00323                                                         Triangle t2 = triangles.get(j);
00324 
00325                                                         if (toRemove.contains(t2))
00326                                                                 continue;
00327                                                         int eqCnt = 0;
00328                                                         for (int k = 0; k < 3; k++) {
00329                                                                 Point3f p1 = t1.getPosition()[k];
00330                                                                 for (Point3f p2 : t2.getPosition()) {
00331                                                                         if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
00332                                                                                 eqCnt++;
00333                                                                                 break;
00334                                                                         }
00335                                                                 }
00336                                                                 if (eqCnt != k + 1) {
00337                                                                         // break if not enough vertices are equal
00338                                                                         break;
00339                                                                 }
00340                                                         }
00341                                                         if (eqCnt == 3) {
00342                                                                 // triangles are the same, so remove j
00343 
00344                                                                 synchronized (toRemove) {
00345                                                                         toRemove.add(t2);
00346                                                                 }
00347                                                         }
00348                                                 }
00349                                         }
00350                                         return null;
00351                                 }
00352 
00353                         });
00354                 };
00355 
00356                 ThreadPool.executeInPool(threads);
00357                 if (toRemove.size() > 0) {
00358                         this.group.removeTriangle(toRemove);
00359                         reloadVertexList();
00360                 }
00361                 return toRemove.size();
00362         }
00363 
00368         private void reloadVertexList() {
00369                 synchronized (triangles) {
00370                         triangles.clear();
00371                         this.group.getAllTriangles(triangles);
00372                 }
00373                 Set<Vertex> vertices = new HashSet<Vertex>(triangles.size() * 2);
00374                 for (Triangle t : triangles) {
00375                         vertices.addAll(Arrays.asList(t.getPosition()));
00376                 }
00377                 for (Line l : lines) {
00378                         vertices.addAll(Arrays.asList(l.getPosition()));
00379                 }
00380                 this.vertices.clear();
00381                 this.vertices.addAll(vertices);
00382         }
00383 
00389         public void updateVertexSharing() {
00390 
00391                 final Set<Triangle> checkedTriangles = Collections.synchronizedSet(new HashSet<Triangle>());
00392 
00393                 Set<Vertex> toRemove = new HashSet<Vertex>();
00394 
00395                 for (Triangle t : triangles)
00396                         updateVertexSharingForTriangle(t, checkedTriangles, toRemove);
00397                 synchronized (vertices) {
00398                         vertices.removeAll(toRemove);
00399                 }
00400                 reloadVertexList();
00401         }
00402 
00418         private void updateVertexSharingForNeighbors(final Triangle t, final Triangle n,
00419                         final Set<Triangle> checkedTriangles, Set<Vertex> toRemove) {
00420                 if (t == n)
00421                         return;
00422                 synchronized (n) {
00423                         if (checkedTriangles.contains(n))
00424                                 return;
00425 
00426                         double angle = t.getDihedralAngle(n);
00427                         // Share vertices if angle is < 15 degree
00428                         boolean share = (angle < 15 / 180.0 * Math.PI);
00429 
00430                         for (Vertex vt : t.getPosition()) {
00431                                 for (int i = 0; i < n.getPosition().length; i++) {
00432                                         Vertex vn = n.getPosition()[i];
00433                                         /*
00434                                         if ((vt.sameCoordinates(vn) && vt.getPointarea() == vn.getPointarea() && vt
00435                                                         .getNormalVector().equals(vn.getNormalVector()))
00436                                                         ||(share && vn != vt && vt.sameCoordinates(vn))) {*/
00437                                         if (share && vn != vt && vt.sameCoordinates(vn)) {
00438                                                 // merge vertices
00439                                                 n.getPosition()[i] = vt;
00440                                                 int cnt = 0;
00441                                                 for (Triangle tmpTri : t.getNeighbors()) {
00442                                                         for (Vertex tmpVer : tmpTri.getPosition())
00443                                                                 if (tmpVer == vn) {
00444                                                                         cnt++;
00445                                                                         break;
00446                                                                 }
00447                                                 }
00448                                                 if (cnt == 0) {
00449                                                         for (Triangle tmpTri : n.getNeighbors()) {
00450                                                                 if (tmpTri == t)
00451                                                                         continue;
00452                                                                 for (Vertex tmpVer : tmpTri.getPosition())
00453                                                                         if (tmpVer == vn) {
00454                                                                                 cnt++;
00455                                                                                 break;
00456                                                                         }
00457                                                         }
00458                                                 }
00459                                                 if (cnt == 0) {
00460                                                         toRemove.add(vn);
00461                                                 }
00462                                         } else if (!share && vn == vt) {
00463                                                 // split vertices
00464                                                 // System.out.println("split");
00465                                                 /*Vertex clone = (Vertex) vt.clone();
00466                                                 synchronized (vertices) {
00467                                                         vertices.add(clone);
00468                                                 }
00469                                                 n.getPosition()[i] = clone;*/
00470                                         }
00471                                 }
00472                         }
00473                 }
00474         }
00475 
00488         private void updateVertexSharingForTriangle(final Triangle t,
00489                         final Set<Triangle> checkedTriangles, final Set<Vertex> toRemove) {
00490                 synchronized (t) {
00491                         if (checkedTriangles.contains(t))
00492                                 return;
00493                         synchronized (t.getNeighbors()) {
00494                                 for (Triangle n : t.getNeighbors()) {
00495                                         updateVertexSharingForNeighbors(t, n, checkedTriangles, toRemove);
00496                                         // also check neighbors of neighbor
00497                                         for (Triangle nn : n.getNeighbors()) {
00498                                                 updateVertexSharingForNeighbors(t, nn, checkedTriangles, toRemove);
00499                                         }
00500                                 }
00501 
00502                         }
00503                         checkedTriangles.add(t);
00504                 }
00505         }
00506 
00514         public void updateVertexNormals() {
00515                 // Compute from faces
00516 
00517                 List<Callable<Void>> threads = new LinkedList<Callable<Void>>();
00518 
00519                 final int interval = 500;
00520 
00521                 // Reset normal vectors, because vertex normals from collada aren't correct
00522                 for (Vertex v : vertices) {
00523                         v.getNormalVector().x = v.getNormalVector().y = v.getNormalVector().z = 0;
00524                 }
00525 
00526                 for (int start = 0; start < triangles.size(); start += interval) {
00527                         final int st = start;
00528                         /*threads.add(new Callable<Void>() {
00529 
00530                                 @Override
00531                                 public Void call() throws Exception {*/
00532                         int end = Math.min(st + interval, triangles.size());
00533                         for (int i = st; i < end; i++) {
00534                                 calculateVertexNormalsForTriangle(triangles.get(i));
00535                         }
00536                         /*      return null;
00537                         }
00538 
00539                         });*/
00540                 };
00541 
00542                 ThreadPool.executeInPool(threads);
00543 
00544                 // Normalize all vectors.
00545                 // Additionally search the vectors which have max x, max y and max z coordinates (needed for
00546                 // vertex winding check / inverted normals check)
00547 
00548                 Vertex extrema[] = new Vertex[6];
00549 
00550                 for (Vertex v : vertices) {
00551                         v.getNormalVector().normalize();
00552                         float coord[] = new float[3];
00553                         v.get(coord);
00554                         // Set all max values
00555                         for (int i = 0; i < 3; i++) {
00556                                 float extCoord[] = new float[3];
00557                                 if (extrema[i] != null)
00558                                         extrema[i].get(extCoord);
00559                                 if (extrema[i] == null || extCoord[i] < coord[i])
00560                                         extrema[i] = v;
00561                         }
00562                         // Set all min values
00563                         for (int i = 0; i < 3; i++) {
00564                                 float extCoord[] = new float[3];
00565                                 if (extrema[i + 3] != null)
00566                                         extrema[i + 3].get(extCoord);
00567                                 if (extrema[i + 3] == null || extCoord[i] > coord[i])
00568                                         extrema[i + 3] = v;
00569                         }
00570                 }
00571 
00572                 int vote = 0;
00573                 // Now the vertex normal of maxX must point in approximately the same direction as the
00574                 // axis. If the angle between the vertex normal and the direction is smaller than 90° vote
00575                 // for inversion.
00576                 for (int i = 0; i < 6; i++) {
00577                         float coord[] = { 0, 0, 0 };
00578                         coord[i % 3] = i < 3 ? 1 : -1;
00579                         double dot = extrema[i].getNormalVector().dot((new Vector3f(coord)));
00580                         double angle = Math.acos(dot);
00581                         // System.out.println("Angle: " + (angle * 180 / Math.PI));
00582                         if (angle < Math.PI / 2)
00583                                 vote--;
00584                         else
00585                                 vote++;
00586                 }
00587                 // System.out.println("VOTE: " + vote);
00588                 if (vote > 0) {
00589                         // They voted for inverting
00590                         logger.debug("Inverting normal vertices, because vote is: " + vote);
00591                         for (Vertex v : vertices) {
00592                                 v.getNormalVector().scale(-1f);
00593                         }
00594                 }
00595 
00596                 normalsInitialized = true;
00597 
00598         }
00599 
00606         static void calculateVertexNormalsForTriangle(final Triangle t) {
00607                 Vertex p0 = t.getPosition()[0];
00608                 Vertex p1 = t.getPosition()[1];
00609                 Vertex p2 = t.getPosition()[2];
00610 
00611                 // get vectors from p0 to p1 and so on
00612                 Vector3f a = new Vector3f(p0);
00613                 a.sub(p1);
00614                 Vector3f b = new Vector3f(p1);
00615                 b.sub(p2);
00616                 Vector3f c = new Vector3f(p2);
00617                 c.sub(p0);
00618                 // length of these vectors
00619                 float l2a = a.lengthSquared(), l2b = b.lengthSquared(), l2c = c.lengthSquared();
00620                 if (l2a == 0 || l2b == 0 || l2c == 0)
00621                         return;
00622 
00623                 Vector3f facenormal = new Vector3f();
00624                 facenormal.cross(a, b); // unscaled normal
00625 
00626                 Vector3f normalP0 = (Vector3f) facenormal.clone();
00627                 normalP0.scale(1.0f / (l2a * l2c));
00628                 synchronized (p0.getNormalVector()) {
00629                         p0.getNormalVector().add(normalP0);
00630                 }
00631 
00632                 Vector3f normalP1 = (Vector3f) facenormal.clone();
00633                 normalP1.scale(1.0f / (l2b * l2a));
00634                 synchronized (p1.getNormalVector()) {
00635                         p1.getNormalVector().add(normalP1);
00636                 }
00637 
00638                 Vector3f normalP2 = (Vector3f) facenormal.clone();
00639                 normalP2.scale(1.0f / (l2c * l2b));
00640                 synchronized (p2.getNormalVector()) {
00641                         p2.getNormalVector().add(normalP2);
00642                 }
00643         }
00644 
00661         public File exportVerticesAsTxt() {
00662                 try {
00663                         File tmp = File.createTempFile("knowrob_", ".txt",
00664                                         new File(System.getProperty("java.io.tmpdir")));
00665                         exportVerticesAsTxt(tmp, true);
00666                         return tmp;
00667                 } catch (IOException e) {
00668                         logger.error("Couldn't create temp file name: " + e.getMessage());
00669                         return null;
00670                 }
00671 
00672         }
00673 
00692         public boolean exportVerticesAsTxt(File path, boolean overwrite) {
00693 
00694                 try {
00695                         if (!overwrite && path.exists()) {
00696                                 logger.error("Couldn't export model to file. Already exists: "
00697                                                 + path.getAbsolutePath());
00698                                 return false;
00699                         }
00700                         FileWriter fstream = new FileWriter(path);
00701                         BufferedWriter out = new BufferedWriter(fstream);
00702                         out.write(vertices.size() + "\n");
00703                         NumberFormat df = new DecimalFormat("0.####################");
00704                         for (int i = 0; i < vertices.size(); i++) {
00705                                 Vertex v = vertices.get(i);
00706                                 out.write(df.format(v.x) + "\t" + df.format(v.y) + "\t" + df.format(v.z));
00707                                 if (normalsInitialized) {
00708                                         out.write("\t" + df.format(v.getNormalVector().x) + "\t"
00709                                                         + df.format(v.getNormalVector().y) + "\t"
00710                                                         + df.format(v.getNormalVector().z));
00711                                 }
00712                                 if (i < vertices.size() - 1)
00713                                         out.write("\n");
00714                         }
00715                         logger.info("Model exported to file " + path.getAbsolutePath());
00716                         out.close();
00717                         return true;
00718                 } catch (IOException e) {
00719                         logger.error("Couldn't export model to file " + path.getAbsolutePath() + ". "
00720                                         + e.getMessage());
00721                 }
00722                 return false;
00723         }
00724 
00730         public double getSizeX() {
00731                 return group.getMaxX() - group.getMinX();
00732         }
00733 
00739         public double getSizeY() {
00740                 return group.getMaxY() - group.getMinY();
00741         }
00742 
00748         public double getSizeZ() {
00749                 return group.getMaxZ() - group.getMinZ();
00750         }
00751 
00758         private void calculateBoundingsphere() {
00759                 if (vertices.size() == 0)
00760                         return;
00761 
00762                 Miniball mb = new Miniball(3);
00763                 for (Vertex v : vertices) {
00764                         double arr[] = new double[3];
00765                         arr[0] = v.x;
00766                         arr[1] = v.y;
00767                         arr[2] = v.z;
00768                         mb.check_in(arr);
00769                 }
00770                 mb.build();
00771                 this.boundingSphere = new BSphere((float) Math.sqrt(mb.squared_radius()), new Vector3f(
00772                                 (float) mb.center()[0], (float) mb.center()[1], (float) mb.center()[2]));
00773 
00774         }
00775 
00783         public float feature_size() {
00784                 if (triangles.size() == 0)
00785                         return 0.0f;
00786 
00787                 int nf = triangles.size();
00788                 int nsamp = Math.min(nf / 2, 333);
00789 
00790                 Float[] samples = new Float[nsamp * 3];
00791 
00792                 for (int i = 0; i < nsamp; i++) {
00793 
00794                         int ind = (int) (Math.random() * nf);
00795                         final Vertex p0 = triangles.get(ind).getPosition()[0];
00796                         final Vertex p1 = triangles.get(ind).getPosition()[1];
00797                         final Vertex p2 = triangles.get(ind).getPosition()[2];
00798                         samples[i * 3] = p0.distanceSquared(p1);
00799                         samples[i * 3 + 1] = p1.distanceSquared(p2);
00800                         samples[i * 3 + 2] = p2.distanceSquared(p0);
00801                 }
00802                 Arrays.sort(samples);
00803                 return getUnscaled((float) Math.sqrt(samples[samples.length / 2]));
00804         }
00805 }


knowrob_cad_parser
Author(s): Stefan Profanter
autogenerated on Sat Dec 28 2013 17:09:45