/* Copyright (c) 1997-2006 Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany) http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version: http://www.gnu.org/licenses/gpl.txt. 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 General Public License for more details. $Project: polymake $$Id: JavaviewSchlegelFrame.java 7529 2006-12-20 16:57:12Z thilosch $ */ package de.tuberlin.polymake.polytope; import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Component; import java.awt.Frame; import java.awt.GridLayout; import java.awt.Panel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import jv.geom.PgPolygonSet; import jv.number.PuDouble; import jv.object.PsDebug; import jv.object.PsObject; import jv.object.PsPanel; import jv.project.PgGeometry; import jv.project.PgGeometryIf; import jv.project.PvDisplayIf; import jv.project.PvGeometryIf; import jv.project.PvPickEvent; import jv.project.PvPickListenerIf; import jv.vecmath.PdVector; import jv.vecmath.PiVector; import de.tuberlin.polymake.common.EmbeddedGeometries; import de.tuberlin.polymake.common.JavaviewControl; import de.tuberlin.polymake.common.PointSet; import de.tuberlin.polymake.common.JavaviewFrame; import de.tuberlin.polymake.common.PolymakePoint; import de.tuberlin.polymake.common.SimpleGeometryParser; /** * Frame used to display a Schlegel Diagram which can be interactively * modified by dragging vertices, changing the zoomFactor and selecting * new projection facets. The data which is sent will be filtered using the * MsgQueue. * * @author Thilo Schröder */ public class JavaviewSchlegelFrame extends JavaviewFrame implements PvPickListenerIf { /** Help frame belonging to the Schlegelframe */ protected static JavaviewSchlegelHelpFrame helpFrame = null; protected Panel topPanel = new Panel(); protected Button storeButton; protected Button sendMarkedButton; protected Button helpButton; protected boolean vertexDragged = false; static protected Color projColor = new Color(0,0,0); static protected Color facetColor = new Color(0,0,0); protected Vector facet = null; /** * Create a frame displaying the given geometry with given zoom parameter. * The output of any event is written into a pipe. * * @param i_geom geometry to be displayed * @param params non Javaview jvx parameters * @param sink */ public JavaviewSchlegelFrame(EmbeddedGeometries geoms, Properties params, Properties iparams, JavaviewControl parent) { super(geoms,params,iparams,parent); setUpGUI(); if(System.getProperty("polymake.user.colors.proj") != null) { StringTokenizer st = new StringTokenizer(System.getProperty("polymake.user.colors.proj")); projColor = new Color(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())); } if(System.getProperty("polymake.user.colors.facets") != null) { StringTokenizer st = new StringTokenizer(System.getProperty("polymake.user.colors.facets")); facetColor = new Color(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken())); } facet = SimpleGeometryParser.parseFacet(parameters.getProperty("facet")); setPolygonColors(); disp.addPickListener(this); // Set display in initial-pick mode, that is, the methods // pickInitial() and dragInitial() of PvPickListenerIf // are called on mouse events. disp.setMajorMode(PvDisplayIf.MODE_PICK); disp.fit(); } /** update the frame with new values for the vertices and the zoom Factor */ public void update(PointSet ps, Properties params, boolean clearTags) { if(!getTitle().equals(ps.getName())) { title = ps.getName(); setTitle(title); } if (!params.getProperty("zoom").equals("null")) { parameters.setProperty("zoom",params.getProperty("zoom")); if(vertexDragged) { ((PuDouble)sliderMap.get("zoom")).setValue(Double.parseDouble(parameters.getProperty("zoom"))); vertexDragged = false; } } geom.update(ps, clearTags); } public void update(PointSet ps, Properties params) { update(ps, params, false); } // ---------------- Begin of PvPickListenerIf ------------------------ /** The name of a listeners allows the display to issue verbal debug messages. */ public String getName() { return "SchlegelFramePicker"; } /** Currently not supported by display yet. */ public void selectGeometry(PgGeometryIf geom) { } /** * Get a location in the display with 2d display and 3d world coordinates. * Method is called when display is in mode PvDisplayIf.MODE_DISPLAY_PICK. * @see jv.project.PvPickListenerIf * @param pos Pick event issued by the display */ public void pickDisplay(PvPickEvent pos) { PsDebug.message("pickDisplay entered."); } /** * Drag a location in the display with 2d display and 3d world coordinates. * Method is called when display is in mode PvDisplayIf.MODE_DISPLAY_PICK. * @see jv.project.PvPickListenerIf * @param pos Pick event issued by the display */ public void dragDisplay(PvPickEvent pos) { PsDebug.message("pickDisplay entered."); } /** * Pick an arbitrary point on a geometry, point may lie inside an element. * Method is called when display is in mode PvDisplayIf.MODE_INITIAL_PICK * or if temporarily the i-key is pressed, and any pixel in the display is picked. * @see jv.project.PvPickListenerIf * @param pos Pick event issued by the display */ public void pickInitial(PvPickEvent pos) { // PsDebug.message("pickInitial entered."); } /** * Drag an arbitrary point along a geometry, point may lie inside an element. * Method is called when display is in mode PvDisplayIf.MODE_INITIAL_PICK * or if temporarily the i-key is pressed, and any pixel in the display is dragged. * @see jv.project.PvPickListenerIf * @param pos Pick event issued by the display */ public void dragInitial(PvPickEvent pos) { // PsDebug.message("dragInitial entered = "+pos.getLocation()); } /** * Get a picked vertex of a geometry. * Method is called when display is in mode PvDisplayIf.MODE_PICK * or if temporarily the p-key is pressed, and a vertex picked. * @see jv.project.PvPickListenerIf * @param geom Picked geometry on which vertex lies * @param index Index of vertex in vertex array of geometry * @param vertex 3d coordinates of vertex position */ public void pickVertex(PgGeometryIf geom, int index, PdVector vertex) { } /** *

Method is called when display is in mode PvDisplayIf.MODE_PICK * or if temporarily the p-key is pressed, and a vertex dragged.

*

Drag a picked vertex of a geometry and put its coordinates into * the MsgQueue. If the queue is empty sent PolymakeFrame.ANSWER * to sink.

* * @param geom Picked geometry on which vertex lies * @param index Index of vertex in vertex array of geometry * @param vertex 3d coordinates of vertex position */ public void dragVertex(PgGeometryIf m_geom, int index, PdVector vertex) { try { geom.moveVertex(m_geom.getName(),index,vertex); PointSet outputVertices = new PointSet(geom.getName(),1); PdVector tmpVertex = geom.getEmbeddedVertex(m_geom.getName(),index); outputVertices.setPoint(0, new PolymakePoint(tmpVertex.getEntries(),tmpVertex.getName())); parent.putMessage(SimpleGeometryParser.write(outputVertices,null),true); statusBar.setText(""); vertexDragged = true; } catch (Exception ex) { System.err.println("SchlegelFrame: error writing to client"); ex.printStackTrace(System.err); } } /** * Mark a set of vertices of a geometry within a given bounding box. * Method is called when display is in mode PvDisplayIf.MODE_MARK * or if temporarily the m-key is pressed, and a rectangle is drawn. * @param markBox contains four coplanar points on the bounding prism, * and direction of prism. */ public void markVertices(PvPickEvent markBox) { } /** * Unmark a set of vertices of a geometry within a given bounding box. * Method is called when display is in mode PvDisplayIf.MODE_UNMARK * or if temporarily the u-key is pressed, and a rectangle is drawn. * @param markBox contains four coplanar points on the bounding prism, and direction of prism. */ public void unmarkVertices(PvPickEvent markBox) { // PsDebug.message("unmarkVertices entered. Unmarked Vertex: " + pos.getVertexInd()); } // ---------------- End of PvPickListenerIf ------------------------ private void setPolygonColors() { PgGeometry[] geoms = geom.getGeometries(); for(int j = 0; j < geoms.length; ++j) { if(geoms[j].getType() == PvGeometryIf.GEOM_POLYGON_SET) { PiVector [] polygon = ((PgPolygonSet)geoms[j]).getPolygons(); for (int i=0; i < polygon.length; i++) { if(facet.contains(new Integer(polygon[i].getEntry(0))) && facet.contains(new Integer(polygon[i].getEntry(1))) ) { ((PgPolygonSet)geoms[j]).setPolygonColor(i,projColor); } else { ((PgPolygonSet)geoms[j]).setPolygonColor(i,facetColor); } } } geoms[j].update(geoms[j]); } } protected void setUpGUI() { // Standard Java technique to add a component to an applet. setLayout(new BorderLayout()); // Create a ZOOM Slider which writes its value to the sink on change PuDouble zoomFactor = new PuDouble("Zoom Factor", new zoomSlider()); zoomFactor.setDefBounds(0.01, 1.0, 0.01, 0.1); zoomFactor.init(); // zoomFactor.setDefValue(0.5); vertexDragged = true; helpButton = new Button("Help"); helpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (helpFrame == null) helpFrame = new JavaviewSchlegelHelpFrame(); if (!helpFrame.isVisible() || helpFrame.getState() == Frame.ICONIFIED) helpFrame.setLocation(getX() + 20, getY() + 20); helpFrame.setState(Frame.NORMAL); helpFrame.setVisible(true); } }); topPanel.setLayout(new BorderLayout()); topPanel.add(zoomFactor.assureInspector(PsPanel.INFO, PsPanel.INFO_EXT), BorderLayout.CENTER); topPanel.add(helpButton, BorderLayout.EAST); sliderMap.put("zoom",zoomFactor); add((Component) disp, BorderLayout.CENTER); add(topPanel, BorderLayout.NORTH); storeButton = new Button("My Favorite View!"); storeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { parent.putMessage(SimpleGeometryParser.write(geom.getName(),"store",1.),false); statusBar.setText(""); } catch (IOException ex) { System.err.println("SchlegelFrame: error writing to client"); ex.printStackTrace(System.err); } } }); sendMarkedButton = new Button("New Projection Facet"); sendMarkedButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { Vector markedVertices = geom.getMarkedVertices(); if(markedVertices.isEmpty()) { statusBar.setText("no points selected"); } else { parent.putMessage(SimpleGeometryParser.writeFacet(geom.getName(),markedVertices),true); statusBar.setText(""); } } catch (IOException ex) { System.err.println("SchlegelFrame: error writing to client"); ex.printStackTrace(System.err); } } }); Panel panel = new Panel(new GridLayout(2,1)); Panel bPanel = new Panel(new GridLayout(1,2)); // bPanel.add(storeButton); bPanel.add(sendMarkedButton); panel.add(bPanel); panel.add(statusBar); add(panel, BorderLayout.SOUTH); } /** * @author Thilo Schröder * * This class implements the update behaviour of the zoom factor slider. */ protected class zoomSlider extends PsObject { public boolean update(java.lang.Object event) { double actualValue = java.lang.Math.round(((PuDouble) event).getValue()*100)/100.0; if (Double.parseDouble(parameters.getProperty("zoom")) == actualValue) { return true; } try { parent.putMessage(SimpleGeometryParser.write(geom.getName(),"zoom",actualValue),true); statusBar.setText(""); } catch (IOException ex) { System.err.println("SchlegelFrame: communication error"); ex.printStackTrace(); return false; } // parameters.setProperty("zoom", Double.toString(actualValue)); return true; } } }