Java tutorial
/***************************************************************************** * Shapeways, Inc Copyright (c) 2012 * Java Source * * This source is licensed under the GNU LGPL v2.1 * Please read http://www.gnu.org/copyleft/lgpl.html for more information * * This software comes with the standard NO WARRANTY disclaimer for any * purpose. Use it at your own risk. If there's a problem you get to fix it. * ****************************************************************************/ package abfab3d.io.input; // External Imports import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Iterator; import java.io.File; import java.io.IOException; import org.apache.commons.io.FilenameUtils; import org.web3d.parser.vrml97.VRML97Reader; import org.web3d.vrml.parser.BaseReader; import xj3d.filter.AbstractFilter; import xj3d.filter.node.CommonEncodedBaseFilter; import xj3d.filter.node.CommonScene; import xj3d.filter.node.CommonEncodable; import xj3d.filter.node.ArrayData; import org.web3d.vrml.export.Exporter; import org.web3d.vrml.export.NullExporter; import org.web3d.vrml.sav.ErrorHandler; import org.web3d.vrml.sav.SAVException; import org.web3d.vrml.sav.InputSource; //import org.web3d.vrml.nodes.*; //import org.xj3d.core.loading.*; import org.web3d.parser.x3d.X3DReader; import org.web3d.vrml.lang.VRMLException; // Internal Imports /** * Loads an X3D file into an in memory representation. * * All supported incoming geometry is converted to an indexed triangle array. * * @author Alan Hudson */ public class X3DFileLoader extends CommonEncodedBaseFilter { /** Default major spec version to export as in X3D */ private static final int DEFAULT_OUPUT_MAJOR_VERSION = 3; /** Default major spec version to export as in X3D */ private static final int DEFAULT_OUPUT_MINOR_VERSION = 1; /** Reference to the registered error handler if we have one */ private static ErrorHandler console; /** The loaded scene */ private CommonScene parsedScene; /** The loaded Shapes */ private ArrayList<CommonEncodable> shapes; public X3DFileLoader(ErrorHandler eh) { console = eh; shapes = new ArrayList<CommonEncodable>(); } /** * Load the specified file X3D file. */ public void loadFile(File input) throws IOException, IllegalArgumentException { int export_major_version = DEFAULT_OUPUT_MAJOR_VERSION; int export_minor_version = DEFAULT_OUPUT_MINOR_VERSION; InputSource is = new InputSource(input); Exporter writer = new NullExporter(export_major_version, export_minor_version, console); BaseReader reader; if (FilenameUtils.getExtension(input.getAbsolutePath()).equalsIgnoreCase("wrl")) { reader = new VRML97Reader(); } else { reader = new X3DReader(); } AbstractFilter filter = this; reader.setContentHandler(filter); reader.setRouteHandler(filter); reader.setScriptHandler(filter); reader.setProtoHandler(filter); reader.setErrorReporter(console); filter.setContentHandler(writer); filter.setRouteHandler(writer); filter.setScriptHandler(writer); filter.setProtoHandler(writer); reader.parse(is); try { // clean up... is.close(); } catch (IOException ioe) { // ignore } // Convert all supported geometry to ITS List<CommonEncodable> nodes = parsedScene.getRootNodes(); // Assume the scenegraph is flat via visual_mesh_conversion.sh int len = nodes.size(); for (int i = 0; i < len; i++) { CommonEncodable enc = nodes.get(i); if (enc.getNodeName().equals("Shape")) { processShape(enc); shapes.add(enc); } } Iterator<CommonEncodable> itr2 = shapes.iterator(); while (itr2.hasNext()) { CommonEncodable n = itr2.next(); parsedScene.removeRootNode(n); } } /** * Load the specified file X3D file. */ public void load(String baseURL, InputStream input) throws IOException, IllegalArgumentException { int export_major_version = DEFAULT_OUPUT_MAJOR_VERSION; int export_minor_version = DEFAULT_OUPUT_MINOR_VERSION; InputSource is = new InputSource(baseURL, input); Exporter writer = new NullExporter(export_major_version, export_minor_version, console); X3DReader reader = new X3DReader(); AbstractFilter filter = this; reader.setContentHandler(filter); reader.setRouteHandler(filter); reader.setScriptHandler(filter); reader.setProtoHandler(filter); reader.setErrorReporter(console); filter.setContentHandler(writer); filter.setRouteHandler(writer); filter.setScriptHandler(writer); filter.setProtoHandler(writer); reader.parse(is); try { // clean up... is.close(); } catch (IOException ioe) { // ignore } // Convert all supported geometry to ITS List<CommonEncodable> nodes = parsedScene.getRootNodes(); // Assume the scenegraph is flat via visual_mesh_conversion.sh int len = nodes.size(); for (int i = 0; i < len; i++) { CommonEncodable enc = nodes.get(i); if (enc.getNodeName().equals("Shape")) { processShape(enc); shapes.add(enc); } } Iterator<CommonEncodable> itr2 = shapes.iterator(); while (itr2.hasNext()) { CommonEncodable n = itr2.next(); parsedScene.removeRootNode(n); } } /** * Get all the global nodes such as Viewpoints. No Shape data will be present. */ public List<CommonEncodable> getGlobals() { return parsedScene.getRootNodes(); } /** * Get the Shape bundles of Appearance and Geometry. */ public List<CommonEncodable> getShapes() { return shapes; } /** * Clear all resources associated with this loader. */ public void clear() { parsedScene = null; shapes = null; } /** * Convert geometry into ITS */ private void processShape(CommonEncodable node) throws IllegalArgumentException { CommonEncodable geom = (CommonEncodable) node.getValue("geometry"); ArrayData adata; int[] coord_index = null; String nodeName = geom.getNodeName(); if (nodeName.equals("IndexedFaceSet")) { adata = (ArrayData) geom.getValue("coordIndex"); } else { adata = (ArrayData) geom.getValue("index"); } coord_index = (int[]) adata.data; if (nodeName.equals("IndexedTriangleSet")) { } else if (nodeName.equals("IndexedFaceSet")) { coord_index = convertIFSToITS(coord_index); } else if (nodeName.equals("IndexedTriangleStripSet")) { coord_index = MeshConverter.convertITSSToITS(coord_index); } else if (nodeName.equals("IndexedTriangleFanSet")) { coord_index = MeshConverter.convertITFSToITS(coord_index); } else { System.out.println("Unsupported geometry: " + geom.getNodeName()); return; } CommonEncodable its = factory.getEncodable("IndexedTriangleSet", null); its.setValue("index", new ArrayData(coord_index, coord_index.length)); its.setValue("coord", (CommonEncodable) geom.getValue("coord")); its.setValue("color", (CommonEncodable) geom.getValue("color")); its.setValue("normal", (CommonEncodable) geom.getValue("normal")); its.setValue("texCoord", (CommonEncodable) geom.getValue("texCoord")); its.setValue("ccw", (Boolean) geom.getValue("ccw")); its.setValue("colorPerVertex", (Boolean) geom.getValue("colorPerVertex")); its.setValue("normalPerVertex", (Boolean) geom.getValue("normalPerVertex")); its.setValue("solid", (Boolean) geom.getValue("solid")); node.setValue("geometry", its); } /** * Converts the IndexedFaceSet index list to IndexedTriangleSet index list. * Assumes that the IFS index list is constructed as triangles (every 4th * index is the -1 separator); otherwise an IllegalArgumentException is thrown. * * @param coord_index The IndexedFaceSet index * @return newly ordered IndexedTriangleSet index * @throws IllegalArgumentException */ private int[] convertIFSToITS(int[] coord_index) throws IllegalArgumentException { // Calculate the length of the new index array // Assumes that every 4th index is the IFS -1 separator int len = coord_index.length - (coord_index.length / 4); int[] triangleIndex = new int[len]; int newIndex = 0; try { for (int i = 0; i < coord_index.length; i++) { // Skip every 4th index if ((i + 1) % 4 == 0) { continue; } // Make sure that index is not -1, which can happen if triangles // and quads (for example) are in the index list if (coord_index[i] < 0) { throw new IllegalArgumentException(); } triangleIndex[newIndex] = coord_index[i]; newIndex++; } } catch (Exception e) { throw new IllegalArgumentException("Error converting IFS to ITS. IFS index list must be in triangles."); } return triangleIndex; } /** * Declaration of the end of the document. There will be no further parsing * and hence events after this. * * @throws SAVException This call is taken at the wrong time in the * structure of the document * @throws VRMLException The content provided is invalid for this * part of the document or can't be parsed */ public void endDocument() throws SAVException, VRMLException { parsedScene = scene; super.endDocument(); } }