/* * 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 2005-2009, by EADS France */ package org.jcae.mesh.xmldata; import java.awt.BorderLayout; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; import java.nio.channels.FileChannel; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jcae.mesh.amibe.ds.Mesh; import org.jcae.mesh.amibe.ds.Triangle; import org.jcae.mesh.amibe.traits.MeshTraitsBuilder; import org.jcae.mesh.xmldata.AmibeReader.SubMesh; import org.xml.sax.SAXException; /** * Manage all the groups of a MeshNode. */ public class Groups { private static final Logger LOGGER = Logger.getLogger(Groups.class.getCanonicalName()); // TODO Create a table selection private final PropertyChangeListener groupPropertyChangeListener=new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if(evt.getPropertyName().equals("name")) { modifyXML(); } else if(evt.getPropertyName().equals("visible")) { throw new RuntimeException("Not yet implemented"); /*if(viewable!=null) { Group g=(Group) evt.getSource(); Map<Integer, Boolean> map=new HashMap<Integer, Boolean>(); map.put(g.getId(), (Boolean)evt.getNewValue()); viewable.setDomainVisible(map); }*/ } } }; protected boolean firstView = true; private final ArrayList<Group> groups = new ArrayList<Group>(); /** The absolute path to the mesh directory */ private String meshFile = null; public Groups(String xmlPath) { meshFile = xmlPath; } public final void addGroup(Group group) { groups.add(group); group.addPropertyChangeListener(groupPropertyChangeListener); } /** * It makes the fusion of groups. * It modifies the list of groups, the file jcae3d.xml and the file groups.bin. * *@param listGroup the list of groups to fuse. *@return the group resulting of the fusion. * @throws IOException * @throws SAXException * @throws ParserConfigurationException */ final Group fuse(Collection<Group> listGroup, String name) throws TransformerException, ParserConfigurationException, SAXException, IOException { String xmlDir=meshFile; Group fuseGroup = new Group(); int number = 0; int offset = 0; int trianglesNumber = 0; for (int k = 0; k < groups.size(); k++) { Group g = groups.get(k); trianglesNumber = trianglesNumber + g.getNumberOfElements(); } String fileGroups = "jcae3d.files/groups.bin"; HashMap<Group, int[]> map = new HashMap<Group, int[]>(groups.size()); Iterator<Group> it = groups.iterator(); while (it.hasNext()) { Group g = it.next(); int[] tri = this.readTrianglesGroup(new File(xmlDir, fileGroups), g); map.put(g, tri); } File groupsBin = new File(xmlDir, fileGroups); File tmpGroupsBin=File.createTempFile("jcae_groups",".bin"); DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream( tmpGroupsBin))); ArrayList<Integer> listTriFuse = new ArrayList<Integer>(); for(Group g:listGroup) { number = number + g.getNumberOfElements(); if (groups.contains(g)) { groups.remove(g); } for(int tri:map.get(g)) listTriFuse.add(tri); } for (int i = 0; i < groups.size(); i++) { Group g = groups.get(i); if (i == 0) { g.setOffset(0); } else { Group previousGroup = groups.get(i - 1); g.setOffset(previousGroup.getOffset() + previousGroup.getNumberOfElements()); } int[] tri = map.get(g); for (int k = 0; k < tri.length; k++) { out.writeInt(tri[k]); } } Iterator it3 = listTriFuse.iterator(); while (it3.hasNext()) { Integer integer = (Integer) it3.next(); out.writeInt(integer.intValue()); } out.close(); if (!groups.isEmpty()) { Group lastGroup = groups.get(groups.size() - 1); offset = lastGroup.getOffset() + lastGroup.getNumberOfElements(); } else { offset = 0; } fuseGroup.setNumberOfElements(number); fuseGroup.setOffset(offset); fuseGroup.setName(name); fuseGroup.addPropertyChangeListener(groupPropertyChangeListener); groups.add(fuseGroup); out.close(); if(!groupsBin.delete()) { System.err.println(Groups.class+": unable to delete "+groupsBin); } copyFile(tmpGroupsBin, groupsBin); if(!tmpGroupsBin.delete()) { System.err.println(Groups.class+": unable to delete "+tmpGroupsBin); } File f = new File(xmlDir, "jcae3d"); org.w3c.dom.Document xmlDoc = null; if (f.exists()) { xmlDoc = org.jcae.mesh.xmldata.XMLHelper.parseXML(f); modifyXMLGroups(xmlDoc); org.jcae.mesh.xmldata.XMLHelper.writeXML(xmlDoc, f); } return fuseGroup; } private String getFreeName(String template) { boolean valid; String current = template; int n = 1; do { valid = true; for(Group g: groups) { if(current.equals(g.getName())) { valid = false; current = template + n; n++; break; } } } while(!valid); return current; } public void fuse(Collection<Group> toFuse) throws TransformerException, ParserConfigurationException, SAXException, IOException { fuse(toFuse, getFreeName("fused_groups")); } /** * @return Returns the Groups */ public final Group[] getGroups() { Group[] toReturn = new Group[groups.size()]; groups.toArray(toReturn); return toReturn; } /** * It writes the file jcae3d.xml to update the groups, after a fusion for example. * *@param xmlDoc the xml document of DOM. It should comes from the parsing of jcae3d.xml. *@param groupFile the file groups.bin. *@param baseDir the directory containing jcae3d.xml. */ final void modifyXMLGroups(org.w3c.dom.Document xmlDoc) { org.w3c.dom.NodeList listGroups = xmlDoc.getElementsByTagName("groups"); if (listGroups.getLength() > 0) { org.w3c.dom.Element eltGroups = (org.w3c.dom.Element) listGroups .item(0); org.w3c.dom.NodeList listGroup = eltGroups .getElementsByTagName("group"); if (listGroup.getLength() > 0) { while (listGroup.getLength() > 0) { org.w3c.dom.Element g = (org.w3c.dom.Element) listGroup .item(0); eltGroups.removeChild(g); } for (int i = 0; i < groups.size(); i++) { Group g = groups.get(i); eltGroups.appendChild(g.createXMLGroup(xmlDoc)); } } } } final void modifyXML() { String xmlDir=meshFile; String xmlFile = "jcae3d"; java.io.File f = new java.io.File(xmlDir, xmlFile); org.w3c.dom.Document xmlDoc = null; if (f.exists()) { try { xmlDoc = org.jcae.mesh.xmldata.XMLHelper.parseXML(f); modifyXMLGroups(xmlDoc); org.jcae.mesh.xmldata.XMLHelper.writeXML(xmlDoc, f); } catch (Exception e) { e.printStackTrace(System.err); } } } /** * It creates an array of integers which contains the indices of triangles in triangles3d.bin for a particular group. * *@param fileGroup the path of the file groups.bin. *@param g the group. *@return an array of integers. */ final int[] readTrianglesGroup(File fileGroup, Group g) { int[] trianglesGroup = null; IntFileReader ifr = null; try { ifr = new PrimitiveFileReaderFactory().getIntReader(fileGroup); trianglesGroup = new int[g.getNumberOfElements()]; ifr.get(g.getOffset(), trianglesGroup); } catch (IOException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } finally { if(ifr != null) ifr.close(); } return trianglesGroup; } /** * @param groups The array of groups to set */ public void setGroups(Group[] groups) { this.groups.clear(); this.groups.addAll(Arrays.asList(groups)); for(int i=0; i<groups.length; i++) { groups[i].addPropertyChangeListener(groupPropertyChangeListener); } } public String getMeshFile() { return meshFile; } /** * @param meshFile the directory of the mesh of a jcae project. */ public void setMeshFile(String meshFile) { this.meshFile = meshFile; } /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public final String toString() { return "Groups"; } //beware JVM bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5056395 //use transferFrom, not transferTo private void copyFile(File src, File dst) throws IOException { FileChannel sourceChannel = new FileInputStream(src).getChannel(); FileChannel destinationChannel = new FileOutputStream(dst).getChannel(); destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size()); sourceChannel.close(); destinationChannel.close(); } public void exportGroupsAsUNV() throws ParserConfigurationException, SAXException, IOException { JScrollPane pane=new JScrollPane(); JList list=new JList(getGroups()); pane.getViewport().add(list); JPanel panel=new JPanel(); panel.setLayout(new BorderLayout()); panel.add(pane, BorderLayout.CENTER); panel.add(new JLabel("Groups to export"), BorderLayout.NORTH); JFileChooser jfc=new JFileChooser(); jfc.setAccessory(panel); if(jfc.showSaveDialog(null)==JFileChooser.APPROVE_OPTION) { Object[] os=list.getSelectedValues(); String[] ids=new String[os.length]; for(int i=0; i<os.length; i++) { ids[i]=((Group)os[i]).getName(); } PrintStream stream=new PrintStream(new BufferedOutputStream(new FileOutputStream(jfc.getSelectedFile()))); MeshExporter.UNV exporter=new MeshExporter.UNV(new File(meshFile), ids); exporter.write(stream); stream.close(); } } public static Groups getGroups(String xmlPath) { Groups groupList = new Groups(xmlPath); try { SubMesh sm = new AmibeReader.Dim3(xmlPath).getSubmeshes().get(0); List<AmibeReader.Group> groups = sm.getGroups(); if (groups.isEmpty()) { int nb = sm.getNumberOfTrias(); if(nb > 0) { Group group = new Group(); group.setName("default"); group.setNumberOfElements(nb); group.setOffset(0); } } else { for (AmibeReader.Group ag:groups) { if(ag.getNumberOfNodes() == 0) { Group group = new Group(); group.setName(ag.getName()); group.setNumberOfElements(ag.getNumberOfTrias()); group.setOffset((int) ag.getTriasOffset()); group.setBeamNumber(ag.getNumberOfBeams()); group.setBeamOffset((int) ag.getBeamsOffset()); groupList.addGroup(group); } } } } catch (SAXException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } catch (IOException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } return groupList; } /** * Remove a set of group from a mesh */ public static void remove(String amibePath, String ... names) throws IOException { MeshTraitsBuilder traits = new MeshTraitsBuilder(); traits.addTriangleSet(); Mesh m = new org.jcae.mesh.amibe.ds.Mesh(traits); MeshReader.readObject3D(m, amibePath); int[] ids = m.getGroupIDs(names); Iterator<Triangle> it = m.getTriangles().iterator(); while(it.hasNext()) { Triangle t = it.next(); if(t.getGroupId() == ids[0]) it.remove(); } MeshWriter.writeObject3D(m, amibePath, null); } }