1 /* BurrTools
2  *
3  * BurrTools is the legal property of its developers, whose
4  * names are listed in the COPYRIGHT file, which is included
5  * within the source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16 
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  */
21 #include "voxel_0.h"
22 
23 #include <stdlib.h>
24 
25 #include "tabs_0/tablesizes.inc"
26 
27 /// this array contains all rotation and mirror rotation matrices for the cubic \ref grid
28 static const int rotationMatrices[NUM_TRANSFORMATIONS_MIRROR][9] = {
29 #include "tabs_0/rotmatrix.inc"
30 };
31 
32 #include "tabs_0/meshverts.inc"
33 
34 /** \page grid Grids in BurrTools
35  *
36  * Grids in BurrTools define how the space is separated into the different volume
37  * elements (voxels). There are many different ways how to do that.
38  *
39  * BurrTools poses a few restrictions on how those grids can look:
40  *
41  * - The grids must be periodical in all directions (so no Penrose Tiling)
42  * - The number of transformations must be limited (this is a problem with the sphere grid)
43  */
44 
45 /** the transformation function for cubic grids
46  *
47  * The nice thing about the cubic grid is that we can easily calculate how big the
48  * grid will be after the transformation, we can also easily calculate the new
49  * bounding box and the now position for the hotspot.
50  *
51  * This makes this transformation function faster than the other 2 variations for
52  * spheres and triangles
53  */
transform(unsigned int nr)54 bool voxel_0_c::transform(unsigned int nr) {
55 
56   bt_assert(nr < NUM_TRANSFORMATIONS_MIRROR);
57 
58   // first transform the corner opposite the 0,0,0 corner to find the final size
59   // and the required shifts
60 
61   int tx = rotationMatrices[nr][0]*(sx-1) + rotationMatrices[nr][1]*(sy-1) + rotationMatrices[nr][2]*(sz-1);
62   int ty = rotationMatrices[nr][3]*(sx-1) + rotationMatrices[nr][4]*(sy-1) + rotationMatrices[nr][5]*(sz-1);
63   int tz = rotationMatrices[nr][6]*(sx-1) + rotationMatrices[nr][7]*(sy-1) + rotationMatrices[nr][8]*(sz-1);
64 
65   // calculate the amount the rotated coodinates must be shifted up
66   int shx = (tx < 0) ? -tx : 0;
67   int shy = (ty < 0) ? -ty : 0;
68   int shz = (tz < 0) ? -tz : 0;
69 
70   // calculate new size
71   int nsx = abs(tx)+1;
72   int nsy = abs(ty)+1;
73   int nsz = abs(tz)+1;
74 
75   voxel_type * s = new voxel_type[nsx*nsy*nsz];
76   memset(s, VX_EMPTY, nsx*nsy*nsz);
77 
78   unsigned int index = 0;
79   for (unsigned int z = 0; z < sz; z++)
80     for (unsigned int y = 0; y < sy; y++)
81       for (unsigned int x = 0; x < sx; x++) {
82         if (space[index]) {
83           tx = rotationMatrices[nr][0]*x + rotationMatrices[nr][1]*y + rotationMatrices[nr][2]*z + shx;
84           ty = rotationMatrices[nr][3]*x + rotationMatrices[nr][4]*y + rotationMatrices[nr][5]*z + shy;
85           tz = rotationMatrices[nr][6]*x + rotationMatrices[nr][7]*y + rotationMatrices[nr][8]*z + shz;
86 
87           bt_assert(tx >= 0);
88           bt_assert(ty >= 0);
89           bt_assert(tz >= 0);
90 
91           s[tx + nsx*(ty + nsy*tz)] = space[index];
92         }
93         index++;
94       }
95 
96   delete [] space;
97   space = s;
98 
99   sx = nsx;
100   sy = nsy;
101   sz = nsz;
102 
103   // update hotspot
104   int thx = rotationMatrices[nr][0]*hx + rotationMatrices[nr][1]*hy + rotationMatrices[nr][2]*hz + shx;
105   int thy = rotationMatrices[nr][3]*hx + rotationMatrices[nr][4]*hy + rotationMatrices[nr][5]*hz + shy;
106   int thz = rotationMatrices[nr][6]*hx + rotationMatrices[nr][7]*hy + rotationMatrices[nr][8]*hz + shz;
107 
108   hx = thx;
109   hy = thy;
110   hz = thz;
111 
112   // update bounding box
113   int tbx1 = rotationMatrices[nr][0]*bx1 + rotationMatrices[nr][1]*by1 + rotationMatrices[nr][2]*bz1 + shx;
114   int tby1 = rotationMatrices[nr][3]*bx1 + rotationMatrices[nr][4]*by1 + rotationMatrices[nr][5]*bz1 + shy;
115   int tbz1 = rotationMatrices[nr][6]*bx1 + rotationMatrices[nr][7]*by1 + rotationMatrices[nr][8]*bz1 + shz;
116 
117   int tbx2 = rotationMatrices[nr][0]*bx2 + rotationMatrices[nr][1]*by2 + rotationMatrices[nr][2]*bz2 + shx;
118   int tby2 = rotationMatrices[nr][3]*bx2 + rotationMatrices[nr][4]*by2 + rotationMatrices[nr][5]*bz2 + shy;
119   int tbz2 = rotationMatrices[nr][6]*bx2 + rotationMatrices[nr][7]*by2 + rotationMatrices[nr][8]*bz2 + shz;
120 
121 #define MIN(a,b) ((a<b)?(a):(b))
122 #define MAX(a,b) ((a>b)?(a):(b))
123 
124   bx1 = MIN(tbx1, tbx2);
125   bx2 = MAX(tbx1, tbx2);
126 
127   by1 = MIN(tby1, tby2);
128   by2 = MAX(tby1, tby2);
129 
130   bz1 = MIN(tbz1, tbz2);
131   bz2 = MAX(tbz1, tbz2);
132 
133 #undef MIN
134 #undef MAX
135 
136   symmetries = symmetryInvalid();
137 
138   return true;
139 }
140 
transformPoint(int * x,int * y,int * z,unsigned int trans) const141 void voxel_0_c::transformPoint(int * x, int * y, int * z, unsigned int trans) const {
142 
143   bt_assert(trans < NUM_TRANSFORMATIONS_MIRROR);
144 
145   int sx = *x;
146   int sy = *y;
147   int sz = *z;
148 
149   *x = rotationMatrices[trans][0]*sx + rotationMatrices[trans][1]*sy + rotationMatrices[trans][2]*sz;
150   *y = rotationMatrices[trans][3]*sx + rotationMatrices[trans][4]*sy + rotationMatrices[trans][5]*sz;
151   *z = rotationMatrices[trans][6]*sx + rotationMatrices[trans][7]*sy + rotationMatrices[trans][8]*sz;
152 }
153 
getNeighbor(unsigned int idx,unsigned int typ,int x,int y,int z,int * xn,int * yn,int * zn) const154 bool voxel_0_c::getNeighbor(unsigned int idx, unsigned int typ, int x, int y, int z, int * xn, int *yn, int *zn) const {
155 
156   switch (typ) {
157     case 0:
158       switch (idx) {
159         case 0: *xn = x-1; *yn = y;   *zn = z;   break;
160         case 1: *xn = x;   *yn = y-1; *zn = z;   break;
161         case 2: *xn = x  ; *yn = y;   *zn = z-1; break;
162         case 3: *xn = x+1; *yn = y;   *zn = z;   break;
163         case 4: *xn = x  ; *yn = y+1; *zn = z;   break;
164         case 5: *xn = x  ; *yn = y;   *zn = z+1; break;
165         default: return false;
166       }
167       break;
168     case 1:
169       switch (idx) {
170         case  0: *xn = x-1; *yn = y-1; *zn = z;   break;
171         case  1: *xn = x-1; *yn = y+1; *zn = z;   break;
172         case  2: *xn = x+1; *yn = y+1; *zn = z;   break;
173         case  3: *xn = x+1; *yn = y-1; *zn = z;   break;
174         case  4: *xn = x-1; *yn = y;   *zn = z-1; break;
175         case  5: *xn = x-1; *yn = y;   *zn = z+1; break;
176         case  6: *xn = x+1; *yn = y;   *zn = z+1; break;
177         case  7: *xn = x+1; *yn = y;   *zn = z-1; break;
178         case  8: *xn = x;   *yn = y-1; *zn = z-1; break;
179         case  9: *xn = x;   *yn = y-1; *zn = z+1; break;
180         case 10: *xn = x;   *yn = y+1; *zn = z+1; break;
181         case 11: *xn = x;   *yn = y+1; *zn = z-1; break;
182         default: return false;
183       }
184       break;
185     case 2:
186       switch (idx) {
187         case 0: *xn = x-1; *yn = y-1; *zn = z-1; break;
188         case 1: *xn = x-1; *yn = y-1; *zn = z+1; break;
189         case 2: *xn = x-1; *yn = y+1; *zn = z-1; break;
190         case 3: *xn = x-1; *yn = y+1; *zn = z+1; break;
191         case 4: *xn = x+1; *yn = y-1; *zn = z-1; break;
192         case 5: *xn = x+1; *yn = y-1; *zn = z+1; break;
193         case 6: *xn = x+1; *yn = y+1; *zn = z-1; break;
194         case 7: *xn = x+1; *yn = y+1; *zn = z+1; break;
195         default: return false;
196       }
197       break;
198   }
199   return true;
200 }
201 
scale(unsigned int amount,bool grid)202 void voxel_0_c::scale(unsigned int amount, bool grid)
203 {
204   voxel_type * s2 = new voxel_type[sx*amount*sy*amount*sz*amount];
205 
206   for (unsigned int x = 0; x < sx; x++)
207     for (unsigned int y = 0; y < sy; y++)
208       for (unsigned int z = 0; z < sz; z++)
209         for (unsigned int ax = 0; ax < amount; ax++)
210           for (unsigned int ay = 0; ay < amount; ay++)
211             for (unsigned int az = 0; az < amount; az++)
212               if (!grid)
213                 s2[(x*amount+ax) + (sx*amount) * ((y*amount+ay) + (sy*amount) * (z*amount+az))] = get(x, y, z);
214               else
215               {
216                 if (!isEmpty(x, y, z) &&
217                       (
218                         (ax == 0        && isEmpty2(x-1, y, z)) ||
219                         (ax == amount-1 && isEmpty2(x+1, y, z)) ||
220                         (ay == 0        && isEmpty2(x, y-1, z)) ||
221                         (ay == amount-1 && isEmpty2(x, y+1, z)) ||
222                         (az == 0        && isEmpty2(x, y, z-1)) ||
223                         (az == amount-1 && isEmpty2(x, y, z+1)) ||
224                         ((ax == 0 || ax == amount-1) && (ay == 0 || ay == amount-1 || az == 0 || az == amount-1)) ||
225                         ((ay == 0 || ay == amount-1) && (ax == 0 || ax == amount-1 || az == 0 || az == amount-1)) ||
226                         ((az == 0 || az == amount-1) && (ax == 0 || ax == amount-1 || ay == 0 || ay == amount-1))
227                       )
228                    )
229 
230                     s2[(x*amount+ax) + (sx*amount) * ((y*amount+ay) + (sy*amount) * (z*amount+az))] = get(x, y, z);
231                 else
232                     s2[(x*amount+ax) + (sx*amount) * ((y*amount+ay) + (sy*amount) * (z*amount+az))] = 0;
233               }
234 
235   delete [] space;
236   space = s2;
237 
238   sx *= amount;
239   sy *= amount;
240   sz *= amount;
241 
242   voxels = sx*sy*sz;
243 
244   hx = hy = hz = 0;
245 
246   recalcBoundingBox();
247 }
248 
scaleDown(unsigned char by,bool action)249 bool voxel_0_c::scaleDown(unsigned char by, bool action) {
250 
251   if (by < 2) return true;
252   if (sx < by || sy < by || sz < by) return false;
253 
254   for (unsigned int shx = 0; shx < by; shx++)
255     for (unsigned int shy = 0; shy < by; shy++)
256       for (unsigned int shz = 0; shz < by; shz++) {
257 
258         bool problem = false;
259 
260         for (int x = 0; x < (int)sx/by+1; x++)
261           for (int y = 0; y < (int)sy/by+1; y++)
262             for (int z = 0; z < (int)sz/by+1; z++)
263 
264               for (unsigned int cx = 0; cx < by; cx++)
265                 for (unsigned int cy = 0; cy < by; cy++)
266                   for (unsigned int cz = 0; cz < by; cz++)
267 
268                     problem |= get2(x*by-shx, y*by-shy, z*by-shz) != get2(x*by-shx+cx, y*by-shy+cy, z*by-shz+cz);
269 
270         if (!problem) {
271 
272           if (action) {
273 
274             // we don't need to include the +1 in the sizes
275             // as we've done for the check as these voxels are
276             // definitively empty
277             unsigned int nsx = sx/by;
278             unsigned int nsy = sy/by;
279             unsigned int nsz = sz/by;
280 
281             voxel_type * s2 = new voxel_type[nsx*nsy*nsz];
282 
283             for (unsigned int x = 0; x < nsx; x++)
284               for (unsigned int y = 0; y < nsy; y++)
285                 for (unsigned int z = 0; z < nsz; z++)
286                   s2[x + nsx * (y + nsy * z)] = get2(x*by, y*by, z*by);
287 
288             delete [] space;
289             space = s2;
290 
291             sx = nsx;
292             sy = nsy;
293             sz = nsz;
294 
295             voxels = sx*sy*sz;
296 
297             recalcBoundingBox();
298           }
299 
300           return true;
301         }
302       }
303 
304   return false;
305 }
306 
resizeInclude(int & px,int & py,int & pz)307 void voxel_0_c::resizeInclude(int & px, int & py, int & pz) {
308 
309   int nsx = getX();
310   int nsy = getY();
311   int nsz = getZ();
312   int tx = 0;
313   int ty = 0;
314   int tz = 0;
315 
316   if (px < 0) {
317 
318     nsx -= px;
319     tx -= px;
320   }
321   if (py < 0) {
322 
323     nsy -= py;
324     ty -= py;
325   }
326   if (pz < 0) {
327 
328     nsz -= pz;
329     tz -= pz;
330   }
331   if (px >= (int)getX()) nsx += (px-getX()+1);
332   if (py >= (int)getY()) nsy += (py-getY()+1);
333   if (pz >= (int)getZ()) nsz += (pz-getZ()+1);
334 
335   resize(nsx, nsy, nsz, 0);
336   translate(tx, ty, tz, 0);
337 
338   px += tx;
339   py += ty;
340   pz += tz;
341 }
342 
validCoordinate(int,int,int) const343 bool voxel_0_c::validCoordinate(int /*x*/, int /*y*/, int /*z*/) const {
344   return true;
345 }
346 
onGrid(int,int,int) const347 bool voxel_0_c::onGrid(int /*x*/, int /*y*/, int /*z*/) const
348 {
349   return true;
350 }
351 
getConnectionFace(int x,int y,int z,int n,double bevel,double offset,std::vector<float> & faceCorners) const352 void voxel_0_c::getConnectionFace(int x, int y, int z, int n, double bevel, double offset, std::vector<float> & faceCorners) const
353 {
354   if (n < 0)
355   {
356     n = -1-n;
357 
358     if (n < 20)
359     {
360       for (int i = 0; i < bevelFaces[n][0]; i++)
361       {
362         int v = bevelFaces[n][i+1];
363         faceCorners.push_back(x+vertices[v][0][0] + offset*vertices[v][1][0] + bevel*vertices[v][2][0]);
364         faceCorners.push_back(y+vertices[v][0][1] + offset*vertices[v][1][1] + bevel*vertices[v][2][1]);
365         faceCorners.push_back(z+vertices[v][0][2] + offset*vertices[v][1][2] + bevel*vertices[v][2][2]);
366       }
367     }
368   }
369   else
370   {
371     if (n < 6)
372     {
373       for (int i = 0; i < 4; i++)
374       {
375         int v = normalFaces[n][i];
376         faceCorners.push_back(x+vertices[v][0][0] + offset*vertices[v][1][0] + bevel*vertices[v][2][0]);
377         faceCorners.push_back(y+vertices[v][0][1] + offset*vertices[v][1][1] + bevel*vertices[v][2][1]);
378         faceCorners.push_back(z+vertices[v][0][2] + offset*vertices[v][1][2] + bevel*vertices[v][2][2]);
379       }
380     }
381   }
382 }
383 
calculateSize(float * x,float * y,float * z) const384 void voxel_0_c::calculateSize(float * x, float * y, float * z) const {
385   *x = getX();
386   *y = getY();
387   *z = getZ();
388 }
389 
meshParamsValid(double bevel,double offset) const390 bool voxel_0_c::meshParamsValid(double bevel, double offset) const {
391   if (bevel+offset > 0.5)
392     return false;
393   else
394     return true;
395 }