Blender  V2.59
sketch.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * $Id: sketch.c 36644 2011-05-12 16:47:36Z campbellbarton $
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * Contributor(s): none yet.
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <string.h>
00032 #include <math.h>
00033 #include <float.h>
00034 
00035 #include "MEM_guardedalloc.h"
00036 
00037 #include "BLI_blenlib.h"
00038 #include "BLI_math.h"
00039 #include "BLI_utildefines.h"
00040 
00041 #include "BKE_sketch.h"
00042 
00043 
00044 #include "DNA_userdef_types.h"
00045 
00046 void freeSketch(SK_Sketch *sketch)
00047 {
00048         SK_Stroke *stk, *next;
00049 
00050         for (stk = sketch->strokes.first; stk; stk = next)
00051         {
00052                 next = stk->next;
00053 
00054                 sk_freeStroke(stk);
00055         }
00056 
00057         BLI_freelistN(&sketch->depth_peels);
00058 
00059         MEM_freeN(sketch);
00060 }
00061 
00062 SK_Sketch* createSketch(void)
00063 {
00064         SK_Sketch *sketch;
00065 
00066         sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch");
00067 
00068         sketch->active_stroke = NULL;
00069         sketch->gesture = NULL;
00070 
00071         sketch->strokes.first = NULL;
00072         sketch->strokes.last = NULL;
00073 
00074         return sketch;
00075 }
00076 
00077 void sk_initPoint(SK_Point *pt, SK_DrawData *dd, float *no)
00078 {
00079         if (no)
00080         {
00081                 normalize_v3_v3(pt->no, no);
00082         }
00083         else
00084         {
00085                 pt->no[0] = 0;
00086                 pt->no[1] = 0;
00087                 pt->no[2] = 1;
00088         }
00089         pt->p2d[0] = dd->mval[0];
00090         pt->p2d[1] = dd->mval[1];
00091         /* more init code here */
00092 }
00093 
00094 void sk_copyPoint(SK_Point *dst, SK_Point *src)
00095 {
00096         memcpy(dst, src, sizeof(SK_Point));
00097 }
00098 
00099 void sk_allocStrokeBuffer(SK_Stroke *stk)
00100 {
00101         stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer");
00102 }
00103 
00104 void sk_freeStroke(SK_Stroke *stk)
00105 {
00106         MEM_freeN(stk->points);
00107         MEM_freeN(stk);
00108 }
00109 
00110 SK_Stroke* sk_createStroke(void)
00111 {
00112         SK_Stroke *stk;
00113 
00114         stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke");
00115 
00116         stk->selected = 0;
00117         stk->nb_points = 0;
00118         stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE;
00119 
00120         sk_allocStrokeBuffer(stk);
00121 
00122         return stk;
00123 }
00124 
00125 void sk_shrinkStrokeBuffer(SK_Stroke *stk)
00126 {
00127         if (stk->nb_points < stk->buf_size)
00128         {
00129                 SK_Point *old_points = stk->points;
00130 
00131                 stk->buf_size = stk->nb_points;
00132 
00133                 sk_allocStrokeBuffer(stk);
00134 
00135                 memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
00136 
00137                 MEM_freeN(old_points);
00138         }
00139 }
00140 
00141 void sk_growStrokeBuffer(SK_Stroke *stk)
00142 {
00143         if (stk->nb_points == stk->buf_size)
00144         {
00145                 SK_Point *old_points = stk->points;
00146 
00147                 stk->buf_size *= 2;
00148 
00149                 sk_allocStrokeBuffer(stk);
00150 
00151                 memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
00152 
00153                 MEM_freeN(old_points);
00154         }
00155 }
00156 
00157 void sk_growStrokeBufferN(SK_Stroke *stk, int n)
00158 {
00159         if (stk->nb_points + n > stk->buf_size)
00160         {
00161                 SK_Point *old_points = stk->points;
00162 
00163                 while (stk->nb_points + n > stk->buf_size)
00164                 {
00165                         stk->buf_size *= 2;
00166                 }
00167 
00168                 sk_allocStrokeBuffer(stk);
00169 
00170                 memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
00171 
00172                 MEM_freeN(old_points);
00173         }
00174 }
00175 
00176 
00177 void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
00178 {
00179         memcpy(stk->points + n, pt, sizeof(SK_Point));
00180 }
00181 
00182 void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
00183 {
00184         int size = stk->nb_points - n;
00185 
00186         sk_growStrokeBuffer(stk);
00187 
00188         memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point));
00189 
00190         memcpy(stk->points + n, pt, sizeof(SK_Point));
00191 
00192         stk->nb_points++;
00193 }
00194 
00195 void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt)
00196 {
00197         sk_growStrokeBuffer(stk);
00198 
00199         memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point));
00200 
00201         stk->nb_points++;
00202 }
00203 
00204 void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end)
00205 {
00206         int size = end - start + 1;
00207 
00208         sk_growStrokeBufferN(stk, len - size);
00209 
00210         if (len != size)
00211         {
00212                 int tail_size = stk->nb_points - end + 1;
00213 
00214                 memmove(stk->points + start + len, stk->points + end + 1, tail_size * sizeof(SK_Point));
00215         }
00216 
00217         memcpy(stk->points + start, pts, len * sizeof(SK_Point));
00218 
00219         stk->nb_points += len - size;
00220 }
00221 
00222 void sk_trimStroke(SK_Stroke *stk, int start, int end)
00223 {
00224         int size = end - start + 1;
00225 
00226         if (start > 0)
00227         {
00228                 memmove(stk->points, stk->points + start, size * sizeof(SK_Point));
00229         }
00230 
00231         stk->nb_points = size;
00232 }
00233 
00234 void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3])
00235 {
00236         SK_Point pt1, pt2;
00237         SK_Point *prev, *next;
00238         float delta_p[3];
00239         int i, total;
00240 
00241         total = end - start;
00242 
00243         sub_v3_v3v3(delta_p, p_end, p_start);
00244 
00245         prev = stk->points + start;
00246         next = stk->points + end;
00247 
00248         VECCOPY(pt1.p, p_start);
00249         VECCOPY(pt1.no, prev->no);
00250         pt1.mode = prev->mode;
00251         pt1.type = prev->type;
00252 
00253         VECCOPY(pt2.p, p_end);
00254         VECCOPY(pt2.no, next->no);
00255         pt2.mode = next->mode;
00256         pt2.type = next->type;
00257 
00258         sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */
00259         sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */
00260 
00261         for (i = 1; i < total; i++)
00262         {
00263                 float delta = (float)i / (float)total;
00264                 float *p = stk->points[start + 1 + i].p;
00265 
00266                 VECCOPY(p, delta_p);
00267                 mul_v3_fl(p, delta);
00268                 add_v3_v3(p, p_start);
00269         }
00270 }
00271 
00272 void sk_polygonizeStroke(SK_Stroke *stk, int start, int end)
00273 {
00274         int offset;
00275         int i;
00276 
00277         /* find first exact points outside of range */
00278         for (;start > 0; start--)
00279         {
00280                 if (stk->points[start].type == PT_EXACT)
00281                 {
00282                         break;
00283                 }
00284         }
00285 
00286         for (;end < stk->nb_points - 1; end++)
00287         {
00288                 if (stk->points[end].type == PT_EXACT)
00289                 {
00290                         break;
00291                 }
00292         }
00293 
00294         offset = start + 1;
00295 
00296         for (i = start + 1; i < end; i++)
00297         {
00298                 if (stk->points[i].type == PT_EXACT)
00299                 {
00300                         if (offset != i)
00301                         {
00302                                 memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point));
00303                         }
00304 
00305                         offset++;
00306                 }
00307         }
00308 
00309         /* some points were removes, move end of array */
00310         if (offset < end)
00311         {
00312                 int size = stk->nb_points - end;
00313                 memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point));
00314                 stk->nb_points = offset + size;
00315         }
00316 }
00317 
00318 void sk_flattenStroke(SK_Stroke *stk, int start, int end)
00319 {
00320         float normal[3], distance[3];
00321         float limit;
00322         int i, total;
00323 
00324         total = end - start + 1;
00325 
00326         VECCOPY(normal, stk->points[start].no);
00327 
00328         sub_v3_v3v3(distance, stk->points[end].p, stk->points[start].p);
00329         project_v3_v3v3(normal, distance, normal);
00330         limit = normalize_v3(normal);
00331 
00332         for (i = 1; i < total - 1; i++)
00333         {
00334                 float d = limit * i / total;
00335                 float offset[3];
00336                 float *p = stk->points[start + i].p;
00337 
00338                 sub_v3_v3v3(distance, p, stk->points[start].p);
00339                 project_v3_v3v3(distance, distance, normal);
00340 
00341                 VECCOPY(offset, normal);
00342                 mul_v3_fl(offset, d);
00343 
00344                 sub_v3_v3(p, distance);
00345                 add_v3_v3(p, offset);
00346         }
00347 }
00348 
00349 void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk)
00350 {
00351         if (sketch->active_stroke == stk)
00352         {
00353                 sketch->active_stroke = NULL;
00354         }
00355 
00356         BLI_remlink(&sketch->strokes, stk);
00357         sk_freeStroke(stk);
00358 }
00359 
00360 void sk_reverseStroke(SK_Stroke *stk)
00361 {
00362         SK_Point *old_points = stk->points;
00363         int i = 0;
00364 
00365         sk_allocStrokeBuffer(stk);
00366 
00367         for (i = 0; i < stk->nb_points; i++)
00368         {
00369                 sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i);
00370         }
00371 
00372         MEM_freeN(old_points);
00373 }
00374 
00375 
00376 /* Ramer-Douglas-Peucker algorithm for line simplification */
00377 void sk_filterStroke(SK_Stroke *stk, int start, int end)
00378 {
00379         SK_Point *old_points = stk->points;
00380         int nb_points = stk->nb_points;
00381         char *marked = NULL;
00382         char work;
00383         int i;
00384 
00385         if (start == -1)
00386         {
00387                 start = 0;
00388                 end = stk->nb_points - 1;
00389         }
00390 
00391         sk_allocStrokeBuffer(stk);
00392         stk->nb_points = 0;
00393 
00394         /* adding points before range */
00395         for (i = 0; i < start; i++)
00396         {
00397                 sk_appendStrokePoint(stk, old_points + i);
00398         }
00399 
00400         marked = MEM_callocN(nb_points, "marked array");
00401         marked[start] = 1;
00402         marked[end] = 1;
00403         
00404         work = 1;
00405         
00406         /* while still reducing */
00407         while (work)
00408         {
00409                 int ls, le;
00410                 work = 0;
00411                 
00412                 ls = start;
00413                 le = start+1;
00414                 
00415                 /* while not over interval */
00416                 while (ls < end)
00417                 {
00418                         int max_i = 0;
00419                         short v1[2];
00420                         float max_dist = 16; /* more than 4 pixels */
00421                         
00422                         /* find the next marked point */
00423                         while(marked[le] == 0)
00424                         {
00425                                 le++;
00426                         }
00427                         
00428                         /* perpendicular vector to ls-le */
00429                         v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0]; 
00430                         v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1]; 
00431                         
00432 
00433                         for( i = ls + 1; i < le; i++ )
00434                         {
00435                                 float mul;
00436                                 float dist;
00437                                 short v2[2];
00438                                 
00439                                 v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0]; 
00440                                 v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1];
00441                                 
00442                                 if (v2[0] == 0 && v2[1] == 0)
00443                                 {
00444                                         continue;
00445                                 }
00446 
00447                                 mul = (float)(v1[0]*v2[0] + v1[1]*v2[1]) / (float)(v2[0]*v2[0] + v2[1]*v2[1]);
00448                                 
00449                                 dist = mul * mul * (v2[0]*v2[0] + v2[1]*v2[1]);
00450                                 
00451                                 if (dist > max_dist)
00452                                 {
00453                                         max_dist = dist;
00454                                         max_i = i;
00455                                 }
00456                         }
00457                         
00458                         if (max_i != 0)
00459                         {
00460                                 work = 1;
00461                                 marked[max_i] = 1;
00462                         }
00463                         
00464                         ls = le;
00465                         le = ls + 1;
00466                 }
00467         }
00468         
00469 
00470         /* adding points after range */
00471         for (i = start; i <= end; i++)
00472         {
00473                 if (marked[i])
00474                 {
00475                         sk_appendStrokePoint(stk, old_points + i);
00476                 }
00477         }
00478 
00479         MEM_freeN(marked);
00480 
00481         /* adding points after range */
00482         for (i = end + 1; i < nb_points; i++)
00483         {
00484                 sk_appendStrokePoint(stk, old_points + i);
00485         }
00486 
00487         MEM_freeN(old_points);
00488 
00489         sk_shrinkStrokeBuffer(stk);
00490 }
00491 
00492 
00493 void sk_filterLastContinuousStroke(SK_Stroke *stk)
00494 {
00495         int start, end;
00496 
00497         end = stk->nb_points -1;
00498 
00499         for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--)
00500         {
00501                 /* nothing to do here*/
00502         }
00503 
00504         if (end - start > 1)
00505         {
00506                 sk_filterStroke(stk, start, end);
00507         }
00508 }
00509 
00510 SK_Point *sk_lastStrokePoint(SK_Stroke *stk)
00511 {
00512         SK_Point *pt = NULL;
00513 
00514         if (stk->nb_points > 0)
00515         {
00516                 pt = stk->points + (stk->nb_points - 1);
00517         }
00518 
00519         return pt;
00520 }
00521 
00522 void sk_endContinuousStroke(SK_Stroke *stk)
00523 {
00524         stk->points[stk->nb_points - 1].type = PT_EXACT;
00525 }
00526 
00527 void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk)
00528 {
00529         if (stk)
00530         {
00531                 memcpy(&sketch->next_point, stk->points[stk->nb_points - 1].p, sizeof(SK_Point));
00532         }
00533 }
00534 
00535 int sk_stroke_filtermval(SK_DrawData *dd)
00536 {
00537         int retval = 0;
00538         if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist)
00539         {
00540                 retval = 1;
00541         }
00542 
00543         return retval;
00544 }
00545 
00546 void sk_initDrawData(SK_DrawData *dd, const int mval[2])
00547 {
00548         dd->mval[0] = mval[0];
00549         dd->mval[1] = mval[1];
00550         dd->previous_mval[0] = -1;
00551         dd->previous_mval[1] = -1;
00552         dd->type = PT_EXACT;
00553 }
00554 
00555 
00556 void sk_deleteSelectedStrokes(SK_Sketch *sketch)
00557 {
00558         SK_Stroke *stk, *next;
00559 
00560         for (stk = sketch->strokes.first; stk; stk = next)
00561         {
00562                 next = stk->next;
00563 
00564                 if (stk->selected == 1)
00565                 {
00566                         sk_removeStroke(sketch, stk);
00567                 }
00568         }
00569 }
00570 
00571 void sk_selectAllSketch(SK_Sketch *sketch, int mode)
00572 {
00573         SK_Stroke *stk = NULL;
00574 
00575         if (mode == -1)
00576         {
00577                 for (stk = sketch->strokes.first; stk; stk = stk->next)
00578                 {
00579                         stk->selected = 0;
00580                 }
00581         }
00582         else if (mode == 0)
00583         {
00584                 for (stk = sketch->strokes.first; stk; stk = stk->next)
00585                 {
00586                         stk->selected = 1;
00587                 }
00588         }
00589         else if (mode == 1)
00590         {
00591                 int selected = 1;
00592 
00593                 for (stk = sketch->strokes.first; stk; stk = stk->next)
00594                 {
00595                         selected &= stk->selected;
00596                 }
00597 
00598                 selected ^= 1;
00599 
00600                 for (stk = sketch->strokes.first; stk; stk = stk->next)
00601                 {
00602                         stk->selected = selected;
00603                 }
00604         }
00605 }