1 /*
2   Teem: Tools to process and visualize scientific data and images             .
3   Copyright (C) 2012, 2011, 2010, 2009  University of Chicago
4   Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5   Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6 
7   This library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Lesser General Public License
9   (LGPL) as published by the Free Software Foundation; either
10   version 2.1 of the License, or (at your option) any later version.
11   The terms of redistributing and/or modifying this software also
12   include exceptions to the LGPL that facilitate static linking.
13 
14   This library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Lesser General Public License for more details.
18 
19   You should have received a copy of the GNU Lesser General Public License
20   along with this library; if not, write to Free Software Foundation, Inc.,
21   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 */
23 
24 
25 #include "limn.h"
26 
27 int
limnObjectCubeAdd(limnObject * obj,unsigned int lookIdx)28 limnObjectCubeAdd(limnObject *obj, unsigned int lookIdx) {
29   unsigned int vII[4], vII0, partIdx;
30 
31   partIdx = limnObjectPartAdd(obj);
32   /* HEY: we have to set this first so that
33      obj->setVertexRGBAFromLook can do the right thing */
34   obj->part[partIdx]->lookIdx = lookIdx;
35   /*
36                                      7     6
37 
38                   z               4     5
39                   |    y
40                   |   /              3     2
41                   |  /
42                   | /             0     1
43                     ------ x
44   */
45   vII0 = limnObjectVertexAdd(obj, partIdx, -1, -1, -1);
46   limnObjectVertexAdd(obj, partIdx, 1, -1, -1);
47   limnObjectVertexAdd(obj, partIdx, 1,  1, -1);
48   limnObjectVertexAdd(obj, partIdx, -1,  1, -1);
49   limnObjectVertexAdd(obj, partIdx, -1, -1,  1);
50   limnObjectVertexAdd(obj, partIdx, 1, -1,  1);
51   limnObjectVertexAdd(obj, partIdx, 1,  1,  1);
52   limnObjectVertexAdd(obj, partIdx, -1,  1,  1);
53   ELL_4V_SET(vII, vII0+3, vII0+2, vII0+1, vII0+0);
54   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
55   ELL_4V_SET(vII, vII0+1, vII0+5, vII0+4, vII0+0);
56   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
57   ELL_4V_SET(vII, vII0+2, vII0+6, vII0+5, vII0+1);
58   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
59   ELL_4V_SET(vII, vII0+3, vII0+7, vII0+6, vII0+2);
60   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
61   ELL_4V_SET(vII, vII0+0, vII0+4, vII0+7, vII0+3);
62   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
63   ELL_4V_SET(vII, vII0+5, vII0+6, vII0+7, vII0+4);
64   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
65 
66   return partIdx;
67 }
68 
69 int
limnObjectSquareAdd(limnObject * obj,unsigned int lookIdx)70 limnObjectSquareAdd(limnObject *obj, unsigned int lookIdx) {
71   unsigned int vII0, vII[4], partIdx;
72 
73   partIdx = limnObjectPartAdd(obj);
74   /* HEY: we have to set this first so that
75      obj->setVertexRGBAFromLook can do the right thing */
76   obj->part[partIdx]->lookIdx = lookIdx;
77   vII0 = limnObjectVertexAdd(obj, partIdx, 0, 0, 0);
78   limnObjectVertexAdd(obj, partIdx, 1, 0, 0);
79   limnObjectVertexAdd(obj, partIdx, 1, 1, 0);
80   limnObjectVertexAdd(obj, partIdx, 0, 1, 0);
81   ELL_4V_SET(vII, vII0+0, vII0+1, vII0+2, vII0+3);
82   limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
83   return partIdx;
84 }
85 
86 /*
87 ******** limnObjectCylinderAdd
88 **
89 ** adds a cylinder that fills up the bi-unit cube [-1,1]^3,
90 ** with axis "axis" (0:X, 1:Y, 2:Z), with discretization "res"
91 */
92 int
limnObjectCylinderAdd(limnObject * obj,unsigned int lookIdx,unsigned int axis,unsigned int res)93 limnObjectCylinderAdd(limnObject *obj, unsigned int lookIdx,
94                       unsigned int axis, unsigned int res) {
95   unsigned int partIdx, ii, jj, tmp, vII0=0, *vII;
96   double theta;
97 
98   partIdx = limnObjectPartAdd(obj);
99   /* HEY: we have to set this first so that
100      obj->setVertexRGBAFromLook can do the right thing */
101   obj->part[partIdx]->lookIdx = lookIdx;
102   vII = (unsigned int *)calloc(res, sizeof(unsigned int));
103 
104   for (ii=0; ii<=res-1; ii++) {
105     theta = AIR_AFFINE(0, ii, res, 0, 2*AIR_PI);
106     switch(axis) {
107     case 0:
108       tmp = limnObjectVertexAdd(obj, partIdx,
109                                 1,
110                                 AIR_CAST(float, -sin(theta)),
111                                 AIR_CAST(float, cos(theta)));
112       limnObjectVertexAdd(obj, partIdx,
113                           -1,
114                           AIR_CAST(float, -sin(theta)),
115                           AIR_CAST(float, cos(theta)));
116       break;
117     case 1:
118       tmp = limnObjectVertexAdd(obj, partIdx,
119                                 AIR_CAST(float, sin(theta)),
120                                 1,
121                                 AIR_CAST(float, cos(theta)));
122       limnObjectVertexAdd(obj, partIdx,
123                           AIR_CAST(float, sin(theta)),
124                           -1,
125                           AIR_CAST(float, cos(theta)));
126       break;
127     case 2: default:
128       tmp = limnObjectVertexAdd(obj, partIdx,
129                                 AIR_CAST(float, cos(theta)),
130                                 AIR_CAST(float, sin(theta)),
131                                 1);
132       limnObjectVertexAdd(obj, partIdx,
133                           AIR_CAST(float, cos(theta)),
134                           AIR_CAST(float, sin(theta)),
135                           -1);
136       break;
137     }
138     if (!ii) {
139       vII0 = tmp;
140     }
141   }
142   /* add all side faces */
143   for (ii=0; ii<=res-1; ii++) {
144     jj = (ii+1) % res;
145     ELL_4V_SET(vII, vII0 + 2*ii, vII0 + 2*ii + 1,
146                vII0 + 2*jj + 1, vII0 + 2*jj);
147     limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
148   }
149   /* add top */
150   for (ii=0; ii<=res-1; ii++) {
151     vII[ii] = vII0 + 2*ii;
152   }
153   limnObjectFaceAdd(obj, partIdx, lookIdx, res, vII);
154   /* add bottom */
155   for (ii=0; ii<=res-1; ii++) {
156     vII[ii] = vII0 + 2*(res-1-ii) + 1;
157   }
158   limnObjectFaceAdd(obj, partIdx, lookIdx, res, vII);
159 
160   free(vII);
161   return partIdx;
162 }
163 
164 int
limnObjectConeAdd(limnObject * obj,unsigned int lookIdx,unsigned int axis,unsigned int res)165 limnObjectConeAdd(limnObject *obj, unsigned int lookIdx,
166                   unsigned int axis, unsigned int res) {
167   double th;
168   unsigned int partIdx, tmp, vII0=0, ii, jj, *vII;
169 
170   vII = (unsigned int *)calloc(res, sizeof(unsigned int));
171 
172   partIdx = limnObjectPartAdd(obj);
173   /* HEY: we have to set this first so that
174      obj->setVertexRGBAFromLook can do the right thing */
175   obj->part[partIdx]->lookIdx = lookIdx;
176   for (ii=0; ii<=res-1; ii++) {
177     th = AIR_AFFINE(0, ii, res, 0, 2*AIR_PI);
178     switch(axis) {
179     case 0:
180       tmp = limnObjectVertexAdd(obj, partIdx,
181                                 0,
182                                 AIR_CAST(float, -sin(th)),
183                                 AIR_CAST(float, cos(th)));
184       break;
185     case 1:
186       tmp = limnObjectVertexAdd(obj, partIdx,
187                                 AIR_CAST(float, sin(th)),
188                                 0,
189                                 AIR_CAST(float, cos(th)));
190       break;
191     case 2: default:
192       tmp = limnObjectVertexAdd(obj, partIdx,
193                                 AIR_CAST(float, cos(th)),
194                                 AIR_CAST(float, sin(th)),
195                                 0);
196       break;
197     }
198     if (!ii) {
199       vII0 = tmp;
200     }
201   }
202   switch(axis) {
203   case 0:
204     limnObjectVertexAdd(obj, partIdx, 1, 0, 0);
205     break;
206   case 1:
207     limnObjectVertexAdd(obj, partIdx, 0, 1, 0);
208     break;
209   case 2: default:
210     limnObjectVertexAdd(obj, partIdx, 0, 0, 1);
211     break;
212   }
213   for (ii=0; ii<=res-1; ii++) {
214     jj = (ii+1) % res;
215     ELL_3V_SET(vII, vII0+ii, vII0+jj, vII0+res);
216     limnObjectFaceAdd(obj, partIdx, lookIdx, 3, vII);
217   }
218   for (ii=0; ii<=res-1; ii++) {
219     vII[ii] = vII0+res-1-ii;
220   }
221   limnObjectFaceAdd(obj, partIdx, lookIdx, res, vII);
222 
223   free(vII);
224   return partIdx;
225 }
226 
227 int
limnObjectPolarSphereAdd(limnObject * obj,unsigned int lookIdx,unsigned int axis,unsigned int thetaRes,unsigned int phiRes)228 limnObjectPolarSphereAdd(limnObject *obj, unsigned int lookIdx,
229                          unsigned int axis, unsigned int thetaRes,
230                          unsigned int phiRes) {
231   unsigned int partIdx, vII0, nti, ti, pi, vII[4], pl;
232   double t, p;
233 
234   thetaRes = AIR_MAX(thetaRes, 3);
235   phiRes = AIR_MAX(phiRes, 2);
236 
237   partIdx = limnObjectPartAdd(obj);
238   /* HEY: we have to set this first so that
239      obj->setVertexRGBAFromLook can do the right thing */
240   obj->part[partIdx]->lookIdx = lookIdx;
241   switch(axis) {
242   case 0:
243     vII0 = limnObjectVertexAdd(obj, partIdx, 1, 0, 0);
244     break;
245   case 1:
246     vII0 = limnObjectVertexAdd(obj, partIdx, 0, 1, 0);
247     break;
248   case 2: default:
249     vII0 = limnObjectVertexAdd(obj, partIdx, 0, 0, 1);
250     break;
251   }
252   for (pi=1; pi<=phiRes-1; pi++) {
253     p = AIR_AFFINE(0, pi, phiRes, 0, AIR_PI);
254     for (ti=0; ti<=thetaRes-1; ti++) {
255       t = AIR_AFFINE(0, ti, thetaRes, 0, 2*AIR_PI);
256       switch(axis) {
257       case 0:
258         limnObjectVertexAdd(obj, partIdx,
259                             AIR_CAST(float, cos(p)),
260                             AIR_CAST(float, -sin(t)*sin(p)),
261                             AIR_CAST(float, cos(t)*sin(p)));
262         break;
263       case 1:
264         limnObjectVertexAdd(obj, partIdx,
265                             AIR_CAST(float, sin(t)*sin(p)),
266                             AIR_CAST(float, cos(p)),
267                             AIR_CAST(float, cos(t)*sin(p)));
268         break;
269       case 2: default:
270         limnObjectVertexAdd(obj, partIdx,
271                             AIR_CAST(float, cos(t)*sin(p)),
272                             AIR_CAST(float, sin(t)*sin(p)),
273                             AIR_CAST(float, cos(p)));
274         break;
275       }
276     }
277   }
278   switch(axis) {
279   case 0:
280     pl = limnObjectVertexAdd(obj, partIdx, -1, 0, 0);
281     break;
282   case 1:
283     pl = limnObjectVertexAdd(obj, partIdx, 0, -1, 0);
284     break;
285   case 2: default:
286     pl = limnObjectVertexAdd(obj, partIdx, 0, 0, -1);
287     break;
288   }
289   for (ti=1; ti<=thetaRes; ti++) {
290     nti = ti < thetaRes ? ti+1 : 1;
291     ELL_3V_SET(vII, vII0+ti, vII0+nti, vII0+0);
292     limnObjectFaceAdd(obj, partIdx, lookIdx, 3, vII);
293   }
294   for (pi=0; pi<=phiRes-3; pi++) {
295     for (ti=1; ti<=thetaRes; ti++) {
296       nti = ti < thetaRes ? ti+1 : 1;
297       ELL_4V_SET(vII, vII0+pi*thetaRes + ti, vII0+(pi+1)*thetaRes + ti,
298                  vII0+(pi+1)*thetaRes + nti, vII0+pi*thetaRes + nti);
299       limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
300     }
301   }
302   for (ti=1; ti<=thetaRes; ti++) {
303     nti = ti < thetaRes ? ti+1 : 1;
304     ELL_3V_SET(vII, vII0+pi*thetaRes + ti, pl, vII0+pi*thetaRes + nti);
305     limnObjectFaceAdd(obj, partIdx, lookIdx, 3, vII);
306   }
307 
308   return partIdx;
309 }
310 
311 int
limnObjectPolarSuperquadFancyAdd(limnObject * obj,unsigned int lookIdx,unsigned int axis,float A,float B,float C,float R,unsigned int thetaRes,unsigned int phiRes)312 limnObjectPolarSuperquadFancyAdd(limnObject *obj,
313                                  unsigned int lookIdx, unsigned int axis,
314                                  float A, float B, float C, float R,
315                                  unsigned int thetaRes, unsigned int phiRes) {
316   unsigned int partIdx, vII0, nti, ti, pi, vII[4], pl;
317   double x, y, z, t, p;
318 
319   AIR_UNUSED(R);
320   thetaRes = AIR_MAX(thetaRes, 3);
321   phiRes = AIR_MAX(phiRes, 2);
322 
323   partIdx = limnObjectPartAdd(obj);
324   /* HEY: we have to set this first so that
325      obj->setVertexRGBAFromLook can do the right thing */
326   obj->part[partIdx]->lookIdx = lookIdx;
327   switch(axis) {
328   case 0:
329     vII0 = limnObjectVertexAdd(obj, partIdx, 1, 0, 0);
330     break;
331   case 1:
332     vII0 = limnObjectVertexAdd(obj, partIdx, 0, 1, 0);
333     break;
334   case 2: default:
335     vII0 = limnObjectVertexAdd(obj, partIdx, 0, 0, 1);
336     break;
337   }
338   for (pi=1; pi<=phiRes-1; pi++) {
339     p = AIR_AFFINE(0, pi, phiRes, 0, AIR_PI);
340     for (ti=0; ti<=thetaRes-1; ti++) {
341       t = AIR_AFFINE(0, ti, thetaRes, 0, 2*AIR_PI);
342       switch(axis) {
343       case 0:
344         x = airSgnPow(cos(p),B);
345         y = -airSgnPow(sin(t),A) * airSgnPow(sin(p),B);
346         z = airSgnPow(cos(t),A) * airSgnPow(sin(p),B);
347         if (C != B) {
348           /* modify profile along y axis to create beta=C */
349           double yp, ymax;
350           yp = airSgnPow(sin(acos(airSgnPow(x, 1/C))), C);
351           ymax = airSgnPow(sin(p), B);
352           if (ymax) {
353             y *= yp/ymax;
354           }
355         }
356         break;
357       case 1:
358         x = airSgnPow(sin(t),A) * airSgnPow(sin(p),B);
359         y = airSgnPow(cos(p),B);
360         z = airSgnPow(cos(t),A) * airSgnPow(sin(p),B);
361         break;
362       case 2: default:
363         x = airSgnPow(cos(t),A) * airSgnPow(sin(p),B);
364         y = airSgnPow(sin(t),A) * airSgnPow(sin(p),B);
365         z = airSgnPow(cos(p),B);
366         if (C != B) {
367           /* modify profile along y axis to create beta=C */
368           double yp, ymax;
369           yp = airSgnPow(sin(acos(airSgnPow(z, 1/C))), C);
370           ymax = airSgnPow(sin(p), B);
371           if (ymax) {
372             y *= yp/ymax;
373           }
374         }
375         break;
376       }
377       limnObjectVertexAdd(obj, partIdx,
378                           AIR_CAST(float, x),
379                           AIR_CAST(float, y),
380                           AIR_CAST(float, z));
381     }
382   }
383   switch(axis) {
384   case 0:
385     pl = limnObjectVertexAdd(obj, partIdx, -1, 0, 0);
386     break;
387   case 1:
388     pl = limnObjectVertexAdd(obj, partIdx, 0, -1, 0);
389     break;
390   case 2: default:
391     pl = limnObjectVertexAdd(obj, partIdx, 0, 0, -1);
392     break;
393   }
394   for (ti=1; ti<=thetaRes; ti++) {
395     nti = ti < thetaRes ? ti+1 : 1;
396     ELL_3V_SET(vII, vII0+ti, vII0+nti, vII0+0);
397     limnObjectFaceAdd(obj, partIdx, lookIdx, 3, vII);
398   }
399   for (pi=0; pi<=phiRes-3; pi++) {
400     for (ti=1; ti<=thetaRes; ti++) {
401       nti = ti < thetaRes ? ti+1 : 1;
402       ELL_4V_SET(vII, vII0+pi*thetaRes + ti, vII0+(pi+1)*thetaRes + ti,
403                  vII0+(pi+1)*thetaRes + nti, vII0+pi*thetaRes + nti);
404       limnObjectFaceAdd(obj, partIdx, lookIdx, 4, vII);
405     }
406   }
407   for (ti=1; ti<=thetaRes; ti++) {
408     nti = ti < thetaRes ? ti+1 : 1;
409     ELL_3V_SET(vII, vII0+pi*thetaRes + ti, pl, vII0+pi*thetaRes + nti);
410     limnObjectFaceAdd(obj, partIdx, lookIdx, 3, vII);
411   }
412 
413   return partIdx;
414 }
415 
416 int
limnObjectPolarSuperquadAdd(limnObject * obj,unsigned int lookIdx,unsigned int axis,float A,float B,unsigned int thetaRes,unsigned int phiRes)417 limnObjectPolarSuperquadAdd(limnObject *obj,
418                             unsigned int lookIdx, unsigned int axis,
419                             float A, float B,
420                             unsigned int thetaRes, unsigned int phiRes) {
421 
422   return limnObjectPolarSuperquadFancyAdd(obj, lookIdx, axis,
423                                           A, B, B, 0,
424                                           thetaRes, phiRes);
425 }
426