/*
* 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 2011, by EADS France
*/
package org.jcae.mesh.xmldata;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jcae.mesh.xmldata.AmibeReader.Group;
import org.jcae.mesh.xmldata.AmibeReader.SubMesh;
import org.xml.sax.SAXException;
/**
*
* @author Jerome Robert
*/
public class Amibe2GEO {
private static class Node
{
public final double x, y, z;
public int surfaceID = -1;
public int edgeID = -1;
private List<Object> elements = new ArrayList<Object>(6);
private Node(double[] buffer, double scale) {
x = buffer[0] * scale;
y = buffer[1] * scale;
z = buffer[2] * scale;
}
public void addElement(Object element)
{
elements.add(element);
}
public void getEdges(Collection<Edge> edges)
{
for(Object o:elements)
if(o instanceof Edge)
edges.add((Edge) o);
}
/**
* @param result contains {nb edges elements, nb triangles elements}
* at return
*/
public void nbElement(int[] result)
{
result[0] = 0;
result[1] = 0;
for(Object o:elements)
{
if(o instanceof Triangle)
result[1] ++;
else
result[0] ++;
}
}
}
private static class Edge
{
public final Node n1, n2;
public String group;
public int id;
public Edge(Node n1, Node n2) {
this.n1 = n1;
this.n2 = n2;
}
@Override
public boolean equals(Object obj) {
Edge o = (Edge) obj;
return (n1 == o.n1 && n2 == o.n2) || (n1 == o.n2 && n2 == o.n1);
}
@Override
public int hashCode() {
return n1.hashCode() ^ n2.hashCode();
}
public Collection<Triangle> getTriangles()
{
HashSet<Triangle> toReturn = new HashSet<Triangle>(4);
for(Object e:n1.elements)
{
if(e instanceof Triangle)
{
Triangle t=(Triangle) e;
if(equals(t.edge1) || equals(t.edge2) || equals(t.edge3))
toReturn.add(t);
}
}
for(Object e:n2.elements)
{
if(e instanceof Triangle)
{
Triangle t=(Triangle) e;
if(equals(t.edge1) || equals(t.edge2) || equals(t.edge3))
toReturn.add(t);
}
}
return toReturn;
}
}
private static class Triangle
{
public String group;
public final Edge edge1, edge2, edge3;
public final int id;
private Triangle(int[] buffer, Map<Edge, Edge> edgesMap, Node[] nodes, int id) {
edge1 = createEdge(buffer[0], buffer[1], nodes, edgesMap);
edge2 = createEdge(buffer[1], buffer[2], nodes, edgesMap);
edge3 = createEdge(buffer[2], buffer[0], nodes, edgesMap);
nodes[buffer[0]].addElement(this);
nodes[buffer[1]].addElement(this);
nodes[buffer[2]].addElement(this);
this.id = id;
}
private Edge createEdge(int i1, int i2, Node[] nodes,
Map<Edge, Edge> edgesMap) {
Edge e = new Edge(nodes[i1], nodes[i2]);
Edge toReturn = edgesMap.get(e);
if(toReturn == null)
{
edgesMap.put(e, e);
toReturn = e;
}
return toReturn;
}
public void getNodes(Set<Node> result)
{
result.add(edge1.n1);
result.add(edge1.n2);
result.add(edge2.n1);
result.add(edge2.n2);
result.add(edge3.n1);
result.add(edge3.n2);
}
}
private static class Source
{
public final int id, wireID;
public Source(int id, int wireID) {
this.id = id;
this.wireID = wireID;
}
}
private List<Source> sources = new ArrayList<Source>();
private final String inputDir;
public Amibe2GEO(String inputDir)
{
this.inputDir = inputDir;
}
public void writeProject(String directory, String name) throws SAXException, IOException
{
File pd = new File(directory, name);
pd.mkdirs();
PrintWriter ps = new PrintWriter(new File(pd, name+".geo"))
{
@Override
public void println() {
write("\r\n");
}
};
write(ps);
ps.close();
}
public void write(PrintWriter out) throws SAXException, IOException
{
writeHeader(out);
AmibeReader.Dim3 ar = new AmibeReader.Dim3(inputDir);
SubMesh sm = ar.getSubmeshes().get(0);
Node[] nodes = readNodes(sm.getNodes());
Map<Edge, Edge> edgesMap = new HashMap<Edge, Edge>();
Triangle[] triangles = readTriangles(sm.getTriangles(), edgesMap, nodes);
Edge[] beams = readBeams(sm.getBeams(), nodes);
Map<String, Integer> groupIDs = new HashMap<String, Integer>();
int gid = 1;
for(Group g:sm.getGroups())
{
for(int i:g.readBeamsIds())
beams[i].group = g.getName();
for(int i:g.readTria3Ids())
triangles[i].group = g.getName();
groupIDs.put(g.getName(), gid++);
}
LinkedHashSet<Node> surfaceNodes = new LinkedHashSet<Node>();
for(Triangle t:triangles)
t.getNodes(surfaceNodes);
LinkedHashSet<Node> beamNodes = new LinkedHashSet<Node>();
for(Edge e:beams)
{
beamNodes.add(e.n1);
beamNodes.add(e.n2);
}
HashSet<Node> junctions = new HashSet<Node>(surfaceNodes);
junctions.retainAll(beamNodes);
writeDim(out, surfaceNodes.size(), edgesMap.size(), triangles.length,
beamNodes.size(), beams.length, junctions.size(), sm.getGroups().size(),
nbSource(beamNodes));
writeSurfNode(out, surfaceNodes);
writeEdges(out, edgesMap.values());
writeTriangles(out, triangles, groupIDs);
writeWireNode(out, beamNodes, groupIDs);
writeSegments(out, beams, groupIDs);
writeJunctions(out, nodes);
writeFreeSpace(out);
if(!sources.isEmpty())
writeSources(out);
writeProperties(out, sm.getGroups());
writeObject(out);
writeSubObject(out, sm.getGroups());
out.println("[ENDFILE]");
}
private Edge[] readBeams(IntFileReader beams, Node[] nodes)
throws IOException
{
Edge[] toReturn = new Edge[(int)(beams.size()/2)];
int[] buffer = new int[2];
for(int i = 0; i < toReturn.length; i++)
{
beams.get(buffer);
Node n1 = nodes[buffer[0]];
Node n2 = nodes[buffer[1]];
toReturn[i] = new Edge(n1, n2);
toReturn[i].id = i+1;
n1.addElement(toReturn[i]);
n2.addElement(toReturn[i]);
}
return toReturn;
}
private Triangle[] readTriangles(IntFileReader trias,
Map<Edge, Edge> edgesMap, Node[] nodes) throws IOException
{
Triangle[] toReturn = new Triangle[(int)(trias.size()/3)];
int[] buffer = new int[3];
for(int i = 0; i < toReturn.length; i++)
{
trias.get(buffer);
assert buffer[0] >= 0 && buffer[0] < nodes.length : buffer[0]+" "+nodes.length;
assert buffer[1] >= 0 && buffer[1] < nodes.length : buffer[0]+" "+nodes.length;
assert buffer[2] >= 0 && buffer[2] < nodes.length : buffer[0]+" "+nodes.length;
toReturn[i] = new Triangle(buffer, edgesMap, nodes, i+1);
}
return toReturn;
}
private Node[] readNodes(DoubleFileReader dfr) throws IOException
{
double scale = getScaleFactor();
Node[] toReturn = new Node[(int)(dfr.size()/3)];
double[] buffer = new double[3];
for(int i = 0; i<toReturn.length; i++)
{
dfr.get(3*i, buffer);
toReturn[i] = new Node(buffer, scale);
}
return toReturn;
}
private void writeHeader(PrintWriter out)
{
out.println("[GENERAL]");
out.println("3.71 //Version number");
out.println(new Date()+" //Creation date");
out.println("jCAE//Origin software");
out.println("FMM//Analysis type");
out.println("2 //Precision 1:simple 2:double");
out.println("[END]");
out.println();
}
private void writeDim(PrintWriter out, int nbSurfNod, int nbEdge,
int nbTriangles, int nbWireNode, int nbWire, int junctionSize, int nbGroups,
int nbSource)
{
out.println("[DIM]");
out.println(nbSurfNod + " //Number of surface-nod");
out.println(nbEdge + " 0 //Number and multiplicity of edge");
out.println(nbTriangles + " //Number of triangle");
out.println(nbWireNode + " 0 //Number and multiplicity of wire-nod");
out.println(nbWire + " //Number of wire");
out.println(junctionSize
+ " 0 0 //Number of junction and number max of triangle and wire");
out.println("1 0 //Number and rank of FreeSpace");
out.println("0 //Number and rank of Image");
out.println("0 //Number and rank of Lossy plane");
out.println("0 //Number and rank of Full-Reg");
out.println("0 //Number and rank of Parallel plate");
out.println("0 //Number and rank of RectWg");
out.println("0 //Number and rank of RectCavit");
out.println("0 //Number and rank of CylWg");
out.println("0 //Number and rank of Cylcavit");
out.println("0 //Number and rank of CoaxialWg");
out.println("0 //Number and rank of CoaxialCavit");
out.println("1 //Number of Object");
out.println((nbGroups+1)+" //Number of Sub-Object");
out.println(nbSource+" //Number of Sources");
out.println(nbGroups+" //Number of Properties");
out.println("0 //Number of Em-Field");
out.println("0 //Number of Antenna");
out.println("[END]");
out.println();
}
private void writeSurfNode(PrintWriter out, Collection<Node> surfaceNodes) {
out.println("[SURFACE-NOD]");
out.println("TNod Label X(m) Y(m) Z(m) Region");
writeUselessLine(out);
int i = 1;
for(Node n:surfaceNodes)
{
n.surfaceID = i;
out.println(i+" "+i+" "+n.x+" "+n.y+" "+n.z+" 1");
i++;
}
out.println("[END]");
out.println();
}
private void writeEdges(PrintWriter out, Collection<Edge> edges)
{
out.println("[EDGE]");
out.println("Edg Labl Np Ns Nd1 Nd2 Mult Tg1 Tg2 .....");
writeUselessLine(out);
int i = 1;
for(Edge e:edges)
{
e.id = i;
Collection<Triangle> ts = e.getTriangles();
out.print(i+" 0 0 0 "+e.n1.surfaceID+" "+e.n2.surfaceID+" "+(ts.size()-1));
for(Triangle t:ts)
out.print(" "+t.id);
out.println();
i++;
}
out.println("[END]");
out.println();
}
private void writeTriangles(PrintWriter out, Triangle[] triangles, Map<String, Integer> groupIDs) {
out.println("[TRIANGLE]");
out.println("Tgl Label Type Met Reg IP Edg1 Edg2 Edg3 SubObj Object Nd1 Nd2 Nd3");
writeUselessLine(out);
HashSet<Node> nodes = new HashSet<Node>();
for(Triangle t:triangles)
{
int gid = groupIDs.get(t.group);
out.print(t.id+" "+t.id+" COND MOM 01 01 "+gid+" "+t.edge1.id+" "+t.edge2.id+" "+t.edge3.id);
out.print(" "+gid+" 0");
t.getNodes(nodes);
for(Node n:nodes)
out.print(" "+n.surfaceID);
nodes.clear();
out.println();
}
out.println("[END]");
out.println();
}
private int nbSource(Collection<Node> wireNodes)
{
int toReturn = 0;
ArrayList<Edge> edges = new ArrayList<Edge>(3);
for(Node n: wireNodes)
{
n.getEdges(edges);
if(edges.size() == 2)
{
String g = edges.get(0).group;
if(g.equals(edges.get(1).group) && isSource(g))
toReturn ++;
}
edges.clear();
}
return toReturn;
}
private void writeWireNode(PrintWriter out, Collection<Node> wireNodes,
Map<String, Integer> groupIDs)
{
out.println("[WIRE-NOD]");
out.println("WNod Label X(m) Y(m) Z(m) Re Np Ns Mult Sg1 Sg2 ....");
writeUselessLine(out);
int id = 1;
int nextPortID = 1;
ArrayList<Edge> edges = new ArrayList<Edge>(3);
for(Node n: wireNodes)
{
n.edgeID = id;
int propertyID = 0;
int sourceID = 0;
n.getEdges(edges);
if(edges.size() == 2)
{
String g = edges.get(0).group;
if(g.equals(edges.get(1).group))
{
if(isNodalResistance(g) && isSource(g))
throw new RuntimeException("CA VA PAS LA TETE ! "+g);
if(isNodalResistance(g))
propertyID = groupIDs.get(edges.get(0).group);
else if(isSource(g))
{
Source p = new Source(nextPortID++, id);
sources.add(p);
sourceID = p.id;
}
}
}
out.print(id+" "+id+" "+n.x+" "+n.y+" "+n.z+" 01 "+propertyID+" "+sourceID+" "+(edges.size()-1));
for(Edge e: edges)
out.print(" "+e.id);
out.println();
edges.clear();
id ++;
}
out.println("[END]");
out.println();
}
private void writeSegments(PrintWriter out, Edge[] beams,
Map<String, Integer> groupIDs) {
out.println("[SEGMENT]");
out.println("Sgl Labl Typ Met Regi. Radius Np Elm1 Elm2 SubObj Object");
writeUselessLine(out);
for(Edge e: beams)
{
int subObject = groupIDs.get(e.group);
int propertyID = isNodalResistance(e.group) ? 0 : subObject;
out.println(e.id+" "+e.id+" COND MOM 01 01 "+getWireRadius(e.group)+
" "+propertyID+" "+e.n1.edgeID+" "+e.n2.edgeID+" "+subObject+" 0");
}
out.println("[END]");
out.println();
}
private void writeJunctions(PrintWriter out, Node[] nodes)
{
out.println("[JUNCTION]");
out.println("jun JWmult JTMult WElm JTNd");
writeUselessLine(out);
writeUselessLine(out);
writeUselessLine(out);
writeUselessLine(out);
int k = 1;
int[] nbElement = new int[2];
for(Node node:nodes)
{
if(node.edgeID >= 0 && node.surfaceID >=0)
{
writeUselessLine(out);
node.nbElement(nbElement);
out.println(k+" "+nbElement[0]+" "+nbElement[1]+" "+node.edgeID+" "+node.surfaceID);
for(int j = 0; j<nbElement[1]+1; j++)
writeUselessLine(out);
k++;
}
}
out.println("[END]");
out.println();
}
private void writeUselessLine(PrintWriter out)
{
out.println("-");
}
private void writeFreeSpace(PrintWriter out)
{
out.println("[FREESPACE]");
writeUselessLine(out);
out.println("1.0000E+00 0.0000E+00 1.0000E+00 0.0000E+00 //Epsilon,Mu for these zone and Name");
out.println("[END]");
out.println();
}
private void writeSources(PrintWriter out)
{
out.println("[SOURCE]");
writeUselessLine(out);
writeUselessLine(out);
for(Source s:sources)
out.println(s.id+" 001 Volt 00 00 0 0 ORDER0 1 0 0 0 0 0 "+getSourceName(
s.id, s.wireID));
out.println("[END]");
out.println();
}
private void writeProperties(PrintWriter out, List<Group> groups)
{
out.println("[PROPERTY]");
int i = 1;
for(Group g:groups)
out.println((i++)+" 0 "+getResistivity(g.getName())+" "+g.getName()+" //R");
out.println("[END]");
out.println();
}
private void writeObject(PrintWriter out)
{
out.println("[OBJECT]");
out.println("00000 not defined");
out.println("[END]");
out.println();
}
private void writeSubObject(PrintWriter out, List<Group> groups)
{
out.println("[SUB-OBJECT]");
out.println("0 not defined");
int i = 1;
for(Group g:groups)
out.println((i++)+" "+g.getName());
out.println("[END]");
out.println();
}
/** Tell if resistances must be on beams or on nodes in a group */
protected boolean isNodalResistance(String groupName)
{
return false;
}
protected double getWireRadius(String groupName)
{
return 0.1;
}
protected double getResistivity(String name) {
return 0;
}
protected double getScaleFactor()
{
return 1.0;
}
protected boolean isSource(String name)
{
return false;
}
protected String getSourceName(int sourceID, int nodeID)
{
return Integer.toString(sourceID);
}
}