curve.h

Go to the documentation of this file.
00001 
00005 /*
00006  Copyright (C) 2001-2006, William Joseph.
00007  All Rights Reserved.
00008 
00009  This file is part of GtkRadiant.
00010 
00011  GtkRadiant is free software; you can redistribute it and/or modify
00012  it under the terms of the GNU General Public License as published by
00013  the Free Software Foundation; either version 2 of the License, or
00014  (at your option) any later version.
00015 
00016  GtkRadiant is distributed in the hope that it will be useful,
00017  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  GNU General Public License for more details.
00020 
00021  You should have received a copy of the GNU General Public License
00022  along with GtkRadiant; if not, write to the Free Software
00023  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00024  */
00025 
00026 #if !defined(INCLUDED_CURVE_H)
00027 #define INCLUDED_CURVE_H
00028 
00029 #include "ientity.h"
00030 #include "selectable.h"
00031 #include "renderable.h"
00032 
00033 #include <set>
00034 
00035 #include "math/curve.h"
00036 #include "stream/stringstream.h"
00037 #include "signal/signal.h"
00038 #include "selectionlib.h"
00039 #include "render.h"
00040 #include "stringio.h"
00041 
00042 class RenderableCurve: public OpenGLRenderable
00043 {
00044     public:
00045         std::vector<PointVertex> m_vertices;
00046         void render (RenderStateFlags state) const
00047         {
00048             pointvertex_gl_array(&m_vertices.front());
00049             glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_vertices.size()));
00050         }
00051 };
00052 
00053 inline void plotBasisFunction (std::size_t numSegments, int point, int degree)
00054 {
00055     Knots knots;
00056     KnotVector_openUniform(knots, 4, degree);
00057 
00058     globalOutputStream() << "plotBasisFunction point " << point << " of 4, knot vector:";
00059     for (Knots::iterator i = knots.begin(); i != knots.end(); ++i) {
00060         globalOutputStream() << " " << *i;
00061     }
00062     globalOutputStream() << "\n";
00063     globalOutputStream() << "t=0 basis=" << BSpline_basis(knots, point, degree, 0.0) << "\n";
00064     for (std::size_t i = 1; i < numSegments; ++i) {
00065         double t = (1.0 / double(numSegments)) * double(i);
00066         globalOutputStream() << "t=" << t << " basis=" << BSpline_basis(knots, point, degree, t) << "\n";
00067     }
00068     globalOutputStream() << "t=1 basis=" << BSpline_basis(knots, point, degree, 1.0) << "\n";
00069 }
00070 
00071 inline bool ControlPoints_parse (ControlPoints& controlPoints, const char* value)
00072 {
00073     StringTokeniser tokeniser(value, " ");
00074 
00075     std::size_t size;
00076     if (!string_parse_size(tokeniser.getToken(), size)) {
00077         return false;
00078     }
00079 
00080     if (size < 3) {
00081         return false;
00082     }
00083     controlPoints.resize(size);
00084 
00085     if (!string_equal(tokeniser.getToken(), "(")) {
00086         return false;
00087     }
00088     for (ControlPoints::iterator i = controlPoints.begin(); i != controlPoints.end(); ++i) {
00089         if (!string_parse_float(tokeniser.getToken(), (*i).x()) || !string_parse_float(tokeniser.getToken(), (*i).y())
00090                 || !string_parse_float(tokeniser.getToken(), (*i).z())) {
00091             return false;
00092         }
00093     }
00094     if (!string_equal(tokeniser.getToken(), ")")) {
00095         return false;
00096     }
00097     return true;
00098 }
00099 
00100 inline void ControlPoints_write (const ControlPoints& controlPoints, StringOutputStream& value)
00101 {
00102     value << Unsigned(controlPoints.size()) << " (";
00103     for (ControlPoints::const_iterator i = controlPoints.begin(); i != controlPoints.end(); ++i) {
00104         value << " " << (*i).x() << " " << (*i).y() << " " << (*i).z() << " ";
00105     }
00106     value << ")";
00107 }
00108 
00109 inline void ControlPoint_testSelect (const Vector3& point, ObservedSelectable& selectable, Selector& selector,
00110         SelectionTest& test)
00111 {
00112     SelectionIntersection best;
00113     test.TestPoint(point, best);
00114     if (best.valid()) {
00115         Selector_add(selector, selectable, best);
00116     }
00117 }
00118 
00119 class ControlPointTransform
00120 {
00121         const Matrix4& m_matrix;
00122     public:
00123         ControlPointTransform (const Matrix4& matrix) :
00124             m_matrix(matrix)
00125         {
00126         }
00127         void operator() (Vector3& point) const
00128         {
00129             matrix4_transform_point(m_matrix, point);
00130         }
00131 };
00132 
00133 class ControlPointSnap
00134 {
00135         float m_snap;
00136     public:
00137         ControlPointSnap (float snap) :
00138             m_snap(snap)
00139         {
00140         }
00141         void operator() (Vector3& point) const
00142         {
00143             vector3_snap(point, m_snap);
00144         }
00145 };
00146 
00147 class ControlPointAdd
00148 {
00149         RenderablePointVector& m_points;
00150     public:
00151         ControlPointAdd (RenderablePointVector& points) :
00152             m_points(points)
00153         {
00154         }
00155         void operator() (const Vector3& point) const
00156         {
00157             m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_vertex));
00158         }
00159 };
00160 
00161 class ControlPointAddSelected
00162 {
00163         RenderablePointVector& m_points;
00164     public:
00165         ControlPointAddSelected (RenderablePointVector& points) :
00166             m_points(points)
00167         {
00168         }
00169         void operator() (const Vector3& point) const
00170         {
00171             m_points.push_back(PointVertex(vertex3f_for_vector3(point), colour_selected));
00172         }
00173 };
00174 
00175 class CurveEditType
00176 {
00177     public:
00178         Shader* m_controlsShader;
00179         Shader* m_selectedShader;
00180 };
00181 
00182 inline void ControlPoints_write (ControlPoints& controlPoints, const char* key, Entity& entity)
00183 {
00184     StringOutputStream value(256);
00185     if (!controlPoints.empty()) {
00186         ControlPoints_write(controlPoints, value);
00187     }
00188     entity.setKeyValue(key, value.c_str());
00189 }
00190 
00191 class CurveEdit
00192 {
00193         SelectionChangeCallback m_selectionChanged;
00194         ControlPoints& m_controlPoints;
00195         typedef Array<ObservedSelectable> Selectables;
00196         Selectables m_selectables;
00197 
00198         RenderablePointVector m_controlsRender;
00199         mutable RenderablePointVector m_selectedRender;
00200 
00201     public:
00202         typedef Static<CurveEditType> Type;
00203 
00204         CurveEdit (ControlPoints& controlPoints, const SelectionChangeCallback& selectionChanged) :
00205             m_selectionChanged(selectionChanged), m_controlPoints(controlPoints), m_controlsRender(GL_POINTS),
00206                     m_selectedRender(GL_POINTS)
00207         {
00208         }
00209 
00210         template<typename Functor>
00211         const Functor& forEachSelected (const Functor& functor)
00212         {
00213             ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
00214             ControlPoints::iterator p = m_controlPoints.begin();
00215             for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
00216                 if ((*i).isSelected()) {
00217                     functor(*p);
00218                 }
00219             }
00220             return functor;
00221         }
00222         template<typename Functor>
00223         const Functor& forEachSelected (const Functor& functor) const
00224         {
00225             ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
00226             ControlPoints::const_iterator p = m_controlPoints.begin();
00227             for (Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
00228                 if ((*i).isSelected()) {
00229                     functor(*p);
00230                 }
00231             }
00232             return functor;
00233         }
00234         template<typename Functor>
00235         const Functor& forEach (const Functor& functor) const
00236         {
00237             for (ControlPoints::const_iterator i = m_controlPoints.begin(); i != m_controlPoints.end(); ++i) {
00238                 functor(*i);
00239             }
00240             return functor;
00241         }
00242 
00243         void testSelect (Selector& selector, SelectionTest& test)
00244         {
00245             ASSERT_MESSAGE(m_controlPoints.size() == m_selectables.size(), "curve instance mismatch");
00246             ControlPoints::const_iterator p = m_controlPoints.begin();
00247             for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i, ++p) {
00248                 ControlPoint_testSelect(*p, *i, selector, test);
00249             }
00250         }
00251 
00252         bool isSelected () const
00253         {
00254             for (Selectables::const_iterator i = m_selectables.begin(); i != m_selectables.end(); ++i) {
00255                 if ((*i).isSelected()) {
00256                     return true;
00257                 }
00258             }
00259             return false;
00260         }
00261         void setSelected (bool selected)
00262         {
00263             for (Selectables::iterator i = m_selectables.begin(); i != m_selectables.end(); ++i) {
00264                 (*i).setSelected(selected);
00265             }
00266         }
00267 
00268         void write (const char* key, Entity& entity)
00269         {
00270             ControlPoints_write(m_controlPoints, key, entity);
00271         }
00272 
00273         void transform (const Matrix4& matrix)
00274         {
00275             forEachSelected(ControlPointTransform(matrix));
00276         }
00277         void snapto (float snap)
00278         {
00279             forEachSelected(ControlPointSnap(snap));
00280         }
00281 
00282         void updateSelected () const
00283         {
00284             m_selectedRender.clear();
00285             forEachSelected(ControlPointAddSelected(m_selectedRender));
00286         }
00287 
00288         void renderComponents (Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
00289         {
00290             renderer.SetState(Type::instance().m_controlsShader, Renderer::eWireframeOnly);
00291             renderer.SetState(Type::instance().m_controlsShader, Renderer::eFullMaterials);
00292             renderer.addRenderable(m_controlsRender, localToWorld);
00293         }
00294 
00295         void renderComponentsSelected (Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
00296         {
00297             updateSelected();
00298             if (!m_selectedRender.empty()) {
00299                 renderer.Highlight(Renderer::ePrimitive, false);
00300                 renderer.SetState(Type::instance().m_selectedShader, Renderer::eWireframeOnly);
00301                 renderer.SetState(Type::instance().m_selectedShader, Renderer::eFullMaterials);
00302                 renderer.addRenderable(m_selectedRender, localToWorld);
00303             }
00304         }
00305 
00306         void curveChanged ()
00307         {
00308             m_selectables.resize(m_controlPoints.size(), m_selectionChanged);
00309 
00310             m_controlsRender.clear();
00311             m_controlsRender.reserve(m_controlPoints.size());
00312             forEach(ControlPointAdd(m_controlsRender));
00313 
00314             m_selectedRender.reserve(m_controlPoints.size());
00315         }
00316         typedef MemberCaller<CurveEdit, &CurveEdit::curveChanged> CurveChangedCaller;
00317 };
00318 
00319 const int NURBS_degree = 3;
00320 
00321 class NURBSCurve
00322 {
00323         Signal0 m_curveChanged;
00324         Callback m_boundsChanged;
00325     public:
00326         ControlPoints m_controlPoints;
00327         ControlPoints m_controlPointsTransformed;
00328         NURBSWeights m_weights;
00329         Knots m_knots;
00330         RenderableCurve m_renderCurve;
00331         AABB m_bounds;
00332 
00333         NURBSCurve (const Callback& boundsChanged) :
00334             m_boundsChanged(boundsChanged)
00335         {
00336         }
00337 
00338         SignalHandlerId connect (const SignalHandler& curveChanged)
00339         {
00340             curveChanged();
00341             return m_curveChanged.connectLast(curveChanged);
00342         }
00343         void disconnect (SignalHandlerId id)
00344         {
00345             m_curveChanged.disconnect(id);
00346         }
00347         void notify ()
00348         {
00349             m_curveChanged();
00350         }
00351 
00352         void tesselate ()
00353         {
00354             if (!m_controlPointsTransformed.empty()) {
00355                 const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
00356                 m_renderCurve.m_vertices.resize(numSegments + 1);
00357                 m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
00358                 for (std::size_t i = 1; i < numSegments; ++i) {
00359                     m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(NURBS_evaluate(
00360                             m_controlPointsTransformed, m_weights, m_knots, NURBS_degree, (1.0 / double(numSegments))
00361                                     * double(i)));
00362                 }
00363                 m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(
00364                         m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
00365             } else {
00366                 m_renderCurve.m_vertices.clear();
00367             }
00368         }
00369 
00370         void curveChanged ()
00371         {
00372             tesselate();
00373 
00374             m_bounds = AABB();
00375             for (ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i) {
00376                 aabb_extend_by_point_safe(m_bounds, (*i));
00377             }
00378 
00379             m_boundsChanged();
00380             notify();
00381         }
00382 
00383         bool parseCurve (const char* value)
00384         {
00385             if (!ControlPoints_parse(m_controlPoints, value)) {
00386                 return false;
00387             }
00388 
00389             m_weights.resize(m_controlPoints.size());
00390             for (NURBSWeights::iterator i = m_weights.begin(); i != m_weights.end(); ++i) {
00391                 (*i) = 1;
00392             }
00393 
00394             KnotVector_openUniform(m_knots, m_controlPoints.size(), NURBS_degree);
00395 
00396             //plotBasisFunction(8, 0, NURBS_degree);
00397 
00398             return true;
00399         }
00400 
00401         void curveChanged (const char* value)
00402         {
00403             if (string_empty(value) || !parseCurve(value)) {
00404                 m_controlPoints.resize(0);
00405                 m_knots.resize(0);
00406                 m_weights.resize(0);
00407             }
00408             m_controlPointsTransformed = m_controlPoints;
00409             curveChanged();
00410         }
00411         typedef MemberCaller1<NURBSCurve, const char*, &NURBSCurve::curveChanged> CurveChangedCaller;
00412 };
00413 
00414 class CatmullRomSpline
00415 {
00416         Signal0 m_curveChanged;
00417         Callback m_boundsChanged;
00418     public:
00419         ControlPoints m_controlPoints;
00420         ControlPoints m_controlPointsTransformed;
00421         RenderableCurve m_renderCurve;
00422         AABB m_bounds;
00423 
00424         CatmullRomSpline (const Callback& boundsChanged) :
00425             m_boundsChanged(boundsChanged)
00426         {
00427         }
00428 
00429         SignalHandlerId connect (const SignalHandler& curveChanged)
00430         {
00431             curveChanged();
00432             return m_curveChanged.connectLast(curveChanged);
00433         }
00434         void disconnect (SignalHandlerId id)
00435         {
00436             m_curveChanged.disconnect(id);
00437         }
00438         void notify ()
00439         {
00440             m_curveChanged();
00441         }
00442 
00443         void tesselate ()
00444         {
00445             if (!m_controlPointsTransformed.empty()) {
00446                 const std::size_t numSegments = (m_controlPointsTransformed.size() - 1) * 16;
00447                 m_renderCurve.m_vertices.resize(numSegments + 1);
00448                 m_renderCurve.m_vertices[0].vertex = vertex3f_for_vector3(m_controlPointsTransformed[0]);
00449                 for (std::size_t i = 1; i < numSegments; ++i) {
00450                     m_renderCurve.m_vertices[i].vertex = vertex3f_for_vector3(CatmullRom_evaluate(
00451                             m_controlPointsTransformed, (1.0 / double(numSegments)) * double(i)));
00452                 }
00453                 m_renderCurve.m_vertices[numSegments].vertex = vertex3f_for_vector3(
00454                         m_controlPointsTransformed[m_controlPointsTransformed.size() - 1]);
00455             } else {
00456                 m_renderCurve.m_vertices.clear();
00457             }
00458         }
00459 
00460         bool parseCurve (const char* value)
00461         {
00462             return ControlPoints_parse(m_controlPoints, value);
00463         }
00464 
00465         void curveChanged ()
00466         {
00467             tesselate();
00468 
00469             m_bounds = AABB();
00470             for (ControlPoints::iterator i = m_controlPointsTransformed.begin(); i != m_controlPointsTransformed.end(); ++i) {
00471                 aabb_extend_by_point_safe(m_bounds, (*i));
00472             }
00473 
00474             m_boundsChanged();
00475             notify();
00476         }
00477 
00478         void curveChanged (const char* value)
00479         {
00480             if (string_empty(value) || !parseCurve(value)) {
00481                 m_controlPoints.resize(0);
00482             }
00483             m_controlPointsTransformed = m_controlPoints;
00484             curveChanged();
00485         }
00486         typedef MemberCaller1<CatmullRomSpline, const char*, &CatmullRomSpline::curveChanged> CurveChangedCaller;
00487 };
00488 
00489 const char* const curve_Nurbs = "curve_Nurbs";
00490 const char* const curve_CatmullRomSpline = "curve_CatmullRomSpline";
00491 
00492 #endif

Generated by  doxygen 1.6.2