pgl
PrimitiveOpenGL3Dprimitivelibrary
primitive.h
Go to the documentation of this file.
1 
22 #ifndef PGL_PRIMITIVE_H_
23 #define PGL_PRIMITIVE_H_
24 
25 #include "pgl.h"
26 
27 // Must be divisible by 4
28 #define FACETS 20
29 
30 namespace pgl {
31 
43 class Primitive : public Object
44 {
45  public:
47 
48  protected:
49  GLuint list_;
50 
51  public:
56  Primitive() : color(1, 1, 1)
57  {
58  list_ = glGenLists(1);
59  }
60 
61  virtual ~Primitive()
62  {
63  glDeleteLists(list_, 1);
64  }
65 
67  virtual void draw()
68  {
69  glColor3d(color.x, color.y, color.z);
70 
71  glPushMatrix();
72  glMultMatrixd(transform.data);
73 
74  glCallList(list_);
75  for (size_t ii=0; ii != children.size(); ++ii)
76  children[ii]->draw();
77  glPopMatrix();
78  }
79 
80  protected:
88  double align(const Vector3 &start, const Vector3 &end)
89  {
90  Vector3 vec = end-start;
91  double len = vec.norm();
92  vec = vec / len;
93 
94  double angle = acos(vec.z);
95  Vector3 axis{-vec.y, vec.x, 0};
96 
97  transform = Transform(axis, angle, start)*Translation({0, 0, len/2});
98 
99  return len;
100  }
101 
103  virtual void normal(const Vector3 &v)
104  {
105  Vector3 n = v/v.normsq();
106 
107  glNormal3d(n.x, n.y, n.z);
108  }
109 
111  virtual void vertex(const Vector3 &v)
112  {
113  glVertex3d(v.x, v.y, v.z);
114  }
115 
121  virtual void quad(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4)
122  {
123  triangle(v1, v2, v3);
124  triangle(v3, v4, v1);
125  }
126 
128  virtual void triangle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
129  {
130  vertex(v1);
131  vertex(v2);
132  vertex(v3);
133  }
134 };
135 
137 class Box : public Primitive
138 {
139  public:
141  Box(const Vector3 &size, const Vector3 &offset = {0, 0 ,0})
142  {
143  make(size);
144  transform = Translation(offset);
145  }
146 
149  Box(const Vector3 &start, const Vector3 &end, double thickness)
150  {
151  make({thickness, thickness, align(start, end)});
152  }
153 
154  protected:
155  void make(const Vector3 &size)
156  {
157  Vector3 s2 = size/2;
158 
159  Vector3 vppp( s2.x, s2.y, s2.z), vnpp(-s2.x, s2.y, s2.z), vnnp(-s2.x, -s2.y, s2.z), vpnp( s2.x, -s2.y, s2.z),
160  vppn( s2.x, s2.y, -s2.z), vnpn(-s2.x, s2.y, -s2.z), vnnn(-s2.x, -s2.y, -s2.z), vpnn( s2.x, -s2.y, -s2.z);
161 
162  glNewList(list_, GL_COMPILE);
163  glBegin(GL_TRIANGLES);
164  glNormal3d(0, 0, 1);
165  quad(vnnp, vpnp, vppp, vnpp); // Z+
166  glNormal3d(0, 0, -1);
167  quad(vnnn, vnpn, vppn, vpnn); // Z-
168  glNormal3d(1, 0, 0);
169  quad(vpnn, vppn, vppp, vpnp); // X+
170  glNormal3d(-1, 0, 0);
171  quad(vnnn, vnnp, vnpp, vnpn); // X-
172  glNormal3d(0, 1, 0);
173  quad(vnpn, vnpp, vppp, vppn); // Y+
174  glNormal3d(0, -1, 0);
175  quad(vnnn, vpnn, vpnp, vnnp); // Y-
176  glEnd();
177  glEndList();
178  }
179 };
180 
182 class WireBox : public Primitive
183 {
184  public:
186  WireBox(const Vector3 &size, const Vector3 &offset = {0, 0, 0})
187  {
188  make(size);
189  transform = Translation(offset);
190  }
191 
192  protected:
193  void make(const Vector3 &size)
194  {
195  Vector3 s2 = size/2;
196 
197  Vector3 vppp( s2.x, s2.y, s2.z), vnpp(-s2.x, s2.y, s2.z), vnnp(-s2.x, -s2.y, s2.z), vpnp( s2.x, -s2.y, s2.z),
198  vppn( s2.x, s2.y, -s2.z), vnpn(-s2.x, s2.y, -s2.z), vnnn(-s2.x, -s2.y, -s2.z), vpnn( s2.x, -s2.y, -s2.z);
199 
200  glNewList(list_, GL_COMPILE);
201  glDisable(GL_LIGHTING);
202  glBegin(GL_LINES);
203  vertex(vnnp); vertex(vpnp);
204  vertex(vnnn); vertex(vpnn);
205  vertex(vnnp); vertex(vnpp);
206  vertex(vnnn); vertex(vnpn);
207  vertex(vppp); vertex(vnpp);
208  vertex(vppn); vertex(vnpn);
209  vertex(vppp); vertex(vpnp);
210  vertex(vppn); vertex(vpnn);
211  vertex(vnnn); vertex(vnnp);
212  vertex(vpnn); vertex(vpnp);
213  vertex(vnpn); vertex(vnpp);
214  vertex(vppn); vertex(vppp);
215  glEnd();
216  glEnable(GL_LIGHTING);
217  glEndList();
218  }
219 };
220 
222 class Sphere : public Primitive
223 {
224  public:
226  Sphere(double radius, const Vector3 &offset = {0, 0, 0})
227  {
228  make(radius);
229  transform = Translation(offset);
230  }
231 
232  protected:
233  void make(double radius)
234  {
235  glNewList(list_, GL_COMPILE);
236  glBegin(GL_TRIANGLES);
237  for (size_t jj=0; jj != FACETS/2; ++jj)
238  {
239  double phi1 = jj*2.*M_PI/FACETS, phi2 = (jj+1)*2.*M_PI/FACETS;
240  double r1 = radius*sin(phi1), r2 = radius*sin(phi2);
241  double z1 = -radius*cos(phi1), z2 = -radius*cos(phi2);
242 
243  for (size_t ii=0; ii != FACETS; ++ii)
244  {
245  double theta1 = ii*2.*M_PI/FACETS, theta2 = (ii+1)*2.*M_PI/FACETS;
246 
247  quad({r1*cos(theta1), r1*sin(theta1), z1},
248  {r1*cos(theta2), r1*sin(theta2), z1},
249  {r2*cos(theta2), r2*sin(theta2), z2},
250  {r2*cos(theta1), r2*sin(theta1), z2});
251  }
252  }
253  glEnd();
254  glEndList();
255  }
256 
257  void vertex(const Vector3 &v)
258  {
259  normal(v);
261  }
262 };
263 
268 class Cylinder : public Primitive
269 {
270  public:
275  Cylinder(double length, double radius, double endradius=-1)
276  {
277  make(length, radius, endradius);
278  }
279 
284  Cylinder(const Vector3 &start, const Vector3 &end, double radius, double endradius=-1)
285  {
286  make(align(start, end), radius, endradius);
287  }
288 
289  protected:
290  void make(double length, double radius, double endradius)
291  {
292  if (endradius < 0)
293  endradius = radius;
294 
295  glNewList(list_, GL_COMPILE);
296 
297  // Body
298  glBegin(GL_TRIANGLES);
299  for (size_t ii=0; ii != FACETS; ++ii)
300  {
301  double theta1 = ii*2*M_PI/FACETS, theta2 = (ii+1.)*2*M_PI/FACETS;
302 
303  quad({ radius*cos(theta1), radius*sin(theta1), -length/2},
304  { radius*cos(theta2), radius*sin(theta2), -length/2},
305  {endradius*cos(theta2), endradius*sin(theta2), length/2},
306  {endradius*cos(theta1), endradius*sin(theta1), length/2});
307  }
308  glEnd();
309 
310  // Top
311  glBegin(GL_TRIANGLE_FAN);
312  normal({0, 0, 1});
313  for (size_t ii=0; ii != FACETS; ++ii)
314  {
315  double theta = ii*2*M_PI/FACETS;
316  vertex({endradius*cos(theta), endradius*sin(theta), length/2});
317  }
318  glEnd();
319 
320  // Bottom
321  glBegin(GL_TRIANGLE_FAN);
322  normal({0, 0, -1});
323  for (size_t ii=0; ii != FACETS; ++ii)
324  {
325  double theta = ii*2.*M_PI/-FACETS;
326  vertex({radius*cos(theta), radius*sin(theta), -length/2});
327  }
328  glEnd();
329  glEndList();
330  }
331 
332  void vertex(const Vector3 &v)
333  {
334  normal({v.x, v.y, 0});
336  }
337 };
338 
340 class Cone : public Cylinder
341 {
342  public:
344  Cone(double length, double radius) : Cylinder(length, radius, 0) { }
345 
347  Cone(const Vector3 &start, const Vector3 &end, double radius) : Cylinder(start, end, radius, 0) { }
348 };
349 
354 class Arrow : public Primitive
355 {
356  protected:
359 
360  public:
365  Arrow(double length, double radius, double headlength=-1, double headradius=-1)
366  {
367  make(length, radius, headlength, headradius);
368  }
369 
374  Arrow(const Vector3 &start, const Vector3 &end, double radius, double headlength=-1, double headradius=-1)
375  {
376  make(align(start, end), radius, headlength, headradius);
377  }
378 
379  void draw()
380  {
381  body_->color = color;
382  head_->color = color;
383 
384  Object::draw();
385  }
386 
387  protected:
388  void make(double length, double radius, double headlength, double headradius)
389  {
390  if (headlength < 0)
391  headlength = radius*6;
392  if (headradius < 0)
393  headradius = headlength/3;
394 
395  attach(body_ = new Cylinder(length, radius));
396  attach(head_ = new Cone(headlength, headradius))->transform = Translation({0, 0, length/2});
397  }
398 };
399 
404 class Capsule : public Primitive
405 {
406  public:
408  Capsule(double length, double radius)
409  {
410  make(length, radius);
411  }
412 
414  Capsule(const Vector3 &start, const Vector3 &end, double radius)
415  {
416  make(align(start, end), radius);
417  }
418 
419  protected:
420  void make(double length, double radius)
421  {
422  glNewList(list_, GL_COMPILE);
423  glBegin(GL_TRIANGLES);
424 
425  // Start at bottom cap
426  int jadj1=0, jadj2=1;
427  double zadj1 = -length/2, zadj2 = -length/2;
428 
429  for (size_t jj=0; jj != FACETS/2+1; ++jj)
430  {
431  if (jj == FACETS/4)
432  {
433  // Move to body
434  jadj2--;
435  zadj2 += length;
436  }
437  else if (jj == FACETS/4 + 1)
438  {
439  // Move to top cap
440  jadj1--;
441  zadj1 += length;
442  }
443 
444  double phi1 = (jj+jadj1)*2.*M_PI/FACETS, phi2 = (jj+jadj2)*2.*M_PI/FACETS;
445  double r1 = radius*sin(phi1), r2 = radius*sin(phi2);
446  double z1 = -radius*cos(phi1)+zadj1, z2 = -radius*cos(phi2)+zadj2;
447 
448  for (size_t ii=0; ii != FACETS; ++ii)
449  {
450  double theta1 = ii*2.*M_PI/FACETS, theta2 = (ii+1)*2.*M_PI/FACETS;
451 
452  quad({r1*cos(theta1), r1*sin(theta1), z1}, zadj1,
453  {r1*cos(theta2), r1*sin(theta2), z1}, zadj1,
454  {r2*cos(theta2), r2*sin(theta2), z2}, zadj2,
455  {r2*cos(theta1), r2*sin(theta1), z2}, zadj2);
456  }
457  }
458  glEnd();
459  glEndList();
460  }
461 
462  void quad(const Vector3 &v1, double z1, const Vector3 &v2, double z2, const Vector3 &v3, double z3, const Vector3 &v4, double z4)
463  {
464  triangle(v1, z1, v2, z2, v3, z3);
465  triangle(v3, z3, v4, z4, v1, z1);
466  }
467 
468  void triangle(const Vector3 &v1, double z1, const Vector3 &v2, double z2, const Vector3 &v3, double z3)
469  {
470  vertex(v1, z1);
471  vertex(v2, z2);
472  vertex(v3, z3);
473  }
474 
475  void vertex(const Vector3 &v, double z)
476  {
477  normal({v.x, v.y, v.z-z});
479  }
480 };
481 
487 class Plane : public Primitive
488 {
489  protected:
490  Texture texture_;
491 
492  public:
502  Plane(const Vector3 &vx, const Vector3 &vy, const Vector3 &offset = {0, 0, 0}, const Texture &texture = Texture(), int repeat=1)
503  {
504  texture_ = texture;
505  make(vx, vy, repeat);
506  transform = Translation(offset);
507  }
508 
509  protected:
510  void make(const Vector3 &vx, const Vector3 &vy, int repeat)
511  {
512  Vector3 n = vx.cross(vy);
513  Vector3 v1 = -vx-vy, v2 = vx-vy, v3=vx+vy, v4=-vx+vy;
514 
515  glNewList(list_, GL_COMPILE);
516  if (texture_)
517  {
518  glEnable(GL_TEXTURE_2D);
519  texture_.bind();
520  glBegin(GL_QUADS);
521  normal(n);
522  glTexCoord2d(0, 0);
523  vertex(v1*repeat);
524  glTexCoord2d(repeat, 0);
525  vertex(v2*repeat);
526  glTexCoord2d(repeat, repeat);
527  vertex(v3*repeat);
528  glTexCoord2d(0, repeat);
529  vertex(v4*repeat);
530  glEnd();
531  glDisable(GL_TEXTURE_2D);
532  }
533  else
534  {
535  glBegin(GL_QUADS);
536  normal(n);
537  vertex(v1*repeat);
538  vertex(v2*repeat);
539  vertex(v3*repeat);
540  vertex(v4*repeat);
541  glEnd();
542  }
543  glEndList();
544  }
545 };
546 
557 class Model : public Primitive
558 {
559  protected:
560  struct Triangle
561  {
562  float n[3], v1[3], v2[3], v3[3];
563  uint16_t attribute;
564  };
565 
566  public:
568  Model(const std::string &file, double scale=1)
569  {
570  make(file, scale);
571  }
572 
574  Model(const std::string &file, const Vector3 &offset, double scale=1)
575  {
576  make(file, scale);
577  transform = Translation(offset);
578  }
579 
580  protected:
581  void make(const std::string &file, double scale)
582  {
583  std::ifstream ifs(file);
584 
585  // Read header
586  uint8_t header[80];
587  uint8_t numchar[4];
588 
589  ifs.read((char*)header, 80);
590  ifs.read((char*)numchar, 4);
591 
592  if (!ifs.good())
593  {
594  std::cerr << file << " is not a valid binary STL" << std::endl;
595  return;
596  }
597 
598  uint32_t numint = ((uint32_t)numchar[0]<<0) + ((uint32_t)numchar[1]<<8) + ((uint32_t)numchar[2]<<16) + ((uint32_t)numchar[3]<<24);
599 
600  glNewList(list_, GL_COMPILE);
601  glBegin(GL_TRIANGLES);
602 
603  // Read triangles
604  for (size_t ii=0; ii != numint; ++ii)
605  {
606  Triangle t;
607  ifs.read((char*)&t, 50);
608 
609  if (!ifs.good())
610  {
611  std::cerr << file << " is truncated" << std::endl;
612  break;
613  }
614 
615  Vector3 n(t.n);
616  Vector3 v1(t.v1), v2(t.v2), v3(t.v3);
617 
618  // Calculate normal, if not given
619  if (n.norm() == 0)
620  n = (v2-v1).cross(v3-v1);
621 
622  normal(n);
623  vertex(v1*scale);
624  vertex(v2*scale);
625  vertex(v3*scale);
626  }
627 
628  glEnd();
629  glEndList();
630  }
631 };
632 
633 }
634 
635 #endif // PGL_PRIMITIVE_H_
virtual void triangle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
Draws triangle.
Definition: primitive.h:128
Box Primitive.
Definition: primitive.h:137
Transform transform
Position and orientation.
Definition: pgl.h:177
Box(const Vector3 &size, const Vector3 &offset={0, 0, 0})
Specfies box size and optional offset.
Definition: primitive.h:141
virtual void quad(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4)
Draws a four-sided polygon using two triangles.
Definition: primitive.h:121
std::vector< Node * > children
Sub-objects.
Definition: pgl.h:132
Capsule(double length, double radius)
Specifies length and radius.
Definition: primitive.h:408
virtual void draw()
Draw children relative to this object.
Definition: pgl.h:188
Sphere(double radius, const Vector3 &offset={0, 0, 0})
Specifies sphere radius and optional offset.
Definition: primitive.h:226
Model(const std::string &file, double scale=1)
Specifies model file name and optional scale.
Definition: primitive.h:568
Plane Primitive.
Definition: primitive.h:487
Arrow Primitive.
Definition: primitive.h:354
Texture.
Definition: pgl.h:299
virtual void normal(const Vector3 &v)
Sets norm for subsequent vertices.
Definition: primitive.h:103
Cone(const Vector3 &start, const Vector3 &end, double radius)
Specifies start and end coordinates, as well as radius.
Definition: primitive.h:347
Generalized cylinder Primitive.
Definition: primitive.h:268
Definition: controller.h:27
void draw()
Draw primitive and its children.
Definition: primitive.h:379
Capsule Primitive.
Definition: primitive.h:404
double align(const Vector3 &start, const Vector3 &end)
Align primitive along axis.
Definition: primitive.h:88
Arrow(double length, double radius, double headlength=-1, double headradius=-1)
Specifies arrow length, radius, head length, and head radius.
Definition: primitive.h:365
Cylinder ending in a point.
Definition: primitive.h:340
Box(const Vector3 &start, const Vector3 &end, double thickness)
Specfies box start and end coordinates, as well as thickness.
Definition: primitive.h:149
Plane(const Vector3 &vx, const Vector3 &vy, const Vector3 &offset={0, 0, 0}, const Texture &texture=Texture(), int repeat=1)
Specifies vectors along which the plane is aligned.
Definition: primitive.h:502
Arrow(const Vector3 &start, const Vector3 &end, double radius, double headlength=-1, double headradius=-1)
Specifies start and end coordinates, as well as radius, head length, and head radius.
Definition: primitive.h:374
virtual void vertex(const Vector3 &v)
Enters vertex into display list.
Definition: primitive.h:111
GLuint list_
OpenGL display list identifier.
Definition: primitive.h:49
Cone(double length, double radius)
Specifies length and radius.
Definition: primitive.h:344
Definition: primitive.h:560
3-component vector.
Definition: math.h:43
Primitive()
Default constructor.
Definition: primitive.h:56
Cylinder(double length, double radius, double endradius=-1)
Specifies length, radius, and end radius.
Definition: primitive.h:275
Model(const std::string &file, const Vector3 &offset, double scale=1)
Specifies model file name, offset, and optional scale.
Definition: primitive.h:574
void bind() const
Use this texture as the current OpenGL 2D texture.
Definition: pgl.h:371
Wireframe box Primitive.
Definition: primitive.h:182
Cylinder(const Vector3 &start, const Vector3 &end, double radius, double endradius=-1)
Specifies start and end coordinates, as well as radius and end radius.
Definition: primitive.h:284
WireBox(const Vector3 &size, const Vector3 &offset={0, 0, 0})
Specfies box size and optional offset.
Definition: primitive.h:186
Capsule(const Vector3 &start, const Vector3 &end, double radius)
Specifies start and end coordinates, as well as radius.
Definition: primitive.h:414
Cone * head_
Arrow head.
Definition: primitive.h:358
Sphere Primitive.
Definition: primitive.h:222
Transform with identity rotation.
Definition: math.h:289
void vertex(const Vector3 &v)
Enters vertex into display list.
Definition: primitive.h:257
Basic 3D primitive.
Definition: primitive.h:43
void vertex(const Vector3 &v)
Enters vertex into display list.
Definition: primitive.h:332
Homogeneous coordinate transform.
Definition: math.h:164
STL model.
Definition: primitive.h:557
Cylinder * body_
Arrow body.
Definition: primitive.h:357
Vector3 color
Primitive color.
Definition: primitive.h:46
Object in a scene.
Definition: pgl.h:174
virtual void draw()
Draw primitive and its children.
Definition: primitive.h:67
T * attach(T *child)
Add child to list of sub-objects.
Definition: pgl.h:160