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
+ *
+ *- is not escaped protected by a matching % or is
+ * not an escape % character,
+ *
- is not at the end of the format string, and
+ *
- 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 n
th
+ * 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.
+ *
+ *Sequence |
+ * Name |
+ * Description |
+ *\\ | backlash | None.
+ * |
+ *\a | alert | Attempts to alert
+ * the user through audible or visible
+ * notification.
+ * |
+ *\b | backspace | Moves the
+ * printing position to one column before
+ * the current position, unless the
+ * current position is the start of a line.
+ * |
+ *\f | form-feed | Moves the
+ * printing position to the initial
+ * printing position of the next logical
+ * page.
+ * |
+ *\n | newline | Moves the
+ * printing position to the start of the
+ * next line.
+ * |
+ *\r | carriage-return | Moves
+ * the printing position to the start of
+ * the current line.
+ * |
+ *\t | tab | Moves the printing
+ * position to the next implementation-
+ * defined horizontal tab position.
+ * |
+ *\v | vertical-tab | Moves 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
+ *
+ *- is not escaped protected by a matching % or
+ * is not an escape % character,
+ *
- is not at the end of the format string, and
+ *
- 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