/* * This source code is the property of EADS France. No part of it shall * be reproduced or transmitted without the express prior written * authorization of EADS France, and its contents shall not be disclosed. * Copyright EADS France. */ package org.jcae.netbeans.mesh.bora; import org.jcae.netbeans.mesh.*; import org.jcae.netbeans.mesh.bora.BCADCellNode; import org.jcae.netbeans.mesh.bora.BoraNode; import org.jcae.netbeans.mesh.bora.BCADGraphNode; import org.jcae.netbeans.mesh.bora.BGroupsNode; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import javax.swing.Action; import org.jcae.mesh.bora.ds.BCADGraphCell; import org.jcae.mesh.bora.ds.BDiscretization; import org.jcae.mesh.bora.ds.BModel; import org.jcae.mesh.bora.ds.BSubMesh; import org.jcae.mesh.bora.ds.Constraint; import org.jcae.mesh.bora.ds.Hypothesis; import org.jcae.mesh.cad.CADShapeEnum; import org.jcae.mesh.cad.occ.OCCShape; import org.jcae.opencascade.jni.TopoDS_Shape; import org.openide.actions.DeleteAction; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.actions.SystemAction; /** * Note : this class is not fused in MeshNode because we may have * more than one subMeshes in a MeshNode in the future * @author Gautam Botrel * */ public class SubmeshNode extends AbstractNode implements Node.Cookie { private final String boraFileName; //needed for delete operation private final DataModel dataModel = new DataModel(); private final BGroupsNode groupsNode; public SubmeshNode(String objName,final BModel bModel) { super(new Children.Keys() { @Override protected Node[] createNodes(Object arg0) {return null;} }); setIconBaseWithExtension("org/jcae/netbeans/mesh/bora/SubmeshNode.png"); if (!bModel.getOutputDir().endsWith(File.separator)) boraFileName = bModel.getOutputDir() + File.separator + bModel.getOutputFile(); else boraFileName = bModel.getOutputDir() + bModel.getOutputFile(); final BCADGraphCell rootCell = bModel.getGraph().getRootCell(); //submeshes can be empty if the user created a meshnode and did not //specify any constraints, so we must "re"create the submesh if (bModel.getSubMeshes().isEmpty()) bModel.newMesh(); dataModel.subMesh = bModel.getSubMeshes().iterator().next(); //now putting cell without constraints as keys Collection<BCADGraphCell> allCells = new ArrayList<BCADGraphCell>(); for (CADShapeEnum type : CADShapeEnum.iterable(CADShapeEnum.VERTEX, CADShapeEnum.COMPOUND)) { allCells.addAll(bModel.getGraph().getCellList(type)); } for (BCADGraphCell cell : allCells) { dataModel.constraints.put(getShapeFromCell(cell), null); } ArrayList<BCADGraphCell> definedCells = new ArrayList<BCADGraphCell>(); //getting the existing constraints and filling the constraints map for (Constraint c : dataModel.subMesh.getConstraints()) { BCADGraphCell cell = c.getGraphCell(); dataModel.constraints.put(getShapeFromCell(cell), c); if (c.getGroup() != null) { //groups initialisation dataModel.addGroup(c.getGroup(), cell); definedCells.add(cell); } } // allCells.removeAll(definedCells); // for (BCADGraphCell cell : allCells) { // //looping on cells whoose groups is undefined (no constraint attached) // dataModel.addGroup(BCADGraphNode.DEFAULT_GROUP_NAME, cell); // } final AbstractNode graph = new AbstractNode(new BCADCellNode(rootCell, dataModel)); graph.setDisplayName("Graph"); graph.setIconBaseWithExtension("org/jcae/netbeans/mesh/bora/GraphNode.png"); final AbstractNode entities = new AbstractNode(new EntitieChildrenNode(rootCell)); entities.setDisplayName("Entities"); entities.setIconBaseWithExtension("org/jcae/netbeans/mesh/bora/EntitieNode.png"); groupsNode = new BGroupsNode(dataModel); groupsNode.setDisplayName("Groups"); groupsNode.setIconBaseWithExtension("org/jcae/netbeans/mesh/bora/GroupsNode.png"); getChildren().add(new Node[] {graph, entities, groupsNode}); this.setDisplayName(objName); refreshGroupsNode(true); } public void viewMesh() { // refreshGroupsNode(true); /** Getting the mesh data from groups **/ HashMap<String, Collection<BDiscretization>> meshData = new HashMap<String, Collection<BDiscretization>>(); for (String group : dataModel.groups.keySet()) { HashSet<BCADGraphCell> cellsInGroup = dataModel.groups.get(group); if (cellsInGroup == null || cellsInGroup.isEmpty()) { continue; } ArrayList<BDiscretization> discrs = new ArrayList<BDiscretization>(); for (BCADGraphCell cell : cellsInGroup) { BDiscretization d = cell.getDiscretizationSubMesh( dataModel.subMesh); if (d != null) { discrs.add(d); } } if (!discrs.isEmpty()) { meshData.put(group, discrs); } } BoraNode.view(getDisplayName() + " mesh", meshData, groupsNode); } /** * Refreshes the groups node from DataModel */ public void refreshGroupsNode(boolean refreshModel) { if (groupsNode != null) { if (refreshModel) { for (Constraint c : dataModel.subMesh.getConstraints()) { dataModel.addGroup(c.getGroup(), c.getGraphCell()); } } groupsNode.fireModelChanged(); } } @Override public void destroy() { try { super.destroy(); new File(boraFileName).delete(); dataModel.subMesh.getModel().cleanWorkDirectory(); } catch (Exception e) { throw new RuntimeException( "Could not delete " + boraFileName + ". Cause : " + e); } } @Override public Action[] getActions(boolean arg0) { ArrayList<Action> l = new ArrayList<Action>(); l.add(SystemAction.get(DeleteAction.class)); l.add(SystemAction.get(ExportBUNVAction.class)); return l.toArray(new Action[l.size()]); } @Override public boolean canDestroy() { return true; } /** * Represent the Entitie's representation * (BCADGraphCell are represented by types : * eg : a folder for faces, a folder for edges... etc) */ private class EntitieChildrenNode extends Children.Keys<CADShapeEnum> { private final BCADGraphCell root; private final ArrayList<CADShapeEnum> shapesToDisplay; public EntitieChildrenNode(BCADGraphCell root) { this.root = root; shapesToDisplay = new ArrayList<CADShapeEnum>(3); shapesToDisplay.add(CADShapeEnum.FACE); shapesToDisplay.add(CADShapeEnum.EDGE); shapesToDisplay.add(CADShapeEnum.VERTEX); } @Override protected void addNotify() { setKeys(shapesToDisplay.toArray( new CADShapeEnum[shapesToDisplay.size()])); } protected Node[] createNodes(CADShapeEnum type) { AbstractNode node = new AbstractNode(Children.LEAF); node.setIconBaseWithExtension("org/jcae/netbeans/mesh/bora/EntitiesNode.png"); ArrayList<BCADGraphNode> toAdd = new ArrayList<BCADGraphNode>(); Iterator<BCADGraphCell> it = root.shapesExplorer(type); while (it.hasNext()) { BCADGraphCell cell = it.next(); toAdd.add(new BCADGraphNode(true,cell, dataModel)); } node.setName(type.toString()); return new Node[] {node}; } } /** * This inner class represents the DataModel of a Submesh * It will be used by Children nodes (which doesn't contains data) */ public class DataModel { private BSubMesh subMesh; public BSubMesh getSubMesh() { return subMesh; } /** Group section **/ private final Map<String, HashSet<BCADGraphCell>> groups = new HashMap<String, HashSet<BCADGraphCell>>(); public void addGroup(String group, BCADGraphCell cell) { removeCell(cell); if (groups.get(group) != null) groups.get(group).add(cell); else { HashSet<BCADGraphCell> set = new HashSet<BCADGraphCell>(); if (cell!=null) set.add(cell); groups.put(group, set); } changeGroupTo(Collections.singletonList(cell), group); refreshGroups(); } private void removeCell(BCADGraphCell cell) { for (String key : groups.keySet()) { HashSet<BCADGraphCell> ens = groups.get(key); if (ens.remove(cell)) break; } } /** * Destroy the given Group from the groups, and migrate the associated cells * to the DEFAULT GROUP or the first group. * @param group */ public void destroyGroup(String group) { HashSet<BCADGraphCell> belongsToGroup = groups.get(group); if (belongsToGroup == null ||belongsToGroup.isEmpty()) { groups.remove(group); refreshGroups(); return; } //we have to "migrate" cells in this group to default group assert (groups.keySet().size() > 1); String DEFAULT = BCADGraphNode.DEFAULT_GROUP_NAME; if (group.equals(DEFAULT) || !groups.keySet().contains(DEFAULT)) { //we are deleting the default group or it doesn't exist Iterator<String> groupIterator = groups.keySet().iterator(); String first = groupIterator.next(); if (group.equals(first)) first = groupIterator.next(); //if we are attempting to delete the first group changeGroupTo(belongsToGroup, first); groups.get(first).addAll(belongsToGroup); } else { changeGroupTo(belongsToGroup, DEFAULT); groups.get(DEFAULT).addAll(belongsToGroup); } groups.remove(group); refreshGroups(); } /** * Changes in the constraint of the model the Group associated with the * given collection of cells to group. * @param cellsToChange * @param group */ private void changeGroupTo(Collection<BCADGraphCell> cellsToChange, String group) { for (Constraint cons : constraints.values()) { if (cons != null && cellsToChange.contains( cons.getGraphCell())) { cons.setGroup(group); } } } public Collection<String> getAllGroups() { return groups.keySet(); } public Map<String, HashSet<BCADGraphCell>> getGroupMap() { return groups; } public void renameGroup(String old, String newName) { if (groups.get(newName) != null) return; //cannot rename group into an existing one HashSet<BCADGraphCell> belongsToGroup = groups.get(old); groups.remove(old); if (belongsToGroup == null) return; changeGroupTo(belongsToGroup, newName); groups.put(newName, belongsToGroup); refreshGroups(); } /** * Called when adding or removing a Cell / group * This method refreshes the group node */ private void refreshGroups() { SubmeshNode.this.refreshGroupsNode(false); } public Collection<BCADGraphCell> getCellsInGroup(String group) { return groups.get(group); } /** End Group section **/ /** Constraint Section **/ //this constraint map is the data model used by the BCADGraphNode //actually, this map maps TopoDS_SHape and constraint, 'cause constraint are applied //to topods_shape, not BCADGraphCell, and this is the only way to detect multiple values in the GUI //for example, the edge between 2 faces of a cube is defined by 2 BCADGraphCell, and only 1 TopoDS_Shape private final Map<TopoDS_Shape, Constraint> constraints = new HashMap<TopoDS_Shape, Constraint>(); public void addConstraint(BCADGraphCell cell, Hypothesis hyp, String group) { subMesh.getModel().resetConstraints(); TopoDS_Shape shape = getShapeFromCell(cell); if (!constraints.containsKey(shape)) { Constraint cons = new Constraint(cell, hyp); cons.setGroup(group); constraints.put(shape, cons); subMesh.add(cons); } else { //the key already exists, but the constraint might not if (constraints.get(shape) == null) { Constraint cons = new Constraint(cell, hyp); cons.setGroup(group); constraints.put(shape, cons); subMesh.add(cons); } else { constraints.get(shape).setHypothesis(hyp); constraints.get(shape).setGroup(group); } } fireModelChanged(); } public void removeConstraint(BCADGraphCell cell) { subMesh.getModel().resetConstraints(); TopoDS_Shape shape = getShapeFromCell(cell); if (!constraints.containsKey(shape)) return; Constraint cons = constraints.get(shape); if (cons != null) { subMesh.remove(cons); constraints.put(shape, null); } fireModelChanged(); } public Constraint getConstraint(BCADGraphCell cell) { return constraints.get(getShapeFromCell(cell)); } /** End Constraint section **/ private ArrayList<BCADGraphNode> listeners = new ArrayList<BCADGraphNode>(); private void fireModelChanged() { for (BCADGraphNode node : listeners) node.refresh(); refreshGroups(); } public void addListener(BCADGraphNode node) { if (!listeners.contains(node)) listeners.add(node); } } private static TopoDS_Shape getShapeFromCell(BCADGraphCell cell) { return ((OCCShape)cell.getShape()).getShape(); } public DataModel getDataModel() { return dataModel; } }