| 1 | $Id: G4NURBS.txt,v 1.1 1999/01/07 16:09:09 gunter Exp $
|
|---|
| 2 | Olivier Crumeyrolle, 17th September 1996.
|
|---|
| 3 |
|
|---|
| 4 | The G4NURBS C++ class library
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 | Documentation (September 6 '96)
|
|---|
| 9 |
|
|---|
| 10 | Introduction
|
|---|
| 11 |
|
|---|
| 12 | In GEANT4, there is a need for visual representations. Non Uniform Rational
|
|---|
| 13 | B-Spline (NURBS) are an interesting choice as they allow an exact
|
|---|
| 14 | representation of conics, unlike others, and have a lot of other convenient
|
|---|
| 15 | properties. Furthermore NURBS are an industry standard in Computer Aided
|
|---|
| 16 | Design (CAD) systems.
|
|---|
| 17 |
|
|---|
| 18 | The goal of the G4NURBS C++ class library is to handle NURBS and to provide all
|
|---|
| 19 | the necessary methods so they can be succesfully used.
|
|---|
| 20 |
|
|---|
| 21 | Summary
|
|---|
| 22 |
|
|---|
| 23 | The G4NURBS class handles the data needed to define a NURBS surface,
|
|---|
| 24 | i.e. the orders of the NURBS used, the knot values and control points
|
|---|
| 25 | (explanations later).
|
|---|
| 26 |
|
|---|
| 27 | G4NURBS provides an important number of access functions to allow any graphics
|
|---|
| 28 | model (GM) to build its own NURBS. Although building the GM's NURBS with
|
|---|
| 29 | G4NURBS data (or vice versa) without any copy would be the more efficient way,
|
|---|
| 30 | different GMs typically use different data types, so copying and converting is
|
|---|
| 31 | required. For that G4NURBS provides some basic functions and also some more
|
|---|
| 32 | clever iterators to simplify the user's task.
|
|---|
| 33 |
|
|---|
| 34 | Some GMs support NURBS (OpenGL, GPHIGS), but for others G4NURBS (will) provide
|
|---|
| 35 | some adaptative tessellation functionalities, if possible as a convertion to
|
|---|
| 36 | G4Polyhedron.
|
|---|
| 37 |
|
|---|
| 38 | For the GEANT4 geometry user, G4NURBSbox, G4NURBScylinder, G4NURBStube and
|
|---|
| 39 | G4NURBStubesector are implemented.
|
|---|
| 40 |
|
|---|
| 41 | Some transformation functions (partial revolution in particular) will may be
|
|---|
| 42 | added so anyone can build almost any shape with G4NURBS, starting with some
|
|---|
| 43 | basic ones only, and without complication.
|
|---|
| 44 |
|
|---|
| 45 | If everything's OK, G4NURBS could become a nice kind of primitive.
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 |
|
|---|
| 50 | 1 Building a G4NURBS instance
|
|---|
| 51 |
|
|---|
| 52 | This section is essentialy dedicated to the GEANT4 geometry user.
|
|---|
| 53 |
|
|---|
| 54 | 1.1 From a G4VSolid to a G4NURBS
|
|---|
| 55 |
|
|---|
| 56 | 1.1.1 Box
|
|---|
| 57 |
|
|---|
| 58 | It's straightforward with G4NURBSbox. If DX, DY and DZ are the half-lengths in
|
|---|
| 59 | the X, Y an Z directions respectively, then
|
|---|
| 60 |
|
|---|
| 61 | G4NURBSbox * pmybox = new
|
|---|
| 62 | G4NURBSbox(DX, DY, DZ);
|
|---|
| 63 |
|
|---|
| 64 | builds the corresponding box. Thanks to polymorphism,
|
|---|
| 65 | this object is a G4NURBS like any other.
|
|---|
| 66 |
|
|---|
| 67 | 1.1.2 Tubs
|
|---|
| 68 |
|
|---|
| 69 | In Geant4, tubs are used to represent some sectors of tube, but also complete
|
|---|
| 70 | tubes and cylinders. To keep it simple, there is no G4NURBStubs, but a
|
|---|
| 71 | G4NURBScylinder, a G4NURBStube and a G4NURBStubesector.
|
|---|
| 72 |
|
|---|
| 73 | If RMIN, RMAX, DZ, PHI1, PHI2 are the tubs parameter (but with angles in
|
|---|
| 74 | radians), then something like
|
|---|
| 75 |
|
|---|
| 76 | G4NURBS * pmynurbs;
|
|---|
| 77 | if (RMIN != 0)
|
|---|
| 78 | {
|
|---|
| 79 | if ( ((PHI2-PHI1) >= 2*M_PI) || (PHI2==PHI1) )
|
|---|
| 80 | pmynurbs = new G4NURBStube(RMIN, RMAX, DZ);
|
|---|
| 81 | else pmynurbs = new G4NURBStubesector(RMIN, RMAX, DZ, PHI1, PHI2);
|
|---|
| 82 | }
|
|---|
| 83 | else
|
|---|
| 84 | {
|
|---|
| 85 | if ( ((PHI2-PHI1) >= 2*M_PI) || (PHI2==PHI1) )
|
|---|
| 86 | pmynurbs = new G4NURBScylinder(RMAX, DZ);
|
|---|
| 87 | else pmynurbs = new G4NURBStubesector(0.0001, RMAX, DZ, PHI1, PHI2);
|
|---|
| 88 | };
|
|---|
| 89 |
|
|---|
| 90 | builds the appropriate representation.
|
|---|
| 91 | NB: as you can see there is no sector of cylinder, so we use
|
|---|
| 92 | G4NURBStubesector(epsilon, RMAX, DZ, PHI1, PHI2). A new release will include
|
|---|
| 93 | G4NURBScylindersector one day.
|
|---|
| 94 |
|
|---|
| 95 | Note that G4NURBStubesector can in principle handle all possible tubs, (it even
|
|---|
| 96 | works with negative radius, negative length and more than two pi angle
|
|---|
| 97 | difference) but the graphics system will probably have some difficulties with
|
|---|
| 98 | the NURBS, and even if it display it, you will not like the result.
|
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 | 1.2 In general
|
|---|
| 102 |
|
|---|
| 103 | One cannot build directly a G4NURBS object. G4NURBS is just an handling class.
|
|---|
| 104 | To have some instance you must derive from G4NURBS and use one of its protected
|
|---|
| 105 | constructors in the child class constructor initialisation list. The first
|
|---|
| 106 | G4NURBS constructor is able to produce a regular knot vector for an unallocated
|
|---|
| 107 | knot vector, and the second one (the most easy to use) handles allocation of
|
|---|
| 108 | all arrays and is able to produce some "linear" but also some "circular" knots.
|
|---|
| 109 | G4NURBSbox and G4NURBStube use the second constructor and are good examples,
|
|---|
| 110 | G4NURBStubs is slightly more complex but shows how to build automatically a
|
|---|
| 111 | G4NURBS. G4NURBScylinder is the only one written with the first constructor, to
|
|---|
| 112 | provide an example. See also comments in G4NURBS.hh. This file contains in the
|
|---|
| 113 | appendix an introduction to NURBS, with some examples. You should also follow
|
|---|
| 114 | the recommendations in 4.2.4.
|
|---|
| 115 |
|
|---|
| 116 |
|
|---|
| 117 | 1.3 Future prospects
|
|---|
| 118 |
|
|---|
| 119 | A child class with an istream based constructor might be written which allows
|
|---|
| 120 | the user to load a NURBS Definition file (as the << overload currently
|
|---|
| 121 | generates them).
|
|---|
| 122 |
|
|---|
| 123 | Some transformation functions might be written in order to help the user to
|
|---|
| 124 | build a NURBS from basic one. (suggestions are welcomed)
|
|---|
| 125 |
|
|---|
| 126 | A child class G4NURBStrimmingcurve might be written with some methods to help
|
|---|
| 127 | the user to clip NURBS or to convert some boolean solids into clipped NURBS.
|
|---|
| 128 | However the GMs must support surface trimming, as it's not straightforward to
|
|---|
| 129 | generate an equivalent representation of a trimmed NURBS (set of smaller NURBS?)
|
|---|
| 130 |
|
|---|
| 131 |
|
|---|
| 132 |
|
|---|
| 133 | 2 Access functions
|
|---|
| 134 |
|
|---|
| 135 | This section will more interest the graphics model devloper.
|
|---|
| 136 |
|
|---|
| 137 | 2.1 Simple data access with and without a direction selector
|
|---|
| 138 |
|
|---|
| 139 | To retrieve NURBS simple data (order, various numbers) a first set of
|
|---|
| 140 | access functions is provided :
|
|---|
| 141 |
|
|---|
| 142 | G4int getUorder() const;
|
|---|
| 143 | G4int getVorder() const;
|
|---|
| 144 | G4int getUnbrKnots() const;
|
|---|
| 145 | G4int getVnbrKnots() const;
|
|---|
| 146 | G4int getUnbrCtrlPts() const;
|
|---|
| 147 | G4int getVnbrCtrlPts() const;
|
|---|
| 148 |
|
|---|
| 149 | where nbr is short for number and CtrlPts for control points.
|
|---|
| 150 |
|
|---|
| 151 | Another set of functions using a _selector_ is provided :
|
|---|
| 152 |
|
|---|
| 153 | G4int getorder(t_direction in_dir) const;
|
|---|
| 154 | G4int getnbrKnots(t_direction in_dir) const;
|
|---|
| 155 | G4int getnbrCtrlPts(t_direction in_dir) const;
|
|---|
| 156 |
|
|---|
| 157 | The selector in_dir is an enum in the G4NURBS scope. So the complete type name
|
|---|
| 158 | is G4NURBS::t_direction, and values are G4NURBS::U for retrieving data related
|
|---|
| 159 | to the U direction, and G4NURBS::V for V.
|
|---|
| 160 |
|
|---|
| 161 | Hence the following calls are equivalent :
|
|---|
| 162 | my_nurbs.getUorder();
|
|---|
| 163 | my_nurbs.getorder(G4NURBS::U);
|
|---|
| 164 | The first may be slightly faster than the second (cf inline code in G4NURBS.hh).
|
|---|
| 165 |
|
|---|
| 166 | G4NURBS::NofD is also defined, where NofD means nbr of directions. One could use
|
|---|
| 167 | it for loops over direction. However as enum can't be incremented this is not as
|
|---|
| 168 | useful as it could be. See the << overload in G4NURBS.cc for a loop example or
|
|---|
| 169 | the constuctors (still in G4NURBS.cc) for another example.
|
|---|
| 170 |
|
|---|
| 171 |
|
|---|
| 172 | 2.2 Access to knots and control points
|
|---|
| 173 |
|
|---|
| 174 | 2.2.1
|
|---|
| 175 | A set of basic functions is provided :
|
|---|
| 176 |
|
|---|
| 177 | G4float getfloatKnot( t_direction in_dir, t_indKnot in_index)
|
|---|
| 178 | const;
|
|---|
| 179 |
|
|---|
| 180 | G4double getdoubleKnot( t_direction in_dir, t_indKnot in_index)
|
|---|
| 181 | const;
|
|---|
| 182 |
|
|---|
| 183 | t_floatCtrlPt* getfloatCtrlPt( t_indCtrlPt in_onedimindex) const;
|
|---|
| 184 |
|
|---|
| 185 | t_floatCtrlPt* getfloatCtrlPt( t_inddCtrlPt in_Uindex,
|
|---|
| 186 | t_inddCtrlPt in_Vindex) const;
|
|---|
| 187 |
|
|---|
| 188 | t_doubleCtrlPt* getdoubleCtrlPt(t_indCtrlPts in_onedimindex) const;
|
|---|
| 189 |
|
|---|
| 190 | t_doubleCtrlPt* getdoubleCtrlPt(t_inddCtrlPts in_Uindex,
|
|---|
| 191 | t_inddCtrlPts in_Vindex) const;
|
|---|
| 192 |
|
|---|
| 193 | The first two return the in_index th knot (with a 0 based numbering, so the
|
|---|
| 194 | valid index goes from 0 to nbrKnots-1) after converting it into G4float or
|
|---|
| 195 | G4double. The four others functions do the same with control points. The
|
|---|
| 196 | returned pointer points to a brand-new allocated array with the control points
|
|---|
| 197 | coordinates. You can do what you want with it, it's _your_ copy, (non-const) and
|
|---|
| 198 | you must delete it after use. You can give the U and V index or a global index,
|
|---|
| 199 | as control points are stored U increasing first.
|
|---|
| 200 |
|
|---|
| 201 | The followings calls are equivalent :
|
|---|
| 202 | // suppose a 5 by 9 net of ctrlpts (5 along U, 9 along V)
|
|---|
| 203 | // and t_doubleCtrlPt * pmycp;
|
|---|
| 204 | pmycp = my_nurbs.getdoubleCtrlPt(3, 2);
|
|---|
| 205 | pmycp = my_nurbs.getdoubleCtrlPt(13);
|
|---|
| 206 |
|
|---|
| 207 | However, iterators are an easier way to retrieve the knots or the control points
|
|---|
| 208 | in a sequential manner.
|
|---|
| 209 |
|
|---|
| 210 | 2.2.2 Iterators
|
|---|
| 211 |
|
|---|
| 212 | Iterators are defined in the G4NURBS public scope, to avoid the global
|
|---|
| 213 | namespace pollution. Therefore their type name is G4NURBS::KnotsIterator,
|
|---|
| 214 | G4NURBS::CtrlPtsCoordsIterator, G4NURBS::CtrlPtsIterator.
|
|---|
| 215 |
|
|---|
| 216 | Iterators are independent objects : you can allocate as many iterators as you
|
|---|
| 217 | want and make them work concurrently. However the G4NURBS object MUST be defined
|
|---|
| 218 | when you use iterators over it (and must not be changed). See the Possible
|
|---|
| 219 | improvements 1.2 section for more about that.
|
|---|
| 220 |
|
|---|
| 221 | 2.2.2.1
|
|---|
| 222 | G4NURBS::KnotsIterator allows the user to retrieve knots one after the other. It
|
|---|
| 223 | can be used as follows to get all the knots along the U direction as 'float'
|
|---|
| 224 | numbers :
|
|---|
| 225 |
|
|---|
| 226 | // assuming mynurb is a G4NURBS, for instance G4NURBSbox my_nurb(1,2,3);
|
|---|
| 227 | G4float * my_array, * my_float_p;
|
|---|
| 228 | my_float_p = my_array = new float [my_nurb.getnbrKnots(G4NURBS::U)];
|
|---|
| 229 | G4NURBS::KnotsIterator my_iterator(my_nurb, G4NURBS::U);
|
|---|
| 230 | while (my_iterator.pick(my_float_p++));
|
|---|
| 231 |
|
|---|
| 232 | Then my_array contain all the knots, and my_float_p point just after the array.
|
|---|
| 233 | The trick is that pick functions return false when they pick the last knot.
|
|---|
| 234 |
|
|---|
| 235 | The constructor has an optional third argument, in_startIndex, preseted to zero.
|
|---|
| 236 | It's possible to give another value to retrieve half of the knots for instance.
|
|---|
| 237 | (will probably be used in splitting)
|
|---|
| 238 |
|
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
|
|---|
| 242 | 2.2.2.2
|
|---|
| 243 | G4NURBS::CtrlPtsCoordsIterator is very similar to the Knots one.
|
|---|
| 244 | The control points are retrieved coordinate after coordinate,
|
|---|
| 245 | and, if we note i the index along U and j the one along V,
|
|---|
| 246 | control points P_i_j themselves are obtained i increasing first, j after :
|
|---|
| 247 | P_1_1, P_2_1, P_3_1, P_4_1, ....., P_1_2, P_2_2, P_3_2, P_4_2, ....
|
|---|
| 248 |
|
|---|
| 249 | G4float * my_array, * my_float_p;
|
|---|
| 250 | my_float_p = my_array = new float [my_nurb.gettotalnbrCtrlPts()
|
|---|
| 251 | *G4NURBS::NofC*sizeof(float)];
|
|---|
| 252 | G4NURBS::CtrlPtsCoordsIterator my_iterator(my_nurb);
|
|---|
| 253 | while (my_iterator.pick(my_float_p++));
|
|---|
| 254 |
|
|---|
| 255 |
|
|---|
| 256 | 2.2.2.3
|
|---|
| 257 | G4NURBS::CtrlPtsIterator work control point by control point, instead of control
|
|---|
| 258 | point coordinate by control point coordinate. Remember that control points are
|
|---|
| 259 | given U index increasing first, V after. The << overload in G4NURBS.cc contains
|
|---|
| 260 | an exemple where the retrieved control point is used immediately.
|
|---|
| 261 |
|
|---|
| 262 |
|
|---|
| 263 | 2.2.3
|
|---|
| 264 |
|
|---|
| 265 | Some "complete-copy" functions are also provided.
|
|---|
| 266 |
|
|---|
| 267 | G4float * getfloatAllKnots(t_direction in_dir) const;
|
|---|
| 268 | G4double * getdoubleAllKnots(t_direction in_dir) const;
|
|---|
| 269 | G4float * getfloatAllCtrlPts() const;
|
|---|
| 270 | G4double * getdoubleAllCtrlPts() const;
|
|---|
| 271 |
|
|---|
| 272 | These functions return a pointer over a new array with all the knots or control
|
|---|
| 273 | points copied. You do not control the allocation nor the copy, but you own the
|
|---|
| 274 | result and will have to delete it.
|
|---|
| 275 |
|
|---|
| 276 | They are more easy to use than iterators, but less flexible.
|
|---|
| 277 |
|
|---|
| 278 | Be careful with these functions, as _you_ choose the type, whereas with
|
|---|
| 279 | iterators the compiler choose the good pick function for you. If G4double or
|
|---|
| 280 | G4float change, you must change your code, instead of just recompile it.
|
|---|
| 281 |
|
|---|
| 282 |
|
|---|
| 283 |
|
|---|
| 284 |
|
|---|
| 285 | 3 Use in GEANT4
|
|---|
| 286 |
|
|---|
| 287 | 3.1 NURBS manipulations
|
|---|
| 288 |
|
|---|
| 289 | The public interface of G4NURBS does not allow the user to modify a NURBS. The
|
|---|
| 290 | user is expected to create G4NURBS via child classes. Splitting, tesslation, or
|
|---|
| 291 | other non-conservative processes should occur only as a conversion to a child
|
|---|
| 292 | class, via its constructor, or eventually with a conversion operator.
|
|---|
| 293 |
|
|---|
| 294 | e.g.
|
|---|
| 295 |
|
|---|
| 296 | G4NURBSashape mynurbs(foo, goo, hoo);
|
|---|
| 297 |
|
|---|
| 298 | // for splitting
|
|---|
| 299 | G4NURBSsplit mypieceofnurbs(mynurbs, splitdirection, splitpointvalue);
|
|---|
| 300 |
|
|---|
| 301 | // for tessellation, if
|
|---|
| 302 | // class G4PolyhedronedNURBS : public G4Polyhedron
|
|---|
| 303 | // has a constructor G4PolyhedronedNURBS(const G4NURBS &, G4Float tolerance)
|
|---|
| 304 | G4PolyhedronedNURBS mytessellatednurbs(mynurbs, thetolerance);
|
|---|
| 305 |
|
|---|
| 306 | // (a multiple inheritance could be used to have a "dual-face"
|
|---|
| 307 | // object Polyhedron/NURBS, with the advantage of keeping
|
|---|
| 308 | // a NURBS and its tessellation together, and the disadvantge
|
|---|
| 309 | // of duplicating the original NURBS into this child)
|
|---|
| 310 |
|
|---|
| 311 | The resulting instance is not necessary constant, G4NURBSsplit could provide
|
|---|
| 312 | some sub-splitting and refinement methods that act on itself.
|
|---|
| 313 |
|
|---|
| 314 |
|
|---|
| 315 | 3.2 Copying policy
|
|---|
| 316 |
|
|---|
| 317 | A copy constructor is provided, but in the private part. A warning message
|
|---|
| 318 | ( "WARNING: G4NURBS::G4NURBS(const G4NURBS &) used" )
|
|---|
| 319 | is printed on cerr each time the copy constructor is called.
|
|---|
| 320 |
|
|---|
| 321 | As long as there is no sophisticated memory management scheme that reduce
|
|---|
| 322 | useless duplications, copying should be avoided. We have already to duplicate
|
|---|
| 323 | data for the GM, once is enough.
|
|---|
| 324 |
|
|---|
| 325 |
|
|---|
| 326 |
|
|---|
| 327 | 4 Possible internal improvements that could have consequences
|
|---|
| 328 |
|
|---|
| 329 | 4.1 Memory management :
|
|---|
| 330 |
|
|---|
| 331 | 4.1.1 G4NURBS use the minimal memory management scheme possible. Control
|
|---|
| 332 | points, knots, are stored in basic arrays. NURBS characteristics are
|
|---|
| 333 | stored in simple structure. All those internal data could be handled in
|
|---|
| 334 | protected classes with ad hoc constructors, which would be more
|
|---|
| 335 | reliable. The G4NURBS copy constructor would be more elegant. However
|
|---|
| 336 | performance may decrease. This point is related to typing. See 2.1.
|
|---|
| 337 |
|
|---|
| 338 | 4.1.2 Some reference counting facilities should be added for internal arrays
|
|---|
| 339 | so that iterators could correctly work after a G4NURBS is
|
|---|
| 340 | deleted/changed. This point could be solved with 1.1 in a elegant way.
|
|---|
| 341 | We should at least warn the user when a nurbs is deleted before the
|
|---|
| 342 | corresponding iterators. However if we want to do the things in a good
|
|---|
| 343 | way references counters must be associated to arrays. Once again 1.1 is
|
|---|
| 344 | the solution for that. To put references as members, we need the future
|
|---|
| 345 | "mutable" keyword planed by the ANSI C++ committee, or the counting will
|
|---|
| 346 | be uncompatible with const instances.
|
|---|
| 347 |
|
|---|
| 348 | 4.2 Internal data type
|
|---|
| 349 |
|
|---|
| 350 | 4.2.1 Knots and control points types are just typedefs, idem for index types.
|
|---|
| 351 | They could be strong types (i.e. classes), but performance costs will
|
|---|
| 352 | may be significant.
|
|---|
| 353 |
|
|---|
| 354 | 4.2.2 enum type are useful to enforce the user to do good things (like using
|
|---|
| 355 | G4NURBS::U instead of 0), but are not really convenient for loops. Some
|
|---|
| 356 | internal alias should be defined to allow some more easy loops. [this
|
|---|
| 357 | concern the geom user only if he/she writes some G4NURBS children]
|
|---|
| 358 |
|
|---|
| 359 |
|
|---|
| 360 |
|
|---|
| 361 | 4.2.3 As the user doesn't know the internal data type, it could be possible
|
|---|
| 362 | for G4NURBS to adapt itself to the GM currently used, so this GM could
|
|---|
| 363 | use directly the G4NURBS data. This adaptation concern the control
|
|---|
| 364 | points storage order and knot values (some fast algorithms exists for
|
|---|
| 365 | knots which differe of 0 or 1 only). It would be necessary to write some
|
|---|
| 366 | inline functions for control points initialization that spare the child
|
|---|
| 367 | class writer to know the storage order, see 4.2.4. But once again, what
|
|---|
| 368 | about performance ? The G4NURBS constructors and the initializations
|
|---|
| 369 | functions used in child constructors would have to change their target
|
|---|
| 370 | type, and thus we need a very clever scheme to be compatible with the
|
|---|
| 371 | use of different GMs in the same time.
|
|---|
| 372 |
|
|---|
| 373 | 4.2.4 For the momment the control points storage order is publicly known, that
|
|---|
| 374 | could change, with a formal class level between G4NURBS and
|
|---|
| 375 | G4NURBSashape children. Calls like CP(mpCtrlPts[..], .... will have to
|
|---|
| 376 | be rewritten; a tool will may be provided to automaticaly do that. Use
|
|---|
| 377 | if possible explicit U & V index values like
|
|---|
| 378 |
|
|---|
| 379 | CP(mpCtrlPts[to1d(U_index, V_index)], .......
|
|---|
| 380 |
|
|---|
| 381 | [this concerns the geometry user only if he/she writes some
|
|---|
| 382 | G4NURBSashape].
|
|---|
| 383 |
|
|---|
| 384 |
|
|---|
| 385 | 4.3 External interfacing types
|
|---|
| 386 |
|
|---|
| 387 | 4.3.1 For the moment G4int, G4double, G4float, are just alias for int, double,
|
|---|
| 388 | float. These G4 types are used in the G4NURBS interface (the public part
|
|---|
| 389 | of G4NURBS). If their definitions are changed, the significance of the
|
|---|
| 390 | access functions will change too, user should take care about that when
|
|---|
| 391 | using access functions with some others types (e.g. GLfloat ) In a more
|
|---|
| 392 | general way this type interfacing problem will have to be solved at a
|
|---|
| 393 | general level as different GS are used. For the moment G4Float is used
|
|---|
| 394 | internally and interfaced to G4float and G4double.
|
|---|
| 395 |
|
|---|
| 396 | 4.3.2 Child constructors take all their arguments as G4double. This may have
|
|---|
| 397 | to change, depending on the exact work that G4VSolid children have to
|
|---|
| 398 | do. Length arguments should be unsigned (but unsigned G4double is
|
|---|
| 399 | illegal), and angles in radians should have a different type from those
|
|---|
| 400 | in degrees.
|
|---|
| 401 |
|
|---|
| 402 |
|
|---|
| 403 | 4.4 Names
|
|---|
| 404 |
|
|---|
| 405 | 4.4.1 G4NURBS could become G4VNurbs, and G4NURBSbox could become G4NurbsBox.
|
|---|
| 406 |
|
|---|
| 407 |
|
|---|
| 408 | 5 Prospects
|
|---|
| 409 |
|
|---|
| 410 |
|
|---|
| 411 | 5.1 For NURBS in general
|
|---|
| 412 |
|
|---|
| 413 | NURBS are likely to become more and more widely supported by software, but also
|
|---|
| 414 | by hardware. Nvidia NV1 PCI card for PCs already accelerate quadratic curves
|
|---|
| 415 | (and may be more) . The new SPARCstation 20TurboZX provide dynamic tessellation
|
|---|
| 416 | for NURBS in firmware.
|
|---|
| 417 |
|
|---|
| 418 | 5.2 Births
|
|---|
| 419 |
|
|---|
| 420 | G4NURBS will probably have others children in the future, in particular for
|
|---|
| 421 | splitting. However the object oriented programming allows anyone to create some
|
|---|
| 422 | child classes. Don't hesitate to enlarge the family.
|
|---|
| 423 |
|
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 |
|
|---|
| 427 |
|
|---|
| 428 |
|
|---|
| 429 |
|
|---|
| 430 | Appendix
|
|---|
| 431 |
|
|---|
| 432 | Non Uniform Rational B-Spline (NURBS).
|
|---|
| 433 |
|
|---|
| 434 | 1 About Representation
|
|---|
| 435 |
|
|---|
| 436 | A curve or a surface are mathematicaly a set of points. However the number of
|
|---|
| 437 | points is infinite, what is not convenient at all. We need a more operational
|
|---|
| 438 | way for describing the set of points. Here we use a parametric representation :
|
|---|
| 439 | the curve is described by a function of 1 real parameter t : C(t), the surface
|
|---|
| 440 | with two parameters called u and v : S(u,v). As the parameter(s) go(es) from a
|
|---|
| 441 | minimal value to a maximal one, the function describes the curve/surface. Now we
|
|---|
| 442 | need a representation for this function itself. To achieve this, the function is
|
|---|
| 443 | projected over a set of basis functions. Of course the kind of functions we can
|
|---|
| 444 | represent in this way is determined by the kind of basis functions used. We will
|
|---|
| 445 | work with real-valued polynomial function, as they are easy to represent, can
|
|---|
| 446 | approximate any continuous function as well as we want and are convenient in
|
|---|
| 447 | general. Once basis functions are chosen, the kind of 'coordinates' that a
|
|---|
| 448 | function will have over such a basis is determined : the function describe a set
|
|---|
| 449 | of point whereas basis functions chosen are real-valued, so the 'coordinates'
|
|---|
| 450 | are necessary some points, called control points, noted P_i (or P_{i,j}),
|
|---|
| 451 | represented by their position-vector, and multipied by the basis functions.
|
|---|
| 452 |
|
|---|
| 453 | A curve will then be expressed as C(t) = sum(i = 1, n) { P_i * B_i(t) }
|
|---|
| 454 | where B_i is the ith basis functions.
|
|---|
| 455 | A surface could be expressed as S(u,v) = sum(i = 1, n) { P_i * B_i(u,v) },
|
|---|
| 456 | but we will use a more easy scheme, explained in 2.5
|
|---|
| 457 |
|
|---|
| 458 | An interesting point is that if T is a linear transformation,
|
|---|
| 459 | T[C(t)] = sum(i = 1, n) { T[P_i] * B_i(t) }
|
|---|
| 460 |
|
|---|
| 461 | 2 B-Spline curves and surfaces
|
|---|
| 462 |
|
|---|
| 463 | 2.1 B-Spline basis functions
|
|---|
| 464 |
|
|---|
| 465 | They are defined as following :
|
|---|
| 466 |
|
|---|
| 467 | B_{i,1} = 1 if t_i <= t <= t_{i+1}, 0 otherwise
|
|---|
| 468 |
|
|---|
| 469 | B_{i,k}(t) = ((t-t_i)/(t_{i+k-1}-t_i))*B_{i,k-1}(t)
|
|---|
| 470 | +
|
|---|
| 471 | ((t_{i+k}-t)/(t_{i+k}-t_{i+1}))*B_{i+1,k-1}
|
|---|
| 472 | i goes from 1 to n, the number of basis functions.
|
|---|
| 473 | k is the order of the B-Spline.
|
|---|
| 474 | (t_i)_{1<=i<=n+k} a sequence of non-decreasing values called knots that defines
|
|---|
| 475 | the B_{i,k}, and is globaly designed as the knot vector.
|
|---|
| 476 | The B-Spline is said to be uniform if t_{i+1}-t_i = d > 0 for any i, non-uniform
|
|---|
| 477 | (NU) otherwise, with the convention 0/0 = 0.
|
|---|
| 478 |
|
|---|
| 479 | We concentrate first on uniform B-Splines (UBS)
|
|---|
| 480 |
|
|---|
| 481 |
|
|---|
| 482 | 2.2 Some UBS properties
|
|---|
| 483 |
|
|---|
| 484 | The recursive relation defines B_{i,k} as a linear interpolation between
|
|---|
| 485 | B_{i,k-1} and B_{i+1,k-1}. Thus B_{i,k} is a polynomial of degree k-1,
|
|---|
| 486 | strictly positive in [t_i, t_{i+k}], nul elsewhere. For a given t / t_i <= t <
|
|---|
| 487 | t_{i+1}, only B_{i-k+1,k} to B_{i,k} are non-nul. The (endknot-startknot)
|
|---|
| 488 | divisors in the relation imply that sum(i = 1,n){B_{i,k}(t)} = 1.
|
|---|
| 489 |
|
|---|
| 490 | [picture of UBS basis functions from k=1 to 2 or 3]
|
|---|
| 491 |
|
|---|
| 492 |
|
|---|
| 493 | 2.3 Change of basis : the Oslo algorithm
|
|---|
| 494 |
|
|---|
| 495 | It is possible to increase the number of basis functions used.
|
|---|
| 496 |
|
|---|
| 497 | If (t_i)_{1<=i<=n+k} is the old knot vector and (t'_i)_{1<=i<=n'+k} the new
|
|---|
| 498 | one, then P'_i = sum (j = 1, n) { alpha_{i,j,k} * P_j }
|
|---|
| 499 |
|
|---|
| 500 | where alpha_{i,j,k} is given by a recursive relations similar to B_i,k ones :
|
|---|
| 501 |
|
|---|
| 502 | alpha_{i,j,k} = ((t'_{j+k-1} - t_i) / (t_{i+k-1} - t_i)) * alpha_{i,j,k-1}
|
|---|
| 503 | + ((t_{i+k} - t'_{j+k-1}) / (t_{i+k} - t_{i+1})) * alpha_{i+1,j,k-1}
|
|---|
| 504 |
|
|---|
| 505 | The Oslo algorithm is not used in the G4NURBS class library at the moment,
|
|---|
| 506 | but it will when splitting functionalities will be added.
|
|---|
| 507 |
|
|---|
| 508 | 2.4 UBS curves
|
|---|
| 509 |
|
|---|
| 510 | Once we have defined the basis function, a curve is expressed as following :
|
|---|
| 511 |
|
|---|
| 512 | C(t) = sum(i = 1, n) { P_i * B_{i,k}(t) }
|
|---|
| 513 |
|
|---|
| 514 | where P_i are the control points and k the order.
|
|---|
| 515 | (This maps [t_min, t_max] to the curve.)
|
|---|
| 516 |
|
|---|
| 517 | If we note C^n the class of functions that are continuous up to the nth
|
|---|
| 518 | derivative (included), then for t_i < t < t_{i+1}, C(t) is C^infinite, and at t
|
|---|
| 519 | = t_i, C(t) is C^{k-2}.
|
|---|
| 520 |
|
|---|
| 521 | [pictures ?]
|
|---|
| 522 |
|
|---|
| 523 | If a control points is repeated k-1 time or more, the curve goes through it.
|
|---|
| 524 |
|
|---|
| 525 |
|
|---|
| 526 | 2.5 UBS surfaces
|
|---|
| 527 |
|
|---|
| 528 | Surfaces are expressed as the tensor product of two curves :
|
|---|
| 529 |
|
|---|
| 530 | S(u,v) = sum(i=1,n) sum(j=1,m) { P_{i,j}*B_{i,k}(u)*B_{j,l}(v) }
|
|---|
| 531 |
|
|---|
| 532 | where P_{i,j} is the net of control points.
|
|---|
| 533 | (This maps [u_min,u_max] x [v_min,v_max] to the surface.)
|
|---|
| 534 |
|
|---|
| 535 |
|
|---|
| 536 | This is more convenient than starting from 2D splines, or similar functions,
|
|---|
| 537 | but you must keep in mind that with such a scheme the curve along one direction
|
|---|
| 538 | must be sufficently complexe to handle the shape complexity all along this
|
|---|
| 539 | direction. However it's sometime possible to choose a direction for a parameter
|
|---|
| 540 | in such a way that the surface is more simple along this direction.
|
|---|
| 541 |
|
|---|
| 542 |
|
|---|
| 543 | 2.6 Choice of parameter domain
|
|---|
| 544 |
|
|---|
| 545 | In the G4NURBS class library, the default is zero as the minimal parameter
|
|---|
| 546 | value, one for the maximal, and t_{i+1}-t_i = ( 0 or constant) ). However
|
|---|
| 547 | examples in section 4 will use t_i = integer for non-coincident knots, as it's
|
|---|
| 548 | more legible.
|
|---|
| 549 |
|
|---|
| 550 |
|
|---|
| 551 |
|
|---|
| 552 | 3 NURBS curves and surfaces
|
|---|
| 553 |
|
|---|
| 554 | 3.1 NU
|
|---|
| 555 |
|
|---|
| 556 | As previously said, the knots interval can vary. As we still impose t_{i+1} >=
|
|---|
| 557 | t_i, the limit case is t_{i+1} = t_i. In such a case, B_{i,1} is reduced to a
|
|---|
| 558 | point, B_{i,2} and B_{i+1,2} overlap on a knot segment reduced to a point, and
|
|---|
| 559 | at this point C(t) will be only C^{k-3}, making the curve less smooth. More
|
|---|
| 560 | generally if a knot appears M times, C(t) is C^{k-M-1}. If M = k-1, C(t) is
|
|---|
| 561 | C^0, the curve is still continuous but can have a corner at t = t_i = ... =
|
|---|
| 562 | t_{i+k-2} and go through the corresponding control point P_{i-1}, thanks to
|
|---|
| 563 | B_{i-1,k} that cover t_i to t_{i+k-2,k}. If M = k, the curve is no longer
|
|---|
| 564 | continous : all the basis B-Splines from B_{i-k,k} to B_{i-1,k} stop at t = t_i
|
|---|
| 565 | = ... = t_{i+k-1} and the curve stop a the corresponding control point
|
|---|
| 566 | P_{i-1}. If there are other knots and control points after, the curve restarts
|
|---|
| 567 | from next control point P_i, as B_{i,k} to B_{i+k-1,k} start at t_{i+k-1} = t'.
|
|---|
| 568 |
|
|---|
| 569 |
|
|---|
| 570 | 3.2 R
|
|---|
| 571 |
|
|---|
| 572 | The control points are no longer usual position vectors in the plane
|
|---|
| 573 | (isomorphic with R^2) or in the space (isomorphic with R^3) but an element of
|
|---|
| 574 | the projective space P^n, which as one dimension more that the corresponding
|
|---|
| 575 | usual space. P^n, isomorphic with R^n, is associated with the usual space
|
|---|
| 576 | isomorphic with R^{n-1} : (x, y, w) in P^3 corresponds to (x/w, y/w) in R^2,
|
|---|
| 577 | (x, y, z, w) in P^4 corresponds to (x/w, y/w, z/w) in R^3 and so on. If w = 0,
|
|---|
| 578 | the point goes to infinity, defining a direction. Thus working in the
|
|---|
| 579 | projective space allows us to work with points and vectors, and all affine
|
|---|
| 580 | transformations in the usual space can be combined into a linear ones in the
|
|---|
| 581 | projective space, as well as projections. The coordinates in P^n are said to be
|
|---|
| 582 | homogeneous or rational, and items expressed with such coordinates are
|
|---|
| 583 | highlighted by an ^h.
|
|---|
| 584 |
|
|---|
| 585 |
|
|---|
| 586 | 3.3 NU R BS
|
|---|
| 587 |
|
|---|
| 588 | NURBS are NUBS in the projective space. Hence to transform a NURBS, one just
|
|---|
| 589 | has to transform the control points, even for projections.
|
|---|
| 590 |
|
|---|
| 591 | The last homogeneous coordinate w is called the "weight".
|
|---|
| 592 |
|
|---|
| 593 | 3.4 NURBS curves
|
|---|
| 594 |
|
|---|
| 595 | If P_i = (x_i, y_i), then P^h_i = (w_i*x_i, w_i*y_i, w_i)
|
|---|
| 596 | and a curve is expressed in P^3 by
|
|---|
| 597 |
|
|---|
| 598 | C^h(t) = sum(i = 1, n) { P^h_i * B_{i,k}(t) }
|
|---|
| 599 |
|
|---|
| 600 | and in R^2 by
|
|---|
| 601 |
|
|---|
| 602 | C(t) = sum(i = 1, n){ w_i* P_i * B_{i,k}(t) } / sum(i = 1, n){ w_i* B_{i,k}(t) }
|
|---|
| 603 |
|
|---|
| 604 |
|
|---|
| 605 | 3.5 NURBS surfaces
|
|---|
| 606 |
|
|---|
| 607 | If P_i = (x_i, y_i, z_i), then P^h_i = (w_i*x_i, w_i*y_i, w_i*z_i, w_i)
|
|---|
| 608 | and a surface is expressed in P^4 by
|
|---|
| 609 |
|
|---|
| 610 | S^h(u,v) = sum(i=1,n) sum(j=1,m) { P^h_{i,j} * B_{i,k}(u) * B_{j,l}(v) }
|
|---|
| 611 |
|
|---|
| 612 | and in R^3 by
|
|---|
| 613 |
|
|---|
| 614 | S(u,v) = sum(i=1,n) sum(j=1,m) { w_{i,j} * P_{i,j} * B_{i,k}(u) * B_{j,l}(v) }
|
|---|
| 615 | /sum(i=1,n) sum(j=1,m) { w_{i,j} * B_{i,k}(u) * B_{j,l}(v) }
|
|---|
| 616 |
|
|---|
| 617 |
|
|---|
| 618 |
|
|---|
| 619 | 3.6 NURBS advantages/disadvantages
|
|---|
| 620 |
|
|---|
| 621 | 3.6.1 Advantages :
|
|---|
| 622 |
|
|---|
| 623 | Common representation for shapes, even with discontinuities.
|
|---|
| 624 |
|
|---|
| 625 | Exact representation of conics section (and for all shapes that have a
|
|---|
| 626 | polynomial parametrisation in the projective space).
|
|---|
| 627 |
|
|---|
| 628 | Invariant under affine and perspective tranformations.
|
|---|
| 629 |
|
|---|
| 630 | Flexible (lot of manipulations possible, cf 4).
|
|---|
| 631 |
|
|---|
| 632 | Generalization of others B-splines / Bezier shapes.
|
|---|
| 633 |
|
|---|
| 634 | 3.6.2 Drawbacks :
|
|---|
| 635 |
|
|---|
| 636 | Today need some calculations to be converted to triangles and/or
|
|---|
| 637 | quadrilaterals as these are the only kind of shapes directly handled
|
|---|
| 638 | by graphics systems at low-level (OpenGL is able to do that but it
|
|---|
| 639 | really generate too many triangles/squares).
|
|---|
| 640 |
|
|---|
| 641 | Extra storage for simple shapes.
|
|---|
| 642 |
|
|---|
| 643 | We must choose a good parameterisation.
|
|---|
| 644 |
|
|---|
| 645 |
|
|---|
| 646 |
|
|---|
| 647 |
|
|---|
| 648 | 4 Examples of NURBS
|
|---|
| 649 |
|
|---|
| 650 | 4.1 Linear
|
|---|
| 651 |
|
|---|
| 652 | With 2.1 definition, linear B-Spline are order 2 : k = 2.
|
|---|
| 653 | All the weigths are equal to ones in what follows.
|
|---|
| 654 |
|
|---|
| 655 | 4.1.1 Segment
|
|---|
| 656 |
|
|---|
| 657 | We want a strait line from P_1 to P_2. To start the curve at P_1, we need a knot
|
|---|
| 658 | repeated k times at the begining and at the end of the knot vector. Thus the
|
|---|
| 659 | knot vector looks like { 0 0 ... 1 1 }. Do we need more than four knots ? No,
|
|---|
| 660 | two control points, a second order NURBS, 2 + 2 = 4, number of knots. (Remember
|
|---|
| 661 | (t_i)_{1<=i<=n+k})
|
|---|
| 662 |
|
|---|
| 663 | 4.1.2 Polyline
|
|---|
| 664 |
|
|---|
| 665 | We could just put some lines in such a way that they connect each other in a
|
|---|
| 666 | head to tail fashion,
|
|---|
| 667 |
|
|---|
| 668 | { 0 0 1 1 }
|
|---|
| 669 | [ P_1, P_2 ]
|
|---|
| 670 | Set P_3 = P_2
|
|---|
| 671 | { 0 0 1 1 }
|
|---|
| 672 | [ P_3, P_4 ]
|
|---|
| 673 | Set P_5 = P_4
|
|---|
| 674 | { 0 0 1 1 }
|
|---|
| 675 | [ P_5, P_6 ]
|
|---|
| 676 |
|
|---|
| 677 | and union them in one NURBS :
|
|---|
| 678 |
|
|---|
| 679 | { 0 0 1 1 2 2 3 3 }
|
|---|
| 680 | [ P_1, P_2, P_3, P_4, P_5, P_6 ] still with P_3 = P_2 and P_5 = P_4.
|
|---|
| 681 |
|
|---|
| 682 | Then we can simplify the NURBS :
|
|---|
| 683 |
|
|---|
| 684 | { 0 0 1 2 3 3 }
|
|---|
| 685 | [ P_1, P_3, P_4, P_6 ]
|
|---|
| 686 |
|
|---|
| 687 |
|
|---|
| 688 | 4.1.3 Square
|
|---|
| 689 |
|
|---|
| 690 | If P_1, P_2, P_3, P_4 are the four corners, we can do a NURBS with
|
|---|
| 691 | a polyline that starts and stop at P_1 :
|
|---|
| 692 |
|
|---|
| 693 | { 0 0 1 2 3 4 4 }
|
|---|
| 694 | [ P_1 P_2 P_3 P_4 P_1 ]
|
|---|
| 695 |
|
|---|
| 696 |
|
|---|
| 697 | 4.1.4 Box
|
|---|
| 698 |
|
|---|
| 699 | If we take a square and move it (=extrude) along a perpendicular edge, we get a
|
|---|
| 700 | box which lack to faces, the two ones that are perpendicular to the edge along
|
|---|
| 701 | which we extruded the square. Note that if you change the order in which you are
|
|---|
| 702 | considering the tensor product, this surface is a segment (the edge) moved along
|
|---|
| 703 | a square.
|
|---|
| 704 |
|
|---|
| 705 | { 0 0 1 2 3 4 4 } by
|
|---|
| 706 |
|
|---|
| 707 | [ P_1 P_2 P_3 P_4 P_1 ] { 0 0
|
|---|
| 708 | [ P'_1 P'_2 P'_3 P'_4 P'_1 ] 1 1 }
|
|---|
| 709 |
|
|---|
| 710 | To close the sides, we repeat the extremeties,
|
|---|
| 711 |
|
|---|
| 712 | { 0 0 1 2 3 4 4 } by
|
|---|
| 713 |
|
|---|
| 714 | [ P_1 P_2 P_3 P_4 P_1 ] { 0 0
|
|---|
| 715 | [ P_1 P_2 P_3 P_4 P_1 ] 1
|
|---|
| 716 | [ P'_1 P'_2 P'_3 P'_4 P'_1 ] 2
|
|---|
| 717 | [ P'_1 P'_2 P'_3 P'_4 P'_1 ] 3 3 }
|
|---|
| 718 |
|
|---|
| 719 | and then reduce the first and last square to a line or a point.
|
|---|
| 720 | For instance if P_0 is the center of the P_i side and P'_0 the one of the P'_i,
|
|---|
| 721 |
|
|---|
| 722 | { 0 0 1 2 3 4 4 } by
|
|---|
| 723 |
|
|---|
| 724 | [ P_0 P_0 P_0 P_0 P_0 ] { 0 0
|
|---|
| 725 | [ P_1 P_2 P_3 P_4 P_1 ] 1
|
|---|
| 726 | [ P'_1 P'_2 P'_3 P'_4 P'_1 ] 2
|
|---|
| 727 | [ P'_0 P'_0 P'_0 P'_0 P'_0 ] 3 3 }
|
|---|
| 728 |
|
|---|
| 729 | (Put differently, we take half of a rectangle and "rotate" it along a square.)
|
|---|
| 730 |
|
|---|
| 731 | The G4NURBSbox use something like
|
|---|
| 732 |
|
|---|
| 733 | { 0 0 1 2 3 4 4 } by
|
|---|
| 734 |
|
|---|
| 735 | [ P_1 P_1 P_4 P_4 P_1 ] { 0 0
|
|---|
| 736 | [ P_1 P_2 P_3 P_4 P_1 ] 1
|
|---|
| 737 | [ P'_1 P'_2 P'_3 P'_4 P'_1 ] 2
|
|---|
| 738 | [ P'_1 P'_1 P'_4 P'_4 P'_1 ] 3 3 }
|
|---|
| 739 |
|
|---|
| 740 | rectangles reduced to lines, to avoid a "star" effect on display.
|
|---|
| 741 |
|
|---|
| 742 |
|
|---|
| 743 | 4.1.4 Trap
|
|---|
| 744 |
|
|---|
| 745 | There is no realy difference with the box. One just have to check
|
|---|
| 746 | that P_i and P'_i are on the same edge, or the trap will be twisted.
|
|---|
| 747 |
|
|---|
| 748 |
|
|---|
| 749 |
|
|---|
| 750 |
|
|---|
| 751 | 4.2 Quadratic :
|
|---|
| 752 |
|
|---|
| 753 | Quadratic B-Splines are order 3 : k = 3.
|
|---|
| 754 |
|
|---|
| 755 |
|
|---|
| 756 | 4.2.1 Arc
|
|---|
| 757 |
|
|---|
| 758 | We start at P_1 = (1,0) in R^2, and stop at P_3 = ( cos phi, sin phi ).
|
|---|
| 759 | With the knot vector { 0 0 0 1 1 1 }, we just need another control point, P_2.
|
|---|
| 760 | P_2 defines with P_1 the tangent at P_1, and with P_2 the tangent at P_2,
|
|---|
| 761 | thus P_2 is at ( 1, tan phi/2 ) and its weight is not 1, unlike P_1 and P_3,
|
|---|
| 762 | but cos phi/2.
|
|---|
| 763 |
|
|---|
| 764 |
|
|---|
| 765 | 4.2.2 Circle
|
|---|
| 766 |
|
|---|
| 767 | To avoid infinite values, a circle is made by many arcs, for instance
|
|---|
| 768 | three 120 degrees arcs or four 90 degrees arcs. They are joined and simplified
|
|---|
| 769 | as for the polyline.
|
|---|
| 770 |
|
|---|
| 771 | ex:
|
|---|
| 772 | the circle used in G4NURBScylinder is made by four 90 degree arc :
|
|---|
| 773 | (s = sqrt(2)/2)
|
|---|
| 774 |
|
|---|
| 775 | { 0 0 0 1 1 2 2 3 3 4 4 4 }
|
|---|
| 776 | [ 1,0,1 s,s,s 0,1,1 -s,s,s -1,0,1 -s,-s,s -1,0,1 -s,s,s 1,0,1 ]
|
|---|
| 777 |
|
|---|
| 778 |
|
|---|
| 779 | 4.2.3 Cylinder
|
|---|
| 780 |
|
|---|
| 781 | We build a cylinder from the circle as we made the box from the square :
|
|---|
| 782 | extrusion + closing
|
|---|
| 783 |
|
|---|
| 784 |
|
|---|
| 785 | 4.2.3 Tube
|
|---|
| 786 |
|
|---|
| 787 | The tube is obtained by revolving a rectangle around the tube axis.
|
|---|
| 788 |
|
|---|
| 789 |
|
|---|
| 790 |
|
|---|
| 791 |
|
|---|
| 792 |
|
|---|
| 793 | For suggestion/change/English corrections : contact me or e-mail (via
|
|---|
| 794 | olivierc@h2.ph.man.ac.uk)
|
|---|
| 795 | ( I'm sure it needs some English corrections )
|
|---|
| 796 |
|
|---|