/*
* Project Info: http://jcae.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2009, by EADS France
*/
package org.jcae.mesh.xmldata;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.set.hash.TIntHashSet;
import gnu.trove.map.hash.TIntIntHashMap;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
/**
*
* @author Jerome Robert
*/
public abstract class AmibeReader extends XMLReader implements JCAEXMLData {
public class Group
{
private String name;
private int numberOfNodes, numberOfTrias, numberOfBeams;
private int nodesOffset, beamsOffset, triasOffset;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the numberOfNodes
*/
public int getNumberOfNodes() {
return numberOfNodes;
}
/**
* @return the numberOfTrias
*/
public int getNumberOfTrias() {
return numberOfTrias;
}
/**
* @return the numberOfBeams
*/
public int getNumberOfBeams() {
return numberOfBeams;
}
/**
* @return the nodesOffset
*/
public long getNodesOffset() {
return nodesOffset;
}
/**
* @return the beamsOffset
*/
public long getBeamsOffset() {
return beamsOffset;
}
/**
* @return the triasOffset
*/
public long getTriasOffset() {
return triasOffset;
}
public int[] readTria3Ids() throws IOException
{
if (numberOfTrias == 0)
return new int[0];
PrimitiveFileReaderFactory pfrf = new PrimitiveFileReaderFactory();
IntFileReader ifrG = pfrf.getIntReader(getBinFile(groupsFilename));
int[] toReturn = new int[numberOfTrias];
for (int i = 0; i < numberOfTrias; i++)
toReturn[i] = ifrG.get(triasOffset+i);
ifrG.close();
return toReturn;
}
public int[] readTria3() throws IOException
{
if (numberOfTrias == 0)
return new int[0];
PrimitiveFileReaderFactory pfrf = new PrimitiveFileReaderFactory();
int[] ids = readTria3Ids();
IntFileReader ifrT = pfrf.getIntReader(getBinFile("triangles"+dim()+"d.bin"));
int[] toReturn = new int[numberOfTrias * 3];
for (int i = 0; i < numberOfTrias; i++)
ifrT.get(ids[i] * 3, toReturn, i * 3, 3);
ifrT.close();
return toReturn;
}
public int[] readBeams() throws IOException
{
if (numberOfBeams == 0)
return new int[0];
PrimitiveFileReaderFactory pfrf = new PrimitiveFileReaderFactory();
int[] ids = readBeamsIds();
IntFileReader ifrT = pfrf.getIntReader(getBinFile("beams"+dim()+"d.bin"));
int[] toReturn = new int[numberOfBeams * 2];
for (int i = 0; i < numberOfBeams; i++)
ifrT.get(ids[i] * 2, toReturn, i * 2, 2);
ifrT.close();
return toReturn;
}
public int[] readBeamsIds() throws IOException {
if (numberOfBeams == 0)
return new int[0];
PrimitiveFileReaderFactory pfrf = new PrimitiveFileReaderFactory();
IntFileReader ifrG = pfrf.getIntReader(getBinFile("bgroups.bin"));
int[] toReturn = new int[numberOfBeams];
for (int i = 0; i < numberOfBeams; i++)
toReturn[i] = ifrG.get(beamsOffset+i);
ifrG.close();
return toReturn;
}
public int[] readNodesIds() throws IOException {
if (numberOfNodes == 0)
return new int[0];
PrimitiveFileReaderFactory pfrf = new PrimitiveFileReaderFactory();
IntFileReader ifrG = pfrf.getIntReader(getBinFile("nodeGroups.bin"));
int[] toReturn = new int[numberOfNodes];
for (int i = 0; i < numberOfNodes; i++)
toReturn[i] = ifrG.get(nodesOffset+i);
ifrG.close();
return toReturn;
}
}
public class SubMesh
{
private int subShape;
private int numberOfNodes, numberOfTrias, numberOfBeams, numberOfReferences;
private int nodesOffset, beamsOffset, triasOffset;
private LinkedHashMap<String, Group> groups = new LinkedHashMap<String, Group>();
/**
* @return the subShape
*/
public int getSubShape() {
return subShape;
}
/**
* @return the numberOfNodes
*/
public int getNumberOfNodes() {
return numberOfNodes;
}
/**
* @return the numberOfTrias
*/
public int getNumberOfTrias() {
return numberOfTrias;
}
/**
* @return the numberOfBeams
*/
public int getNumberOfBeams() {
return numberOfBeams;
}
/**
* @return the nodesOffset
*/
public long getNodesOffset() {
return nodesOffset;
}
/**
* @return the beamsOffset
*/
public long getBeamsOffset() {
return beamsOffset;
}
/**
* @return the triasOffset
*/
public long getTriasOffset() {
return triasOffset;
}
/**
* @return the groups
*/
public List<Group> getGroups() {
return new ArrayList<Group>(groups.values());
}
public Group getGroup(String id)
{
return groups.get(id);
}
public DoubleFileReader getNodes() throws IOException
{
File f = getBinFile("nodes"+dim()+"d.bin");
return new PrimitiveFileReaderFactory().getDoubleReader(f);
}
public DoubleFileReader getNormals() throws IOException
{
File f = getBinFile("normals"+dim()+"d.bin");
return new PrimitiveFileReaderFactory().getDoubleReader(f);
}
public IntFileReader getBeams() throws IOException
{
return new PrimitiveFileReaderFactory().getIntReader(
getBinFile("beams"+dim()+"d.bin"));
}
public IntFileReader getTriangles() throws IOException
{
return new PrimitiveFileReaderFactory().getIntReader(
getBinFile("triangles"+dim()+"d.bin"));
}
public float[] readNodes(int[] nodesID) throws IOException
{
DoubleFileReader dfr = getNodes();
float[] toReturn = new float[nodesID.length * dim()];
for (int i = 0; i < nodesID.length; i++)
{
int ii = i * dim();
int iid = nodesID[i] * dim() + nodesOffset * dim();
for(int j = 0; j < dim(); j++)
toReturn[ii+j] = (float) dfr.get(iid+j);
}
dfr.close();
return toReturn;
}
public int[] getReferences() throws IOException
{
int[] refs = new int[numberOfReferences];
if(numberOfReferences > 0)
{
IntFileReader ifrR = new PrimitiveFileReaderFactory().getIntReader(
getBinFile("nodes1dref.bin"));
ifrR.get(refs);
ifrR.close();
}
return refs;
}
public int getNumberOfReferences() {
return numberOfReferences;
}
private void flushByteBuffer(ByteBuffer bb, WritableByteChannel out)
throws IOException
{
bb.limit(bb.position());
bb.rewind();
out.write(bb);
bb.clear();
}
/** Read a group and write it to a channel */
public void readGroup(Group group, WritableByteChannel out)
throws IOException
{
int[] trias = group.readTria3();
int[] nodesIds = new TIntHashSet(trias).toArray();
Arrays.sort(nodesIds);
ByteBuffer bb = ByteBuffer.allocate(128*1024);
bb.order(ByteOrder.nativeOrder());
bb.putInt(nodesIds.length * 3);
TIntIntHashMap nodeMap = new TIntIntHashMap(nodesIds.length);
DoubleFileReader nodes = getNodes();
double[] coords = new double[3];
int k = 0;
for(int id:nodesIds)
{
nodes.get(3*id, coords);
if(bb.remaining() < 24)
flushByteBuffer(bb, out);
for(int i = 0; i < 3; i++)
bb.putDouble(coords[i]);
nodeMap.put(id, k++);
}
nodesIds = null;
nodes.close();
flushByteBuffer(bb, out);
bb.putInt(group.getNumberOfTrias() * 3);
for(int i = 0; i < trias.length / 3; i++)
{
if(bb.remaining() < 12)
flushByteBuffer(bb, out);
for(int j = 0; j < 3; j++)
bb.putInt(nodeMap.get(trias[3*i+j]));
}
flushByteBuffer(bb, out);
}
}
public static class Dim1 extends AmibeReader {
public Dim1(String path) throws SAXException, IOException {
super(path);
}
@Override
protected int dim() {
return 1;
}
}
public static class Dim2 extends AmibeReader {
private final String binDirectory, xmlFile;
public Dim2(String name, int index) throws SAXException, IOException {
super(name);
binDirectory = "jcae2d."+ index +".files";
xmlFile = "jcae2d."+index;
}
@Override
protected int dim() {
return 2;
}
@Override
protected String binDirectory() {
return binDirectory;
}
@Override
protected String xmlFile() {
return xmlFile;
}
}
public static class Dim3 extends AmibeReader {
public Dim3(String path) throws SAXException, IOException {
super(path);
}
@Override
protected int dim() {
return 3;
}
}
private static class AFile
{
public String location;
public int offset;
public String format;
}
private static AFile readFile(Element e)
{
Element f = getElement(e, "file");
AFile r = new AFile();
if(f != null)
{
r.location = f.getAttribute("location");
String s = f.getAttribute("offset");
r.offset = s.isEmpty() ? 0 : Integer.parseInt(s);
r.format = f.getAttribute("format");
}
return r;
}
private static int readInt(Element e, String tag)
{
Element t = getElement(e, tag);
if(t != null)
return Integer.parseInt(t.getTextContent());
else
return 0;
}
private String shape;
private List<SubMesh> submeshes = new ArrayList<SubMesh>();
private final String path;
@Override
protected void read(Document dom) {
Element mesh = getElement(dom.getDocumentElement(), "mesh");
assert mesh != null;
shape = readFile(getElement(mesh, "shape")).location;
for(Element e:getElements(mesh, "submesh"))
{
SubMesh sm = new SubMesh();
sm.subShape = readInt(e, "subshape");
Element nodes = getElement(e, "nodes");
sm.numberOfNodes = readInt(nodes, "number");
sm.nodesOffset = readFile(nodes).offset;
Element references = getElement(nodes, "references");
if(references != null)
sm.numberOfReferences = readInt(references, "number");
Element triangles = getElement(e, "triangles");
if(triangles != null)
{
sm.numberOfTrias = readInt(triangles, "number");
sm.triasOffset = readFile(triangles).offset;
}
Element beams = getElement(e, "beams");
if(beams != null)
{
sm.numberOfBeams = readInt(beams, "number");
sm.beamsOffset = readFile(beams).offset;
}
for(Element eg:getElements(e, "groups", "group"))
{
Group g = new Group();
g.name = getElement(eg, "name").getTextContent();
g.numberOfTrias = readInt(eg, "number");
g.triasOffset = readFile(eg).offset;
Element beg = getElement(eg, "beams");
if(beg != null)
{
g.numberOfBeams = readInt(beg, "number");
g.beamsOffset = readFile(beg).offset;
}
sm.groups.put(g.getName(), g);
}
for(Element eg:getElements(e, "nodeGroups", "group"))
{
String name = getElement(eg, "name").getTextContent();
Group g = sm.groups.get(name);
if(g == null)
{
g = new Group();
g.name = name;
sm.groups.put(g.getName(), g);
g.numberOfNodes = readInt(eg, "number");
g.nodesOffset = readFile(eg).offset;
}
}
submeshes.add(sm);
}
}
public List<SubMesh> getSubmeshes() {
return Collections.unmodifiableList(submeshes);
}
public String getShape() {
return shape;
}
@Override
protected String getXSD() {
return "jcae.xsd";
}
protected abstract int dim();
protected String binDirectory()
{
return "jcae" + dim() + "d.files";
}
protected String xmlFile()
{
return "jcae" + dim() + "d";
}
protected File getBinFile(String name)
{
return new File(new File(path, binDirectory()), name);
}
public AmibeReader(String path) throws SAXException, IOException {
this.path = path;
read(new File(path, xmlFile()));
}
}