package bs.bs2d.io;
import bs.bs2d.fea.Edge;
import bs.bs2d.fea.Node2D;
import bs.bs2d.fea.TriMesh2D;
import java.awt.geom.Line2D;
import java.io.File;
import java.util.List;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.vecmath.Point2f;
import org.apache.commons.io.FileUtils;
/**
* Class for reading meshes from mesh files
* @author Djen
*/
public class MeshReader {
public static final String WHITESPACE_DELIMITER = "\\s+";
private static FileNameExtensionFilter fileFilter;
public static TriMesh2D readMesh(File f) throws Exception{
TriMesh2D mesh;
if(f.getName().endsWith(".grd")){
mesh = readGrdFile(f);
} else if(f.getName().endsWith(".vol")){
mesh = readVolFile(f);
} else if(f.getName().endsWith(".msh")){
mesh = readMshFile(f);
} else {
throw new Exception("Unknown file format!");
}
checkMesh(mesh);
return mesh;
}
/**
* Read a 2D mesh consisting of triangular (three node) elements from a
* Gridgen style .grd file.
* @param f file to read mesh data from
* @return the mesh object described by the file
*/
public static TriMesh2D readGrdFile(File f) throws Exception{
TriMesh2D mesh = new TriMesh2D();
List<String> lines;
lines = FileUtils.readLines(f);
int index = 0;
while(lines.get(index).startsWith("#"))
index++;
String[] vals = lines.get(index).split(WHITESPACE_DELIMITER);
index++;
int nodes = Integer.parseInt(vals[0]);
int elems = Integer.parseInt(vals[1]);
// read nodes
for(int i=0; i < nodes; i++){
vals = lines.get(index+i).split(WHITESPACE_DELIMITER);
int ni = Integer.parseInt(vals[0]);
float x = Float.parseFloat(vals[1]);
float y = Float.parseFloat(vals[2]);
mesh.addNode(new Node2D(ni, x, y));
}
index += nodes;
// read elements
for(int i=0; i < elems; i++){
vals = lines.get(index+i).split(WHITESPACE_DELIMITER);
if(!vals[2].equals("tri"))
throw new Exception("Element type not supported: " + vals[2]);
int ei = Integer.parseInt(vals[0]);
int[] nodeIndex = new int[3];
for(int j=0; j < 3; j++)
nodeIndex[j] = Integer.parseInt(vals[j+3]);
mesh.addNewElement(ei, nodeIndex);
}
mesh.finalizeConstruction();
return mesh;
}
/**
* Read a 2D mesh consisting of triangular (three node) elements from a
* GMesh style .msh file.
* @param f file to read mesh data from
* @return the mesh object described by the file
*/
public static TriMesh2D readMshFile(File f) throws Exception{
TriMesh2D mesh = new TriMesh2D();
List<String> lines;
lines = FileUtils.readLines(f);
int index = lines.indexOf("$Nodes") + 1;
String[] vals;
// read nodes
int nodes = Integer.parseInt(lines.get(index++));
for(int i=0; i < nodes; i++){
vals = lines.get(index+i).split(WHITESPACE_DELIMITER);
int ni = Integer.parseInt(vals[0]);
float x = Float.parseFloat(vals[1]);
float y = Float.parseFloat(vals[2]);
mesh.addNode(new Node2D(ni, x, y));
}
index += nodes;
// done
while(!lines.get(index).equals("$Elements"))
index++;
index++;
// read elements
int elems = Integer.parseInt(lines.get(index++));
for(int i=0; i < elems; i++){
vals = lines.get(index+i).split(WHITESPACE_DELIMITER);
if(!vals[1].equals("2"))
continue;
int ei = Integer.parseInt(vals[0]);
int tags = Integer.parseInt(vals[2]);
int[] nodeIndex = new int[3];
for(int j=0; j < 3; j++)
nodeIndex[j] = Integer.parseInt(vals[3+tags+j]);
mesh.addNewElement(ei, nodeIndex);
}
mesh.finalizeConstruction();
return mesh;
}
/**
* Read a 2D mesh consisting of triangular (three node) elements from a
* Netgen style .vol file.
* @param f file to read mesh data from
* @return the mesh object described by the file
*/
public static TriMesh2D readVolFile(File f) throws Exception{
TriMesh2D mesh = new TriMesh2D();
List<String> lines;
lines = FileUtils.readLines(f);
int iElems = -1;
int nElems = 0;
int iNodes = -1;
int nNodes = 0;
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
if(line.equals("points")){
nNodes = Integer.parseInt(lines.get(++i));
iNodes = ++i;
}
if(line.equals("surfaceelementsuv")){
nElems = Integer.parseInt(lines.get(++i));
iElems = ++i;
}
}
String[] vals;
// read nodes
for(int i=0; i < nNodes; i++){
vals = lines.get(iNodes + i).split(WHITESPACE_DELIMITER);
float x = Float.parseFloat(vals[1]);
float y = Float.parseFloat(vals[2]);
mesh.addNode(new Node2D(i+1, x, y));
}
// read elements
for(int i=0; i < nElems; i++){
vals = lines.get(iElems + i).split(WHITESPACE_DELIMITER);
if(!vals[5].equals("3"))
throw new Exception("Element type not supported: " + vals[5]);
int[] nodeIndex = new int[3];
for(int j=0; j < 3; j++)
nodeIndex[j] = Integer.parseInt(vals[j+6]);
mesh.addNewElement(i, nodeIndex);
}
mesh.finalizeConstruction();
return mesh;
}
public static void checkMesh(TriMesh2D mesh) throws Exception{
if(mesh.getNodeCount() == 0 || mesh.getElementCount() == 0)
throw new Exception("Empty mesh!");
List<Node2D> nodes = mesh.getNodes();
for (int i = 0; i < nodes.size(); i++) {
// test manifold
Node2D n = nodes.get(i);
int d = 0;
if(n.isOuter())
d = 1;
if(n.getEdgeCount()-n.getElementCount() > d){
throw new Exception("Mesh is non-manifold!");
}
if(n.getElementCount() == 0){
System.err.println("Mesh contains unused nodes");
}
}
List<Edge> edges = mesh.getEdges();
Line2D[] lines = new Line2D[mesh.getEdgeCount()];
for (int i = 0; i < lines.length; i++) {
Edge e = edges.get(i);
Point2f p0 = e.getNode(0).getPoint2f();
Point2f p1 = e.getNode(1).getPoint2f();
lines[i] = new Line2D.Float(p0.x, p0.y, p1.x, p1.y);
for(int j=0; j<i; j++){
if(lines[i].intersectsLine(lines[j])){
if(!(lines[i].getP1().equals(lines[j].getP1()) ||
lines[i].getP1().equals(lines[j].getP2()) ||
lines[i].getP2().equals(lines[j].getP1()) ||
lines[i].getP2().equals(lines[j].getP2()) )){
throw new Exception("Mesh contains intersecting edges!");
}
}
}
}
}
/**
* @return the fileFilter
*/
public static FileNameExtensionFilter getFileFilter() {
if(fileFilter == null){
String description = "Mesh Files (*.grd, *.vol, *.msh)";
String[] extensions = new String[]{"grd", "vol", "msh"};
fileFilter = new FileNameExtensionFilter(description, extensions);
}
return fileFilter;
}
}