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 }