package de.gaalop.visualizer; import de.gaalop.api.cfg.AssignmentNodeCollector; import de.gaalop.cfg.AssignmentNode; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; import de.gaalop.CodeGenerator; import de.gaalop.CodeGeneratorException; import de.gaalop.OutputFile; import de.gaalop.cfg.ControlFlowGraph; import de.gaalop.dfg.Addition; import de.gaalop.dfg.Exponentiation; import de.gaalop.dfg.Expression; import de.gaalop.dfg.FloatConstant; import de.gaalop.dfg.MultivectorComponent; import de.gaalop.dfg.Variable; import de.gaalop.visitors.ReplaceVisitor; import de.gaalop.visualizer.engines.lwjgl.RenderingEngine; import de.gaalop.visualizer.engines.lwjgl.SimpleLwJglRenderingEngine; import de.gaalop.visualizer.gui.DrawSettings; import de.gaalop.visualizer.gui.InputsPanel; import de.gaalop.visualizer.gui.SettingsPanel; import de.gaalop.visualizer.gui.VisiblePanel; import de.gaalop.visualizer.zerofinding.DiscreteCubeMethod; import de.gaalop.visualizer.zerofinding.GradientMethod; import de.gaalop.visualizer.zerofinding.PrepareZerofinder; import de.gaalop.visualizer.zerofinding.RayMethod; import de.gaalop.visualizer.zerofinding.ZeroFinder; import java.awt.BorderLayout; import java.awt.Color; import java.awt.MenuItem; import java.awt.PopupMenu; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Collections; import java.util.HashMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.event.ChangeEvent; /** * Extends the DrawSettings gui by implementing the actions. * Represents a Gaalop CodeGenerator. * * @author Christian Steinmetz */ public class NewDrawSettingsCodeGen extends DrawSettings implements CodeGenerator, Rendering { private String lwJglNativePath; private LinkedList<AssignmentNode> graphAssignmentNodes; private Differentiater differentiater; public PointClouds loadedPointClouds = new PointClouds(); private PointClouds computedPointClouds = new PointClouds(); private InputsPanel inputsPanel; private SettingsPanel settingsPanel; private VisiblePanel visiblePanel; public HashMap<String, Color> colors; private RenderingEngine renderingEngine; private boolean newDataSetAvailable = false; private HashMap<String, Expression> renderingExpressions; private boolean renderIn2d; //for cr4d public NewDrawSettingsCodeGen(String lwJglNativePath) { this.lwJglNativePath = lwJglNativePath; jButton_Repaint.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { recomputeCommand(); } }); inputsPanel = new InputsPanel(jPanel_Inputs) { @Override public void stateChanged(ChangeEvent e) { if (settingsPanel.isAutoRendering()) recomputeCommand(); } }; settingsPanel = new SettingsPanel(jScrollPane_Settings, jPanel_Settings); visiblePanel = new VisiblePanel(jPanel_Visible) { @Override public void stateChanged(ChangeEvent e) { repaintCommand(); } }; jButton_LoadPointCloud.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JFileChooser chooser = new JFileChooser(); if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) loadedPointClouds.loadFromFile(chooser.getSelectedFile()); } }); jButton_SavePointCloud.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JFileChooser chooser = new JFileChooser(); if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { computedPointClouds.saveToFile(chooser.getSelectedFile()); } } }); jComboBox_ZerofindingMethod.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { settingsPanel.setSettings(getSelectedZeroFinder().getSettings()); repaint(); } }); jButton_DisplayEquations.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JFrame frame = new JFrame("Gaalop - Rendering equations"); frame.setLayout(new BorderLayout(5,5)); frame.setSize(500, 500); JScrollPane pane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); frame.add(pane, BorderLayout.CENTER); JTextArea area = new JTextArea(getDisplayEquationsAsString()); area.setLineWrap(true); area.setEditable(false); pane.setViewportView(area); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); JButton buttonCopy = new JButton("Copy content to clipboard"); frame.add(buttonCopy, BorderLayout.SOUTH); buttonCopy.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents( new StringSelection(getDisplayEquationsAsString()), null ); } }); } }); //Add ZeroFinding methods LinkedList<ZeroFinder> zerofinderList = new LinkedList<ZeroFinder>(); ZeroFinder defaultZeroFinder = new GradientMethod(); zerofinderList.add(defaultZeroFinder); zerofinderList.add(new RayMethod()); zerofinderList.add(new DiscreteCubeMethod()); setZerofinderMethods(zerofinderList, defaultZeroFinder); } @Override public Set<OutputFile> generate(ControlFlowGraph in) throws CodeGeneratorException { renderIn2d = ("cr4d".equals(in.algebraName)); renderingEngine = new SimpleLwJglRenderingEngine(lwJglNativePath, this); renderingEngine.start(); //extract informations from the graph AssignmentNodeCollector collector = new AssignmentNodeCollector(); in.accept(collector); graphAssignmentNodes = collector.getAssignmentNodes(); differentiater = new DifferentiaterCreator(in.globalSettings.optMaxima, in.globalSettings.maximaCommand).createDifferentiater(); renderingExpressions = in.getRenderingExpressions(); colors = ColorEvaluater.getColors(in); //Determine all input variables LinkedList<String> inputs = new LinkedList<String>(); for (Variable inputVar: in.getInputVariables()) if (!isPositionVariable(inputVar.getName())) inputs.add(inputVar.getName()); Collections.sort(inputs); inputsPanel.setInputs(inputs); //Make form visible and relayout it setVisible(true); setSize(getSize().width+1, getSize().height); setSize(getSize().width-1, getSize().height); return new HashSet<OutputFile>(); } /** * Recomputes the point clouds by executing zerofinding methods */ private void recomputeCommand() { computedPointClouds.clear(); final ZeroFinder curZeroFinder = getSelectedZeroFinder(); curZeroFinder.setDifferentiater(differentiater); jLabel_Info.setText("Please wait while rendering ..."); jLabel_Info.repaint(); //fill global values from sliders final HashMap<MultivectorComponent, Double> globalValues = new HashMap<MultivectorComponent, Double>(); HashMap<String, Double> inputValues = inputsPanel.getValues(); for (String variable: inputValues.keySet()) globalValues.put(new MultivectorComponent(variable, 0), inputValues.get(variable)); //Start thread for finding zero points with the possiblility to cancel the search anytime new Thread() { @Override public void run() { long start = System.currentTimeMillis(); //Copy List LinkedList<AssignmentNode> list = new LinkedList<AssignmentNode>(); for (AssignmentNode node: graphAssignmentNodes) list.add(node.copyElements()); HashMap<String, LinkedList<Point3d>> pointsToRender = curZeroFinder.findZeroLocations(globalValues, list, settingsPanel.getSettings(), renderIn2d); long sum = 0; for (String key : pointsToRender.keySet()) { LinkedList<Point3d> points = pointsToRender.get(key); sum += points.size(); String myKey = (key.endsWith("_S"))? key.substring(0, key.length()-2): key; computedPointClouds.put(key, new PointCloud(key, colors.get(myKey), points)); } findingComplete(sum, (System.currentTimeMillis()-start)/1000.0d); } }.start(); } private String getDisplayEquationsAsString() { //Copy List LinkedList<AssignmentNode> list = new LinkedList<AssignmentNode>(); for (AssignmentNode node: graphAssignmentNodes) list.add(node.copyElements()); ReplaceVisitor visitor = new ReplaceVisitor() { private void visitVar(Variable node) { if (node.getName().equals("_V_X")) result = new Variable("x"); if (node.getName().equals("_V_Y")) result = new Variable("y"); if (node.getName().equals("_V_Z")) result = new Variable("z"); } @Override public void visit(MultivectorComponent node) { visitVar(node); } @Override public void visit(Variable node) { visitVar(node); } }; for (AssignmentNode node: list) { node.setVariable((Variable) visitor.replace(node.getVariable())); node.setValue(visitor.replace(node.getValue())); } //WithoutSums StringBuilder sb = new StringBuilder(); sb.append("//All components that should be zero on the surface of the multivector"); sb.append("\n"); for (AssignmentNode node: list) { String name = node.getVariable().getName(); String newName = renderingExpressions.get(name).toString(); AssignmentNode nodeCpy = node.copyElements(); nodeCpy.setVariable(new MultivectorComponent(newName, ((MultivectorComponent) nodeCpy.getVariable()).getBladeIndex())); sb.append(nodeCpy.toString()); sb.append("\n"); } list = createSumOfSquares(list); sb.append("\n"); sb.append("//Sum of the squared components that should be zero on the surface of the multivector"); sb.append("\n"); for (AssignmentNode node: list) { sb.append(node.toString()); sb.append("\n"); } return sb.toString(); } /** * Search _V_PRODUCT in a list of assignment nodes, * applies the sum of the squares to _V_PRODUCT_S * and returns the result * @param nodes The list of assignment nodes * @return The new list of assignment nodes */ private LinkedList<AssignmentNode> createSumOfSquares(LinkedList<AssignmentNode> nodes) { HashMap<String, LinkedList<AssignmentNode>> collect = new HashMap<String, LinkedList<AssignmentNode>>(); for (AssignmentNode node: nodes) { MultivectorComponent m = (MultivectorComponent) node.getVariable(); String name = m.getName(); if (!collect.containsKey(name)) collect.put(name, new LinkedList<AssignmentNode>()); collect.get(name).add(node); } LinkedList<AssignmentNode> myNodes = new LinkedList<AssignmentNode>(); for (String s: collect.keySet()) if (s.startsWith("_V_PRODUCT")) { Expression sumOfSquares = null; if (collect.get(s).size() > 1) { for (AssignmentNode node: collect.get(s)) { Expression square = new Exponentiation(node.getValue(), new FloatConstant(2)); if (sumOfSquares == null) sumOfSquares = square; else sumOfSquares = new Addition(sumOfSquares, square); } } else { if (collect.get(s).size() == 1) sumOfSquares = collect.get(s).getFirst().getValue(); } if (sumOfSquares != null) { AssignmentNode newNode = new AssignmentNode(null, new Variable(renderingExpressions.get(s).toString()), sumOfSquares); myNodes.add(newNode); listInsertBefore(myNodes, newNode, collect.get(s).getFirst()); for (AssignmentNode node: collect.get(s)) myNodes.remove(node); } } return myNodes; } /** * Inserts an element in a list before a certain element * @param list The list to insert in * @param toInsert The element to be insert * @param before The suceeding element */ protected static void listInsertBefore(LinkedList<AssignmentNode> list, AssignmentNode toInsert, AssignmentNode before) { LinkedList<AssignmentNode> listCopy = new LinkedList<AssignmentNode>(list); list.clear(); for (AssignmentNode node: listCopy) { if (node == before) list.add(toInsert); list.add(node); } } /** * This method is called, when finding has finished. * It shows all visible objects in the VisiblePanel. */ private void findingComplete(long sum, double tokenTime) { newDataSetAvailable = true; jLabel_Info.setText(sum + " points, time = "+tokenTime+" s"); visiblePanel.setObjects(getDataSet().keySet(), renderingExpressions); renderingEngine.pointSize = settingsPanel.getPointSize(); } /** * Request repainting */ private void repaintCommand() { newDataSetAvailable = true; } @Override public boolean isNewDataSetAvailable() { return newDataSetAvailable; } @Override public HashMap<String, PointCloud> getDataSet() { PointClouds pointClouds = new PointClouds(); pointClouds.putAll(computedPointClouds); return pointClouds; } @Override public PointClouds getLoadedPointClouds() { return loadedPointClouds; } @Override public HashSet<String> getVisibleObjects() { return visiblePanel.getVisibleObjects(); } /** * Determines, if a variable with the given name is an input variable * @param name The name of the variable * @return true, if the variable with the given name is an input variable, otherwise false */ public boolean isPositionVariable(String name) { if (name.equals("_V_X")) return true; if (name.equals("_V_Y")) return true; if (name.equals("_V_Z")) return true; return false; } }