/* jCAE stand for Java Computer Aided Engineering. Features are : Small CAD
modeler, Finite element mesher, Plugin architecture.
Copyright (C) 2006, by EADS CRC
Copyright (C) 2007,2008,2009, by EADS France
This library 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 library 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 library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
package org.jcae.mesh.bora.ds;
import org.jcae.mesh.bora.xmldata.BModelWriter;
import org.jcae.mesh.bora.xmldata.Storage;
import org.jcae.mesh.cad.CADShapeFactory;
import org.jcae.mesh.cad.CADShape;
import org.jcae.mesh.cad.CADShapeEnum;
import java.util.Collection;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Stack;
import java.util.Iterator;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* CAD object.
*/
public class BModel
{
private static final Logger LOGGER = Logger.getLogger(BModel.class.getName());
// Next available index
private static int freeIndex = 1;
// Model number
private final int id;
// CAD graph
private final BCADGraph cad;
// List of submeshes
private final Collection<BSubMesh> submesh = new ArrayList<BSubMesh>();
// Geometry file
private final String cadFile;
// Output variables
private String xmlDir;
private final String xmlFile = "model";
private final String xmlBrepDir;
// List of all constraints
private final Collection<Constraint> allConstraints = new LinkedHashSet<Constraint>();
// Internal state
private static enum State {
INPUT,
CONSTRAINTS,
TESSELLATION_0,
TESSELLATION_1,
TESSELLATION_2,
TESSELLATION_3
}
private State state = State.INPUT;
/**
* Bind a CAD representation to a disk directory.
*/
public BModel (String brep, String out)
{
id = freeIndex;
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "Building model "+id+" from "+brep+" into "+out);
freeIndex++;
CADShapeFactory factory = CADShapeFactory.getFactory();
xmlDir = out;
File xmlDirF = new File(xmlDir);
xmlDirF.mkdirs();
if(!xmlDirF.exists() || !xmlDirF.isDirectory())
throw new RuntimeException("Cannot write to "+xmlDir);
cadFile = (new File(brep)).getAbsoluteFile().getPath();
xmlBrepDir = relativize(new File(brep).getAbsoluteFile().getParentFile(), new File(xmlDir).getAbsoluteFile()).getPath();
// CAD graph
cad = new BCADGraph(this, factory.newShape(brep));
}
public void setOutputDir(String newDir) {
xmlDir = newDir;
}
public static void reset()
{
freeIndex = 1;
BDiscretization.nextId = -1;
}
/**
* Cleans up the current working directory
* Remove all files except model
*/
public void cleanWorkDirectory() {
LOGGER.info("Cleaning " + xmlDir);
deleteDirectory(new File(xmlDir), true, new File(xmlFile));
BDiscretization.nextId = -1;
}
private static void deleteDirectory(File dir, boolean clean,final File toConserve) {
if (dir.exists()) {
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].equals(toConserve))
continue;
if (files[i].isDirectory()) {
deleteDirectory(files[i], false, toConserve);
}
else {
files[i].delete();
}
}
}
if (!clean)
dir.delete();
}
public int getId()
{
return id;
}
public final String getCADFile()
{
return cadFile;
}
public String getRelativeCADDir()
{
return xmlBrepDir;
}
public CADShape getCADShape()
{
return cad.getRootCell().getShape();
}
public final String getOutputDir()
{
return xmlDir;
}
public final String getOutputDir(BDiscretization d)
{
String ret = xmlDir+File.separator;
CADShapeEnum cse = d.getGraphCell().getType();
if (cse == CADShapeEnum.EDGE)
ret += "1";
else if (cse == CADShapeEnum.FACE)
ret += "2";
else if (cse == CADShapeEnum.SOLID)
ret += "3";
else
throw new RuntimeException("Invalid CADShapeEnum: "+cse);
return ret+"d"+d.getId();
}
public final String getOutputFile()
{
return xmlFile;
}
public final BCADGraph getGraph()
{
return cad;
}
public final Collection<Constraint> getConstraints()
{
return allConstraints;
}
private static File relativize(File file, File reference)
{
File current = file;
Stack<String> l = new Stack<String>();
while (current != null && !current.equals(reference))
{
l.push(current.getName());
current = current.getParentFile();
}
if (l.isEmpty())
return new File(".");
else if (current == null)
return file;
else
{
current = new File(l.pop());
while(!l.isEmpty())
current = new File(current, l.pop());
return current;
}
}
public final BSubMesh newMesh()
{
if (state != State.INPUT)
throw new RuntimeException("BModel.newMesh() cannot be called after model has been computed");
BSubMesh ret = new BSubMesh(this, cad.getFreeIndex());
submesh.add(ret);
return ret;
}
/**
* Get an immutable view of the list of submeshes.
* @return the list of submeshes.
*/
public final Collection<BSubMesh> getSubMeshes()
{
return Collections.unmodifiableCollection(submesh);
}
final void addConstraint(Constraint cons)
{
if (state != State.INPUT)
throw new RuntimeException("Constraints cannot be added after model has been computed");
allConstraints.add(cons);
}
final void removeConstraint(Constraint cons) {
if (state != State.INPUT)
throw new RuntimeException("Constraints cannot be removed after model has been computed");
allConstraints.remove(cons);
}
/**
* Combines all hypothesis.
*/
public final void computeConstraints()
{
LOGGER.info("Compute constraints");
BCADGraphCell root = cad.getRootCell();
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.SOLID); its.hasNext(); )
{
BCADGraphCell cell = its.next();
cell.addImplicitConstraints(CADShapeEnum.FACE, true);
cell.addImplicitConstraints(CADShapeEnum.EDGE, false);
cell.addImplicitConstraints(CADShapeEnum.VERTEX, false);
}
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.FACE); its.hasNext(); )
{
BCADGraphCell cell = its.next();
cell.addImplicitConstraints(CADShapeEnum.EDGE, true);
cell.addImplicitConstraints(CADShapeEnum.VERTEX, false);
}
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.EDGE); its.hasNext(); )
{
BCADGraphCell cell = its.next();
cell.addImplicitConstraints(CADShapeEnum.VERTEX, true);
}
state = State.CONSTRAINTS;
// Update constraints
BModelWriter.writeObject(this);
}
public void resetConstraints()
{
if (state == State.INPUT)
return;
Map<BSubMesh, Collection<Constraint>> saveConstraints = new HashMap<BSubMesh, Collection<Constraint>>();
for (BSubMesh s : submesh)
{
saveConstraints.put(s, new ArrayList<Constraint>(s.getConstraints()));
s.resetConstraints();
}
BCADGraphCell root = cad.getRootCell();
for (CADShapeEnum cse : CADShapeEnum.iterable(CADShapeEnum.VERTEX, CADShapeEnum.COMPOUND))
{
for (Iterator<BCADGraphCell> it = root.shapesExplorer(cse); it.hasNext(); )
it.next().removeDiscretizations();
}
state = State.INPUT;
allConstraints.clear();
for (BSubMesh s : submesh)
{
for (Constraint c : saveConstraints.get(s)) {
s.add(c);
}
}
}
public final void save() {
BModelWriter.writeObject(this);
}
/**
* Combines all hypothesis and computes meshes.
*/
public final void compute()
{
LOGGER.info("Computing the model");
discretizeSolids();
LOGGER.info("Done");
}
final void discretizeVertices()
{
if (state.compareTo(State.TESSELLATION_0) >= 0)
return;
if (state == State.INPUT)
computeConstraints();
BCADGraphCell root = cad.getRootCell();
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.VERTEX); its.hasNext(); )
{
BCADGraphCell cell = its.next();
for (BDiscretization d : cell.getDiscretizations())
d.discretize();
}
state = State.TESSELLATION_0;
}
final void discretizeEdges()
{
if (state.compareTo(State.TESSELLATION_1) >= 0)
return;
discretizeVertices();
LOGGER.config("Discretize edges");
BCADGraphCell root = cad.getRootCell();
int nrEdges = 0;
if (LOGGER.isLoggable(Level.CONFIG))
{
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.EDGE); its.hasNext(); its.next())
nrEdges++;
}
int cnt = 0;
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.EDGE); its.hasNext(); )
{
BCADGraphCell cell = its.next();
cnt++;
LOGGER.config(" edge "+cnt+"/"+nrEdges);
for (BDiscretization d : cell.getDiscretizations())
{
d.discretize();
Storage.writeEdge(d);
}
}
state = State.TESSELLATION_1;
}
final void discretizeFaces()
{
if (state.compareTo(State.TESSELLATION_2) >= 0)
return;
discretizeEdges();
LOGGER.info("Discretize faces");
BCADGraphCell root = cad.getRootCell();
int nrFaces = 0;
if (LOGGER.isLoggable(Level.INFO))
{
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.FACE); its.hasNext(); its.next())
nrFaces++;
}
int cnt = 0;
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.FACE); its.hasNext(); )
{
BCADGraphCell cell = its.next();
cnt++;
LOGGER.info(" face "+cnt+"/"+nrFaces);
for (BDiscretization d : cell.getDiscretizations())
{
d.discretize();
Storage.writeFace(d);
d.setMesh(null);
}
}
state = State.TESSELLATION_2;
}
final void discretizeSolids()
{
if (state.compareTo(State.TESSELLATION_3) >= 0)
return;
discretizeFaces();
LOGGER.info("Discretize solids");
BCADGraphCell root = cad.getRootCell();
int nrSolids = 0;
if (LOGGER.isLoggable(Level.INFO))
{
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.SOLID); its.hasNext(); its.next())
nrSolids++;
}
int cnt = 0;
for (Iterator<BCADGraphCell> its = root.shapesExplorer(CADShapeEnum.SOLID); its.hasNext(); )
{
BCADGraphCell cell = its.next();
cnt++;
LOGGER.info(" solid "+cnt+"/"+nrSolids);
for (BDiscretization d : cell.getDiscretizations())
{
d.discretize();
Storage.writeSolid(d);
}
}
state = State.TESSELLATION_3;
}
/**
* Prints all hypothesis applied to any submesh.
*/
public void printAllHypothesis()
{
System.out.println("List of hypothesis");
for (Constraint cons : allConstraints)
{
Hypothesis h = cons.getHypothesis();
System.out.println(" + ("+Integer.toHexString(h.hashCode())+") "+h);
}
System.out.println("End list");
}
/**
* Prints the constraints applied to geometrical elements of the current mesh.
*/
public void printConstraints()
{
System.out.println("List of constraints");
BCADGraphCell root = cad.getRootCell();
StringBuilder indent = new StringBuilder();
for (CADShapeEnum cse : CADShapeEnum.iterable(CADShapeEnum.VERTEX, CADShapeEnum.COMPOUND))
{
String tab = indent.toString();
for (Iterator<BCADGraphCell> it = root.shapesExplorer(cse); it.hasNext(); )
{
BCADGraphCell cell = it.next();
boolean first = true;
for (BDiscretization d : cell.getDiscretizations())
{
if (first)
System.out.println(tab+"Shape "+cell);
first = false;
System.out.println(tab+" + "+d);
}
}
indent.append(" ");
}
System.out.println("End list");
}
/**
* Prints the constraints applied to a given submesh.
*/
public void printConstraints(BSubMesh sm)
{
System.out.println("List of constraints applied on submesh "+sm.getId());
BCADGraphCell root = cad.getRootCell();
StringBuilder indent = new StringBuilder();
for (CADShapeEnum cse : CADShapeEnum.iterable(CADShapeEnum.VERTEX, CADShapeEnum.COMPOUND))
{
String tab = indent.toString();
for (Iterator<BCADGraphCell> it = root.shapesExplorer(cse); it.hasNext(); )
{
BCADGraphCell cell = it.next();
for (BDiscretization d : cell.getDiscretizations())
{
if (d.contains(sm))
{
System.out.println(tab+"Shape "+cell);
System.out.println(tab+" + "+d);
}
}
}
indent.append(" ");
}
System.out.println("End list");
}
/**
* Print all discretizations.
*/
@SuppressWarnings("unused")
private void printDiscretizations()
{
System.out.println("List of discretizations");
BCADGraphCell root = cad.getRootCell();
StringBuilder indent = new StringBuilder();
for (CADShapeEnum cse : CADShapeEnum.iterable(CADShapeEnum.VERTEX, CADShapeEnum.COMPOUND))
{
CADShapeEnum normalChildType;
if (cse == CADShapeEnum.EDGE)
normalChildType = CADShapeEnum.VERTEX;
else if (cse == CADShapeEnum.FACE)
normalChildType = CADShapeEnum.EDGE;
else if (cse == CADShapeEnum.SOLID)
normalChildType = CADShapeEnum.FACE;
else
normalChildType = CADShapeEnum.VERTEX;
if ((cse == CADShapeEnum.WIRE) || (cse == CADShapeEnum.SHELL) ||
(cse == CADShapeEnum.COMPSOLID) || (cse == CADShapeEnum.COMPOUND))
continue;
String tab = indent.toString();
for (Iterator<BCADGraphCell> itp = root.shapesExplorer(cse); itp.hasNext(); )
{
BCADGraphCell pcell = itp.next();
System.out.println(tab+"Discretizations of shape "+pcell);
for (BDiscretization pd : pcell.getDiscretizations())
{
if (pcell == pd.getGraphCell())
System.out.println(tab+" + "+"Used discretization: "+pd.getId()+" with orientation: forward; element type : "+pd.getConstraint().getHypothesis().getElement()+" constraint : "+pd.getConstraint().getId()+" submesh list : "+pd.getSubmesh());
else if (pcell == pd.getGraphCell().getReversed() )
System.out.println(tab+" + "+"Used discretization: "+pd.getId()+" with orientation: reversed; element type : "+pd.getConstraint().getHypothesis().getElement()+" constraint : "+pd.getConstraint().getId()+" submesh list : "+pd.getSubmesh());
else
throw new RuntimeException("Invalid discretization "+pd+" on shape "+pcell);
if (cse != CADShapeEnum.VERTEX)
{
System.out.println(tab+" + "+" + "+"discretizations of boundary shapes: ");
for (Iterator<BCADGraphCell> itc = pcell.shapesExplorer(normalChildType); itc.hasNext(); )
{
BCADGraphCell ccell = itc.next();
for (BDiscretization cd : ccell.getDiscretizations())
{
if (pd.contained(cd))
{
if (ccell == cd.getGraphCell())
System.out.println(tab+" + "+" + "+" + "+"Used discretization: "+cd.getId()+" with orientation: forward; element type : "+cd.getConstraint().getHypothesis().getElement()+" constraint : "+cd.getConstraint().getId()+" submesh list : "+cd.getSubmesh());
else if (ccell == cd.getGraphCell().getReversed() )
System.out.println(tab+" + "+" + "+" + "+"Used discretization: "+cd.getId()+" with orientation: reversed; element type : "+cd.getConstraint().getHypothesis().getElement()+" constraint : "+cd.getConstraint().getId()+" submesh list : "+cd.getSubmesh());
else
throw new RuntimeException("Invalid discretization "+cd+" on shape "+ccell);
}
}
}
boolean first = true;
if (cse != CADShapeEnum.EDGE)
{
for (CADShapeEnum ccse : CADShapeEnum.iterable(CADShapeEnum.VERTEX, normalChildType))
{
for (Iterator<BCADGraphCell> itc = pcell.shapesIterator(); itc.hasNext(); )
{
BCADGraphCell ccell = itc.next();
if (ccell.getType() == ccse)
{
for (BDiscretization cd : ccell.getDiscretizations())
{
if (pd.contained(cd))
{
if (first)
{
System.out.println(tab+" + "+" + "+"discretizations of additionnal boundary shapes: ");
first = false;
}
if (ccell == cd.getGraphCell())
System.out.println(tab+" + "+" + "+" + "+" + "+"Used discretization: "+cd.getId()+" with orientation: forward; element type : "+cd.getConstraint().getHypothesis().getElement()+" constraint : "+cd.getConstraint().getId()+" submesh list : "+cd.getSubmesh());
else if (ccell == cd.getGraphCell().getReversed() )
System.out.println(tab+" + "+" + "+" + "+" + "+"Used discretization: "+cd.getId()+" with orientation: reversed; element type : "+cd.getConstraint().getHypothesis().getElement()+" constraint : "+cd.getConstraint().getId()+" submesh list : "+cd.getSubmesh());
else
throw new RuntimeException("Invalid discretization "+cd+" on shape "+ccell);
}
}
}
}
}
}
}
}
}
indent.append(" ");
}
System.out.println("End list");
}
/**
* Prints the list of geometrical elements.
*/
@SuppressWarnings("unused")
private void printShapes()
{
cad.printShapes();
}
}