package org.jcae.vtk;
import gnu.trove.list.array.TFloatArrayList;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntIntHashMap;
import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class UNVParser
{
private static final int TETRA4_MASK = 0x10000000;
private static final int HEXA8_MASK = 0x20000000;
private static final int TRIA3_MASK = 0x10000000;
private static final int TRIA6_MASK = 0x20000000;
private static final int QUAD4_MASK = 0x40000000;
private static final int BEAM2_MASK = 0x80000000;
private float[] nodesCoordinates;
private TIntIntHashMap nodesIndicesMap;
private boolean hasBeam2, hasTria3, hasTria6, hasQuad4, hasTetra4, hasHexa8;
private ArrayList<String> surfaceGroupNames=new ArrayList<String>();
private ArrayList<int[]> surfaceGroups=new ArrayList<int[]>();
private TIntArrayList surfaceIndices=new TIntArrayList();
private TIntArrayList volumeIndices=new TIntArrayList();
private TIntIntHashMap elementSurfaceIndicesMap, elementVolumeIndicesMap;
public float[] getNodesCoordinates()
{
return nodesCoordinates;
}
/**
* @return
* @deprecated use getGroupNames instead.
*/
@Deprecated
public String[] getTria3GroupNames()
{
return getGroupNames();
}
public String[] getGroupNames()
{
return surfaceGroupNames.toArray(new String[0]);
}
public int[] getTria3FromGroup(int groupId)
{
int[] elids=surfaceGroups.get(groupId);
int cnt = 0;
for(int val: elids)
{
if ((val & TRIA3_MASK) != 0)
cnt++;
}
int[] toReturn=new int[cnt*3];
cnt = 0;
for(int val: elids)
{
if ((val & TRIA3_MASK) == 0)
continue;
int iid=(val & ~TRIA3_MASK);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
}
return toReturn;
}
public int[] getQuad4FromGroup(int groupId)
{
int[] elids=surfaceGroups.get(groupId);
int cnt = 0;
for(int val: elids)
{
if ((val & QUAD4_MASK) != 0)
cnt++;
}
int[] toReturn=new int[cnt*4];
cnt = 0;
for(int val: elids)
{
if ((val & QUAD4_MASK) == 0)
continue;
int iid=(val & ~QUAD4_MASK);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
}
return toReturn;
}
public int[] getBeam2FromGroup(int groupId)
{
int[] elids=surfaceGroups.get(groupId);
int cnt = 0;
for(int val: elids)
{
if ((val & BEAM2_MASK) != 0)
cnt++;
}
int[] toReturn=new int[cnt*2];
cnt = 0;
for(int val: elids)
{
if ((val & BEAM2_MASK) == 0)
continue;
int iid=(val & ~BEAM2_MASK);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
}
return toReturn;
}
public int[] getTria6FromGroup(int groupId)
{
int[] elids=surfaceGroups.get(groupId);
int cnt = 0;
for(int val: elids)
{
if ((val & TRIA6_MASK) != 0)
cnt++;
}
int[] toReturn=new int[cnt*6];
cnt = 0;
for(int val: elids)
{
if ((val & TRIA6_MASK) == 0)
continue;
int iid=(val & ~TRIA6_MASK);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
toReturn[cnt++]=surfaceIndices.get(iid++);
}
return toReturn;
}
public boolean hasBeam2()
{
return hasBeam2;
}
public boolean hasTria6()
{
return hasTria6;
}
public void parse(BufferedReader rd) throws IOException
{
double unit = 1.0;
String line;
elementSurfaceIndicesMap=new TIntIntHashMap();
elementVolumeIndicesMap=new TIntIntHashMap();
nodesIndicesMap=new TIntIntHashMap();
while ((line = rd.readLine()) != null)
{
line = rd.readLine();
int blockID=Integer.parseInt(line.trim());
switch(blockID)
{
case 2411:
case 781:
readNodes(rd, unit);
break;
case 2412:
readFace(rd);
break;
case 164:
unit=readUnit(rd);
break;
case 2435:
case 2430:
readGroup(rd, blockID);
break;
case 790:
readLoadSets(rd);
break;
default:
while (!(line = rd.readLine()).equals(" -1"))
{
// Do nothing
}
}
}
//If there are triangles but no groups
if(surfaceGroupNames.size()==0 && surfaceIndices.size()>0)
{
surfaceGroupNames.add("");
int[] group=new int[surfaceIndices.size()];
int i = 0;
for(int val : elementSurfaceIndicesMap.values())
{
group[i]=val;
i++;
}
surfaceGroups.add(group);
}
//free indices maps.
nodesIndicesMap=null;
elementSurfaceIndicesMap=null;
elementVolumeIndicesMap=null;
}
private void readFace(BufferedReader rd) throws IOException
{
String line;
while (!(line = rd.readLine().trim()).equals("-1"))
{
// first line: type of object
StringTokenizer st = new StringTokenizer(line);
int ind = Integer.parseInt(st.nextToken());
int type = Integer.parseInt(st.nextToken());
line = rd.readLine(); //RECORD 2
switch(type)
{
case 21: // Linear beam
st = new StringTokenizer(line);
elementSurfaceIndicesMap.put(ind, BEAM2_MASK | surfaceIndices.size());
for(int i=0; i<2; i++)
surfaceIndices.add(nodesIndicesMap.get(Integer.parseInt(st.nextToken())));
hasBeam2 = true;
break;
case 74: // Membrane Linear Triangle
case 91: // Thin Shell Linear Triangle
case 41: // Plane Stress Linear Triangle
st = new StringTokenizer(line);
elementSurfaceIndicesMap.put(ind, TRIA3_MASK | surfaceIndices.size());
for(int i=0; i<3; i++)
surfaceIndices.add(nodesIndicesMap.get(Integer.parseInt(st.nextToken())));
hasTria3 = true;
break;
case 92: // Thin Shell Parabolic Triangle
st = new StringTokenizer(line);
elementSurfaceIndicesMap.put(ind, TRIA6_MASK | surfaceIndices.size());
for(int i=0; i<3; i++)
{
surfaceIndices.add(nodesIndicesMap.get(Integer.parseInt(st.nextToken())));
st.nextToken(); //keep only vertex nodes
}
hasTria6 = true;
break;
case 94: // Thin Shell Linear Quadrilateral
st = new StringTokenizer(line);
elementSurfaceIndicesMap.put(ind, QUAD4_MASK | surfaceIndices.size());
for(int i=0; i<4; i++)
surfaceIndices.add(nodesIndicesMap.get(Integer.parseInt(st.nextToken())));
hasQuad4 = true;
break;
case 111: // Solid Linear Tetrahedron
st = new StringTokenizer(line);
elementVolumeIndicesMap.put(ind, TETRA4_MASK | volumeIndices.size());
for(int i=0; i<4; i++)
volumeIndices.add(nodesIndicesMap.get(Integer.parseInt(st.nextToken())));
hasTetra4 = true;
break;
case 115: // Solid Linear Brick
st = new StringTokenizer(line);
elementVolumeIndicesMap.put(ind, HEXA8_MASK | volumeIndices.size());
for(int i=0; i<8; i++)
volumeIndices.add(nodesIndicesMap.get(Integer.parseInt(st.nextToken())));
hasHexa8 = true;
break;
}
}
}
private void readGroup(BufferedReader rd, int blockID) throws IOException
{
String line = rd.readLine();
while (!line.trim().equals("-1"))
{
// read the number of elements to read in the last number of the line
StringTokenizer st = new StringTokenizer(line);
String snb = st.nextToken();
while (st.hasMoreTokens())
{
snb = st.nextToken();
}
int nbelem = Integer.parseInt(snb);
// Read group name
surfaceGroupNames.add(rd.readLine().trim());
TIntArrayList facelist = new TIntArrayList();
while ((line = rd.readLine().trim()).startsWith("8"))
{
st = new StringTokenizer(line);
// read one element over two, the first one doesnt matter
while (st.hasMoreTokens()) {
st.nextToken();
String index = st.nextToken();
int id=elementSurfaceIndicesMap.get(Integer.parseInt(index));
facelist.add(id);
nbelem--;
if (blockID == 2435)
{
st.nextToken();
st.nextToken();
}
}
if (nbelem <= 0)
{
line = rd.readLine();
break;
}
}
surfaceGroups.add(facelist.toArray());
}
}
private void readTetra4LoadSet(int element, int faceId, TIntArrayList group)
{
int p1=volumeIndices.get(element++);
int p2=volumeIndices.get(element++);
int p3=volumeIndices.get(element++);
int p4=volumeIndices.get(element++);
group.add(TRIA3_MASK | surfaceIndices.size());
switch(faceId)
{
case 1:
surfaceIndices.add(p1);
surfaceIndices.add(p2);
surfaceIndices.add(p3);
break;
case 2:
surfaceIndices.add(p1);
surfaceIndices.add(p2);
surfaceIndices.add(p4);
break;
case 3:
surfaceIndices.add(p2);
surfaceIndices.add(p3);
surfaceIndices.add(p4);
break;
case 4:
surfaceIndices.add(p1);
surfaceIndices.add(p3);
surfaceIndices.add(p4);
break;
default:
throw new IllegalStateException("Face ID should be 1,2,3 or 4");
}
}
private void readHexa8LoadSet(int element, int faceId, TIntArrayList group)
{
int p1=volumeIndices.get(element++);
int p2=volumeIndices.get(element++);
int p3=volumeIndices.get(element++);
int p4=volumeIndices.get(element++);
int p5=volumeIndices.get(element++);
int p6=volumeIndices.get(element++);
int p7=volumeIndices.get(element++);
int p8=volumeIndices.get(element++);
group.add(QUAD4_MASK | surfaceIndices.size());
switch(faceId)
{
case 1:
surfaceIndices.add(p1);
surfaceIndices.add(p2);
surfaceIndices.add(p3);
surfaceIndices.add(p4);
break;
case 2:
surfaceIndices.add(p5);
surfaceIndices.add(p6);
surfaceIndices.add(p7);
surfaceIndices.add(p8);
break;
case 3:
surfaceIndices.add(p1);
surfaceIndices.add(p2);
surfaceIndices.add(p6);
surfaceIndices.add(p5);
break;
case 4:
surfaceIndices.add(p2);
surfaceIndices.add(p3);
surfaceIndices.add(p7);
surfaceIndices.add(p6);
break;
case 5:
surfaceIndices.add(p3);
surfaceIndices.add(p4);
surfaceIndices.add(p8);
surfaceIndices.add(p7);
break;
case 6:
surfaceIndices.add(p1);
surfaceIndices.add(p4);
surfaceIndices.add(p8);
surfaceIndices.add(p5);
break;
default:
throw new IllegalStateException("Face ID should be 1,2,3,4,5 or 6");
}
}
private void readLoadSets(BufferedReader rd) throws IOException
{
rd.readLine(); //RECORD 1 (skip)
String name=rd.readLine(); //RECORD 2 (skip)
String line;
TIntArrayList groupTetra4=new TIntArrayList();
TIntArrayList groupHexa8=new TIntArrayList();
while (!(line = rd.readLine().trim()).equals("-1")) //RECORD 3 (type 2)
{
// first line: type of object
StringTokenizer st = new StringTokenizer(line);
st.nextToken(); //skip face pressure load label
int element=elementVolumeIndicesMap.get(Integer.parseInt(st.nextToken()));
int faceId=Integer.parseInt(st.nextToken());
if((element & TETRA4_MASK) != 0)
{
readTetra4LoadSet(element & (~TETRA4_MASK), faceId, groupTetra4);
}
else if((element & HEXA8_MASK) != 0)
{
readHexa8LoadSet(element & (~HEXA8_MASK), faceId, groupHexa8);
}
rd.readLine(); //RECORD 4
rd.readLine(); //RECORD 5
}
if(!groupTetra4.isEmpty())
{
surfaceGroupNames.add(name);
surfaceGroups.add(groupTetra4.toArray());
}
if(!groupHexa8.isEmpty())
{
surfaceGroupNames.add(name);
surfaceGroups.add(groupHexa8.toArray());
}
return;
}
private void readNodes(BufferedReader rd, double unit) throws IOException
{
TIntIntHashMap indices=new TIntIntHashMap();
TFloatArrayList coords=new TFloatArrayList();
float x, y, z;
String line;
int k=0;
while (!(line = rd.readLine().trim()).equals("-1"))
{
// First number : the node's id
StringTokenizer st = new StringTokenizer(line);
int index = new Integer(st.nextToken()).intValue();
line = rd.readLine();
// line contains coord x,y,z
st = new StringTokenizer(line);
String x1 = st.nextToken();
String y1 = st.nextToken();
String z1;
if(st.hasMoreTokens())
z1 = st.nextToken();
else
z1 = "0.0";
x1 = x1.replace('D', 'E');
y1 = y1.replace('D', 'E');
z1 = z1.replace('D', 'E');
x = (float) (Double.parseDouble(x1) / unit);
y = (float) (Double.parseDouble(y1) / unit);
z = (float) (Double.parseDouble(z1) / unit);
indices.put(index, k++);
coords.add(x);
coords.add(y);
coords.add(z);
}
this.nodesIndicesMap=indices;
this.nodesCoordinates=coords.toArray();
}
private double readUnit(BufferedReader rd)
{
double unit = 1.0;
String line;
try {
//retrieve the second line
line = rd.readLine();
line = rd.readLine();
// fisrt number : the unit
StringTokenizer st = new StringTokenizer(line);
String unite = st.nextToken();
unite = unite.replace('D', 'E');
unit = Double.parseDouble(unite);
while (!(line = rd.readLine().trim()).equals("-1")) {
// ???
}
} catch (Exception e) {
e.printStackTrace();
}
return unit;
}
/**
* Debug
* @param args
*/
public static void main(String[] args)
{
try
{
UNVParser unvp=new UNVParser();
unvp.parse(new BufferedReader(new FileReader("/home/jerome/cassiope/resources/example/tecplot50x50x50.unv")));
System.out.println(unvp.getQuad4FromGroup(0).length);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}