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 --- 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 ++ 7 files changed, 1509 insertions(+) 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 (limited to 'src/demos/nurbs/curveapp') 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(); + } +} -- cgit v1.2.3