From c8e0d487886dbec1e3a994ea36724bbf59f5122a Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Tue, 9 Oct 2007 07:38:25 +0000 Subject: Integration of Tomas Hrasky's port of basic GLU NURBS functionality from C++ to Java, plus example applications, done as part of his Bachelor of Science degree at the University of Hradec Králové, Faculty of Informatics and Management. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current state of code is documented in src/classes/com/sun/opengl/impl/nurbs/README.txt. Example applications require Java 1.5 and are not currently built by default. Specify -Djogl.nurbs=1 during jogl-demos build with a 1.5 javac on the PATH to build them. Dependent jars are copied to build output directory. Deleted old partially-complete GLU NURBS port. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/jogl-demos/trunk@223 3298f667-5e0e-4b4a-8ed4-a3559d26a5f4 --- lib/simple-xml-1.1.1.jar | Bin 0 -> 67122 bytes lib/stax-1.2.0.jar | Bin 0 -> 179346 bytes lib/stax-api-1.0.1.jar | Bin 0 -> 25897 bytes make/build.xml | 23 +- src/demos/nurbs/curveapp/ActListener.java | 114 + src/demos/nurbs/curveapp/Curve.java | 313 ++ src/demos/nurbs/curveapp/CurveApp.java | 659 +++++ src/demos/nurbs/curveapp/CurveMouseListener.java | 180 ++ src/demos/nurbs/curveapp/GLListener.java | 141 + src/demos/nurbs/curveapp/MyFloat.java | 55 + src/demos/nurbs/curveapp/SpinnerListener.java | 47 + src/demos/nurbs/icons/IconFactory.java | 19 + src/demos/nurbs/icons/add.png | Bin 0 -> 1447 bytes src/demos/nurbs/icons/adept_sourceseditor.png | Bin 0 -> 2055 bytes src/demos/nurbs/icons/exit.png | Bin 0 -> 1426 bytes src/demos/nurbs/icons/fileclose.png | Bin 0 -> 2023 bytes src/demos/nurbs/icons/fileimport.png | Bin 0 -> 1831 bytes src/demos/nurbs/icons/filenew.png | Bin 0 -> 1580 bytes src/demos/nurbs/icons/folder_new.png | Bin 0 -> 2311 bytes src/demos/nurbs/icons/info.png | Bin 0 -> 1884 bytes src/demos/nurbs/icons/math_rsup.png | Bin 0 -> 1243 bytes src/demos/nurbs/icons/mouse.png | Bin 0 -> 1771 bytes src/demos/nurbs/icons/newfunction.png | Bin 0 -> 1901 bytes .../nurbs/knotslidercomponent/JKnotSlider.java | 468 +++ .../nurbs/knotslidercomponent/KnotPolygon.java | 159 + src/demos/nurbs/surfaceapp/ActListener.java | 330 +++ src/demos/nurbs/surfaceapp/GLListener.java | 336 +++ src/demos/nurbs/surfaceapp/MyFloat.java | 55 + src/demos/nurbs/surfaceapp/PrintfFormat.java | 3090 ++++++++++++++++++++ src/demos/nurbs/surfaceapp/SliderListener.java | 36 + src/demos/nurbs/surfaceapp/SpinnerListener.java | 52 + src/demos/nurbs/surfaceapp/Surface.java | 472 +++ src/demos/nurbs/surfaceapp/SurfaceApp.java | 1066 +++++++ .../nurbs/surfaceapp/SurfaceMouseListener.java | 277 ++ 34 files changed, 7891 insertions(+), 1 deletion(-) create mode 100644 lib/simple-xml-1.1.1.jar create mode 100644 lib/stax-1.2.0.jar create mode 100644 lib/stax-api-1.0.1.jar create mode 100755 src/demos/nurbs/curveapp/ActListener.java create mode 100755 src/demos/nurbs/curveapp/Curve.java create mode 100755 src/demos/nurbs/curveapp/CurveApp.java create mode 100755 src/demos/nurbs/curveapp/CurveMouseListener.java create mode 100755 src/demos/nurbs/curveapp/GLListener.java create mode 100755 src/demos/nurbs/curveapp/MyFloat.java create mode 100755 src/demos/nurbs/curveapp/SpinnerListener.java create mode 100755 src/demos/nurbs/icons/IconFactory.java create mode 100644 src/demos/nurbs/icons/add.png create mode 100644 src/demos/nurbs/icons/adept_sourceseditor.png create mode 100644 src/demos/nurbs/icons/exit.png create mode 100644 src/demos/nurbs/icons/fileclose.png create mode 100644 src/demos/nurbs/icons/fileimport.png create mode 100644 src/demos/nurbs/icons/filenew.png create mode 100644 src/demos/nurbs/icons/folder_new.png create mode 100644 src/demos/nurbs/icons/info.png create mode 100644 src/demos/nurbs/icons/math_rsup.png create mode 100644 src/demos/nurbs/icons/mouse.png create mode 100644 src/demos/nurbs/icons/newfunction.png create mode 100755 src/demos/nurbs/knotslidercomponent/JKnotSlider.java create mode 100755 src/demos/nurbs/knotslidercomponent/KnotPolygon.java create mode 100755 src/demos/nurbs/surfaceapp/ActListener.java create mode 100755 src/demos/nurbs/surfaceapp/GLListener.java create mode 100755 src/demos/nurbs/surfaceapp/MyFloat.java create mode 100755 src/demos/nurbs/surfaceapp/PrintfFormat.java create mode 100755 src/demos/nurbs/surfaceapp/SliderListener.java create mode 100755 src/demos/nurbs/surfaceapp/SpinnerListener.java create mode 100755 src/demos/nurbs/surfaceapp/Surface.java create mode 100755 src/demos/nurbs/surfaceapp/SurfaceApp.java create mode 100755 src/demos/nurbs/surfaceapp/SurfaceMouseListener.java diff --git a/lib/simple-xml-1.1.1.jar b/lib/simple-xml-1.1.1.jar new file mode 100644 index 0000000..20c8bb1 Binary files /dev/null and b/lib/simple-xml-1.1.1.jar differ diff --git a/lib/stax-1.2.0.jar b/lib/stax-1.2.0.jar new file mode 100644 index 0000000..0df112a Binary files /dev/null and b/lib/stax-1.2.0.jar differ diff --git a/lib/stax-api-1.0.1.jar b/lib/stax-api-1.0.1.jar new file mode 100644 index 0000000..483dc30 Binary files /dev/null and b/lib/stax-api-1.0.1.jar differ diff --git a/make/build.xml b/make/build.xml index e73061a..1394819 100644 --- a/make/build.xml +++ b/make/build.xml @@ -43,6 +43,7 @@ + @@ -54,17 +55,37 @@ + + + + + + + + + + + + + + + + + + + - + + diff --git a/src/demos/nurbs/curveapp/ActListener.java b/src/demos/nurbs/curveapp/ActListener.java new file mode 100755 index 0000000..52e89b8 --- /dev/null +++ b/src/demos/nurbs/curveapp/ActListener.java @@ -0,0 +1,114 @@ +package demos.nurbs.curveapp; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; + +import demos.nurbs.icons.*; + +/** + * Class reacting to events from toolbar and menu + * Třída reagující na události z nástrojové lišty a menu + * @author Tomáš Hráský + * + */ +@SuppressWarnings("serial") +public class ActListener extends AbstractAction +{ + + /** + * Parent window + * Odkaz na rodičovské okno + */ + private CurveApp app; + /** + * File chooser object + * Objekt pro výběr souboru + */ + private JFileChooser fc; + + /** + * Creates instance of object with pointer to parent window + * Vytvoří instanci objektu s odkazem na rodičovské okno + * @param app parent window + */ + public ActListener(CurveApp app) { + this.app=app; + fc=new JFileChooser("./"); + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + + + if(e.getActionCommand()==CurveApp.PRIDAT_AC){ + + }else if(e.getActionCommand()==CurveApp.SMAZAT_AC){ + + }else if(e.getActionCommand()==CurveApp.UZAVRENY_AC){ + app.uzavernyKV(); + }else if(e.getActionCommand()==CurveApp.OTEVRENY_AC){ + app.otevrenyKV(); + }else if(e.getActionCommand()==CurveApp.ULOZIT_AC){ + if(fc.showSaveDialog(app)==JFileChooser.APPROVE_OPTION){ + Curve.getInstance().persist(fc.getSelectedFile()); + } + }else if(e.getActionCommand()==CurveApp.NACIST_AC){ + if(fc.showOpenDialog(app)==JFileChooser.APPROVE_OPTION){ + try { + Curve.getInstance().unPersist(fc.getSelectedFile()); + app.updateGLCanvas(); + app.selectMoveButt(); + app.updateJKnotSlider(); + } catch (Exception e1) { + //JOptionPane.showMessageDialog(app,"Chyba při načítání ze souboru","Chyba",JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(app,"Error loading file","Error",JOptionPane.ERROR_MESSAGE); + } + } + }else if(e.getActionCommand()==CurveApp.NOVA_AC){ + Curve.getInstance().clear(); + app.getMouseListener().setBodIndex(-1); + Curve.getInstance().setBodIndex(-1); + app.updateGLCanvas(); + app.updateJKnotSlider(); + }else if(e.getActionCommand()==CurveApp.EXIT_AC){ + //TODO exit confirmation ? + System.exit(0); + }else if(e.getActionCommand()==CurveApp.STUPEN_AC){ + try{ + //String retval = JOptionPane.showInputDialog(null,"Zadejte stupeň křivky",new Integer(Curve.getInstance().getOrder())); + String retval = JOptionPane.showInputDialog(null,"Curve degree",new Integer(Curve.getInstance().getOrder())); + if(retval!=null){ + int stupen=(new Integer(retval)).intValue(); + Curve.getInstance().setOrder(stupen); + Curve.getInstance().setIsCurveFinished(false); + } + }catch (NumberFormatException ex){ + //JOptionPane.showMessageDialog(null,"Chybný formát přirozeného čísla","Chyba!",JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null,"Wrong natural number format","Error!",JOptionPane.ERROR_MESSAGE); + } + }else if(e.getActionCommand()==CurveApp.INFO_AC){ + /* + JOptionPane.showMessageDialog(null,"Ukázková aplikace rozšířené funkcionality knihovny JOGL\n" + + "Autor: Tomáš Hráský\n" + + "Součást bakalářské práce na téma Softwarová implementace NURBS křivek a ploch\n" + + "2007 Fakulta Informatiky a Managementu UHK\n" + + "Pro serializaci objektů využívá open source framework Simple XML - http://simple.sourceforge.net/","O aplikaci",JOptionPane.INFORMATION_MESSAGE,IconFactory.getIcon("demos/nurbs/icons/info.png")); + */ + JOptionPane.showMessageDialog(null,"Example aplication of extended functionality JOGL library\n" + + "Author: Tomáš Hráský\n" + + "Part of bachelor's degree thesis Software implementation of NURBS curves and surfaces\n" + + "2007 Faculty of Informatics and Management University of Hradec Králové\n" + + "Simple XML framework is used for object serialization - http://simple.sourceforge.net/","About",JOptionPane.INFORMATION_MESSAGE,IconFactory.getIcon("demos/nurbs/icons/info.png")); + } + + app.getMouseListener().setActionType(e.getActionCommand()); + + + } +} diff --git a/src/demos/nurbs/curveapp/Curve.java b/src/demos/nurbs/curveapp/Curve.java new file mode 100755 index 0000000..b772973 --- /dev/null +++ b/src/demos/nurbs/curveapp/Curve.java @@ -0,0 +1,313 @@ +package demos.nurbs.curveapp; + +import java.io.File; +import java.util.Vector; + +import simple.xml.Element; +import simple.xml.ElementList; +import simple.xml.Root; +import simple.xml.Serializer; +import simple.xml.load.Persister; + +/** + * Třída definice NURBS křivky, vystavěna podle návrhového vzoru Singleton + * @author Tomáš Hráský + * + */ +@Root(name="curve") +public class Curve +{ + /** + * Odkaz na instanci třídy + */ + private static Curve singleton; + /** + * Indikuje, zda je zadání křivky kompletní + */ + @Element(name="finished") + private boolean isCurveFinished; + + /** + * Index aktuálního vybraného řídícího bodu + */ + private int bodIndex = -1; + + /** + * Stupeň křivky + */ + @Element(name="order") + private int order=3; + + /** + * Pole souřadnic řídícíh bodů + * + */ + private float[] ctrlPoints; + + /** + * Pole hodnot uzlového vektoru + */ + private float knots[]; + + /** + * Kolekce vektor pro persistenci souřadnic řídících bodů + */ + @ElementList(name="ctrlpoints",type=MyFloat.class) + private Vector ctrlVector; + + /** + * Kolekce vektor pro persistenci uzlového vektoru + */ + @ElementList(name="knots",type=MyFloat.class) + private Vector knotVector; + + /** + * Vytvoří prázdnou definici křivky + */ + public void clear(){ + isCurveFinished=false; + ctrlPoints=new float[0]; + knots=new float[0]; + order=3; + } + + /** + * Pomocí framweorku Simple serializuje definici křivky do XML souboru + * @param f soubor pro uložení + */ + public void persist(File f){ + ctrlVector=new Vector(ctrlPoints.length); + knotVector=new Vector(knots.length); + + for(Float ff:ctrlPoints) + ctrlVector.add(new MyFloat(ff)); + + for(Float ff:knots) + knotVector.add(new MyFloat(ff)); + + Serializer s=new Persister(); + try { + System.out.println("ukládám"); + s.write(Curve.getInstance(),f); + } catch (Exception e1) { + e1.printStackTrace(); + } + + + } + + /** + * Vytvoří pomocí frameworku Simple křivku z definice uložené v XML souboru + * @param f soubor,z něhož se má definice načíst + * @throws Exception chyba při čtení ze souboru + */ + public void unPersist(File f) throws Exception{ + Serializer s=new Persister(); + Curve c=s.read(Curve.class,f); + initFromCurve(c); + } + + /** + * Inicializuje objekt podle jiného objektu typu Curve + * @param c referenční objekt - křivka + */ + private void initFromCurve(Curve c) { + this.order=c.getOrder(); + this.ctrlPoints=new float[c.getCtrlVector().size()]; + this.knots=new float[c.getKnotVector().size()]; + int i=0; + for(MyFloat f:c.getCtrlVector()) + ctrlPoints[i++]=f.getValue(); + i=0; + for(MyFloat f:c.getKnotVector()) + knots[i++]=f.getValue(); + + this.isCurveFinished=c.isCurveFinished(); + } + + /** + * Konstruktor, nastaví prázdné hodnoty polí definujících NURBS křivku + */ + private Curve(){ + ctrlPoints=new float[0]; + knots=new float[0]; + isCurveFinished=false; + } + + /** + * Vrací instanci třídy (podle návrhového vzoru Singleton) + * @return instance třídy Curve + */ + public static Curve getInstance() { + if (singleton == null) + singleton = new Curve(); + return singleton; + + } + + /** + * Vrací pole uzlového vektoru + * @return pole hodnot uzlového vektoru + */ + public float[] getKnots() { + return this.knots; + } + + /** + * Vrací pole s hodnotami souřadnic řídících bodů + * @return pole souřadnic řídících bodů + */ + public float[] getCtrlPoints() { + return this.ctrlPoints; + } + + /** + * Vrací stupeň NURBS křivky + * @return stupeň NURBS křivky + */ + public int getOrder() { + return this.order; + } + + /** + * Vrací index aktuálně vybraného řídícího bodu + * @return index aktuálně vybraného řídícího bodu + */ + public int getBodIndex() { + return bodIndex; + } + + /** + * Nastavuje index požadovaného aktuálně vybraného řídícího bodu + * @param bodIndex index požadovaného aktuálně vybraného řídícího bodu + */ + public void setBodIndex(int bodIndex) { + this.bodIndex = bodIndex; + } + + /** + * Vrací X-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu z homogenních souřadnic + * @return X-ová souadnice aktuálně vybraného řídícího bodu + */ + public float getActiveX(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4]/ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + /** + * Vrací Y-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu z homogenních souřadnic + * @return Y-ová souadnice aktuálně vybraného řídícího bodu + */ + public float getActiveY(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4+1]/ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + + /** + * Vrací váhu aktuálně vybraného řídícího bodu + * @return váha aktuálně vybraného řídícího bodu + */ + public float getActiveW(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + + /** + * Nastavuje X-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu do homogenních souřadnic + * @param x X-ová souřadnice aktuálně vybraného řídícího bodu + */ + public void setActiveX(float x){ + if(bodIndex>=0){ + ctrlPoints[bodIndex*4]=x*ctrlPoints[bodIndex*4+3]; + } + } + /** + * Nastavuje Y-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu do homogenních souřadnic + * @param y Y-ová souřadnice aktuálně vybraného řídícího bodu + */ + + public void setActiveY(float y){ + if(bodIndex>=0){ + ctrlPoints[bodIndex*4+1]=y*ctrlPoints[bodIndex*4+3]; + } + } + + /** + *Nastavuje váhu aktuálně vybraného řídícího bodu, upravuje hodnoty stávajícíh souřadic vzhledem k váze a použití homogenních souřadnic + * @param w váha aktuálně vybraného řídícího bodu + */ + public void setActiveW(float w){ + if(bodIndex>=0){ + float oldW=ctrlPoints[bodIndex*4+3]; + if(w>0){ + ctrlPoints[bodIndex*4+3]=w; + //úprava souřadnic + ctrlPoints[bodIndex*4]=ctrlPoints[bodIndex*4]/oldW*w; + ctrlPoints[bodIndex*4+1]=ctrlPoints[bodIndex*4+1]/oldW*w; + } + + } + } + + /** + * Nastavuje uzlový vektor + * @param knots nový uzlový vektor + */ + public void setKnots(float[] knots) { + this.knots = knots; + } + + /** + * Vrací informaci o stavu dokončení definice křvky + * @return true pokud je definice křivky kompletní, jinak false + */ + public boolean isCurveFinished() { + return isCurveFinished; + } + + /** + * Nastavuje řídící body + * @param ctrlPoints pole souřadnic řídících bodů + */ + public void setCtrlPoints(float[] ctrlPoints) { + this.ctrlPoints = ctrlPoints; + } + + /** + * Nastavuje stav dokončení definice křivky + * @param b stav dokončení definice křivky + * + */ + public void setIsCurveFinished(boolean b) { + isCurveFinished=b; + } + + /** + * Vrací vektor souřadnic řídích bodů pro serializaci + * @return vektor souřadnic řídících bodů + */ + private Vector getCtrlVector() { + return ctrlVector; + } + + /** + * Vrací vektor prvků uzlového vektoru pro serializaci + * @return vektor prvků uzlového vektoru + */ + private Vector getKnotVector() { + return knotVector; + } + + /** + * Nastaví stupeň křivky + * @param order požadovaný stupeň + */ + public void setOrder(int order) { + this.order = order; + } +} diff --git a/src/demos/nurbs/curveapp/CurveApp.java b/src/demos/nurbs/curveapp/CurveApp.java new file mode 100755 index 0000000..ff70f68 --- /dev/null +++ b/src/demos/nurbs/curveapp/CurveApp.java @@ -0,0 +1,659 @@ +package demos.nurbs.curveapp; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.media.opengl.GLCanvas; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.JSpinner; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SpinnerNumberModel; +import javax.swing.ToolTipManager; + +import demos.nurbs.icons.*; +import demos.nurbs.knotslidercomponent.JKnotSlider; + +/** + * Main class of application demostrating capabilities of JOGL when working with NURBS curves + * Hlavní třída aplikace demonstrující shopnosti knihovny JOGL při práci s NURBS křivkami + * @author Tomáš Hráský + * + */ +@SuppressWarnings("serial") +public class CurveApp extends JFrame implements ActionListener +{ + + /** + * Name of X-coord editing component of actually selected control point + * Jméno komponenty pro editaci X-ové souřadnice aktuálního bodu + */ + public static final String X_SPINNER_NAME = "xspinner"; + /** + * Name of Y-coord editing component of actually selected control point + * Jméno komponenty pro editaci Y-ové souřadnice aktuálního bodu + */ + public static final String Y_SPINNER_NAME = "yspinner"; + /** + * Name of weight editing component of actually selected control point + * Jméno komponenty pro editaci váhy aktuálního bodu + */ + public static final String W_SPINNER_NAME = "wspinner"; + + /** + * Name of ADD CONTROL POINT event + * Jméno události přidání řídícího bodu + */ + public static final String PRIDAT_AC = "PRIDAT"; + + /** + * Name of SET CURVE DEGREE event + * Jméno události zadání stupně křivky + */ + public static final String STUPEN_AC="STUPEN"; + /** + * Name of DELETE CONTROL POINT event + * Jméno události smazání řídícího bodu + */ + public static final String SMAZAT_AC = "SMAZAT"; + /** + * Name of MAKE CLOSED KNOTVECTOR event + * Jméno události vytvoření uzavřeného uzlového vektoru + */ + public static final String UZAVRENY_AC = "UZAVRENY"; + /** + * Name of MAKE OPEN (UNIFORM) KNOTVECTOR event + * Jméno události vytvoření otevřeného (uniformního) uzlového vektoru + */ + public static final String OTEVRENY_AC = "OTEVRENY"; + /** + * Name of SAVE CURVE event + * Jméno události uložení křivky + */ + public static final String ULOZIT_AC = "ULOZIT"; + /** + * Name of LOAD CURVE event + * Jméno události načetení uložené definice křivky + */ + public static final String NACIST_AC = "NACIST"; + /** + * Name of MOVE CONTROL POINT event + * Jméno události pohybu řídícího bodu + */ + private static final String MOVE_AC = "MOVE"; + + /** + * Name of CREATE NEW CURVE event + * Jméno události vytvoření nové křivky + */ + static final String NOVA_AC = "NEWCURVE"; + + /** + * Name of EXIT APP event + * Jméno události ukončení aplikace + */ + public static final String EXIT_AC = "EXIT"; + /** + * Name of SHOW ABOUT event + * Jméno události zobrazení okna o aplikaci + */ + public static final String INFO_AC = "INFO"; + + /** + * OpenGL canvas + * Plátno pro vykreslování pomocí OpenGL + */ + private GLCanvas glCanvas; + + /** + * X-coord editing component + * Komponenta pro editaci X-ové souřadnice aktuálního bodu + */ + private JSpinner xSpinner; + /** + * Y-coord editing component + * Komponenta pro editaci Y-ové souřadnice aktuálního bodu + */ + private JSpinner ySpinner; + /** + * Weight editing component + * Komponenta pro editaci váhy aktuálního bodu + */ + private JSpinner wSpinner; + + /** + * Mouse events listener + * Listener událostí myši + */ + private CurveMouseListener mouseListener; + + /** + * Knot vector editing component + * Komponenta pro editaci uzlového vektoru + */ + private JKnotSlider knotSlider; + + /** + * Start "move control point" mode + * Tlačítko pro zapnutí módu pohybu řídících bodů + */ + private JToggleButton moveTB; + + /** + * Constructor, initializes GUI + * Konstruktor, vytvoří grafické uživatelské rozhraní + */ + public CurveApp() { + super("Tomáš Hráský - example application demonstrating GLU NURBS capabilites - JOGL"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + initGUI(); + } + + /** + * GUI initialization + * Inicializace grafického uživatelského rozhraní + */ + private void initGUI() { + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); + + this.glCanvas = new GLCanvas(); + glCanvas.setSize(new Dimension(750, 500)); + glCanvas.addGLEventListener(new GLListener()); + mouseListener = new CurveMouseListener(this); + glCanvas.addMouseListener(mouseListener); + glCanvas.addMouseMotionListener(mouseListener); + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + c.gridy = 0; + c.gridwidth = GridBagConstraints.REMAINDER; + + ActListener listener = new ActListener(this); + + JMenuBar menuBar = new JMenuBar(); + getContentPane().add(menuBar, c); + + //JMenu aplikaceMenu = new JMenu("Aplikace"); + JMenu aplikaceMenu = new JMenu("Application"); + menuBar.add(aplikaceMenu); + + //JMenuItem aboutMI=new JMenuItem("O aplikaci"); + JMenuItem aboutMI=new JMenuItem("About"); + aboutMI.setActionCommand(INFO_AC); + aboutMI.addActionListener(listener); + aplikaceMenu.add(aboutMI); + + aplikaceMenu.add(new JSeparator()); + + //JMenuItem konecMI=new JMenuItem("Ukončit"); + JMenuItem konecMI=new JMenuItem("Exit"); + konecMI.addActionListener(listener); + konecMI.setActionCommand(EXIT_AC); + aplikaceMenu.add(konecMI); + + //JMenu krivkaMenu = new JMenu("Křivka"); + JMenu krivkaMenu = new JMenu("Curve"); + menuBar.add(krivkaMenu); + + //JMenuItem pridatBodyMI = new JMenuItem("Přidat body"); + JMenuItem pridatBodyMI = new JMenuItem("Add control points"); + krivkaMenu.add(pridatBodyMI); + pridatBodyMI.addActionListener(listener); + + + pridatBodyMI.setActionCommand(PRIDAT_AC); + JMenuItem smazatBodyMI = new JMenuItem( + //"Smazat body"); + "Delete points"); + krivkaMenu.add(smazatBodyMI); + smazatBodyMI.addActionListener(listener); + + smazatBodyMI.setActionCommand(SMAZAT_AC); + + //JMenuItem stupenMI=new JMenuItem("Zadat stupeň křivky"); + JMenuItem stupenMI=new JMenuItem("Set curve degree"); + krivkaMenu.add(stupenMI); + stupenMI.addActionListener(listener); + stupenMI.setActionCommand(STUPEN_AC); + + //JMenu knotVecMenu = new JMenu("Vytvořit uzlový vektor"); + JMenu knotVecMenu = new JMenu("Create knot vector"); + krivkaMenu.add(knotVecMenu); + + //JMenuItem clampedKVMI = new JMenuItem("Okrajový"); + JMenuItem clampedKVMI = new JMenuItem("Clamped"); + knotVecMenu.add(clampedKVMI); + clampedKVMI.setActionCommand(UZAVRENY_AC); + clampedKVMI.addActionListener(listener); + //JMenuItem unclampedKVMI = new JMenuItem("Uniformní"); + JMenuItem unclampedKVMI = new JMenuItem("Uniform"); + knotVecMenu.add(unclampedKVMI); + unclampedKVMI.setActionCommand(OTEVRENY_AC); + unclampedKVMI.addActionListener(listener); + + //JMenuItem moveMI=new JMenuItem("Hýbat body"); + JMenuItem moveMI=new JMenuItem("Move points"); + krivkaMenu.add(moveMI); + moveMI.setActionCommand(MOVE_AC); + moveMI.addActionListener(listener); + + krivkaMenu.add(new JSeparator()); + + krivkaMenu.add(new JSeparator()); + + //JMenuItem novaMI=new JMenuItem("Nová křivka"); + JMenuItem novaMI=new JMenuItem("New curve"); + krivkaMenu.add(novaMI); + novaMI.setActionCommand(NOVA_AC); + novaMI.addActionListener(listener); + + //JMenuItem ulozitMI = new JMenuItem("Uložit křivku jako..."); + JMenuItem ulozitMI = new JMenuItem("Save curve as..."); + krivkaMenu.add(ulozitMI); + ulozitMI.setActionCommand(ULOZIT_AC); + ulozitMI.addActionListener(listener); + //JMenuItem nacistMI = new JMenuItem("Načíst křivku"); + JMenuItem nacistMI = new JMenuItem("Load curve"); + krivkaMenu.add(nacistMI); + nacistMI.setActionCommand(NACIST_AC); + nacistMI.addActionListener(listener); + + c.gridy++; + JToolBar toolBar = new JToolBar(); + getContentPane().add(toolBar, c); + + ButtonGroup bg = new ButtonGroup(); + + + JButton novaB=new JButton(); + // novaB.setText("Nová"); + //novaB.setToolTipText("Nová křivka"); + novaB.setToolTipText("New curve"); + novaB.setIcon(IconFactory.getIcon("demos/nurbs/icons/folder_new.png")); + novaB.setActionCommand(NOVA_AC); + novaB.addActionListener(listener); + toolBar.add(novaB); + + JButton ulozitB=new JButton(); + ulozitB.setIcon(IconFactory.getIcon("demos/nurbs/icons/adept_sourceseditor.png")); + // ulozitB.setText("Uložit"); + //ulozitB.setToolTipText("Uložit"); + ulozitB.setToolTipText("Save"); + ulozitB.setActionCommand(ULOZIT_AC); + ulozitB.addActionListener(listener); + toolBar.add(ulozitB); + + JButton nahratB=new JButton(); + // nahratB.setText("Nahrát"); + //nahratB.setToolTipText("Nahrát uloženou křivku"); + nahratB.setToolTipText("Load curve"); + nahratB.setIcon(IconFactory.getIcon("demos/nurbs/icons/fileimport.png")); + nahratB.setActionCommand(NACIST_AC); + nahratB.addActionListener(listener); + toolBar.add(nahratB); + + toolBar.add(new JToolBar.Separator()); + + JToggleButton pridatTB = new JToggleButton(); + // pridatTB.setText("Přidat body"); + //pridatTB.setToolTipText("Přidat body"); + pridatTB.setToolTipText("Add points"); + toolBar.add(pridatTB); + pridatTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/add.png")); + pridatTB.setActionCommand(PRIDAT_AC); + pridatTB.addActionListener(listener); + bg.add(pridatTB); + JToggleButton smazatTB = new JToggleButton(); + // smazatTB.setText("Smazat body"); + //smazatTB.setToolTipText("Smazat body"); + smazatTB.setToolTipText("Delete points"); + toolBar.add(smazatTB); + smazatTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/fileclose.png")); + smazatTB.setActionCommand(SMAZAT_AC); + smazatTB.addActionListener(listener); + bg.add(smazatTB); + + JToggleButton stupenTB = new JToggleButton(); + // stupenTB.setText("Smazat body"); + //stupenTB.setToolTipText("Zadat stupeň křivky"); + stupenTB.setToolTipText("Set curve degree"); + toolBar.add(stupenTB); + stupenTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/math_rsup.png")); + stupenTB.setActionCommand(STUPEN_AC); + stupenTB.addActionListener(listener); + bg.add(stupenTB); + + + final JPopupMenu popup = new JPopupMenu(); + + //JMenuItem uzavrenyPopupMI = new JMenuItem("Okrajový"); + JMenuItem uzavrenyPopupMI = new JMenuItem("Clamped"); + popup.add(uzavrenyPopupMI); + uzavrenyPopupMI.setActionCommand(UZAVRENY_AC); + uzavrenyPopupMI.addActionListener(listener); + //JMenuItem otevrenyPopupMI = new JMenuItem("Uniformní"); + JMenuItem otevrenyPopupMI = new JMenuItem("Uniform"); + popup.add(otevrenyPopupMI); + otevrenyPopupMI.setActionCommand(OTEVRENY_AC); + otevrenyPopupMI.addActionListener(listener); + + JToggleButton vytvoritButton = new JToggleButton(); + // vytvoritButton.setText("Vytvořit uzlový vektor"); + //vytvoritButton.setToolTipText("Vytvořit uzlový vektor"); + vytvoritButton.setToolTipText("Create knot vector"); + vytvoritButton.setIcon(IconFactory.getIcon("demos/nurbs/icons/newfunction.png")); + bg.add(vytvoritButton); + + vytvoritButton.addMouseListener(new + /** + * @author Tomáš Hráský + * Class connecting context menu to button on toolbar + * Třída pro připojení kontextového menu na tlačítko na liště nástrojů + */ + MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + e.isPopupTrigger(); + popup.show(e.getComponent(), e.getX(), e.getY()); + } + + }); + popup.setInvoker(vytvoritButton); + toolBar.add(vytvoritButton); + + moveTB=new JToggleButton(); + // moveTB.setText("Hýbat body"); + //moveTB.setToolTipText("Hýbat body"); + moveTB.setToolTipText("Move points"); + moveTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/mouse.png")); + toolBar.add(moveTB); + moveTB.setActionCommand(MOVE_AC); + moveTB.addActionListener(listener); + bg.add(moveTB); + toolBar.add(new JToolBar.Separator()); + JButton infoB=new JButton(); + // infoB.setText("Ukončit"); + //infoB.setToolTipText("O aplikaci"); + infoB.setToolTipText("About"); + + infoB.setIcon(IconFactory.getIcon("demos/nurbs/icons/info.png")); + toolBar.add(infoB); + infoB.setActionCommand(INFO_AC); + infoB.addActionListener(listener); + toolBar.add(new JToolBar.Separator()); + + JButton exitB=new JButton(); + // exitB.setText("Ukončit"); + //exitB.setToolTipText("Ukončit"); + exitB.setToolTipText("Exit"); + + exitB.setIcon(IconFactory.getIcon("demos/nurbs/icons/exit.png")); + toolBar.add(exitB); + exitB.setActionCommand(EXIT_AC); + exitB.addActionListener(listener); + + c.gridwidth = 1; + + c.gridx = 0; + c.gridy = 2; + + c.weightx = 1; + c.weighty = 1; + + getContentPane().add(glCanvas, c); + c.gridx = 1; + JPanel rightPanel = new JPanel(new GridBagLayout()); + GridBagConstraints cc = new GridBagConstraints(); + cc.insets = new Insets(5, 5, 5, 5); + xSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 10000.0, 1)); + ySpinner = new JSpinner(new SpinnerNumberModel(0, 0, 10000.0, 1)); + wSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 10000.0, .05)); + + SpinnerListener spinnerListener = new SpinnerListener(this); + xSpinner.addChangeListener(spinnerListener); + xSpinner.setName(X_SPINNER_NAME); + ySpinner.addChangeListener(spinnerListener); + ySpinner.setName(Y_SPINNER_NAME); + wSpinner.addChangeListener(spinnerListener); + wSpinner.setName(W_SPINNER_NAME); + + cc.gridx = 0; + cc.gridy = 0; + + cc.gridwidth = 2; + cc.weighty = 1; + rightPanel.add(new JPanel(), cc); + cc.weighty = 0; + cc.gridwidth = 1; + + cc.gridy++; + rightPanel.add(new JLabel("X"), cc); + cc.gridy++; + rightPanel.add(new JLabel("Y"), cc); + cc.gridy++; + rightPanel.add(new JLabel("W"), cc); + + cc.gridx = 1; + cc.gridy = 1; + rightPanel.add(xSpinner, cc); + cc.gridy++; + rightPanel.add(ySpinner, cc); + cc.gridy++; + rightPanel.add(wSpinner, cc); + + xSpinner.setEnabled(false); + ySpinner.setEnabled(false); + wSpinner.setEnabled(false); + + c.weightx = 0; + c.weighty = 0; + getContentPane().add(rightPanel, c); + + c.gridx = 0; + c.gridy++; + + knotSlider = new JKnotSlider(Curve.getInstance().getKnots()); + knotSlider.addActionListener(this); + getContentPane().add(knotSlider, c); + + pack(); + invalidate(); + setVisible(true); + } + + /** + * Main method starting application + * Metoda pro spuštění aplikace + * @param args no arguments accepted + * + */ + public static void main(String[] args) { + new CurveApp(); + + } + + /** + * Reaction to request for redrive OpenGL canvas - repaints canvas, sets actually selected control points coords to editing components + * Reakce na požadavek překreslení OpenGL plátna, překreslí plátno a nastaví souřadnice aktuálního vybraného bodu do editačních komponent + */ + public void updateGLCanvas() { + glCanvas.repaint(); + if (Curve.getInstance().getBodIndex() >= 0) { + xSpinner.setEnabled(true); + ySpinner.setEnabled(true); + wSpinner.setEnabled(true); + + xSpinner.setValue(Double.valueOf(Math.round(Curve.getInstance() + .getActiveX()))); + ySpinner.setValue(Double.valueOf(Math.round(Curve.getInstance() + .getActiveY()))); + wSpinner.setValue(Double.valueOf(Curve.getInstance().getActiveW())); + } else { + xSpinner.setEnabled(false); + ySpinner.setEnabled(false); + wSpinner.setEnabled(false); + } + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + JKnotSlider src = (JKnotSlider) e.getSource(); + if(src.checkKnotMulti(Curve.getInstance().getOrder())){ + Curve.getInstance().setKnots(src.getKnotsFloat()); + }else{ + //JOptionPane.showMessageDialog(this,"Překročení maximální násobnosti uzlu","Chyba",JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this,"Maximum knot multiplicity exceeded","Error",JOptionPane.ERROR_MESSAGE); + src.setKnots(Curve.getInstance().getKnots()); + } + updateGLCanvas(); + } + + /** + * Returns OpenGL canvas + * Vrací OpenGL plátno + * @return OpenGL canvas + */ + public GLCanvas getGlCanvas() { + return glCanvas; + } + + /** + * Returns mouse events listener + * Vrací listener událostí myši + * @return mouse listener + */ + public CurveMouseListener getMouseListener() { + return mouseListener; + } + + /** + * Creates NURBS curve with clamped knot vector + * Vytvoří NURBS křivku s okrajovým uzlovým vektorem + */ + public void uzavernyKV() { + int stupen = Curve.getInstance().getOrder(); + int pocetBodu = Curve.getInstance().getCtrlPoints().length / 4; + if (stupen <= pocetBodu) { + int knotCount = stupen + pocetBodu; + int middlePartSize = knotCount - 2 * stupen; + float[] newKnots = new float[knotCount]; + int i; + int j = 0; + float middleStep = 1f / (middlePartSize + 2); + float knot = middleStep; + + // knot=.5f; + + for (i = 0; i < stupen; i++) + newKnots[j++] = 0; + for (i = 0; i < middlePartSize; i++) { + newKnots[j++] = knot; + knot += middleStep; + } + for (i = 0; i < stupen; i++) + newKnots[j++] = 1; + + postNewKnot(newKnots); + + } else + //errorMessage("Malý počet řídících bodů vzhledem k zadanému stupni křivky"); + errorMessage("Too few control points regarding set curve degree"); + } + + /** + * Displays modal window with error report + * Zobrazí modální okno s hlášením chyby + * @param error error message + */ + public void errorMessage(String error){ + //JOptionPane.showMessageDialog(this,error,"Chyba!",JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this,error,"Error!",JOptionPane.ERROR_MESSAGE); + } + + /** + * Creates NURBS curves with uniform knot vector + * Vytvoří NURBS křivku s uniformním uzlovým vektorem + */ + public void otevrenyKV() { + int stupen = Curve.getInstance().getOrder(); + int pocetBodu = Curve.getInstance().getCtrlPoints().length / 4; + if (stupen <= pocetBodu) { + int knotCount = stupen + pocetBodu; + int middlePartSize = knotCount; + float[] newKnots = new float[knotCount]; + int i; + int j = 0; + float middleStep = 1f / (middlePartSize - 1); + float knot = 0; + + // knot=.5f; + + // for(i=0;i=0){ + Curve.getInstance().setIsCurveFinished(false); + int size=Curve.getInstance().getCtrlPoints().length; + float[] newCtrls=new float[size-4]; + + int firstPartSize=(bodIndex)*4; + int secondPartSize=newCtrls.length-firstPartSize; + System.arraycopy(Curve.getInstance().getCtrlPoints(),0,newCtrls,0,firstPartSize); + System.arraycopy(Curve.getInstance().getCtrlPoints(),firstPartSize+4,newCtrls,firstPartSize,secondPartSize); + bodIndex=-1; + Curve.getInstance().setBodIndex(bodIndex); + Curve.getInstance().setCtrlPoints(newCtrls); + } + appWindow.updateGLCanvas(); + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) + */ + public void mousePressed(MouseEvent e) { + // if(actionType==MOVE_AC){ + float[] ctrlpoints=Curve.getInstance().getCtrlPoints(); + int x=e.getX(); + int y=e.getY(); + this.bodIndex=-1; + // System.out.println(ctrlpoints.length); + for(int i=0;i=xS-TOLERANCE&&x<=xS+TOLERANCE&&y>=yS-TOLERANCE&&y<=yS+TOLERANCE){ + this.bodIndex=i; + } + } + + Curve.getInstance().setBodIndex(bodIndex); + // } + appWindow.updateGLCanvas(); + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) + */ + public void mouseReleased(MouseEvent e) { + // this.bodIndex=-1; + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) + */ + public void mouseEntered(MouseEvent e) { + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) + */ + public void mouseExited(MouseEvent e) { + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) + */ + public void mouseDragged(MouseEvent e) { + if(this.bodIndex>=0){ + int x=e.getX(); + int y=e.getY(); + + Curve.getInstance().setActiveX(x); + Curve.getInstance().setActiveY(y); + } + appWindow.updateGLCanvas(); + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) + */ + public void mouseMoved(MouseEvent e) { + + } + + /** + * Set action type + * Nastaví typ prováděné činnosti + * @param action Action type + */ + public void setActionType(String action) { + this.actionType=action; + } + + /** + * Returns actually selected control point index + * Vrací index aktuálně vybraného řídícího bodu + * @return actually selected control point index + */ + public int getBodIndex() { + return bodIndex; + } + + /** + * Sets actually selected control point index + * Nastavuje index aktuálně vybraného řídícího bodu + * @param bodIndex actually selected control point index + */ + public void setBodIndex(int bodIndex) { + this.bodIndex = bodIndex; + } +} diff --git a/src/demos/nurbs/curveapp/GLListener.java b/src/demos/nurbs/curveapp/GLListener.java new file mode 100755 index 0000000..18bf36f --- /dev/null +++ b/src/demos/nurbs/curveapp/GLListener.java @@ -0,0 +1,141 @@ +package demos.nurbs.curveapp; + +import javax.media.opengl.GL; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.glu.*; + +import com.sun.opengl.util.GLUT; + +/** + * Listener raacting to OpenGL canvas events + * Listener reagující na události na OpenGL plátně + * @author Tomáš Hráský + * + */ +public class GLListener implements GLEventListener { + + /** + * OpenGL object + * objekt realizující základní OpenGL funkce + */ + private GL gl; + + /** + * GLU + * Objekt realizující funkce nadstavbové knihovny GLU + */ + private GLU glu; + + /** + * GLUT object + * Objekt realizující funkce nadstavbové knihovny GLUT + */ + private GLUT glut; + + /** + * NURBS curve object + * OpenGL Objekt NURBS křivky + */ + private GLUnurbs nurbs; + + + /* (non-Javadoc) + * @see javax.media.opengl.GLEventListener#init(javax.media.opengl.GLAutoDrawable) + */ + public void init(GLAutoDrawable drawable) { + this.gl = drawable.getGL(); + this.glu = new GLU(); + this.glut=new GLUT(); + + this.nurbs = glu.gluNewNurbsRenderer(); + gl.glClearColor(1, 1, 1, 1); + } + + /* (non-Javadoc) + * @see javax.media.opengl.GLEventListener#display(javax.media.opengl.GLAutoDrawable) + */ + public void display(GLAutoDrawable drawable) { + + gl.glClear(GL.GL_COLOR_BUFFER_BIT); + + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + float[] knots = Curve.getInstance().getKnots(); + float[] ctrlpoints = Curve.getInstance().getCtrlPoints(); + + gl.glEnable(GL.GL_LINE_SMOOTH); + gl.glEnable(GL.GL_BLEND); + gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); + gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_DONT_CARE); + + gl.glLineWidth(3); + + if(Curve.getInstance().isCurveFinished()){ + glu.gluBeginCurve(nurbs); + glu.gluNurbsCurve(nurbs, knots.length, knots, 4, ctrlpoints, Curve.getInstance().getOrder(), GL.GL_MAP1_VERTEX_4); + glu.gluEndCurve(nurbs); + } + + gl.glColor3f(0,0,0); + gl.glPointSize(5); + gl.glBegin(GL.GL_POINTS); + for (int i = 0; i < ctrlpoints.length / 4; i++) { + // if(i!=Curve.getInstance().getBodIndex()) + gl.glVertex3d(ctrlpoints[i * 4]/ctrlpoints[i * 4 + 3], ctrlpoints[i * 4 + 1]/ctrlpoints[i * 4 + 3], + ctrlpoints[i * 4 + 2]/ctrlpoints[i * 4 + 3]); + } + gl.glEnd(); + + + for (int i = 0; i < ctrlpoints.length / 4; i++) { + // if(i!=Curve.getInstance().getBodIndex()) + // gl.glPushMatrix(); + gl.glRasterPos2f(ctrlpoints[i * 4]/ctrlpoints[i * 4 + 3], ctrlpoints[i * 4 + 1]/ctrlpoints[i * 4 + 3]-5); + glut.glutBitmapString(GLUT.BITMAP_HELVETICA_18,String.valueOf(i+1)); + // gl.glPopMatrix(); + } + + + gl.glLineWidth(1); + gl.glBegin(GL.GL_LINE_STRIP); + for (int i = 0; i < ctrlpoints.length / 4; i++) { + // if(i!=Curve.getInstance().getBodIndex()) + gl.glVertex3d(ctrlpoints[i * 4]/ctrlpoints[i * 4 + 3], ctrlpoints[i * 4 + 1]/ctrlpoints[i * 4 + 3], + ctrlpoints[i * 4 + 2]/ctrlpoints[i * 4 + 3]); + } + gl.glEnd(); + gl.glColor3f(0,0,1); + if(Curve.getInstance().getBodIndex()>=0){ + gl.glPointSize(8); + gl.glBegin(GL.GL_POINTS); + int i=Curve.getInstance().getBodIndex(); + gl.glVertex3d(ctrlpoints[i * 4]/ctrlpoints[i * 4 + 3], ctrlpoints[i * 4 + 1]/ctrlpoints[i * 4 + 3], + ctrlpoints[i * 4 + 2]/ctrlpoints[i * 4 + 3]); + gl.glEnd(); + } + + + + } + + /* (non-Javadoc) + * @see javax.media.opengl.GLEventListener#reshape(javax.media.opengl.GLAutoDrawable, int, int, int, int) + */ + public void reshape(GLAutoDrawable drawable, int x, int y, int width, + int height) { + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + gl.glOrtho(0, drawable.getWidth(), 0, drawable.getHeight(), -1, 1); + gl.glScalef(1, -1, 1); + gl.glTranslatef(0, -drawable.getHeight(), 0); + + } + + /* (non-Javadoc) + * @see javax.media.opengl.GLEventListener#displayChanged(javax.media.opengl.GLAutoDrawable, boolean, boolean) + */ + public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { + } +} diff --git a/src/demos/nurbs/curveapp/MyFloat.java b/src/demos/nurbs/curveapp/MyFloat.java new file mode 100755 index 0000000..6adc2ef --- /dev/null +++ b/src/demos/nurbs/curveapp/MyFloat.java @@ -0,0 +1,55 @@ +package demos.nurbs.curveapp; + +import simple.xml.Attribute; +import simple.xml.Root; + +/** + * Class for serializing decimal point number using SimpleXML + * Třída umožňující serializaci desetinného čísla ve formátu plovoucí čárky (float) + * @author Tomáš Hráský + * + */ +@Root(name="floatval") +public class MyFloat { + /** + * Value + * Hodnota + */ + @Attribute(name="val") + private float value; + + /** + * Constructor, sets value to 0 + * Konstrktor, hodnota je defaultně 0 + */ + public MyFloat(){ + value=0; + } + + /** + * Creates instance with specified value + * Vytvoří instanci objektu s požadovanou hodnotou + * @param f value + */ + public MyFloat(float f) { + value = f; + } + + /** + * Returns value of decimal number + * Vrací hodnotu des. čísla + * @return value + */ + public float getValue() { + return value; + } + + /** + * Sets value + * Nastavuje hodnotu objektu + * @param value value + */ + public void setValue(float value) { + this.value = value; + } +} diff --git a/src/demos/nurbs/curveapp/SpinnerListener.java b/src/demos/nurbs/curveapp/SpinnerListener.java new file mode 100755 index 0000000..ccc5ac4 --- /dev/null +++ b/src/demos/nurbs/curveapp/SpinnerListener.java @@ -0,0 +1,47 @@ +package demos.nurbs.curveapp; + +import javax.swing.JSpinner; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * Listener reacting to events on GUI components setting coords and weight of selected control point + * Listener zpracovávající události na komponentách editujících souřadnice a váhu vybraného řídícícho bodu + * @author Tomáš Hráský + * + */ +public class SpinnerListener implements ChangeListener { + + /** + * Application window + * Okno aplikace, k němuž listener patří + */ + private CurveApp appWindow; + + /** + * Creates new instance with link to parent window + * Vytvoří instanci objektu s odkazem na rodičovské okno + * @param app app window + */ + public SpinnerListener(CurveApp app) { + this.appWindow=app; + } + + /* (non-Javadoc) + * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) + */ + public void stateChanged(ChangeEvent e) { + JSpinner src=(JSpinner) e.getSource(); + float val = 0; + if(src.getValue() instanceof Double) val=((Double) src.getValue()).floatValue(); + if(src.getValue() instanceof Float) val=((Float) src.getValue()).floatValue(); + + if(src.getName()==CurveApp.X_SPINNER_NAME) + Curve.getInstance().setActiveX(val); + if(src.getName()==CurveApp.Y_SPINNER_NAME) + Curve.getInstance().setActiveY(val); + if(src.getName()==CurveApp.W_SPINNER_NAME) + Curve.getInstance().setActiveW(val); + appWindow.updateGLCanvas(); + } +} diff --git a/src/demos/nurbs/icons/IconFactory.java b/src/demos/nurbs/icons/IconFactory.java new file mode 100755 index 0000000..88d8539 --- /dev/null +++ b/src/demos/nurbs/icons/IconFactory.java @@ -0,0 +1,19 @@ +package demos.nurbs.icons; + +import java.io.*; +import javax.swing.ImageIcon; +import com.sun.opengl.util.StreamUtil; + +public class IconFactory { + private IconFactory() {} + + public static ImageIcon getIcon(String resourceName) { + try { + InputStream input = IconFactory.class.getClassLoader().getResourceAsStream(resourceName); + byte[] data = StreamUtil.readAll(input); + return new ImageIcon(data, resourceName); + } catch (IOException e) { + return new ImageIcon(); + } + } +} diff --git a/src/demos/nurbs/icons/add.png b/src/demos/nurbs/icons/add.png new file mode 100644 index 0000000..ade93b9 Binary files /dev/null and b/src/demos/nurbs/icons/add.png differ diff --git a/src/demos/nurbs/icons/adept_sourceseditor.png b/src/demos/nurbs/icons/adept_sourceseditor.png new file mode 100644 index 0000000..c69015a Binary files /dev/null and b/src/demos/nurbs/icons/adept_sourceseditor.png differ diff --git a/src/demos/nurbs/icons/exit.png b/src/demos/nurbs/icons/exit.png new file mode 100644 index 0000000..5313b7a Binary files /dev/null and b/src/demos/nurbs/icons/exit.png differ diff --git a/src/demos/nurbs/icons/fileclose.png b/src/demos/nurbs/icons/fileclose.png new file mode 100644 index 0000000..84813bc Binary files /dev/null and b/src/demos/nurbs/icons/fileclose.png differ diff --git a/src/demos/nurbs/icons/fileimport.png b/src/demos/nurbs/icons/fileimport.png new file mode 100644 index 0000000..3bf3b99 Binary files /dev/null and b/src/demos/nurbs/icons/fileimport.png differ diff --git a/src/demos/nurbs/icons/filenew.png b/src/demos/nurbs/icons/filenew.png new file mode 100644 index 0000000..1f7f88e Binary files /dev/null and b/src/demos/nurbs/icons/filenew.png differ diff --git a/src/demos/nurbs/icons/folder_new.png b/src/demos/nurbs/icons/folder_new.png new file mode 100644 index 0000000..1ea3951 Binary files /dev/null and b/src/demos/nurbs/icons/folder_new.png differ diff --git a/src/demos/nurbs/icons/info.png b/src/demos/nurbs/icons/info.png new file mode 100644 index 0000000..e3c8adb Binary files /dev/null and b/src/demos/nurbs/icons/info.png differ diff --git a/src/demos/nurbs/icons/math_rsup.png b/src/demos/nurbs/icons/math_rsup.png new file mode 100644 index 0000000..d689192 Binary files /dev/null and b/src/demos/nurbs/icons/math_rsup.png differ diff --git a/src/demos/nurbs/icons/mouse.png b/src/demos/nurbs/icons/mouse.png new file mode 100644 index 0000000..fd57fac Binary files /dev/null and b/src/demos/nurbs/icons/mouse.png differ diff --git a/src/demos/nurbs/icons/newfunction.png b/src/demos/nurbs/icons/newfunction.png new file mode 100644 index 0000000..f890ef2 Binary files /dev/null and b/src/demos/nurbs/icons/newfunction.png differ diff --git a/src/demos/nurbs/knotslidercomponent/JKnotSlider.java b/src/demos/nurbs/knotslidercomponent/JKnotSlider.java new file mode 100755 index 0000000..02da402 --- /dev/null +++ b/src/demos/nurbs/knotslidercomponent/JKnotSlider.java @@ -0,0 +1,468 @@ +package demos.nurbs.knotslidercomponent; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.util.Collections; +import java.util.LinkedList; +import java.util.Vector; + +import javax.swing.JComponent; + +/** + * GUI component for editing NURBS curve/surface knotvector + * Komponenta grafického uživatelského rozhraní pro editaci uzlového vektoru NURBS křivky + * @author Tomáš Hráský + * + */ +@SuppressWarnings("serial") +public class JKnotSlider extends JComponent implements ComponentListener, + MouseMotionListener, MouseListener { + + /** + * Knot value change event + * Událost změny hodoty prvku uzlového vektoru + */ + private static final String KNOT_MOVED = "KnotMoved"; + + /** + * Vector representing knots + * Vektor objektů reprezentujících prvky uzlového vektoru + */ + private Vector knots; + + /** + * Previous knot vector (for recovery after user wrong setting) + * Předchozí vektor objektů reprezentujících prvky uzlového vektoru - pro obnovení při chybě uživatele + */ + private Vector previousState; + + /** + * List of listeners attached to component + * Seznam ActionListenerů navázaných na komponentu + */ + private LinkedList actionListeners; + + /** + * Value of one pixel movement + * Hodnota posunu o jeden pixel + */ + private double oneStep; + + /** + * Side space + * Mezera na straně osy + */ + private int side; + + /** + * Top space + * Mezera nad osou + */ + private int top; + + /** + * Actually selected knot index + * Index aktuálně vybraného prvku uzlového vektoru + */ + private int activeKnot; + +// private Vector xVector; + + + /** + * Creates component + * Vytvoří komponentu + */ + public JKnotSlider() { + oneStep = 0; + top = 0; + side = 0; + knots = new Vector(); + previousState=new Vector(); +// xVector=new Vector(); + + actionListeners = new LinkedList(); + this.addComponentListener(this); + this.addMouseMotionListener(this); + this.addMouseListener(this); + } + + /** + * Adds listener to notified list. list + * Přidá zadaný listener do seznamu naslouchajících objektů + * @param listener added listener + */ + public void addActionListener(ActionListener listener) { + actionListeners.add(listener); + } + + /** + * Creates component with given knotvector knots + * Vytvoří komponentu se zadanými hodnotami uzlového vektoru + * @param knots knot vector + */ + public JKnotSlider(double[] knots) { + this(); + for (double d : knots) { + addKnot(new Double(d)); + } + } + + /** + * Creates component with given knotvector knots + * Vytvoří komponentu se zadanými hodnotami uzlového vektoru + * @param knots knot vector + */ + public JKnotSlider(Vector knots) { + this(); + for (Double d : knots) { + addKnot(d); + } + } + /** + * Creates component with given knotvector knots + * Vytvoří komponentu se zadanými hodnotami uzlového vektoru + * @param knots uzlový vektor + */ + public JKnotSlider(float[] knots) { + this(); + if(knots!=null) + for(double d:knots) + addKnot(new Double(d)); + } + + /** + * Adds a knot + * Přidá uzel do uzlového vektoru + * @param d knot + */ + public void addKnot(Double d) { +// preserveState(); + knots.add(new KnotPolygon(d, oneStep, top, side)); + } + + + /** + * Saves actual knotvector for later recovery + * Uloží aktuální uzlový vektor pro pozdější obnovení + */ + private void preserveState(){ + previousState.clear(); + previousState.addAll(knots); + } + +// /** +// * Přidá uzel do uzlového vektoru +// * @param d hodnota přidávaného uzlu +// */ +// public void addKnot(double d) { +// addKnot(new Double(d)); +// } + + /** + * Returns knotvector + * Vrací uzlový vektor + * @return knotvector array + */ + @SuppressWarnings("unchecked") + public double[] getKnots() { + double[] output = new double[knots.size()]; + int i = 0; + if (activeKnot >= 0) { + Double d = knots.get(activeKnot).getValue(); + Collections.sort(knots); + for (int j = 0; j < knots.size(); j++) + if (knots.get(j).getValue().equals(d)) { + activeKnot = j; + break; + } + } else + Collections.sort(knots); + for (KnotPolygon p : knots) + output[i++] = p.getValue().doubleValue(); + return output; + } + /** + * Returns knotvector + * Vrací uzlový vektor + * @return knotvector array + */ + public float[] getKnotsFloat(){ + float[] output=new float[knots.size()]; + int i=0; + for(double d:getKnots()){ + output[i++]=(float) d; + } + return output; + } + + /* (non-Javadoc) + * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) + */ + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + drawBaseLine((Graphics2D) g); + updateMultis((Graphics2D)g); + drawKnots((Graphics2D) g); + } + + /** + * Draws info about knot multiplicity + * Vykreslí informaci o násobnosti uzlů + * @param graphics2D object to draw to + */ + private void updateMultis(Graphics2D graphics2D) { + Vector vrcholy=new Vector(); + for(int i=0;i počet stejných hodnot nám zjistí multiplicitu + for(Integer ii:vrcholy) + if(ii.intValue()==knots.get(i).xpoints[0]) + knots.get(i).setMulti(knots.get(i).getMulti()+1); + } + } + + /** + * Sends event to all notified listeners + * Pošle všem navešeným listenerům událost + * @param ae event being sent + */ + private void notificateActionListeners(ActionEvent ae) { + for (ActionListener a : actionListeners) + a.actionPerformed(ae); + } + + /** + * "Draws" knotvector + * Vykreslí reprezentaci uzlového vektoru + * @param g object to draw to + */ + private void drawKnots(Graphics2D g) { + String txt; +// int freq; + for (KnotPolygon p : knots) { + g.drawPolygon(p); + g.drawString(p.getMulti()+"x",p.xpoints[1],top); +// freq=Collections.frequency(xVector,Integer.valueOf(p.xpoints[0])); +// g.drawString(freq+"x",p.xpoints[1],top-8); + } + g.rotate(Math.PI / 2); + for (KnotPolygon p : knots) { + txt = p.getValue().toString(); + if (txt.length() > 5) + txt = txt.substring(0, 4); + g.translate(top + 15, -p.xpoints[1]); + g.drawString(txt, 0, 0); + g.translate(-(top + 15), p.xpoints[1]); + } + } + + + /** + * Draws baseline + * Vykreslí základní linku + * @param g object to draw to + */ + private void drawBaseLine(Graphics2D g) { + g.drawLine(side, top, (int) (side + (this.getWidth() * .8)), top); + } + + /* (non-Javadoc) + * @see java.awt.Component#getMinimumSize() + */ + @Override + public Dimension getMinimumSize() { + return new Dimension(100, 60); + } + + /* (non-Javadoc) + * @see java.awt.Component#getPreferredSize() + */ + @Override + public Dimension getPreferredSize() { + return new Dimension(250, 60); + } + + /* (non-Javadoc) + * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent) + */ + public void componentResized(ComponentEvent e) { + int width = this.getWidth(); + int height = this.getHeight(); + + side = (int) (width * .1); + top = (int) (height * .3); + + width *= .8; + height *= .8; + + oneStep = 1d / (width); + + updateKnotPolygons(); + repaint(); + } + + /** + * Updates all objects representing knots + * Aktualizuje nastavení všech objektů reprezentujících uzly + */ + private void updateKnotPolygons() { + for (KnotPolygon p : knots) { + p.update(oneStep, top, side); + } + + } + + /* (non-Javadoc) + * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent) + */ + public void componentMoved(ComponentEvent e) { + } + + /* (non-Javadoc) + * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent) + */ + public void componentShown(ComponentEvent e) { + } + + /* (non-Javadoc) + * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent) + */ + public void componentHidden(ComponentEvent e) { + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) + */ + public void mouseDragged(MouseEvent e) { + + if (activeKnot >= 0) { +// preserveState(); + + if (e.getX() >= side && e.getX() <= (getWidth() * .8 + side)) { + knots.get(activeKnot).updateByX(e.getX()); + } else if (e.getX() < side) + knots.get(activeKnot).updateByValue(new Double(0)); + else + knots.get(activeKnot).updateByValue(new Double(1)); + + notificateActionListeners(new ActionEvent(this, + ActionEvent.ACTION_PERFORMED, KNOT_MOVED)); + repaint(); + } + } + +// private void updateXVector() { +// xVector.clear(); +// for(KnotPolygon p:knots){ +// xVector.add(Integer.valueOf(p.xpoints[0])); +// } +// } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) + */ + public void mouseMoved(MouseEvent e) { + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) + */ + public void mouseClicked(MouseEvent e) { + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) + */ + public void mousePressed(MouseEvent e) { + int x = e.getX(); + int y = e.getY(); + KnotPolygon p; + this.activeKnot = -1; + for (int i = 0; i < knots.size(); i++) { + p = knots.get(i); + if (p.contains(x, y)) { + activeKnot = i; + break; + } + } + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) + */ + public void mouseReleased(MouseEvent e) { + this.activeKnot = -1; + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) + */ + public void mouseEntered(MouseEvent e) { + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) + */ + public void mouseExited(MouseEvent e) { + } + +// /** +// * Nastaví uzlový vektor +// * @param knots nový uzlový vektor +// */ +// public void setKnots(double[] knots) { +// preserveState(); +// for(double d:knots) +// addKnot(new Double(d)); +// repaint(); +// } + /** + * Sets knotvector + * Nastaví uzlový vektor + * @param knots new knotvector + */ + public void setKnots(float[] knots) { +// preserveState(); + this.knots.clear(); + for(double d:knots) + addKnot(new Double(d)); + repaint(); + } + + /** + * Checks whether knot multiplicity is not bigger than given value + * Zkontroluje, zda násobnost uzlů nepřekročila zadanou hodnotu + * @param maxMulti maximum multiplicity + * @return true if multiplicity is NOT bigger + */ + public boolean checkKnotMulti(int maxMulti) { + updateMultis((Graphics2D) this.getGraphics()); + for(KnotPolygon p:knots) + if(p.getMulti()>maxMulti) + return false; + return true; + } + +// /** +// * Obnosví poslední uložený stav uzlového vektoru +// */ +// public void restoreState() { +// knots.clear(); +// knots.addAll(previousState); +// repaint(); +// } +} diff --git a/src/demos/nurbs/knotslidercomponent/KnotPolygon.java b/src/demos/nurbs/knotslidercomponent/KnotPolygon.java new file mode 100755 index 0000000..5665392 --- /dev/null +++ b/src/demos/nurbs/knotslidercomponent/KnotPolygon.java @@ -0,0 +1,159 @@ +package demos.nurbs.knotslidercomponent; + +import java.awt.Polygon; + +/** + * Object representing knot + * Objekt reprezentující uzel v uzlovém vektoru + * @author Tomáš Hráský + * + */ +@SuppressWarnings("serial") +class KnotPolygon extends Polygon implements Comparable { + /** + * Knot value + * Hodnota uzlu + */ + private Double value; + + /** + * Size of change when moved by one pixel + * Velikost změny při posunu o jeden pixel + */ + private double oneStep; + + /** + * Top space + * Horní mezera osy + */ + private int top; + + /** + * Side space + * Boční mezera osy + */ + private int side; + + /** + * Knot multiplicity + * Násobnost uzlu + */ + private int multi; + + /** + * Creates new instance with given values + * Vytvoří instanci se zadanými hodnotami + * @param d knot value + * @param oneStep change of one pixel movement + * @param top top space + * @param side side space + */ + public KnotPolygon(Double d, double oneStep, int top, int side) { + this.value = d; + xpoints = new int[3]; + ypoints = new int[3]; + npoints = 3; + multi=1; + makeCoords(oneStep, top, side); + } + + /** + * Computes coords of polygon representing knot + * Vypočte souřadnice polygonu reprezentujícího uzel + * @param oneStep change of one pixel movement + * @param top top space + * @param side side space + */ + private void makeCoords(double oneStep, int top, int side) { + this.oneStep = oneStep; + this.top = top; + this.side = side; + + int x = (int) (value / oneStep); + x += side; + + xpoints[0] = x; + xpoints[1] = x - 4; + xpoints[2] = x + 4; + ypoints[0] = top + 2; + ypoints[1] = top + 12; + ypoints[2] = top + 12; + + invalidate(); + } + + /** + * Computes coords from set values + * Vypočte souřadnice podle nastavených hodont + */ + private void makeCoords() { + makeCoords(oneStep, top, side); + } + + /** + * Computes coords from given values + * Vypočte souřadnice podle zadaných hodont + * @param oneStep step of one pixel movement + * @param top top space + * @param side side space + */ + public void update(double oneStep, int top, int side) { + makeCoords(oneStep, top, side); + } + + /** + * Updates coords from given coord of polygon top + * Upraví souřadnice podle nové zadané souřadnice vrcholu polygonu + * @param x nová souřadnice vrcholu + */ + public void updateByX(int x) { + value = oneStep * (x - side); + makeCoords(); + } + + /** + * Updates coords from given value of knot + * Upraví souřadnice polygonu podle nové hodnoty + * @param d nová hodnota + */ + public void updateByValue(Double d){ + value=d; + makeCoords(); + } + + public int compareTo(Object o) { + if (o instanceof KnotPolygon) { + KnotPolygon kp = (KnotPolygon) o; + return getValue().compareTo(kp.getValue()); + } else + return 0; + } + + /** + * Returns knot value + * Vrací hodnotu uzlu + * @return knot value + */ + public Double getValue() { + return value; + } + + /** + * Returns knot multiplicity + * Vrací násobnost uzlu + * @return knot multiplicity + */ + public int getMulti() { + return multi; + } + + /** + * Sets knot multiplicity + * Nastavuje násobnost uzlu + * @param multi knot multiplicity + */ + public void setMulti(int multi) { + this.multi = multi; + } + +} diff --git a/src/demos/nurbs/surfaceapp/ActListener.java b/src/demos/nurbs/surfaceapp/ActListener.java new file mode 100755 index 0000000..c55b561 --- /dev/null +++ b/src/demos/nurbs/surfaceapp/ActListener.java @@ -0,0 +1,330 @@ +package demos.nurbs.surfaceapp; + +import java.awt.AWTEvent; +import java.awt.event.ActionEvent; +import java.util.Collections; +import java.util.Vector; + +import javax.swing.AbstractAction; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; + +import demos.nurbs.icons.*; + +/** + * Class reacting to events occuring on toolbar and menu + * Třída reagující na události z nástrojové lišty a menu + * @author Tomáš Hráský + * + */ +@SuppressWarnings("serial") +public class ActListener extends AbstractAction +{ + /** + * Parent window + * Odkaz na rodičovské okno + */ + private SurfaceApp app; + /** + * FIle chooser object + * Objekt pro výběr souboru + */ + private JFileChooser fc; + + /** + * Creates new instance with link to parent window + * Vytvoří instanci objektu s odkazem na rodičovské okno + * @param app parent window + */ + public ActListener(SurfaceApp app) { + this.app=app; + fc=new JFileChooser("./"); + } + + /* (non-Javadoc) + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + if(e.getActionCommand()==SurfaceApp.PRIDAT_AC_RADEK){ + if(Surface.getInstance().getPointsInU()>=2){ + Surface surface=Surface.getInstance(); + Vector lastRow=new Vector(); + int i; + for(i=surface.getCtrlPoints().length-1;i>=surface.getCtrlPoints().length-surface.getPointsInV()*4;i--){ + lastRow.add(surface.getCtrlPoints()[i]); + } + + Collections.reverse(lastRow); + + for(int j=0;j prevLastRow=new Vector(); + for(;i>=surface.getCtrlPoints().length-2*surface.getPointsInV()*4;i--){ + prevLastRow.add(surface.getCtrlPoints()[i]); + } + Collections.reverse(prevLastRow); + + for(int j=0;j diffs=new Vector(); + for(i=0;i newCtrls=new Vector(); + i=0; + + for(float f:surface.getCtrlPoints()){ + newCtrls.add(f); + } + // newCtrls.addAll(lastRow); + for(i=0;i yes/no dialog -> if yes->new surface action + //int retval=JOptionPane.showOptionDialog(null,"Malý počet bodů pro vytvoření nového řádku. Přejete si definovat novou plochu?","Definovat novou plochu?",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null,null,JOptionPane.YES_OPTION); + int retval=JOptionPane.showOptionDialog(null,"Not enough points for newe row. Would you like to define new surface?","Define new surface?",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null,null,JOptionPane.YES_OPTION); + if(retval==JOptionPane.YES_OPTION) + actionPerformed(new ActionEvent(this,AWTEvent.RESERVED_ID_MAX+1,SurfaceApp.NOVA_AC)); + } + }else if(e.getActionCommand()==SurfaceApp.PRIDAT_AC_SLOUPEC){ + if(Surface.getInstance().getPointsInV()>=2){ + Surface srf = Surface.getInstance(); + Vector leftCol=new Vector(); + for(int i=0;i nextCol=new Vector(); + for(int i=4;i diffs=new Vector(); + for(int i=0;i newCol=new Vector(); + for(int i=0;i oldPoints=new Vector(); + for(int i=0;i indexes=new Vector(); + + for(int i=index;i=0&&j>=0;i--,j-=4){ + for(int i=0,j=0;i souradnice=new Vector(); + float x = 0,z = 0; + for(int i=0;i=0){ + gl.glPointSize(8); + gl.glBegin(GL.GL_POINTS); + int i=Surface.getInstance().getBodIndex(); + gl.glVertex3d(ctrlpoints[i * 4]/ctrlpoints[i * 4 + 3], ctrlpoints[i * 4 + 1]/ctrlpoints[i * 4 + 3], + ctrlpoints[i * 4 + 2]/ctrlpoints[i * 4 + 3]); + gl.glEnd(); + } + + + } + + /* (non-Javadoc) + * @see javax.media.opengl.GLEventListener#reshape(javax.media.opengl.GLAutoDrawable, int, int, int, int) + */ + public void reshape(GLAutoDrawable drawable, int x, int y, int width, + int height) { + gl.glViewport(0, 0, width, height); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(65.0, (double) width / height, 0.1, 1000.0); + // gl.glScalef(1, -1, 1); + // gl.glTranslatef(0, -drawable.getHeight(), 0); + + } + + /* (non-Javadoc) + * @see javax.media.opengl.GLEventListener#displayChanged(javax.media.opengl.GLAutoDrawable, boolean, boolean) + */ + public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { + } + + /** + * Returns GLU object in use + * Vrací používáný GLU objekt + * @return GLU objekt + */ + public GLU getGlu() { + return glu; + } + + /** + * Returns viewpord corners coords + * Vrací souřadnice rohů viewportu + * @return array with viewport corner's coords + */ + public int[] getViewport() { + return viewport; + } + + /** + * Returns model view matrix + * Vrací modelview matici + * @return modelview matrix + */ + public double[] getMvmatrix() { + return mvmatrix; + } + + /** + * Returns projection matrix + * Vrací projekční matici + * @return projection matrix + */ + public double[] getProjmatrix() { + return projmatrix; + } +} diff --git a/src/demos/nurbs/surfaceapp/MyFloat.java b/src/demos/nurbs/surfaceapp/MyFloat.java new file mode 100755 index 0000000..a9bd7cf --- /dev/null +++ b/src/demos/nurbs/surfaceapp/MyFloat.java @@ -0,0 +1,55 @@ +package demos.nurbs.surfaceapp; + +import simple.xml.Attribute; +import simple.xml.Root; + +/** + * Class for serializing decimal point number using SimpleXML + * Třída umožňující serializaci desetinného čísla ve formátu plovoucí čárky (float) + * @author Tomáš Hráský + * + */ +@Root(name="floatval") +public class MyFloat { + /** + * Value + * Hodnota + */ + @Attribute(name="val") + private float value; + + /** + * Constructor, sets value to 0 + * Konstrktor, hodnota je defaultně 0 + */ + public MyFloat(){ + value=0; + } + + /** + * Creates instance with specified value + * Vytvoří instanci objektu s požadovanou hodnotou + * @param f value + */ + public MyFloat(float f) { + value = f; + } + + /** + * Returns value of decimal number + * Vrací hodnotu des. čísla + * @return value + */ + public float getValue() { + return value; + } + + /** + * Sets value + * Nastavuje hodnotu objektu + * @param value value + */ + public void setValue(float value) { + this.value = value; + } +} diff --git a/src/demos/nurbs/surfaceapp/PrintfFormat.java b/src/demos/nurbs/surfaceapp/PrintfFormat.java new file mode 100755 index 0000000..153460a --- /dev/null +++ b/src/demos/nurbs/surfaceapp/PrintfFormat.java @@ -0,0 +1,3090 @@ +package demos.nurbs.surfaceapp; +// +// (c) 2000 Sun Microsystems, Inc. +// ALL RIGHTS RESERVED +// +// License Grant- +// +// +// Permission to use, copy, modify, and distribute this Software and its +// documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is +// hereby granted. +// +// This Software is provided "AS IS". All express warranties, including any +// implied warranty of merchantability, satisfactory quality, fitness for a +// particular purpose, or non-infringement, are disclaimed, except to the extent +// that such disclaimers are held to be legally invalid. +// +// You acknowledge that Software is not designed, licensed or intended for use in +// the design, construction, operation or maintenance of any nuclear facility +// ("High Risk Activities"). Sun disclaims any express or implied warranty of +// fitness for such uses. +// +// Please refer to the file http://www.sun.com/policies/trademarks/ for further +// important trademark information and to +// http://java.sun.com/nav/business/index.html for further important licensing +// information for the Java Technology. +// + + +import java.util.Enumeration; +import java.util.Vector; +import java.util.Locale; +import java.text.DecimalFormatSymbols; + +/** + * PrintfFormat allows the formatting of an array of + * objects embedded within a string. Primitive types + * must be passed using wrapper types. The formatting + * is controlled by a control string. + *

+ * A control string is a Java string that contains a + * control specification. The control specification + * starts at the first percent sign (%) in the string, + * provided that this percent sign + *

    + *
  1. is not escaped protected by a matching % or is + * not an escape % character, + *
  2. is not at the end of the format string, and + *
  3. precedes a sequence of characters that parses as + * a valid control specification. + *
+ *

+ * A control specification usually takes the form: + *

 % ['-+ #0]* [0..9]* { . [0..9]* }+
+ *                { [hlL] }+ [idfgGoxXeEcs]
+ *
+ * There are variants of this basic form that are + * discussed below.

+ *

+ * The format is composed of zero or more directives + * defined as follows: + *

    + *
  • ordinary characters, which are simply copied to + * the output stream; + *
  • escape sequences, which represent non-graphic + * characters; and + *
  • conversion specifications, each of which + * results in the fetching of zero or more arguments. + *

+ *

+ * The results are undefined if there are insufficient + * arguments for the format. Usually an unchecked + * exception will be thrown. If the format is + * exhausted while arguments remain, the excess + * arguments are evaluated but are otherwise ignored. + * In format strings containing the % form of + * conversion specifications, each argument in the + * argument list is used exactly once.

+ *

+ * Conversions can be applied to the nth + * argument after the format in the argument list, + * rather than to the next unused argument. In this + * case, the conversion characer % is replaced by the + * sequence %n$, where n is + * a decimal integer giving the position of the + * argument in the argument list.

+ *

+ * In format strings containing the %n$ + * form of conversion specifications, each argument + * in the argument list is used exactly once.

+ * + *

Escape Sequences

+ *

+ * The following table lists escape sequences and + * associated actions on display devices capable of + * the action. + * + * + * + * + * + * + * + * + * + * + * + * + *
SequenceNameDescription
\\backlashNone. + *
\aalertAttempts to alert + * the user through audible or visible + * notification. + *
\bbackspaceMoves the + * printing position to one column before + * the current position, unless the + * current position is the start of a line. + *
\fform-feedMoves the + * printing position to the initial + * printing position of the next logical + * page. + *
\nnewlineMoves the + * printing position to the start of the + * next line. + *
\rcarriage-returnMoves + * the printing position to the start of + * the current line. + *
\ttabMoves the printing + * position to the next implementation- + * defined horizontal tab position. + *
\vvertical-tabMoves the + * printing position to the start of the + * next implementation-defined vertical + * tab position. + *

+ *

Conversion Specifications

+ *

+ * Each conversion specification is introduced by + * the percent sign character (%). After the character + * %, the following appear in sequence:

+ *

+ * Zero or more flags (in any order), which modify the + * meaning of the conversion specification.

+ *

+ * An optional minimum field width. If the converted + * value has fewer characters than the field width, it + * will be padded with spaces by default on the left; + * t will be padded on the right, if the left- + * adjustment flag (-), described below, is given to + * the field width. The field width takes the form + * of a decimal integer. If the conversion character + * is s, the field width is the the minimum number of + * characters to be printed.

+ *

+ * An optional precision that gives the minumum number + * of digits to appear for the d, i, o, x or X + * conversions (the field is padded with leading + * zeros); the number of digits to appear after the + * radix character for the e, E, and f conversions, + * the maximum number of significant digits for the g + * and G conversions; or the maximum number of + * characters to be written from a string is s and S + * conversions. The precision takes the form of an + * optional decimal digit string, where a null digit + * string is treated as 0. If a precision appears + * with a c conversion character the precision is + * ignored. + *

+ *

+ * An optional h specifies that a following d, i, o, + * x, or X conversion character applies to a type + * short argument (the argument will be promoted + * according to the integral promotions and its value + * converted to type short before printing).

+ *

+ * An optional l (ell) specifies that a following + * d, i, o, x, or X conversion character applies to a + * type long argument.

+ *

+ * A field width or precision may be indicated by an + * asterisk (*) instead of a digit string. In this + * case, an integer argument supplised the field width + * precision. The argument that is actually converted + * is not fetched until the conversion letter is seen, + * so the the arguments specifying field width or + * precision must appear before the argument (if any) + * to be converted. If the precision argument is + * negative, it will be changed to zero. A negative + * field width argument is taken as a - flag, followed + * by a positive field width.

+ *

+ * In format strings containing the %n$ + * form of a conversion specification, a field width + * or precision may be indicated by the sequence + * *m$, where m is a decimal integer + * giving the position in the argument list (after the + * format argument) of an integer argument containing + * the field width or precision.

+ *

+ * The format can contain either numbered argument + * specifications (that is, %n$ and + * *m$), or unnumbered argument + * specifications (that is % and *), but normally not + * both. The only exception to this is that %% can + * be mixed with the %n$ form. The + * results of mixing numbered and unnumbered argument + * specifications in a format string are undefined.

+ * + *

Flag Characters

+ *

+ * The flags and their meanings are:

+ *
+ *
'
integer portion of the result of a + * decimal conversion (%i, %d, %f, %g, or %G) will + * be formatted with thousands' grouping + * characters. For other conversions the flag + * is ignored. The non-monetary grouping + * character is used. + *
-
result of the conversion is left-justified + * within the field. (It will be right-justified + * if this flag is not specified). + *
+
result of a signed conversion always + * begins with a sign (+ or -). (It will begin + * with a sign only when a negative value is + * converted if this flag is not specified.) + *
<space>
If the first character of a + * signed conversion is not a sign, a space + * character will be placed before the result. + * This means that if the space character and + + * flags both appear, the space flag will be + * ignored. + *
#
value is to be converted to an alternative + * form. For c, d, i, and s conversions, the flag + * has no effect. For o conversion, it increases + * the precision to force the first digit of the + * result to be a zero. For x or X conversion, a + * non-zero result has 0x or 0X prefixed to it, + * respectively. For e, E, f, g, and G + * conversions, the result always contains a radix + * character, even if no digits follow the radix + * character (normally, a decimal point appears in + * the result of these conversions only if a digit + * follows it). For g and G conversions, trailing + * zeros will not be removed from the result as + * they normally are. + *
0
d, i, o, x, X, e, E, f, g, and G + * conversions, leading zeros (following any + * indication of sign or base) are used to pad to + * the field width; no space padding is + * performed. If the 0 and - flags both appear, + * the 0 flag is ignored. For d, i, o, x, and X + * conversions, if a precision is specified, the + * 0 flag will be ignored. For c conversions, + * the flag is ignored. + *
+ * + *

Conversion Characters

+ *

+ * Each conversion character results in fetching zero + * or more arguments. The results are undefined if + * there are insufficient arguments for the format. + * Usually, an unchecked exception will be thrown. + * If the format is exhausted while arguments remain, + * the excess arguments are ignored.

+ * + *

+ * The conversion characters and their meanings are: + *

+ *
+ *
d,i
The int argument is converted to a + * signed decimal in the style [-]dddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + *
o
The int argument is converted to unsigned + * octal format in the style ddddd. The + * precision specifies the minimum number of + * digits to appear; if the value being + * converted can be represented in fewer + * digits, it will be expanded with leading + * zeros. The default precision is 1. The + * result of converting 0 with an explicit + * precision of 0 is no characters. + *
x
The int argument is converted to unsigned + * hexadecimal format in the style dddd; the + * letters abcdef are used. The precision + * specifies the minimum numberof digits to + * appear; if the value being converted can be + * represented in fewer digits, it will be + * expanded with leading zeros. The default + * precision is 1. The result of converting 0 + * with an explicit precision of 0 is no + * characters. + *
X
Behaves the same as the x conversion + * character except that letters ABCDEF are + * used instead of abcdef. + *
f
The floating point number argument is + * written in decimal notation in the style + * [-]ddd.ddd, where the number of digits after + * the radix character (shown here as a decimal + * point) is equal to the precision + * specification. A Locale is used to determine + * the radix character to use in this format. + * If the precision is omitted from the + * argument, six digits are written after the + * radix character; if the precision is + * explicitly 0 and the # flag is not specified, + * no radix character appears. If a radix + * character appears, at least 1 digit appears + * before it. The value is rounded to the + * appropriate number of digits. + *
e,E
The floating point number argument is + * written in the style [-]d.ddde{+-}dd + * (the symbols {+-} indicate either a plus or + * minus sign), where there is one digit before + * the radix character (shown here as a decimal + * point) and the number of digits after it is + * equal to the precision. A Locale is used to + * determine the radix character to use in this + * format. When the precision is missing, six + * digits are written after the radix character; + * if the precision is 0 and the # flag is not + * specified, no radix character appears. The + * E conversion will produce a number with E + * instead of e introducing the exponent. The + * exponent always contains at least two digits. + * However, if the value to be written requires + * an exponent greater than two digits, + * additional exponent digits are written as + * necessary. The value is rounded to the + * appropriate number of digits. + *
g,G
The floating point number argument is + * written in style f or e (or in sytle E in the + * case of a G conversion character), with the + * precision specifying the number of + * significant digits. If the precision is + * zero, it is taken as one. The style used + * depends on the value converted: style e + * (or E) will be used only if the exponent + * resulting from the conversion is less than + * -4 or greater than or equal to the precision. + * Trailing zeros are removed from the result. + * A radix character appears only if it is + * followed by a digit. + *
c,C
The integer argument is converted to a + * char and the result is written. + * + *
s,S
The argument is taken to be a string and + * bytes from the string are written until the + * end of the string or the number of bytes + * indicated by the precision specification of + * the argument is reached. If the precision + * is omitted from the argument, it is taken to + * be infinite, so all characters up to the end + * of the string are written. + *
%
Write a % character; no argument is + * converted. + *
+ *

+ * If a conversion specification does not match one of + * the above forms, an IllegalArgumentException is + * thrown and the instance of PrintfFormat is not + * created.

+ *

+ * If a floating point value is the internal + * representation for infinity, the output is + * [+]Infinity, where Infinity is either Infinity or + * Inf, depending on the desired output string length. + * Printing of the sign follows the rules described + * above.

+ *

+ * If a floating point value is the internal + * representation for "not-a-number," the output is + * [+]NaN. Printing of the sign follows the rules + * described above.

+ *

+ * In no case does a non-existent or small field width + * cause truncation of a field; if the result of a + * conversion is wider than the field width, the field + * is simply expanded to contain the conversion result. + *

+ *

+ * The behavior is like printf. One exception is that + * the minimum number of exponent digits is 3 instead + * of 2 for e and E formats when the optional L is used + * before the e, E, g, or G conversion character. The + * optional L does not imply conversion to a long long + * double.

+ *

+ * The biggest divergence from the C printf + * specification is in the use of 16 bit characters. + * This allows the handling of characters beyond the + * small ASCII character set and allows the utility to + * interoperate correctly with the rest of the Java + * runtime environment.

+ *

+ * Omissions from the C printf specification are + * numerous. All the known omissions are present + * because Java never uses bytes to represent + * characters and does not have pointers:

+ *
    + *
  • %c is the same as %C. + *
  • %s is the same as %S. + *
  • u, p, and n conversion characters. + *
  • %ws format. + *
  • h modifier applied to an n conversion character. + *
  • l (ell) modifier applied to the c, n, or s + * conversion characters. + *
  • ll (ell ell) modifier to d, i, o, u, x, or X + * conversion characters. + *
  • ll (ell ell) modifier to an n conversion + * character. + *
  • c, C, d,i,o,u,x, and X conversion characters + * apply to Byte, Character, Short, Integer, Long + * types. + *
  • f, e, E, g, and G conversion characters apply + * to Float and Double types. + *
  • s and S conversion characters apply to String + * types. + *
  • All other reference types can be formatted + * using the s or S conversion characters only. + *
+ *

+ * Most of this specification is quoted from the Unix + * man page for the sprintf utility.

+ * + * @author Allan Jacobs + * @version 1 + * Release 1: Initial release. + * Release 2: Asterisk field widths and precisions + * %n$ and *m$ + * Bug fixes + * g format fix (2 digits in e form corrupt) + * rounding in f format implemented + * round up when digit not printed is 5 + * formatting of -0.0f + * round up/down when last digits are 50000... + */ +public class PrintfFormat { + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * @param fmtArg Control string. + * @exception IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(String fmtArg) + throws IllegalArgumentException { + this(Locale.getDefault(),fmtArg); + } + /** + * Constructs an array of control specifications + * possibly preceded, separated, or followed by + * ordinary strings. Control strings begin with + * unpaired percent signs. A pair of successive + * percent signs designates a single percent sign in + * the format. + * @param fmtArg Control string. + * @exception IllegalArgumentException if the control + * string is null, zero length, or otherwise + * malformed. + */ + public PrintfFormat(Locale locale,String fmtArg) + throws IllegalArgumentException { + dfs = new DecimalFormatSymbols(locale); + int ePos=0; + ConversionSpecification sFmt=null; + String unCS = this.nonControl(fmtArg,0); + if (unCS!=null) { + sFmt = new ConversionSpecification(); + sFmt.setLiteral(unCS); + vFmt.addElement(sFmt); + } + while(cPos!=-1 && cPosstart and ending at either the end + * of the String s, the next unpaired + * percent sign, or at the end of the String if the + * last character is a percent sign. + * @param s Control string. + * @param start Position in the string + * s to begin looking for the start + * of a control string. + * @return the substring from the start position + * to the beginning of the control string. + */ + private String nonControl(String s,int start) { + String ret=""; + cPos=s.indexOf("%",start); + if (cPos==-1) cPos=s.length(); + return s.substring(start,cPos); + } + /** + * Format an array of objects. Byte, Short, + * Integer, Long, Float, Double, and Character + * arguments are treated as wrappers for primitive + * types. + * @param o The array of objects to format. + * @return The formatted String. + */ + public String sprintf(Object[] o) { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + int i=0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + else { + if (cs.isPositionalSpecification()) { + i=cs.getArgumentPosition()-1; + if (cs.isPositionalFieldWidth()) { + int ifw=cs.getArgumentPositionForFieldWidth()-1; + cs.setFieldWidthWithArg(((Integer)o[ifw]).intValue()); + } + if (cs.isPositionalPrecision()) { + int ipr=cs.getArgumentPositionForPrecision()-1; + cs.setPrecisionWithArg(((Integer)o[ipr]).intValue()); + } + } + else { + if (cs.isVariableFieldWidth()) { + cs.setFieldWidthWithArg(((Integer)o[i]).intValue()); + i++; + } + if (cs.isVariablePrecision()) { + cs.setPrecisionWithArg(((Integer)o[i]).intValue()); + i++; + } + } + if (o[i] instanceof Byte) + sb.append(cs.internalsprintf( + ((Byte)o[i]).byteValue())); + else if (o[i] instanceof Short) + sb.append(cs.internalsprintf( + ((Short)o[i]).shortValue())); + else if (o[i] instanceof Integer) + sb.append(cs.internalsprintf( + ((Integer)o[i]).intValue())); + else if (o[i] instanceof Long) + sb.append(cs.internalsprintf( + ((Long)o[i]).longValue())); + else if (o[i] instanceof Float) + sb.append(cs.internalsprintf( + ((Float)o[i]).floatValue())); + else if (o[i] instanceof Double) + sb.append(cs.internalsprintf( + ((Double)o[i]).doubleValue())); + else if (o[i] instanceof Character) + sb.append(cs.internalsprintf( + ((Character)o[i]).charValue())); + else if (o[i] instanceof String) + sb.append(cs.internalsprintf( + (String)o[i])); + else + sb.append(cs.internalsprintf( + o[i])); + if (!cs.isPositionalSpecification()) + i++; + } + } + return sb.toString(); + } + /** + * Format nothing. Just use the control string. + * @return the formatted String. + */ + public String sprintf() { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + } + return sb.toString(); + } + /** + * Format an int. + * @param x The int to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(int x) + throws IllegalArgumentException { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + else sb.append(cs.internalsprintf(x)); + } + return sb.toString(); + } + /** + * Format an long. + * @param x The long to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, G, s, + * or S. + */ + public String sprintf(long x) + throws IllegalArgumentException { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + else sb.append(cs.internalsprintf(x)); + } + return sb.toString(); + } + /** + * Format a double. + * @param x The double to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is c, C, s, S, + * d, d, x, X, or o. + */ + public String sprintf(double x) + throws IllegalArgumentException { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + else sb.append(cs.internalsprintf(x)); + } + return sb.toString(); + } + /** + * Format a String. + * @param x The String to format. + * @return The formatted String. + * @exception IllegalArgumentException if the + * conversion character is neither s nor S. + */ + public String sprintf(String x) + throws IllegalArgumentException { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + else sb.append(cs.internalsprintf(x)); + } + return sb.toString(); + } + /** + * Format an Object. Convert wrapper types to + * their primitive equivalents and call the + * appropriate internal formatting method. Convert + * Strings using an internal formatting method for + * Strings. Otherwise use the default formatter + * (use toString). + * @param x the Object to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is inappropriate for + * formatting an unwrapped value. + */ + public String sprintf(Object x) + throws IllegalArgumentException { + Enumeration e = vFmt.elements(); + ConversionSpecification cs = null; + char c = 0; + StringBuffer sb=new StringBuffer(); + while (e.hasMoreElements()) { + cs = (ConversionSpecification) + e.nextElement(); + c = cs.getConversionCharacter(); + if (c=='\0') sb.append(cs.getLiteral()); + else if (c=='%') sb.append("%"); + else { + if (x instanceof Byte) + sb.append(cs.internalsprintf( + ((Byte)x).byteValue())); + else if (x instanceof Short) + sb.append(cs.internalsprintf( + ((Short)x).shortValue())); + else if (x instanceof Integer) + sb.append(cs.internalsprintf( + ((Integer)x).intValue())); + else if (x instanceof Long) + sb.append(cs.internalsprintf( + ((Long)x).longValue())); + else if (x instanceof Float) + sb.append(cs.internalsprintf( + ((Float)x).floatValue())); + else if (x instanceof Double) + sb.append(cs.internalsprintf( + ((Double)x).doubleValue())); + else if (x instanceof Character) + sb.append(cs.internalsprintf( + ((Character)x).charValue())); + else if (x instanceof String) + sb.append(cs.internalsprintf( + (String)x)); + else + sb.append(cs.internalsprintf(x)); + } + } + return sb.toString(); + } + /** + *

+ * ConversionSpecification allows the formatting of + * a single primitive or object embedded within a + * string. The formatting is controlled by a + * format string. Only one Java primitive or + * object can be formatted at a time. + *

+ * A format string is a Java string that contains + * a control string. The control string starts at + * the first percent sign (%) in the string, + * provided that this percent sign + *

    + *
  1. is not escaped protected by a matching % or + * is not an escape % character, + *
  2. is not at the end of the format string, and + *
  3. precedes a sequence of characters that parses + * as a valid control string. + *
+ *

+ * A control string takes the form: + *

 % ['-+ #0]* [0..9]* { . [0..9]* }+
+   *                { [hlL] }+ [idfgGoxXeEcs]
+   *
+ *

+ * The behavior is like printf. One (hopefully the + * only) exception is that the minimum number of + * exponent digits is 3 instead of 2 for e and E + * formats when the optional L is used before the + * e, E, g, or G conversion character. The + * optional L does not imply conversion to a long + * long double. + */ + private class ConversionSpecification { + /** + * Constructor. Used to prepare an instance + * to hold a literal, not a control string. + */ + ConversionSpecification() { } + /** + * Constructor for a conversion specification. + * The argument must begin with a % and end + * with the conversion character for the + * conversion specification. + * @param fmtArg String specifying the + * conversion specification. + * @exception IllegalArgumentException if the + * input string is null, zero length, or + * otherwise malformed. + */ + ConversionSpecification(String fmtArg) + throws IllegalArgumentException { + if (fmtArg==null) + throw new NullPointerException(); + if (fmtArg.length()==0) + throw new IllegalArgumentException( + "Control strings must have positive"+ + " lengths."); + if (fmtArg.charAt(0)=='%') { + fmt = fmtArg; + pos=1; + setArgPosition(); + setFlagCharacters(); + setFieldWidth(); + setPrecision(); + setOptionalHL(); + if (setConversionCharacter()) { + if (pos==fmtArg.length()) { + if(leadingZeros&&leftJustify) + leadingZeros=false; + if(precisionSet&&leadingZeros){ + if(conversionCharacter=='d' + ||conversionCharacter=='i' + ||conversionCharacter=='o' + ||conversionCharacter=='x') + { + leadingZeros=false; + } + } + } + else + throw new IllegalArgumentException( + "Malformed conversion specification="+ + fmtArg); + } + else + throw new IllegalArgumentException( + "Malformed conversion specification="+ + fmtArg); + } + else + throw new IllegalArgumentException( + "Control strings must begin with %."); + } + /** + * Set the String for this instance. + * @param s the String to store. + */ + void setLiteral(String s) { + fmt = s; + } + /** + * Get the String for this instance. Translate + * any escape sequences. + * + * @return s the stored String. + */ + String getLiteral() { + StringBuffer sb=new StringBuffer(); + int i=0; + while (itrue if the conversion + * uses an * field width; otherwise + * false. + */ + boolean isVariableFieldWidth() { + return variableFieldWidth; + } + /** + * Set the field width with an argument. A + * negative field width is taken as a - flag + * followed by a positive field width. + * @param fw the field width. + */ + void setFieldWidthWithArg(int fw) { + if (fw<0) leftJustify = true; + fieldWidthSet = true; + fieldWidth = Math.abs(fw); + } + /** + * Check whether the specifier has a variable + * precision that is going to be set by an + * argument. + * @return true if the conversion + * uses an * precision; otherwise + * false. + */ + boolean isVariablePrecision() { + return variablePrecision; + } + /** + * Set the precision with an argument. A + * negative precision will be changed to zero. + * @param pr the precision. + */ + void setPrecisionWithArg(int pr) { + precisionSet = true; + precision = Math.max(pr,0); + } + /** + * Format an int argument using this conversion + * specification. + * @param s the int to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(int s) + throws IllegalArgumentException { + String s2 = ""; + switch(conversionCharacter) { + case 'd': + case 'i': + if (optionalh) + s2 = printDFormat((short)s); + else if (optionall) + s2 = printDFormat((long)s); + else + s2 = printDFormat(s); + break; + case 'x': + case 'X': + if (optionalh) + s2 = printXFormat((short)s); + else if (optionall) + s2 = printXFormat((long)s); + else + s2 = printXFormat(s); + break; + case 'o': + if (optionalh) + s2 = printOFormat((short)s); + else if (optionall) + s2 = printOFormat((long)s); + else + s2 = printOFormat(s); + break; + case 'c': + case 'C': + s2 = printCFormat((char)s); + break; + default: + throw new IllegalArgumentException( + "Cannot format a int with a format using a "+ + conversionCharacter+ + " conversion character."); + } + return s2; + } + /** + * Format a long argument using this conversion + * specification. + * @param s the long to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is f, e, E, g, or G. + */ + String internalsprintf(long s) + throws IllegalArgumentException { + String s2 = ""; + switch(conversionCharacter) { + case 'd': + case 'i': + if (optionalh) + s2 = printDFormat((short)s); + else if (optionall) + s2 = printDFormat(s); + else + s2 = printDFormat((int)s); + break; + case 'x': + case 'X': + if (optionalh) + s2 = printXFormat((short)s); + else if (optionall) + s2 = printXFormat(s); + else + s2 = printXFormat((int)s); + break; + case 'o': + if (optionalh) + s2 = printOFormat((short)s); + else if (optionall) + s2 = printOFormat(s); + else + s2 = printOFormat((int)s); + break; + case 'c': + case 'C': + s2 = printCFormat((char)s); + break; + default: + throw new IllegalArgumentException( + "Cannot format a long with a format using a "+ + conversionCharacter+" conversion character."); + } + return s2; + } + /** + * Format a double argument using this conversion + * specification. + * @param s the double to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is c, C, s, S, i, d, + * x, X, or o. + */ + String internalsprintf(double s) + throws IllegalArgumentException { + String s2 = ""; + switch(conversionCharacter) { + case 'f': + s2 = printFFormat(s); + break; + case 'E': + case 'e': + s2 = printEFormat(s); + break; + case 'G': + case 'g': + s2 = printGFormat(s); + break; + default: + throw new IllegalArgumentException("Cannot "+ + "format a double with a format using a "+ + conversionCharacter+" conversion character."); + } + return s2; + } + /** + * Format a String argument using this conversion + * specification. + * @param s the String to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(String s) + throws IllegalArgumentException { + String s2 = ""; + if(conversionCharacter=='s' + || conversionCharacter=='S') + s2 = printSFormat(s); + else + throw new IllegalArgumentException("Cannot "+ + "format a String with a format using a "+ + conversionCharacter+" conversion character."); + return s2; + } + /** + * Format an Object argument using this conversion + * specification. + * @param s the Object to format. + * @return the formatted String. + * @exception IllegalArgumentException if the + * conversion character is neither s nor S. + */ + String internalsprintf(Object s) { + String s2 = ""; + if(conversionCharacter=='s' + || conversionCharacter=='S') + s2 = printSFormat(s.toString()); + else + throw new IllegalArgumentException( + "Cannot format a String with a format using"+ + " a "+conversionCharacter+ + " conversion character."); + return s2; + } + /** + * For f format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both + * a '+' and a ' ' are specified, the blank flag + * is ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the number of digits + * to appear after the radix character. Padding is + * with trailing 0s. + */ + private char[] fFormatDigits(double x) { + // int defaultDigits=6; + String sx,sxOut; + int i,j,k; + int n1In,n2In; + int expon=0; + boolean minusSign=false; + if (x>0.0) + sx = Double.toString(x); + else if (x<0.0) { + sx = Double.toString(-x); + minusSign=true; + } + else { + sx = Double.toString(x); + if (sx.charAt(0)=='-') { + minusSign=true; + sx=sx.substring(1); + } + } + int ePos = sx.indexOf('E'); + int rPos = sx.indexOf('.'); + if (rPos!=-1) n1In=rPos; + else if (ePos!=-1) n1In=ePos; + else n1In=sx.length(); + if (rPos!=-1) { + if (ePos!=-1) n2In = ePos-rPos-1; + else n2In = sx.length()-rPos-1; + } + else + n2In = 0; + if (ePos!=-1) { + int ie=ePos+1; + expon=0; + if (sx.charAt(ie)=='-') { + for (++ie; ie0) { + ca6 = new char[ca5.length+nThousands+lead]; + ca6[0]=ca5[0]; + for (i=lead,k=lead; i0 && (dp-i)%3==0) { + // ca6[k]=','; + ca6[k]=dfs.getGroupingSeparator(); + ca6[k+1]=ca5[i]; + k+=2; + } + else { + ca6[k]=ca5[i]; k++; + } + } + for (; i0.0) + sx = Double.toString(x); + else if (x<0.0) { + sx = Double.toString(-x); + minusSign=true; + } + else { + sx = Double.toString(x); + if (sx.charAt(0)=='-') { + minusSign=true; + sx=sx.substring(1); + } + } + ePos = sx.indexOf('E'); + if (ePos==-1) ePos = sx.indexOf('e'); + rPos = sx.indexOf('.'); + if (rPos!=-1) n1In=rPos; + else if (ePos!=-1) n1In=ePos; + else n1In=sx.length(); + if (rPos!=-1) { + if (ePos!=-1) n2In = ePos-rPos-1; + else n2In = sx.length()-rPos-1; + } + else + n2In = 0; + if (ePos!=-1) { + int ie=ePos+1; + expon=0; + if (sx.charAt(ie)=='-') { + for (++ie; ie=100) { + switch(expon/100) { + case 1: ca2[i]='1'; break; + case 2: ca2[i]='2'; break; + case 3: ca2[i]='3'; break; + case 4: ca2[i]='4'; break; + case 5: ca2[i]='5'; break; + case 6: ca2[i]='6'; break; + case 7: ca2[i]='7'; break; + case 8: ca2[i]='8'; break; + case 9: ca2[i]='9'; break; + } + i++; + } + switch((expon%100)/10) { + case 0: ca2[i]='0'; break; + case 1: ca2[i]='1'; break; + case 2: ca2[i]='2'; break; + case 3: ca2[i]='3'; break; + case 4: ca2[i]='4'; break; + case 5: ca2[i]='5'; break; + case 6: ca2[i]='6'; break; + case 7: ca2[i]='7'; break; + case 8: ca2[i]='8'; break; + case 9: ca2[i]='9'; break; + } + i++; + switch(expon%10) { + case 0: ca2[i]='0'; break; + case 1: ca2[i]='1'; break; + case 2: ca2[i]='2'; break; + case 3: ca2[i]='3'; break; + case 4: ca2[i]='4'; break; + case 5: ca2[i]='5'; break; + case 6: ca2[i]='6'; break; + case 7: ca2[i]='7'; break; + case 8: ca2[i]='8'; break; + case 9: ca2[i]='9'; break; + } + int nZeros=0; + if (!leftJustify && leadingZeros) { + int xThousands=0; + if (thousands) { + int xlead=0; + if (ca2[0]=='+'||ca2[0]=='-'||ca2[0]==' ') + xlead=1; + int xdp=xlead; + for (; xdp0) { + ca4 = new char[ca3.length+nThousands+lead]; + ca4[0]=ca3[0]; + for (i=lead,k=lead; i0 && (dp-i)%3==0) { + // ca4[k]=','; + ca4[k]=dfs.getGroupingSeparator(); + ca4[k+1]=ca3[i]; + k+=2; + } + else { + ca4[k]=ca3[i]; k++; + } + } + for (; itrue if the truncation forces + * a round that will change the print + */ + private boolean checkForCarry(char[] ca1,int icarry) { + boolean carry=false; + if (icarry0) { + carry=(ca1[icarry-1]=='1'||ca1[icarry-1]=='3' + ||ca1[icarry-1]=='5'||ca1[icarry-1]=='7' + ||ca1[icarry-1]=='9'); + } + } + } + return carry; + } + /** + * Start the symbolic carry process. The process + * is not quite finished because the symbolic + * carry may change the length of the string and + * change the exponent (in e format). + * @param cLast index of the last digit changed + * by the round + * @param cFirst index of the first digit allowed + * to be changed by this phase of the round + * @return true if the carry forces + * a round that will change the print still + * more + */ + private boolean startSymbolicCarry( + char[] ca,int cLast,int cFirst) { + boolean carry=true; + for (int i=cLast; carry && i>=cFirst; i--) { + carry = false; + switch(ca[i]) { + case '0': ca[i]='1'; break; + case '1': ca[i]='2'; break; + case '2': ca[i]='3'; break; + case '3': ca[i]='4'; break; + case '4': ca[i]='5'; break; + case '5': ca[i]='6'; break; + case '6': ca[i]='7'; break; + case '7': ca[i]='8'; break; + case '8': ca[i]='9'; break; + case '9': ca[i]='0'; carry=true; break; + } + } + return carry; + } + /** + * An intermediate routine on the way to creating + * an e format String. The method decides whether + * the input double value is an infinity, + * not-a-number, or a finite double and formats + * each type of input appropriately. + * @param x the double value to be formatted. + * @param eChar an 'e' or 'E' to use in the + * converted double value. + * @return the converted double value. + */ + private String eFormatString(double x,char eChar) { + boolean noDigits=false; + char[] ca4,ca5; + if (Double.isInfinite(x)) { + if (x==Double.POSITIVE_INFINITY) { + if (leadingSign) ca4 = "+Inf".toCharArray(); + else if (leadingSpace) + ca4 = " Inf".toCharArray(); + else ca4 = "Inf".toCharArray(); + } + else + ca4 = "-Inf".toCharArray(); + noDigits = true; + } + else if (Double.isNaN(x)) { + if (leadingSign) ca4 = "+NaN".toCharArray(); + else if (leadingSpace) + ca4 = " NaN".toCharArray(); + else ca4 = "NaN".toCharArray(); + noDigits = true; + } + else + ca4 = eFormatDigits(x,eChar); + ca5 = applyFloatPadding(ca4,false); + return new String(ca5); + } + /** + * Apply zero or blank, left or right padding. + * @param ca4 array of characters before padding is + * finished + * @param noDigits NaN or signed Inf + * @return a padded array of characters + */ + private char[] applyFloatPadding( + char[] ca4,boolean noDigits) { + char[] ca5 = ca4; + if (fieldWidthSet) { + int i,j,nBlanks; + if (leftJustify) { + nBlanks = fieldWidth-ca4.length; + if (nBlanks > 0) { + ca5 = new char[ca4.length+nBlanks]; + for (i=0; i 0) { + ca5 = new char[ca4.length+nBlanks]; + for (i=0; i 0) { + ca5 = new char[ca4.length+nBlanks]; + i=0; j=0; + if (ca4[0]=='-') { ca5[0]='-'; i++; j++; } + for (int k=0; k=-4 && expon=0; i--) + if (sy.charAt(i)!='0') break; + if (i>=0 && sy.charAt(i)=='.') i--; + if (i==-1) sz="0"; + else if (!Character.isDigit(sy.charAt(i))) + sz=sy.substring(0,i+1)+"0"; + else sz=sy.substring(0,i+1); + if (expon>=-4 && expon=-4 && expon=0) ret = " "+ret; + ca4 = ret.toCharArray(); + } + // Pad with blanks or zeros. + ca5 = applyFloatPadding(ca4,false); + precision=savePrecision; + return new String(ca5); + } + /** + * Format method for the d conversion specifer and + * short argument. + * + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the short to format. + * @return the formatted String. + */ + private String printDFormat(short x) { + return printDFormat(Short.toString(x)); + } + /** + * Format method for the d conversion character and + * long argument. + * + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the long to format. + * @return the formatted String. + */ + private String printDFormat(long x) { + return printDFormat(Long.toString(x)); + } + /** + * Format method for the d conversion character and + * int argument. + * + * For d format, the flag character '-', means that + * the output should be left justified within the + * field. The default is to pad with blanks on the + * left. A '+' character means that the conversion + * will always begin with a sign (+ or -). The + * blank flag character means that a non-negative + * input will be preceded with a blank. If both a + * '+' and a ' ' are specified, the blank flag is + * ignored. The '0' flag character implies that + * padding to the field width will be done with + * zeros instead of blanks. + * + * The field width is treated as the minimum number + * of characters to be printed. The default is to + * add no padding. Padding is with blanks by + * default. + * + * The precision, if set, is the minimum number of + * digits to appear. Padding is with leading 0s. + * @param x the int to format. + * @return the formatted String. + */ + private String printDFormat(int x) { + return printDFormat(Integer.toString(x)); + } + /** + * Utility method for formatting using the d + * conversion character. + * @param sx the String to format, the result of + * converting a short, int, or long to a + * String. + * @return the formatted String. + */ + private String printDFormat(String sx) { + int nLeadingZeros=0; + int nBlanks=0,n=0; + int i=0,jFirst=0; + boolean neg = sx.charAt(0)=='-'; + if (sx.equals("0")&&precisionSet&&precision==0) + sx=""; + if (!neg) { + if (precisionSet && sx.length() < precision) + nLeadingZeros = precision-sx.length(); + } + else { + if (precisionSet&&(sx.length()-1)precision) + nPrint=precision; + if (!fieldWidthSet) width = nPrint; + int n=0; + if (width>nPrint) n+=width-nPrint; + if (nPrint>=x.length()) n+= x.length(); + else n+= nPrint; + char[] ca = new char[n]; + int i=0; + if (leftJustify) { + if (nPrint>=x.length()) { + char[] csx = x.toCharArray(); + for (i=0; i=x.length()) { + char[] csx = x.toCharArray(); + for (int j=0; jtrue if the conversion + * character is there, and + * false otherwise. + */ + private boolean setConversionCharacter() { + /* idfgGoxXeEcs */ + boolean ret = false; + conversionCharacter='\0'; + if (pos < fmt.length()) { + char c = fmt.charAt(pos); + if (c=='i'||c=='d'||c=='f'||c=='g'||c=='G' + || c=='o' || c=='x' || c=='X' || c=='e' + || c=='E' || c=='c' || c=='s' || c=='%') { + conversionCharacter = c; + pos++; + ret = true; + } + } + return ret; + } + /** + * Check for an h, l, or L in a format. An L is + * used to control the minimum number of digits + * in an exponent when using floating point + * formats. An l or h is used to control + * conversion of the input to a long or short, + * respectively, before formatting. If any of + * these is present, store them. + */ + private void setOptionalHL() { + optionalh=false; + optionall=false; + optionalL=false; + if (pos < fmt.length()) { + char c = fmt.charAt(pos); + if (c=='h') { optionalh=true; pos++; } + else if (c=='l') { optionall=true; pos++; } + else if (c=='L') { optionalL=true; pos++; } + } + } + /** + * Set the precision. + */ + private void setPrecision() { + int firstPos = pos; + precisionSet = false; + if (pos firstPos+1) { + String sz = fmt.substring(firstPos+1,pos); + precision = Integer.parseInt(sz); + precisionSet = true; + } + } + } + } + /** + * Set the field width. + */ + private void setFieldWidth() { + int firstPos = pos; + fieldWidth = 0; + fieldWidthSet = false; + if ((pos < fmt.length()) + && (fmt.charAt(pos)=='*')) { + pos++; + if (!setFieldWidthArgPosition()) { + variableFieldWidth = true; + fieldWidthSet = true; + } + } + else { + while (pos < fmt.length()) { + char c = fmt.charAt(pos); + if (Character.isDigit(c)) pos++; + else break; + } + if (firstPosn in %n$ forms. + */ + private void setArgPosition() { + int xPos; + for (xPos=pos; xPospos && xPosn in *n$ forms. + */ + private boolean setFieldWidthArgPosition() { + boolean ret=false; + int xPos; + for (xPos=pos; xPospos && xPosn in *n$ forms. + */ + private boolean setPrecisionArgPosition() { + boolean ret=false; + int xPos; + for (xPos=pos; xPospos && xPos ctrlVector; + + /** + * Kolekce vektor pro persistenci uzlového vektoru ve směru parametru U + */ + @ElementList(name="knotsU",type=MyFloat.class) + private Vector knotVectorU; + + /** + * Kolekce vektor pro persistenci uzlového vektoru ve směru parametru V + */ + @ElementList(name="knotsV",type=MyFloat.class) + private Vector knotVectorV; + + /** + * Vytvoří prázdnou definici plochy + */ + public void clear(){ + isSurfaceFinished=false; + ctrlPoints=new float[0]; + knotsU=new float[0]; + knotsV=new float[0]; + orderU=3; + orderV=3; + pointsInU=0; + pointsInV=0; + } + + /** + * Pomocí framweorku Simple serializuje definici křivky do XML souboru + * @param f soubor pro uložení + */ + public void persist(File f){ + ctrlVector=new Vector(ctrlPoints.length); + knotVectorU=new Vector(knotsU.length); + knotVectorV=new Vector(knotsV.length); + + for(Float ff:ctrlPoints) + ctrlVector.add(new MyFloat(ff)); + + for(Float ff:knotsU) + knotVectorU.add(new MyFloat(ff)); + + for(Float ff:knotsV) + knotVectorV.add(new MyFloat(ff)); + + Serializer s=new Persister(); + try { + System.out.println("ukládám"); + s.write(Surface.getInstance(),f); + } catch (Exception e1) { + e1.printStackTrace(); + } + + + } + + /** + * Vytvoří pomocí frameworku Simple křivku z definice uložené v XML souboru + * @param f soubor,z něhož se má definice načíst + * @throws Exception chyba při čtení ze souboru + */ + public void unPersist(File f) throws Exception{ + Serializer s=new Persister(); + Surface c=s.read(Surface.class,f); + initFromSurface(c); + } + + /** + * Inicializuje objekt podle jiného objektu typu Curve + * @param c referenční objekt - křivka + */ + private void initFromSurface(Surface c) { + this.orderU=c.getOrderU(); + this.orderV=c.getOrderV(); + this.ctrlPoints=new float[c.getCtrlVector().size()]; + this.knotsU=new float[c.getKnotVectorU().size()]; + this.knotsV=new float[c.getKnotVectorV().size()]; + int i=0; + for(MyFloat f:c.getCtrlVector()) + ctrlPoints[i++]=f.getValue(); + i=0; + for(MyFloat f:c.getKnotVectorU()) + knotsU[i++]=f.getValue(); + i=0; + for(MyFloat f:c.getKnotVectorV()) + knotsV[i++]=f.getValue(); + + this.pointsInU=c.getPointsInU(); + this.pointsInV=c.getPointsInV(); + + this.isSurfaceFinished=c.isSurfaceFinished(); + } + + /** + * Konstruktor, nastaví prázdné hodnoty polí definujících NURBS plochu + */ + private Surface(){ + // ctrlPoints=new float[0]; + // knotsU=new float[0]; + // knotsV=new float[0]; + // isSurfaceFinished=false; + clear(); + } + + /** + * Vrací instanci třídy (podle návrhového vzoru Singleton) + * @return instance třídy Curve + */ + public static Surface getInstance() { + if (singleton == null) + singleton = new Surface(); + return singleton; + + } + + /** + * Vrací pole uzlového vektoru ve směru parametru U + * @return pole hodnot uzlového vektoru ve směru parametru U + */ + public float[] getKnotsU() { + return this.knotsU; + } + + /** + * Vrací pole s hodnotami souřadnic řídících bodů + * @return pole souřadnic řídících bodů + */ + public float[] getCtrlPoints() { + return this.ctrlPoints; + } + + /** + * Vrací stupeň NURBS plochy ve směru parametru U + * @return stupeň NURBS plochy ve směru parametru U + */ + public int getOrderU() { + return this.orderU; + } + + /** + * Vrací index aktuálně vybraného řídícího bodu + * @return index aktuálně vybraného řídícího bodu + */ + public int getBodIndex() { + return bodIndex; + } + + /** + * Nastavuje index požadovaného aktuálně vybraného řídícího bodu + * @param bodIndex index požadovaného aktuálně vybraného řídícího bodu + */ + public void setBodIndex(int bodIndex) { + this.bodIndex = bodIndex; + } + + /** + * Vrací X-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu z homogenních souřadnic + * @return X-ová souadnice aktuálně vybraného řídícího bodu + */ + public float getActiveX(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4]/ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + /** + * Vrací Y-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu z homogenních souřadnic + * @return Y-ová souadnice aktuálně vybraného řídícího bodu + */ + public float getActiveY(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4+1]/ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + /** + * Vrací Z-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu z homogenních souřadnic + * @return Z-ová souadnice aktuálně vybraného řídícího bodu + */ + public float getActiveZ(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4+2]/ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + + /** + * Vrací váhu aktuálně vybraného řídícího bodu + * @return váha aktuálně vybraného řídícího bodu + */ + public float getActiveW(){ + if(bodIndex>=0){ + return ctrlPoints[bodIndex*4+3]; + } + else return 0; + } + + /** + * Nastavuje X-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu do homogenních souřadnic + * @param x X-ová souřadnice aktuálně vybraného řídícího bodu + */ + public void setActiveX(float x){ + if(bodIndex>=0){ + ctrlPoints[bodIndex*4]=x*ctrlPoints[bodIndex*4+3]; + } + } + /** + * Nastavuje Y-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu do homogenních souřadnic + * @param y Y-ová souřadnice aktuálně vybraného řídícího bodu + */ + + public void setActiveY(float y){ + if(bodIndex>=0){ + ctrlPoints[bodIndex*4+1]=y*ctrlPoints[bodIndex*4+3]; + } + } + /** + * Nastavuje Z-ovou souadnici aktuálně vybraného řídícího bodu, přepočítává hodnotu do homogenních souřadnic + * @param z Z-ová souřadnice aktuálně vybraného řídícího bodu + */ + + public void setActiveZ(float z){ + if(bodIndex>=0){ + ctrlPoints[bodIndex*4+2]=z*ctrlPoints[bodIndex*4+3]; + } + } + + /** + *Nastavuje váhu aktuálně vybraného řídícího bodu, upravuje hodnoty stávajícíh souřadic vzhledem k váze a použití homogenních souřadnic + * @param w váha aktuálně vybraného řídícího bodu + */ + public void setActiveW(float w){ + if(bodIndex>=0){ + float oldW=ctrlPoints[bodIndex*4+3]; + if(w>0){ + ctrlPoints[bodIndex*4+3]=w; + //úprava souřadnic + ctrlPoints[bodIndex*4]=ctrlPoints[bodIndex*4]/oldW*w; + ctrlPoints[bodIndex*4+1]=ctrlPoints[bodIndex*4+1]/oldW*w; + ctrlPoints[bodIndex*4+2]=ctrlPoints[bodIndex*4+2]/oldW*w; + } + + } + } + + /** + * Nastavuje uzlový vektor ve směru parametru U + * @param knots nový uzlový vektor ve směru parametru U + */ + public void setKnotsU(float[] knots) { + this.knotsU = knots; + } + + /** + * Vrací informaci o stavu dokončení definice křvky + * @return true pokud je definice křivky kompletní, jinak false + */ + public boolean isSurfaceFinished() { + return isSurfaceFinished; + } + + /** + * Nastavuje řídící body + * @param ctrlPoints pole souřadnic řídících bodů + */ + public void setCtrlPoints(float[] ctrlPoints) { + this.ctrlPoints = ctrlPoints; + } + + /** + * Nastavuje stav dokončení definice křivky + * @param b stav dokončení definice křivky + * + */ + public void setIsSurfaceFinished(boolean b) { + isSurfaceFinished=b; + } + + /** + * Vrací vektor souřadnic řídích bodů pro serializaci + * @return vektor souřadnic řídících bodů + */ + private Vector getCtrlVector() { + return ctrlVector; + } + + /** + * Vrací vektor prvků uzlového vektoru ve směru parametru U pro serializaci + * @return vektor prvků uzlového vektoru ve směru parametru U + */ + private Vector getKnotVectorU() { + return knotVectorU; + } + + /** + * Vrací stupeň plochy ve směru parametru U + * @param order stupeň plochy ve směru parametru U + */ + public void setOrderU(int order) { + this.orderU = order; + } + /** + * Vrací pole uzlového vektoru ve směru parametru V + * @return pole hodnot uzlového vektoru ve směru parametru V + */ + public float[] getKnotsV() { + return knotsV; + } + /** + * Nastavuje uzlový vektor ve směru parametru V + * @param knotsV nový uzlový vektor ve směru parametru V + */ + public void setKnotsV(float[] knotsV) { + this.knotsV = knotsV; + } + /** + * Vrací stupeň plochy ve směru parametru V + * @return stupeň plochy ve směru parametru V + */ + public int getOrderV() { + return orderV; + } + /** + * Nastavuje stupeň NURBS plochy ve směru parametru V + * @param orderV stupeň plochy ve směru parametru V + */ + public void setOrderV(int orderV) { + this.orderV = orderV; + } + /** + * Vrací vektor prvků uzlového vektoru ve směru parametru V pro serializaci + * @return vektor prvků uzlového vektoru ve směru parametru V + */ + private Vector getKnotVectorV() { + return knotVectorV; + } + + /** + * Vrací počet řídících bodů ve směru parametru V (tj. počet sloupců) + * @return počet řídících bodů ve směru parametru V + */ + public int getPointsInV() { + return pointsInV; + } + + /** + * Nastavuje počet řídících bodů ve směru parametru V + * @param pointsInV počet řídících bodů ve směru parametru V + */ + public void setPointsInV(int pointsInV) { + this.pointsInV = pointsInV; + } + + /** + * Vrací počet řídících bodů ve směru parametru U (tj. počet řádků) + * @return počet řídících bodů ve směru parametru U + + */ + public int getPointsInU() { + return pointsInU; + } + + /** + * Nastavuje počet řídících bodů ve směru parametru U + * @param pointsInU počet řídících bodů ve směru parametru U + */ + public void setPointsInU(int pointsInU) { + this.pointsInU = pointsInU; + } +} diff --git a/src/demos/nurbs/surfaceapp/SurfaceApp.java b/src/demos/nurbs/surfaceapp/SurfaceApp.java new file mode 100755 index 0000000..7f2a546 --- /dev/null +++ b/src/demos/nurbs/surfaceapp/SurfaceApp.java @@ -0,0 +1,1066 @@ +package demos.nurbs.surfaceapp; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.media.opengl.GLCanvas; +import javax.swing.AbstractAction; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SpinnerNumberModel; +import javax.swing.ToolTipManager; + +import demos.nurbs.icons.*; +import demos.nurbs.knotslidercomponent.JKnotSlider; + +/** + * Main class for application demostrating capabilitues of JOGL library extend by NURBS surface functionalities + * Hlavní třída aplikace demonstrující shopnosti knihovny JOGL při práci s NURBS + * plochami + * + * @author Tomáš Hráský + * + */ +@SuppressWarnings("serial") +public class SurfaceApp extends JFrame implements ActionListener +{ + + /** + * X-coord editing component name + * Jméno komponenty pro editaci X-ové souřadnice aktuálního bodu + */ + public static final String X_SPINNER_NAME = "xspinner"; + + /** + * Y-coord editing component name + * Jméno komponenty pro editaci Y-ové souřadnice aktuálního bodu + */ + public static final String Y_SPINNER_NAME = "yspinner"; + + /** + * Z-coord editing component name + * Jméno komponenty pro editaci Z-ové souřadnice aktuálního bodu + */ + public static final String Z_SPINNER_NAME = "zspinner"; + + /** + * Weight editing component name + * Jméno komponenty pro editaci váhy aktuálního bodu + */ + public static final String W_SPINNER_NAME = "wspinner"; + + /** + * U direction knotvector editing component + * Jméno komponenty pro editaci uzlového vektoru ve směru parametru U + */ + private static final String U_KNOTSLIDER = "Uknotspinner"; + + /** + * V direction knotvector editing component + * Jméno komponenty pro editaci uzlového vektoru ve směru parametru V + */ + private static final String V_KNOTSLIDER = "Vknotspinner"; + + /** + * New control point action name + * Jméno události přidání řídícího bodu + */ + public static final String PRIDAT_AC = "PRIDAT"; + + /** + * Degree set event name + * Jméno události zadání stupně křivky + */ + public static final String STUPEN_AC = "STUPEN"; + + /** + * Delete control point event name + * Jméno události smazání řídícího bodu + */ + public static final String SMAZAT_AC = "SMAZAT"; + + /** + * New clamped knotvector event name + * Jméno události vytvoření uzavřeného uzlového vektoru + */ + public static final String UZAVRENY_AC = "UZAVRENY"; + + /** + * New uniform knotvector event name + * Jméno události vytvoření otevřeného (uniformního) uzlového vektoru + */ + public static final String OTEVRENY_AC = "OTEVRENY"; + + /** + * Save surface event name + * Jméno události uložení plochy + */ + public static final String ULOZIT_AC = "ULOZIT"; + + /** + * Load surface event name + * Jméno události načetení uložené definice plochy + */ + public static final String NACIST_AC = "NACIST"; + + /** + * Move control point event name + * Jméno události pohybu řídícího bodu + */ + private static final String MOVE_AC = "MOVE"; + + /** + * New surface event name + * Jméno události vytvoření nové plochy + */ + static final String NOVA_AC = "NEWSURFACE"; + + /** + * Exit app event name + * Jméno události ukončení aplikace + */ + public static final String EXIT_AC = "EXIT"; + + /** + * Show about event name + * Jméno události zobrazení okna o aplikaci + */ + public static final String INFO_AC = "INFO"; + + /** + * Add column of control points event name + * Jméno události přidání sloupce řídících bodů + */ + public static final String PRIDAT_AC_SLOUPEC = "ADDCOL"; + + /** + * Add row of control points event name + * Jméno události přidání řádku řídících bodů + */ + public static final String PRIDAT_AC_RADEK = "ADDROW"; + + /** + * Remove row of control points event name + * Jméno události smazání řádku řídících bodů + */ + public static final String SMAZAT_AC_RADEK = "DELROW"; + + /** + * Remove column of control points event name + * Jméno události smazání sloupce řídících bodů + */ + public static final String SMAZAT_AC_SLOUPEC = "DELCOL"; + + /** + * OpenGL drawing canvas + * Plátno pro vykreslování pomocí OpenGL + */ + private GLCanvas glCanvas; + + /** + * X-coord editing component + * Komponenta pro editaci X-ové souřadnice aktuálního bodu + */ + private JSpinner xSpinner; + + /** + * Y-coord editing component + * Komponenta pro editaci Y-ové souřadnice aktuálního bodu + */ + private JSpinner ySpinner; + + /** + * Weight editing component + * Komponenta pro editaci váhy aktuálního bodu + */ + private JSpinner wSpinner; + + /** + * Z-coord editing component + * Komponenta pro editaci Z-ové souřadnice aktuálního bodu + */ + private JSpinner zSpinner; + + /** + * Mouse listener + * Listener událostí myši + */ + private SurfaceMouseListener mouseListener; + + /** + * U direction knotvector editing component + * Komponenta pro editaci uzlového vektoru ve směru parametru U + */ + private JKnotSlider knotSlider; + + /** + * V direction knotvector editing component + * Komponenta pro editaci uzlového vektoru ve směru parametru V + */ + private JKnotSlider knotSlider2; + + /** + * Set move points mode + * Tlačítko pro zapnutí módu pohybu řídících bodů + */ + private JToggleButton moveTB; + + /** + * X rotation component + * Komponenta ovládající otočení definované plochy kolem osy X + */ + private JSlider rotaceXSlider; + + /** + * Y rotation component + * Komponenta ovládající otočení definované plochy kolem osy Y + */ + private JSlider rotaceYSlider; + + /** + * Z rotation component + * Komponenta ovládající otočení definované plochy kolem osy Z + */ + private JSlider rotaceZSlider; + + /** + * Label for X rotation editing component + * Nadpis komponenty ovládající otočení definované plochy kolem osy X + */ + private JLabel rotaceXLabel; + /** + * Label for Y rotation editing component + * Nadpis komponenty ovládající otočení definované plochy kolem osy Y + */ + private JLabel rotaceYLabel; + /** + * Label for Z rotation editing component + * Nadpis komponenty ovládající otočení definované plochy kolem osy Z + */ + private JLabel rotaceZLabel; + + /** + * GL events listener + * Objekt reagující na události OpenGL plátna + */ + private GLListener glListener; + + /** + * Use lighting checkbox + * Checkbox použití nasvícení objektu + */ + private JCheckBox lightingChBox; + + /** + * Constructor, creates GUI + * Konstruktor, vytvoří grafické uživatelské rozhraní + */ + public SurfaceApp() { + //super( "Tomáš Hráský - ukázková aplikace funkcionality GLU NURBS funkcí - JOGL"); + super( "Tomáš Hráský - example application of GLU NURBS in JOGL"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + initGUI(); + } + + /** + * GUI initialization + * Inicializace grafického uživatelského rozhraní + */ + private void initGUI() { + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); + + this.glCanvas = new GLCanvas(); + glCanvas.setSize(new Dimension(750, 500)); + this.glListener=new GLListener(this); + glCanvas.addGLEventListener(glListener); + mouseListener = new SurfaceMouseListener(this); + glCanvas.addMouseListener(mouseListener); + glCanvas.addMouseMotionListener(mouseListener); + setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + c.gridy = 0; + c.gridwidth = GridBagConstraints.REMAINDER; + + ActListener listener = new ActListener(this); + + JMenuBar menuBar = new JMenuBar(); + getContentPane().add(menuBar, c); + + JMenu aplikaceMenu = new JMenu("Aplication"); + menuBar.add(aplikaceMenu); + + JMenuItem aboutMI = new JMenuItem("About"); + aboutMI.setActionCommand(INFO_AC); + aboutMI.addActionListener(listener); + aplikaceMenu.add(aboutMI); + + aplikaceMenu.add(new JSeparator()); + + JMenuItem konecMI = new JMenuItem("Exit"); + konecMI.addActionListener(listener); + konecMI.setActionCommand(EXIT_AC); + aplikaceMenu.add(konecMI); + + JMenu krivkaMenu = new JMenu("Surface"); + menuBar.add(krivkaMenu); + + JMenu pridatBodyM = new JMenu("Add points"); + krivkaMenu.add(pridatBodyM); + // pridatBodyM.addActionListener(listener); + + // pridatBodyM.setActionCommand(PRIDAT_AC); + + JMenuItem pridatRadkyMI=new JMenuItem("Points row"); + pridatRadkyMI.setActionCommand(PRIDAT_AC_RADEK); + pridatRadkyMI.addActionListener(listener); + + JMenuItem pridatSloupceMI=new JMenuItem("Points column"); + pridatSloupceMI.setActionCommand(PRIDAT_AC_SLOUPEC); + pridatSloupceMI.addActionListener(listener); + pridatBodyM.add(pridatRadkyMI); + pridatBodyM.add(pridatSloupceMI); + + + JMenu smazatBodyM = new JMenu("Delete points"); + krivkaMenu.add(smazatBodyM); + // smazatBodyM.addActionListener(listener); + + // smazatBodyM.setActionCommand(SMAZAT_AC); + + JMenuItem smazatRadkyMI=new JMenuItem("Points row"); + smazatRadkyMI.setActionCommand(SMAZAT_AC_RADEK); + smazatRadkyMI.addActionListener(listener); + smazatBodyM.add(smazatRadkyMI); + JMenuItem smazatSloupceMI=new JMenuItem("Points column"); + smazatSloupceMI.setActionCommand(SMAZAT_AC_SLOUPEC); + smazatSloupceMI.addActionListener(listener); + smazatBodyM.add(smazatSloupceMI); + + + JMenuItem stupenMI = new JMenuItem("Set surface degree"); + krivkaMenu.add(stupenMI); + stupenMI.addActionListener(listener); + stupenMI.setActionCommand(STUPEN_AC); + + JMenu knotVecMenu = new JMenu("Create knotvectors"); + krivkaMenu.add(knotVecMenu); + + JMenuItem clampedKVMI = new JMenuItem("Clamped"); + knotVecMenu.add(clampedKVMI); + clampedKVMI.setActionCommand(UZAVRENY_AC); + clampedKVMI.addActionListener(listener); + JMenuItem unclampedKVMI = new JMenuItem("Uniform"); + knotVecMenu.add(unclampedKVMI); + unclampedKVMI.setActionCommand(OTEVRENY_AC); + unclampedKVMI.addActionListener(listener); + + JMenuItem moveMI = new JMenuItem("Move points"); + krivkaMenu.add(moveMI); + moveMI.setActionCommand(MOVE_AC); + moveMI.addActionListener(listener); + + krivkaMenu.add(new JSeparator()); + + krivkaMenu.add(new JSeparator()); + + JMenuItem novaMI = new JMenuItem("New surface"); + krivkaMenu.add(novaMI); + novaMI.setActionCommand(NOVA_AC); + novaMI.addActionListener(listener); + + JMenuItem ulozitMI = new JMenuItem("Safe surface as..."); + krivkaMenu.add(ulozitMI); + ulozitMI.setActionCommand(ULOZIT_AC); + ulozitMI.addActionListener(listener); + JMenuItem nacistMI = new JMenuItem("Load surface"); + krivkaMenu.add(nacistMI); + nacistMI.setActionCommand(NACIST_AC); + nacistMI.addActionListener(listener); + + c.gridy++; + JToolBar toolBar = new JToolBar(); + getContentPane().add(toolBar, c); + + ButtonGroup bg = new ButtonGroup(); + + JButton novaB = new JButton(); + // novaB.setText("Nová"); + novaB.setToolTipText("New surface"); + novaB.setIcon(IconFactory.getIcon("demos/nurbs/icons/folder_new.png")); + novaB.setActionCommand(NOVA_AC); + novaB.addActionListener(listener); + toolBar.add(novaB); + + JButton ulozitB = new JButton(); + ulozitB.setIcon(IconFactory.getIcon("demos/nurbs/icons/adept_sourceseditor.png")); + // ulozitB.setText("Uložit"); + ulozitB.setToolTipText("Save"); + ulozitB.setActionCommand(ULOZIT_AC); + ulozitB.addActionListener(listener); + toolBar.add(ulozitB); + + JButton nahratB = new JButton(); + // nahratB.setText("Nahrát"); + nahratB.setToolTipText("Load surface"); + nahratB.setIcon(IconFactory.getIcon("demos/nurbs/icons/fileimport.png")); + nahratB.setActionCommand(NACIST_AC); + nahratB.addActionListener(listener); + toolBar.add(nahratB); + + toolBar.add(new JToolBar.Separator()); + + JToggleButton pridatTB = new JToggleButton(); + // pridatTB.setText("Přidat body"); + pridatTB.setToolTipText("Add contol points"); + toolBar.add(pridatTB); + pridatTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/add.png")); + // pridatTB.setActionCommand(PRIDAT_AC); + // pridatTB.addActionListener(listener); + + bg.add(pridatTB); + + final JPopupMenu popup2=new JPopupMenu(); + JMenuItem radkyPopupMI=new JMenuItem("Poits row"); + radkyPopupMI.setActionCommand(PRIDAT_AC_RADEK); + JMenuItem sloupcePopupMI=new JMenuItem("Points column"); + sloupcePopupMI.setActionCommand(PRIDAT_AC_SLOUPEC); + radkyPopupMI.addActionListener(listener); + sloupcePopupMI.addActionListener(listener); + + popup2.add(radkyPopupMI); + popup2.add(sloupcePopupMI); + + pridatTB.addMouseListener(new + /** + * CLass to add context menu to toolbar button + * Třída pro připojení kontextového menu na + * tlačítko na liště nástrojů + * @author Tomáš Hráský + */ + MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + e.isPopupTrigger(); + popup2.show(e.getComponent(), e.getX(), e.getY()); + } + + + }); + + JToggleButton smazatTB = new JToggleButton(); + // smazatTB.setText("Smazat body"); + smazatTB.setToolTipText("Delete points"); + toolBar.add(smazatTB); + smazatTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/fileclose.png")); + // smazatTB.setActionCommand(SMAZAT_AC); + // smazatTB.addActionListener(listener); + bg.add(smazatTB); + + final JPopupMenu popup3=new JPopupMenu(); + JMenuItem radky2PopupMI=new JMenuItem("Points row"); + radky2PopupMI.setActionCommand(SMAZAT_AC_RADEK); + JMenuItem sloupce2PopupMI=new JMenuItem("Points column"); + sloupce2PopupMI.setActionCommand(SMAZAT_AC_SLOUPEC); + radky2PopupMI.addActionListener(listener); + sloupce2PopupMI.addActionListener(listener); + + popup3.add(radky2PopupMI); + popup3.add(sloupce2PopupMI); + + + smazatTB.addMouseListener(new + /** + * CLass to add context menu to toolbar button + * Třída pro připojení kontextového menu na + * tlačítko na liště nástrojů + * @author Tomáš Hráský + */ + MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + e.isPopupTrigger(); + popup3.show(e.getComponent(), e.getX(), e.getY()); + } + + + }); + + JToggleButton stupenTB = new JToggleButton(); + // stupenTB.setText("Smazat body"); + stupenTB.setToolTipText("Set surface degree"); + toolBar.add(stupenTB); + stupenTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/math_rsup.png")); + stupenTB.setActionCommand(STUPEN_AC); + stupenTB.addActionListener(listener); + bg.add(stupenTB); + + final JPopupMenu popup = new JPopupMenu(); + + JMenuItem uzavrenyPopupMI = new JMenuItem("Clamped"); + popup.add(uzavrenyPopupMI); + uzavrenyPopupMI.setActionCommand(UZAVRENY_AC); + uzavrenyPopupMI.addActionListener(listener); + JMenuItem otevrenyPopupMI = new JMenuItem("Uniform"); + popup.add(otevrenyPopupMI); + otevrenyPopupMI.setActionCommand(OTEVRENY_AC); + otevrenyPopupMI.addActionListener(listener); + + JToggleButton vytvoritButton = new JToggleButton(); + // vytvoritButton.setText("Vytvořit uzlový vektor"); + vytvoritButton.setToolTipText("Create knotvectors"); + vytvoritButton.setIcon(IconFactory.getIcon("demos/nurbs/icons/newfunction.png")); + bg.add(vytvoritButton); + + vytvoritButton.addMouseListener(new + /** + * CLass to add context menu to toolbar button + * Třída pro připojení kontextového menu na + * tlačítko na liště nástrojů + * @author Tomáš Hráský + */ + MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + e.isPopupTrigger(); + popup.show(e.getComponent(), e.getX(), e.getY()); + } + + }); + popup.setInvoker(vytvoritButton); + toolBar.add(vytvoritButton); + + moveTB = new JToggleButton(); + // moveTB.setText("Hýbat body"); + moveTB.setToolTipText("Move points"); + moveTB.setIcon(IconFactory.getIcon("demos/nurbs/icons/mouse.png")); + toolBar.add(moveTB); + moveTB.setActionCommand(MOVE_AC); + moveTB.addActionListener(listener); + bg.add(moveTB); + toolBar.add(new JToolBar.Separator()); + JButton infoB = new JButton(); + // infoB.setText("Ukončit"); + infoB.setToolTipText("About"); + + infoB.setIcon(IconFactory.getIcon("demos/nurbs/icons/info.png")); + toolBar.add(infoB); + infoB.setActionCommand(INFO_AC); + infoB.addActionListener(listener); + toolBar.add(new JToolBar.Separator()); + + JButton exitB = new JButton(); + // exitB.setText("Ukončit"); + exitB.setToolTipText("Exit"); + + exitB.setIcon(IconFactory.getIcon("demos/nurbs/icons/exit.png")); + toolBar.add(exitB); + exitB.setActionCommand(EXIT_AC); + exitB.addActionListener(listener); + + c.gridwidth = 1; + + c.gridx = 0; + c.gridy = 2; + + c.weightx = 1; + c.weighty = 1; + + getContentPane().add(glCanvas, c); + c.gridx = 1; + JPanel rightPanel = new JPanel(new GridBagLayout()); + GridBagConstraints cc = new GridBagConstraints(); + cc.insets = new Insets(5, 5, 5, 5); + xSpinner = new JSpinner(new SpinnerNumberModel(0, -10000, 10000.0, 1)); + ySpinner = new JSpinner(new SpinnerNumberModel(0, -10000.0, 10000.0, 1)); + zSpinner = new JSpinner(new SpinnerNumberModel(0, -10000.0, 10000.0, 1)); + wSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 10000.0, .05)); + + SpinnerListener spinnerListener = new SpinnerListener(this); + SliderListener sliderListener=new SliderListener(this); + + xSpinner.addChangeListener(spinnerListener); + xSpinner.setName(X_SPINNER_NAME); + ySpinner.addChangeListener(spinnerListener); + ySpinner.setName(Y_SPINNER_NAME); + wSpinner.addChangeListener(spinnerListener); + wSpinner.setName(W_SPINNER_NAME); + + zSpinner.setName(Z_SPINNER_NAME); + zSpinner.addChangeListener(spinnerListener); + + cc.gridx = 0; + cc.gridy = 0; + cc.gridwidth = 2; + cc.weighty = 0; + + rotaceXLabel = new JLabel(); + rightPanel.add(rotaceXLabel, cc); + cc.gridy++; + + rotaceXSlider = new JSlider(-180, 180, 0); + rotaceXSlider.addChangeListener(sliderListener); + rightPanel.add(rotaceXSlider, cc); + cc.gridy++; + + rotaceYLabel = new JLabel(); + rightPanel.add(rotaceYLabel, cc); + cc.gridy++; + + rotaceYSlider = new JSlider(-180, 180, 0); + rotaceYSlider.addChangeListener(sliderListener); + rightPanel.add(rotaceYSlider, cc); + cc.gridy++; + + rotaceZLabel = new JLabel(); + rightPanel.add(rotaceZLabel, cc); + cc.gridy++; + + rotaceZSlider = new JSlider(-180, 180, 0); + rotaceZSlider.addChangeListener(sliderListener); + rightPanel.add(rotaceZSlider, cc); + cc.gridy++; + + lightingChBox=new JCheckBox(new + /** + * Class for easy reaction to checkbox event + * Třída pro jendoduché zpracování akce na checkboxu + * @author Tomáš Hráský + */ + AbstractAction("Show Bézier plates"){ + + public void actionPerformed(ActionEvent e) { + updateGLCanvas(); + } + + }); + lightingChBox.setSelected(false); + + rightPanel.add(lightingChBox,cc); + + cc.gridy++; + + updateRotationLabels(); + + cc.weighty = 1; + rightPanel.add(new JPanel(), cc); + cc.weighty = 0; + cc.gridwidth = 1; + + cc.gridy++; + rightPanel.add(new JLabel("X"), cc); + cc.gridy++; + rightPanel.add(new JLabel("Y"), cc); + cc.gridy++; + rightPanel.add(new JLabel("Z"), cc); + cc.gridy++; + rightPanel.add(new JLabel("W"), cc); + + cc.gridx = 1; + cc.gridy -= 3; + rightPanel.add(xSpinner, cc); + cc.gridy++; + rightPanel.add(ySpinner, cc); + cc.gridy++; + rightPanel.add(zSpinner, cc); + cc.gridy++; + rightPanel.add(wSpinner, cc); + + xSpinner.setEnabled(false); + ySpinner.setEnabled(false); + zSpinner.setEnabled(false); + wSpinner.setEnabled(false); + + c.weightx = 0; + c.weighty = 0; + getContentPane().add(rightPanel, c); + + c.gridx = 0; + c.gridy++; + + knotSlider = new JKnotSlider(Surface.getInstance().getKnotsU()); + knotSlider.addActionListener(this); + knotSlider.setName(U_KNOTSLIDER); + getContentPane().add(knotSlider, c); + + c.gridy++; + knotSlider2 = new JKnotSlider(Surface.getInstance().getKnotsU()); + knotSlider2.addActionListener(this); + knotSlider2.setName(V_KNOTSLIDER); + getContentPane().add(knotSlider2, c); + + pack(); + invalidate(); + setVisible(true); + } + + /** + * Method for running application + * Metoda pro spuštění aplikace + * + * @param args + * no arguments from command line + * + */ + public static void main(String[] args) { + new SurfaceApp(); + + } + + /** + * Reaction to reqest for canvas redraw - redraws canvas and sets coords of actually selected control point to editing components + * Reakce na požadavek překreslení OpenGL plátna, překreslí plátno a nastaví + * souřadnice aktuálního vybraného bodu do editačních komponent + */ + public void updateGLCanvas() { + glCanvas.repaint(); + if (Surface.getInstance().getBodIndex() >= 0) { + xSpinner.setEnabled(true); + ySpinner.setEnabled(true); + zSpinner.setEnabled(true); + wSpinner.setEnabled(true); + + xSpinner.setValue(Double.valueOf(Math.round(Surface.getInstance() + .getActiveX()))); + ySpinner.setValue(Double.valueOf(Math.round(Surface.getInstance() + .getActiveY()))); + zSpinner.setValue(Double.valueOf(Math.round(Surface.getInstance() + .getActiveZ()))); + wSpinner.setValue(Double + .valueOf(Surface.getInstance().getActiveW())); + } else { + xSpinner.setEnabled(false); + ySpinner.setEnabled(false); + zSpinner.setEnabled(false); + wSpinner.setEnabled(false); + } + } + + /* + * (non-Javadoc) + * + * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) + */ + public void actionPerformed(ActionEvent e) { + if (e.getSource() instanceof JKnotSlider) { + JKnotSlider src = (JKnotSlider) e.getSource(); + if (src.getName().equals(U_KNOTSLIDER)) { + if(src.checkKnotMulti(Surface.getInstance().getOrderU())){ + Surface.getInstance().setKnotsU(src.getKnotsFloat()); + }else{ + JOptionPane.showMessageDialog(this,"Maximum knot multiplicity exceeded","Error",JOptionPane.ERROR_MESSAGE); + src.setKnots(Surface.getInstance().getKnotsU()); + } + + } else { + if(src.checkKnotMulti(Surface.getInstance().getOrderV())){ + Surface.getInstance().setKnotsV(src.getKnotsFloat()); + }else{ + JOptionPane.showMessageDialog(this,"Maximum knot multiplicity exceeded","Error",JOptionPane.ERROR_MESSAGE); + //JOptionPane.showMessageDialog(this,"Překročení maximální násobnosti uzlu","Chyba",JOptionPane.ERROR_MESSAGE); + src.setKnots(Surface.getInstance().getKnotsV()); + } + } + updateGLCanvas(); + } + } + + /** + * Returns OpenGL canvas + * Vrací OpenGL plátno + * + * @return OpenGL canvas + */ + public GLCanvas getGlCanvas() { + return glCanvas; + } + + /** + * Returns mouse listener + * Vrací listener událostí myši + * + * @return mouse listener + */ + public SurfaceMouseListener getMouseListener() { + return mouseListener; + } + + /** + * Creates NURBS surface with clamped knotvectors + * Vytvoří NURBS plochu s okrajovými uzlovými vektory + */ + public void uzavernyKV() { + int stupen; + int pocetBodu; + boolean isOK=true; + float[] newKnots = null,newKnotsV = null; + + stupen= Surface.getInstance().getOrderU(); + pocetBodu= Surface.getInstance().getPointsInU(); + if (stupen <= pocetBodu) { + int knotCount = stupen + pocetBodu; + int middlePartSize = knotCount - 2 * stupen; + newKnots = new float[knotCount]; + int i; + int j = 0; + float middleStep = 1f / (middlePartSize + 2); + float knot = middleStep; + + // knot=.5f; + + for (i = 0; i < stupen; i++) + newKnots[j++] = 0; + for (i = 0; i < middlePartSize; i++) { + newKnots[j++] = knot; + knot += middleStep; + } + for (i = 0; i < stupen; i++) + newKnots[j++] = 1; + + + + } else{ + isOK=false; + //errorMessage("Malý počet řídících bodů ve směru paramteru U vzhledem k zadanému stupni plochy"); + errorMessage("Too few control points as of U degree"); + } + + stupen= Surface.getInstance().getOrderV(); + pocetBodu= Surface.getInstance().getPointsInV(); + if (stupen <= pocetBodu) { + int knotCount = stupen + pocetBodu; + int middlePartSize = knotCount - 2 * stupen; + newKnotsV = new float[knotCount]; + int i; + int j = 0; + float middleStep = 1f / (middlePartSize + 2); + float knot = middleStep; + + // knot=.5f; + + for (i = 0; i < stupen; i++) + newKnotsV[j++] = 0; + for (i = 0; i < middlePartSize; i++) { + newKnotsV[j++] = knot; + knot += middleStep; + } + for (i = 0; i < stupen; i++) + newKnotsV[j++] = 1; + + + + } else{ + isOK=false; + //errorMessage("Malý počet řídících bodů ve směru paramteru V vzhledem k zadanému stupni plochy"); + errorMessage("Too few control points as of V degree"); + } + + if(isOK) + postNewKnot(newKnots,newKnotsV); + } + + /** + * Shows modal window with error report + * Zobrazí modální okno s hlášením chyby + * + * @param error + * error report + */ + + public void errorMessage(String error) { + JOptionPane.showMessageDialog(this, error, "Error!", + JOptionPane.ERROR_MESSAGE); + } + + /** + * Creates NURBS surface with uniform knotvectors + * Vytvoří NURBS plochu s uniformními uzlovými vektory + */ + public void otevrenyKV() { + int stupen,pocetBodu; + + boolean isOK=true; + float[] newKnots = null,newKnotsV = null; + + + stupen = Surface.getInstance().getOrderU(); + pocetBodu = Surface.getInstance().getPointsInU(); + if (stupen <= pocetBodu) { + int knotCount = stupen + pocetBodu; + int middlePartSize = knotCount; + newKnots = new float[knotCount]; + int i; + int j = 0; + float middleStep = 1f / (middlePartSize - 1); + float knot = 0; + + for (i = 0; i < middlePartSize; i++) { + newKnots[j++] = knot; + knot += middleStep; + } + + + } else{ + isOK=false; + //errorMessage("Malý počet řídících bodů ve směru parametru U vzhledem k zadanému stupni plochy"); + errorMessage("Too few control points as of U degree"); + } + + stupen = Surface.getInstance().getOrderV(); + pocetBodu = Surface.getInstance().getPointsInV(); + if (stupen <= pocetBodu) { + int knotCount = stupen + pocetBodu; + int middlePartSize = knotCount; + newKnotsV = new float[knotCount]; + int i; + int j = 0; + float middleStep = 1f / (middlePartSize - 1); + float knot = 0; + + for (i = 0; i < middlePartSize; i++) { + newKnotsV[j++] = knot; + knot += middleStep; + } + + + } else{ + isOK=false; + //errorMessage("Malý počet řídících bodů ve směru parametru V vzhledem k zadanému stupni plochy"); + errorMessage("Too few control points as of V degree"); + } + + if(isOK) + postNewKnot(newKnots,newKnotsV); + + } + + + /** + * Method called after adding new knot + * Metoda volaná po přidání nového uzlu + * @param newKnots new U knotvector + * @param newKnotsV new V knotvector + */ + private void postNewKnot(float[] newKnots,float[] newKnotsV) { + Surface.getInstance().setKnotsU(newKnots); + Surface.getInstance().setKnotsV(newKnotsV); + knotSlider.setKnots(newKnots); + knotSlider2.setKnots(newKnotsV); + Surface.getInstance().setIsSurfaceFinished(true); + updateGLCanvas(); + moveTB.setSelected(true); + } + + /** + * Activates move mode button + * Aktivuje tlačítko módu pohybu řícími body + */ + public void selectMoveButt() { + moveTB.setSelected(true); + } + + /** + * Sets datasource for editation of knotvectors from surface definition object + * Nastaví zdroje dat komponent pro editaci uzlových vektorů podle uz. + * vektorů v objektu plochy + */ + public void updateJKnotSlider() { + knotSlider.setKnots(Surface.getInstance().getKnotsU()); + knotSlider2.setKnots(Surface.getInstance().getKnotsV()); + } + + /** + * Returns value of X axe rotation set in editing component + * Vrací hodnotu rotace kolem osy X nastavenou v editační komponentě + * @return X rotation + */ + public float getXrotation() { + return rotaceXSlider.getValue(); + } + + /** + * Returns value of Y axe rotation set in editing component + * Vrací hodnotu rotace kolem osy Y nastavenou v editační komponentě + * @return Y rotation + */ + public float getYrotation() { + return rotaceYSlider.getValue(); + } + + /** + * Returns value of Z axe rotation set in editing component + * Vrací hodnotu rotace kolem osy Z nastavenou v editační komponentě + * @return Z rotation + */ + public float getZrotation() { + return rotaceZSlider.getValue(); + } + + /** + * Updates labels's text according to their actual state + * Upraví text popisků prvků pro ovládání rotace podle jejich aktuálního stavu + */ + public void updateRotationLabels(){ + String zakladniText = "Rotation by axe "; + + PrintfFormat format=new PrintfFormat("%0.3d"); + String add; + if(rotaceXSlider.getValue()<0)add="-"; + else add="+"; + rotaceXLabel.setText(zakladniText+"X "+add+format.sprintf(Math.abs(rotaceXSlider.getValue()))+"˚"); + if(rotaceYSlider.getValue()<0)add="-"; + else add="+"; + rotaceYLabel.setText(zakladniText+"Y "+add+format.sprintf(Math.abs(rotaceYSlider.getValue()))+"˚"); + if(rotaceZSlider.getValue()<0)add="-"; + else add="+"; + rotaceZLabel.setText(zakladniText+"Z "+add+format.sprintf(Math.abs(rotaceZSlider.getValue()))+"˚"); + } + + /** + * Return OpenGL canvas listener + * Vrací listener OpenGL plátna + * @return OpenGL canvas listener + */ + public GLListener getGlListener() { + return glListener; + } + + /** + * Notifies about reqest to light surface + * Informuje o požadavku na nasvětlení tělesa + * @return true if lighting is enabled + */ + public boolean isLightingEnabled() { + return !lightingChBox.isSelected(); + } +} diff --git a/src/demos/nurbs/surfaceapp/SurfaceMouseListener.java b/src/demos/nurbs/surfaceapp/SurfaceMouseListener.java new file mode 100755 index 0000000..834ae46 --- /dev/null +++ b/src/demos/nurbs/surfaceapp/SurfaceMouseListener.java @@ -0,0 +1,277 @@ +package demos.nurbs.surfaceapp; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.util.Vector; + +import javax.media.opengl.GL; +import javax.media.opengl.glu.GLU; + +/** + * Třída zpracovávající události myši (implementuje rozhraní zpracovávající stisk tlačítek i pohyb a tažení myší) + * @author Tomáš Hráský + * + */ +public class SurfaceMouseListener implements MouseListener, MouseMotionListener { + /** + * Index aktuálně vybraného řídícího bodu + */ + private int bodIndex; + + /** + * Okno k nemuž liustener patří + */ + private SurfaceApp appWindow; + + /** + * Typ prováděné činnosti + */ + private String actionType; + + /** + * Tolerance pro indikaci kliku na řídící bod + */ + private static final int TOLERANCE=10; + + /** + * Vytvoří listener s odkazem na zadané okno + * @param app rodičovské okno + */ + public SurfaceMouseListener(SurfaceApp app) { + this.appWindow=app; + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) + */ + public void mouseClicked(MouseEvent e) { + if(actionType==SurfaceApp.PRIDAT_AC){ + // Surface.getInstance().setIsSurfaceFinished(false); + // float x=e.getX(); + // float y=e.getY(); + // float z=0; + // float w=1; + // int size; + // float[] newCtrls; + // try{ + // size=Surface.getInstance().getCtrlPoints().length; + // }catch (Exception ex) { + // size=0; + // } + // newCtrls=new float[size+4]; + // System.arraycopy(Surface.getInstance().getCtrlPoints(),0,newCtrls,0,size); + // + // newCtrls[size]=x; + // newCtrls[size+1]=y; + // newCtrls[size+2]=z; + // newCtrls[size+3]=w; + // Surface.getInstance().setCtrlPoints(newCtrls); + }else if(actionType==SurfaceApp.SMAZAT_AC&&bodIndex>=0){ + // Surface.getInstance().setIsSurfaceFinished(false); + // int size=Surface.getInstance().getCtrlPoints().length; + // float[] newCtrls=new float[size-4]; + // + // int firstPartSize=(bodIndex)*4; + // int secondPartSize=newCtrls.length-firstPartSize; + // System.arraycopy(Surface.getInstance().getCtrlPoints(),0,newCtrls,0,firstPartSize); + // System.arraycopy(Surface.getInstance().getCtrlPoints(),firstPartSize+4,newCtrls,firstPartSize,secondPartSize); + // bodIndex=-1; + // Surface.getInstance().setBodIndex(bodIndex); + // Surface.getInstance().setCtrlPoints(newCtrls); + }else if(actionType==SurfaceApp.SMAZAT_AC_RADEK&&bodIndex>=0){ + + Vector oldPoints=new Vector(); + Surface srf=Surface.getInstance(); + for(int i=0;i indexes=new Vector(); + for(int i=index;i newOldPoints=new Vector(); + for(int i=0;i=0){ + Vector oldPoints=new Vector(); + Surface srf=Surface.getInstance(); + for(int i=0;i indexes=new Vector(); + + for(int i=index;i>=0;i-=srf.getPointsInV()){ + indexes.add(i-1); + } + for(int i=index;i newOldPoints=new Vector(); + for(int i=0;i=x-TOLERANCE&&xE<=x+TOLERANCE&&yE>=y-TOLERANCE&&yE<=y+TOLERANCE){ + this.bodIndex=i; + } + } + + Surface.getInstance().setBodIndex(bodIndex); + appWindow.updateGLCanvas(); + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) + */ + public void mouseReleased(MouseEvent e) { + // this.bodIndex=-1; + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) + */ + public void mouseEntered(MouseEvent e) { + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) + */ + public void mouseExited(MouseEvent e) { + + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) + */ + public void mouseDragged(MouseEvent e) { + // if(this.bodIndex>=0){ + // int x=e.getX(); + // int y=e.getY(); + // + // Surface.getInstance().setActiveX(x); + // Surface.getInstance().setActiveY(y); + // } + // appWindow.updateGLCanvas(); + } + + /* (non-Javadoc) + * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) + */ + public void mouseMoved(MouseEvent e) { + + } + + /** + * Nastaví typ prováděné činnosti + * @param action typ prováděné činnosti + */ + public void setActionType(String action) { + this.actionType=action; + } + + /** + * Vrací index aktuálně vybraného řídícího bodu + * @return index aktuálně vybraného řídícího bodu + */ + public int getBodIndex() { + return bodIndex; + } + + /** + * Vrací index aktuálně vybraného řídícího bodu + * @param bodIndex aktuálně vybraného řídícího bodu + */ + public void setBodIndex(int bodIndex) { + this.bodIndex = bodIndex; + } +} -- cgit v1.2.3