ColladaParser.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.parser;
00009 
00010 import java.awt.Color;
00011 import java.io.File;
00012 import java.io.FileNotFoundException;
00013 import java.io.IOException;
00014 import java.util.ArrayList;
00015 import java.util.HashMap;
00016 import java.util.LinkedList;
00017 import java.util.List;
00018 import java.util.Map;
00019 import java.util.regex.Matcher;
00020 
00021 import javax.vecmath.Point2f;
00022 import javax.vecmath.Vector3f;
00023 import javax.xml.parsers.DocumentBuilder;
00024 import javax.xml.parsers.DocumentBuilderFactory;
00025 import javax.xml.parsers.ParserConfigurationException;
00026 
00027 import org.w3c.dom.Document;
00028 import org.w3c.dom.Element;
00029 import org.w3c.dom.NodeList;
00030 import org.xml.sax.SAXException;
00031 
00032 import com.dddviewr.collada.Collada;
00033 import com.dddviewr.collada.Input;
00034 import com.dddviewr.collada.Source;
00035 import com.dddviewr.collada.Unit;
00036 import com.dddviewr.collada.effects.Blinn;
00037 import com.dddviewr.collada.effects.Effect;
00038 import com.dddviewr.collada.effects.EffectAttribute;
00039 import com.dddviewr.collada.effects.Lambert;
00040 import com.dddviewr.collada.geometry.Geometry;
00041 import com.dddviewr.collada.geometry.Lines;
00042 import com.dddviewr.collada.geometry.Mesh;
00043 import com.dddviewr.collada.geometry.Primitives;
00044 import com.dddviewr.collada.geometry.Triangles;
00045 import com.dddviewr.collada.materials.Material;
00046 import com.dddviewr.collada.nodes.Node;
00047 import com.dddviewr.collada.visualscene.BaseXform;
00048 import com.dddviewr.collada.visualscene.InstanceGeometry;
00049 import com.dddviewr.collada.visualscene.InstanceMaterial;
00050 import com.dddviewr.collada.visualscene.InstanceNode;
00051 import com.dddviewr.collada.visualscene.Matrix;
00052 import com.dddviewr.collada.visualscene.VisualScene;
00053 
00054 import edu.tum.cs.ias.knowrob.utils.FileUtil;
00055 import edu.tum.cs.ias.knowrob.utils.ResourceRetriever;
00056 import edu.tum.cs.vis.model.Model;
00057 import edu.tum.cs.vis.model.util.Appearance;
00058 import edu.tum.cs.vis.model.util.Group;
00059 import edu.tum.cs.vis.model.util.Line;
00060 import edu.tum.cs.vis.model.util.Triangle;
00061 import edu.tum.cs.vis.model.util.Vertex;
00062 
00071 public class ColladaParser extends ModelParser {
00072 
00082         private static Appearance getAppearance(Material mat, Collada collada) {
00083                 Appearance appearance = new Appearance();
00084                 Effect effect = collada.findEffect(mat.getInstanceEffect().getUrl().substring(1));
00085                 if (effect.getEffectMaterial() instanceof Lambert) {
00086                         Lambert lambert = (Lambert) effect.getEffectMaterial();
00087                         EffectAttribute diffuse = lambert.getDiffuse();
00088                         String texturePath = null;
00089                         Color materialColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
00090                         if (diffuse.getTexture() != null) {
00091                                 texturePath = collada.findImage(
00092                                                 effect.findNewParam(
00093                                                                 effect.findNewParam(diffuse.getTexture().getTexture())
00094                                                                                 .getSampler2D().getSource()).getSurface().getInitFrom())
00095                                                 .getInitFrom();
00096                                 if (texturePath.startsWith("./images/"))
00097                                         texturePath = "." + texturePath;
00098                         } else {
00099                                 float[] colors = diffuse.getData();
00100                                 // System.out.println("Diffuse");
00101                                 materialColor = new Color(colors[0], colors[1], colors[2], colors[3]);
00102                         }
00103 
00104                         if (texturePath != null) {
00105                                 appearance.setImageFileName(texturePath);
00106                         } else {
00107                                 // Fill will be set to null if it is a line, Line will be set to null if it is a
00108                                 // Triangle
00109                                 appearance.setColorFill(materialColor);
00110                                 appearance.setColorLine(materialColor);
00111                         }
00112                 } else if (effect.getEffectMaterial() instanceof Blinn) {
00113                         // <emission> + <ambient>*al + <diffuse> + <specular>^<shininess>
00114                         Blinn blinn = (Blinn) effect.getEffectMaterial();
00115 
00116                         String texturePath = null;
00117                         if (blinn.getDiffuse().getTexture() != null) {
00118                                 texturePath = collada.findImage(
00119                                                 effect.findNewParam(
00120                                                                 effect.findNewParam(blinn.getDiffuse().getTexture().getTexture())
00121                                                                                 .getSampler2D().getSource()).getSurface().getInitFrom())
00122                                                 .getInitFrom();
00123                                 if (texturePath.startsWith("./images/"))
00124                                         texturePath = "." + texturePath;
00125                                 appearance.setImageFileName(texturePath);
00126                         } else {
00127 
00128                                 float[] emission = blinn.getEmission().getData();
00129                                 float[] ambient = blinn.getAmbient().getData();
00130                                 float[] diffuse = blinn.getDiffuse().getData();
00131                                 float[] specular = blinn.getSpecular().getData();
00132                                 float[] shininess = blinn.getShininess().getData();
00133                                 float[] result = new float[4];
00134                                 for (int i = 0; i < 4; i++) {
00135                                         result[i] = 0;
00136                                         if (emission != null)
00137                                                 result[i] += emission[i];
00138                                         if (ambient != null)
00139                                                 result[i] += ambient[i];
00140                                         if (diffuse != null)
00141                                                 result[i] += diffuse[i];
00142                                         if (specular != null && shininess != null)
00143                                                 result[i] += (float) Math.pow(specular[i], shininess[0]);
00144                                 }
00145                                 // Fill will be set to null if it is a line, Line will be set to null if it is a
00146                                 // Triangle
00147                                 appearance.setColorFill(new Color(result[0], result[1], result[2], Math.min(
00148                                                 result[3], 1f)));
00149                                 appearance.setColorLine(appearance.getColorFill());
00150                         }
00151 
00152                 }
00153                 return appearance;
00154         }
00155 
00164         private static String getDaeLocation(String tmpPath) {
00165                 File kmlFile = new File(tmpPath + "doc.kml");
00166                 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
00167                 DocumentBuilder dBuilder = null;
00168                 try {
00169                         dBuilder = dbFactory.newDocumentBuilder();
00170                 } catch (ParserConfigurationException e) {
00171                         System.err.println("Couldn't get .dae location from doc.kml: " + e.getMessage());
00172                         return null;
00173                 }
00174                 Document doc;
00175                 try {
00176                         doc = dBuilder.parse(kmlFile);
00177                 } catch (SAXException e) {
00178                         System.err.println("Couldn't get .dae location from doc.kml: " + e.getMessage());
00179                         return null;
00180                 } catch (IOException e) {
00181                         System.err.println("Couldn't get .dae location from doc.kml: " + e.getMessage());
00182                         return null;
00183                 }
00184                 doc.getDocumentElement().normalize();
00185 
00186                 if (!doc.getDocumentElement().getNodeName().equalsIgnoreCase("kml")) {
00187                         System.out.println("Invalid doc.kml file. Root node must be 'kml'");
00188                         return null;
00189                 }
00190 
00191                 LinkedList<String> nodeNames = new LinkedList<String>();
00192                 nodeNames.add("Placemark");
00193                 nodeNames.add("Model");
00194                 nodeNames.add("Link");
00195                 nodeNames.add("href");
00196 
00197                 NodeList nList = doc.getElementsByTagName(nodeNames.poll());
00198 
00199                 String loc = getNodeValue(nList, nodeNames);
00200                 if (loc == null) {
00201                         System.out.println("Couldn't get .dae location from doc.kml");
00202                         return null;
00203                 }
00204 
00205                 String ret = tmpPath + loc;
00206                 if (File.separator.equals("\\")) {
00207                         ret = ret.replaceAll("/", Matcher.quoteReplacement(File.separator));
00208                 } else {
00209                         ret = ret.replaceAll("\\\\", Matcher.quoteReplacement(File.separator));
00210                 }
00211                 return ret;
00212         }
00213 
00225         private static String getNodeValue(NodeList nList, LinkedList<String> nodeNames) {
00226                 if (nodeNames.isEmpty() || nList == null) {
00227                         return null;
00228                 }
00229                 if (nodeNames.size() == 1) {
00230                         for (int temp = 0; temp < nList.getLength(); temp++) {
00231                                 org.w3c.dom.Node nNode = nList.item(temp);
00232                                 if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
00233                                         Element element = (Element) nNode;
00234                                         NodeList nlList = element.getElementsByTagName(nodeNames.poll());
00235                                         if (nlList == null)
00236                                                 return null;
00237                                         nlList = nlList.item(0).getChildNodes();
00238 
00239                                         org.w3c.dom.Node nValue = nlList.item(0);
00240                                         return nValue.getNodeValue();
00241 
00242                                 }
00243                         }
00244                 } else {
00245                         for (int temp = 0; temp < nList.getLength(); temp++) {
00246 
00247                                 org.w3c.dom.Node nNode = nList.item(temp);
00248 
00249                                 if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
00250 
00251                                         Element element = (Element) nNode;
00252 
00253                                         LinkedList<String> tmpNodeNames = new LinkedList<String>();
00254                                         tmpNodeNames.addAll(nodeNames);
00255                                         String val = getNodeValue(element.getElementsByTagName(tmpNodeNames.poll()),
00256                                                         tmpNodeNames);
00257                                         if (val != null)
00258                                                 return val;
00259                                 }
00260                         }
00261                 }
00262                 return null;
00263         }
00264 
00276         private static ArrayList<Vertex> getVerticesOfMesh(Mesh m, List<Input> inputs, String type) {
00277                 Source vertexSource = null;
00278                 for (Input in : inputs) {
00279                         if (in.getSemantic().compareTo(type) == 0) {
00280                                 vertexSource = m.getSource(in.getSource().substring(1));
00281                         }
00282                 }
00283 
00284                 if (vertexSource == null) {
00285                         return null;
00286                 }
00287 
00288                 float[][] vertPoints = SourceToFloat(vertexSource);
00289 
00290                 ArrayList<Vertex> vertices = new ArrayList<Vertex>();
00291                 for (int i = 0; i < vertPoints.length; i++) {
00292                         vertices.add(new Vertex(vertPoints[i][0], vertPoints[i][1], vertPoints[i][2]));
00293                 }
00294 
00295                 return vertices;
00296         }
00297 
00314         private static void parseGeometry(Geometry g, Group currGroup,
00315                         Map<String, String> instanceMaterial, List<BaseXform> transformations, Collada collada) {
00316                 Mesh m = g.getMesh();
00317                 ArrayList<Vertex> vertices = getVerticesOfMesh(m, m.getVertices().getInputs(), "POSITION");
00318                 ArrayList<Vertex> normals = getVerticesOfMesh(m, m.getVertices().getInputs(), "NORMAL");
00319 
00320                 for (int i = 0; i < vertices.size(); i++) {
00321                         Vertex v = vertices.get(i);
00322                         useTransformation(v, transformations, true);
00323                         if (normals != null) {
00324                                 Vertex n = normals.get(i);
00325                                 useTransformation(n, transformations, false);
00326                                 v.setNormalVector(new Vector3f(n.x, n.y, n.z));
00327                         }
00328                 }
00329 
00330                 currGroup.getModel().getVertices().addAll(vertices);
00331 
00332                 for (Primitives p : m.getPrimitives()) {
00333                         if (p instanceof Triangles) {
00334                                 Triangles t = (Triangles) p;
00335                                 parseGeometryTriangle(t, currGroup, instanceMaterial, collada, vertices, m);
00336                         } else if (p instanceof Lines) {
00337                                 Lines l = (Lines) p;
00338                                 parseGeometryLine(l, currGroup, instanceMaterial, collada, vertices);
00339                         }
00340                 }
00341         }
00342 
00358         private static void parseGeometryLine(Lines l, Group currGroup,
00359                         Map<String, String> instanceMaterial, Collada collada, List<Vertex> vertices) {
00360                 Material mat = null;
00361                 if (instanceMaterial.containsKey(l.getMaterial())) {
00362                         mat = collada.findMaterial(instanceMaterial.get(l.getMaterial()));
00363 
00364                 } else {
00365                         l.dump(System.err, 5);
00366                         throw new RuntimeException("No material given for Line (see above) ");
00367                 }
00368 
00369                 int stride = l.getInputs().size();
00370                 int count = l.getCount();
00371 
00372                 int[][] indexes = new int[count * 3][stride];
00373 
00374                 for (int i = 0, k = 0; i < count * 3; i++) {
00375                         for (int j = 0; j < stride; j++, k++)
00376                                 indexes[i][j] = l.getData()[k];
00377                 }
00378 
00379                 int vertexOffset = 0;
00380                 for (Input i : l.getInputs()) {
00381                         if (i.getSemantic().compareTo("VERTEX") == 0)
00382                                 vertexOffset = i.getOffset();
00383 
00384                 }
00385 
00386                 Appearance appearance = getAppearance(mat, collada);
00387                 appearance.setColorFill(null);
00388 
00389                 // one single line from the line-set
00390                 for (int i = 0; i < indexes.length && i + 2 < indexes.length; i++) {
00391                         Line line = new Line();
00392                         line.setAppearance(appearance);
00393 
00394                         for (int v = 0; v < 2; v++) {
00395                                 // set the vertices for Point
00396                                 line.getPosition()[v] = vertices.get(indexes[i][vertexOffset]);
00397 
00398                                 i++;
00399                         }
00400                         line.updateCentroid();
00401                         i -= 2;
00402 
00403                         // useTransformation(line, transformations);
00404                         // add it to the Collection
00405                         currGroup.getMesh().getLines().add(line);
00406                         currGroup.getModel().getLines().add(line);
00407                 }
00408         }
00409 
00427         private static void parseGeometryTriangle(Triangles t, Group currGroup,
00428                         Map<String, String> instanceMaterial, Collada collada, List<Vertex> vertices, Mesh m) {
00429                 Appearance appearance;
00430                 if (instanceMaterial.containsKey(t.getMaterial())) {
00431                         Material mat = collada.findMaterial(instanceMaterial.get(t.getMaterial()));
00432                         appearance = getAppearance(mat, collada);
00433                         appearance.setColorLine(null);
00434 
00435                 } else {
00436                         // Triangle has no material defined.
00437                         appearance = new Appearance();
00438                         appearance.setColorFill(new Color(120, 120, 120));
00439                 }
00440 
00441                 int stride = t.getInputs().size();
00442                 int count = t.getCount();
00443 
00444                 int[][] indexes = new int[count * 3][stride];
00445 
00446                 for (int i = 0, k = 0; i < count * 3; i++) {
00447                         for (int j = 0; j < stride; j++, k++)
00448                                 indexes[i][j] = t.getData()[k];
00449                 }
00450 
00451                 int vertexOffset = 0, textureOffset = 0, normalOffset = 0;
00452                 Source textureSource = null;
00453                 Source normalSource = null;
00454                 for (Input i : t.getInputs()) {
00455                         if (i.getSemantic().equals("VERTEX"))
00456                                 vertexOffset = i.getOffset();
00457                         else if (i.getSemantic().equals("TEXCOORD")) {
00458                                 textureOffset = i.getOffset();
00459                                 textureSource = m.getSource(i.getSource().substring(1));
00460                         } else if (i.getSemantic().equals("NORMAL")) {
00461                                 normalOffset = i.getOffset();
00462                                 normalSource = m.getSource(i.getSource().substring(1));
00463                         }
00464 
00465                 }
00466 
00467                 float[][] texturePoints = null; // dummy init
00468                 if (textureSource != null) {
00469                         // Triangle has texture
00470                         texturePoints = SourceToFloat(textureSource);
00471                 }
00472 
00473                 float[][] normalCoordinates = null; // dummy init
00474                 if (normalSource != null) {
00475                         // Triangle has texture
00476                         normalCoordinates = SourceToFloat(normalSource);
00477                 }
00478 
00479                 // one single triangle from the triangle-set
00480                 for (int i = 0; i < indexes.length; i++) {
00481                         Triangle tri = new Triangle();
00482                         tri.setAppearance(appearance);
00483 
00484                         if (tri.getAppearance().getImageFileName() != null)
00485                                 tri.setTexPosition(new Point2f[3]);
00486                         // calculate triangle normal
00487 
00488                         for (int v = 0; v < 3; v++) {
00489                                 // set the vertices for Point
00490                                 Vertex vert = vertices.get(indexes[i][vertexOffset]);
00491 
00492                                 tri.getPosition()[v] = vert;
00493 
00494                                 // set texture position
00495                                 if (tri.getAppearance().getImageFileName() != null) {
00496                                         tri.getTexPosition()[v] = new Point2f(
00497                                                         texturePoints[indexes[i][textureOffset]][0],
00498                                                         texturePoints[indexes[i][textureOffset]][1]);
00499                                 }
00500 
00501                                 if (normalCoordinates != null) {
00502                                         Vector3f norm = new Vector3f(normalCoordinates[indexes[i][normalOffset]][0],
00503                                                         normalCoordinates[indexes[i][normalOffset]][1],
00504                                                         normalCoordinates[indexes[i][normalOffset]][2]);
00505                                         vert.setNormalVector(norm);
00506                                 }
00507 
00508                                 i++;
00509                         }
00510                         i--;
00511 
00512                         if (!tri.calculateNormalVector()) {
00513                                 continue;
00514                         }
00515                         tri.updateCentroid();
00516 
00517                         // add it to the Collection
00518                         currGroup.addTriangle(tri);
00519                 }
00520 
00521         }
00522 
00530         private static float[][] SourceToFloat(Source s) {
00531                 float ret[][] = new float[s.getAccessor().getCount()][s.getAccessor().getStride()];
00532                 for (int i = 0, k = 0; i < s.getAccessor().getCount(); i++) {
00533                         for (int j = 0; j < s.getAccessor().getStride(); j++, k++)
00534                                 ret[i][j] = s.getFloatArray().get(k);
00535                 }
00536                 return ret;
00537         }
00538 
00550         private static void useTransformation(Vertex vertex, List<BaseXform> transformations,
00551                         boolean withTranslate) {
00552                 for (int idx = transformations.size() - 1; idx >= 0; idx--) {
00553                         BaseXform transform = transformations.get(idx);
00554                         if (transform instanceof Matrix) {
00555                                 int cnt = 4;
00556                                 float matrix[][] = new float[cnt][cnt];
00557                                 int v = 0;
00558                                 for (int ma_y = 0; ma_y < cnt; ma_y++) {
00559                                         for (int ma_x = 0; ma_x < cnt; ma_x++) {
00560                                                 if (!withTranslate && (ma_y > 2 || ma_x > 2) && ma_y != ma_x)
00561                                                         // only use rotation matrix (eg for rotating and not translating normal
00562                                                         // vector)
00563                                                         matrix[ma_y][ma_x] = 0;
00564                                                 else
00565                                                         matrix[ma_y][ma_x] = ((Matrix) transform).getData()[v];
00566 
00567                                                 v++;
00568                                         }
00569                                 }
00570                                 vertex.transform(matrix);
00571                         } else {
00572                                 System.out.println("Transformation not implemented: ");
00573                                 transform.dump(System.out, 4);
00574                         }
00575                 }
00576         }
00577 
00582         private String  textureBasePath = "";
00583 
00584         @Override
00585         protected boolean loadModel(String filename) {
00586                 Collada collada = null;
00587                 textureBasePath = null;
00588                 String daeFile = null;
00589 
00590                 // Extract kmz if needed and determin location of .dae file
00591                 String extension = getExtension(filename);
00592                 if (extension.equalsIgnoreCase("kmz")) {
00593                         String tmpPath = ResourceRetriever.createTempDirectory();
00594                         if (!tmpPath.endsWith("/") && !tmpPath.endsWith("\\"))
00595                                 tmpPath += File.separator;
00596                         FileUtil.Unzip(filename, tmpPath);
00597 
00598                         daeFile = getDaeLocation(tmpPath);
00599 
00600                         textureBasePath = daeFile.substring(0, daeFile.lastIndexOf(File.separator));
00601 
00602                         if (!textureBasePath.endsWith("/") && !textureBasePath.endsWith("\\"))
00603                                 textureBasePath += File.separator;
00604 
00605                 } else if (extension.equalsIgnoreCase("dae")) {
00606                         String fullPath = new File(filename).getPath();
00607                         textureBasePath = fullPath.substring(0, fullPath.length()
00608                                         - new File(filename).getName().length());
00609                         daeFile = filename;
00610                 }
00611 
00612                 // Parse dae with collada xml parser
00613                 try {
00614                         collada = Collada.readFile(daeFile);
00615                 } catch (FileNotFoundException e) {
00616                         System.err.println("File doesn't exists: " + daeFile);
00617                         e.printStackTrace();
00618                         return false;
00619                 } catch (SAXException e) {
00620                         System.err.println("XML-Exception in : " + daeFile);
00621                         e.printStackTrace();
00622                         return false;
00623                 } catch (IOException e) {
00624                         System.err.println("IO-Exception in : " + daeFile);
00625                         e.printStackTrace();
00626                         return false;
00627                 }
00628 
00629                 model = new Model();
00630                 model.setGroup(new Group(model));
00631 
00632                 // collada.dump(System.out, 0);
00633 
00634                 // library_visual_scenes is where everything begins
00635                 VisualScene scene = collada.getLibraryVisualScenes().getScene(
00636                                 collada.getScene().getInstanceVisualScene().getUrl());
00637 
00638                 for (Node n : scene.getNodes()) {
00639                         parseNode(n, model.getGroup(), new ArrayList<BaseXform>(), collada);
00640                 }
00641 
00642                 model.setTextureBasePath(textureBasePath);
00643 
00644                 Unit unit = collada.getUnit();
00645                 if (unit != null && unit.getMeter() != 1.0) {
00646                         model.scale(unit.getMeter());
00647                 }
00648 
00649                 model.mirrorX();
00650 
00651                 return true;
00652         }
00653 
00667         private void parseNode(Node node, Group currGroup, ArrayList<BaseXform> transformations,
00668                         Collada collada) {
00669 
00670                 // Add transformations like a stack
00671                 if (node.getXforms() != null)
00672                         transformations.addAll(node.getXforms());
00673 
00674                 // Parse all child nodes
00675                 if (node.getChildNodes() != null) {
00676                         for (Node child : node.getChildNodes()) {
00677                                 Group g = new Group(currGroup.getModel());
00678                                 g.setName(child.getName());
00679                                 currGroup.addChild(g);
00680                                 parseNode(child, g, transformations, collada);
00681                         }
00682                 }
00683 
00684                 // Parse referencing nodes
00685                 InstanceNode instNode = node.getInstanceNode();
00686                 if (instNode != null) {
00687                         parseNode(collada.findNode(instNode.getUrl()), currGroup, transformations, collada);
00688                 }
00689 
00690                 // Parse referencing geometries and Material
00691                 List<InstanceGeometry> instGeoList = node.getInstanceGeometry();
00692 
00693                 for (InstanceGeometry instGeo : instGeoList) {
00694                         HashMap<String, String> instanceMaterial = new HashMap<String, String>();
00695                         for (InstanceMaterial mat : instGeo.getInstanceMaterials()) {
00696                                 instanceMaterial.put(mat.getSymbol(), mat.getTarget());
00697                         }
00698                         parseGeometry(collada.findGeometry(instGeo.getUrl()), currGroup, instanceMaterial,
00699                                         transformations, collada);
00700                 }
00701 
00702                 // remove added transformations
00703                 if (node.getXforms() != null)
00704                         transformations.removeAll(node.getXforms());
00705         }
00706 }


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