2.5: Various Fixes
[blender.git] / source / blender / editors / curve / editcurve.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <string.h>
32
33 #ifndef WIN32
34 #include <unistd.h>
35 #else
36 #include <io.h>
37 #endif
38 #include <stdlib.h>
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43 #include "BLI_dynstr.h"
44 #include "BLI_rand.h"
45
46 #include "DNA_curve_types.h"
47 #include "DNA_key_types.h"
48 #include "DNA_mesh_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_view3d_types.h"
54 #include "DNA_userdef_types.h"
55
56 #include "BKE_context.h"
57 #include "BKE_curve.h"
58 #include "BKE_depsgraph.h"
59 #include "BKE_fcurve.h"
60 #include "BKE_global.h"
61 #include "BKE_key.h"
62 #include "BKE_library.h"
63 #include "BKE_main.h"
64 #include "BKE_object.h"
65 #include "BKE_report.h"
66 #include "BKE_utildefines.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "ED_anim_api.h"
72 #include "ED_curve.h"
73 #include "ED_keyframes_edit.h"
74 #include "ED_object.h"
75 #include "ED_screen.h"
76 #include "ED_types.h"
77 #include "ED_util.h"
78 #include "ED_view3d.h"
79
80 #include "UI_interface.h"
81
82 #include "BIF_transform.h"
83
84 #include "RNA_access.h"
85 #include "RNA_define.h"
86
87 /* still need to eradicate a few :( */
88 #define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
89
90 /* for curve objects in editmode that can have hidden handles  */
91 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
92
93 float nurbcircle[8][2]= {
94         {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0,  1.0},
95         {0.0,  1.0}, { 1.0,  1.0}, { 1.0, 0.0}, { 1.0, -1.0}
96 };
97
98 ListBase *curve_get_editcurve(Object *ob)
99 {
100         if(ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
101                 Curve *cu= ob->data;
102                 return cu->editnurb;
103         }
104         return NULL;
105 }
106
107 /* this replaces the active flag used in uv/face mode */
108 void set_actNurb(Object *obedit, Nurb *nu)
109 {
110         Curve *cu= obedit->data;
111         
112         if(nu==NULL)
113                 cu->actnu = -1;
114         else
115                 cu->actnu = BLI_findindex(cu->editnurb, nu);
116 }
117
118 Nurb *get_actNurb(Object *obedit)
119 {
120         Curve *cu= obedit->data;
121         
122         return BLI_findlink(cu->editnurb, cu->actnu);
123 }
124
125 /* ******************* SELECTION FUNCTIONS ********************* */
126
127 #define HIDDEN                  1
128 #define VISIBLE                 0
129
130 #define FIRST                   1
131 #define LAST                    0
132
133
134 /* returns 1 in case (de)selection was successful */
135 static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
136 {       
137         if(bezt) {
138                 if((bezt->hide==0) || (hidden==1)) {
139                         if(selstatus==1) { /* selects */                        
140                                 bezt->f1 |= flag;
141                                 bezt->f2 |= flag;
142                                 bezt->f3 |= flag;
143                                 return 1;                       
144                         }
145                         else { /* deselects */  
146                                 bezt->f1 &= ~flag; 
147                                 bezt->f2 &= ~flag; 
148                                 bezt->f3 &= ~flag; 
149                                 return 1;
150                         }
151                 }
152         }
153         
154         return 0;
155 }
156
157 /* returns 1 in case (de)selection was successful */
158 static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden) 
159 {       
160         if(bp) {
161                 if((bp->hide==0) || (hidden==1)) {
162                         if(selstatus==1) {
163                                 bp->f1 |= flag;
164                                 return 1;
165                         }
166                         else {
167                                 bp->f1 &= ~flag;
168                                 return 1;
169                         }
170                 }
171         }
172
173         return 0;
174 }
175
176 static short swap_selection_beztriple(BezTriple *bezt)
177 {
178         if(bezt->f2 & SELECT)
179                 return select_beztriple(bezt, DESELECT, 1, VISIBLE);
180         else
181                 return select_beztriple(bezt, SELECT, 1, VISIBLE);
182 }
183
184 static short swap_selection_bpoint(BPoint *bp)
185 {
186         if(bp->f1 & SELECT)
187                 return select_bpoint(bp, DESELECT, 1, VISIBLE);
188         else
189                 return select_bpoint(bp, SELECT, 1, VISIBLE);
190 }
191
192 int isNurbsel(Nurb *nu)
193 {
194         BezTriple *bezt;
195         BPoint *bp;
196         int a;
197
198         if((nu->type & 7)==CU_BEZIER) {
199                 bezt= nu->bezt;
200                 a= nu->pntsu;
201                 while(a--) {
202                         if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
203                         bezt++;
204                 }
205         }
206         else {
207                 bp= nu->bp;
208                 a= nu->pntsu*nu->pntsv;
209                 while(a--) {
210                         if( (bp->f1 & SELECT) ) return 1;
211                         bp++;
212                 }
213         }
214         return 0;
215 }
216
217 int isNurbsel_count(Nurb *nu)
218 {
219         BezTriple *bezt;
220         BPoint *bp;
221         int a, sel=0;
222
223         if((nu->type & 7)==CU_BEZIER) {
224                 bezt= nu->bezt;
225                 a= nu->pntsu;
226                 while(a--) {
227                         if (BEZSELECTED_HIDDENHANDLES(bezt)) sel++;
228                         bezt++;
229                 }
230         }
231         else {
232                 bp= nu->bp;
233                 a= nu->pntsu*nu->pntsv;
234                 while(a--) {
235                         if( (bp->f1 & SELECT) ) sel++;
236                         bp++;
237                 }
238         }
239         return sel;
240 }
241
242 /* ******************* PRINTS ********************* */
243
244 void printknots(Object *obedit)
245 {
246         ListBase *editnurb= curve_get_editcurve(obedit);
247         Nurb *nu;
248         int a, num;
249
250         for(nu= editnurb->first; nu; nu= nu->next) {
251                 if(isNurbsel(nu) &&  (nu->type & 7)==CU_NURBS) {
252                         if(nu->knotsu) {
253                                 num= KNOTSU(nu);
254                                 for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
255                         }
256                         if(nu->knotsv) {
257                                 num= KNOTSV(nu);
258                                 for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
259                         }
260                 }
261         }
262 }
263
264 /* ********************* LOAD and MAKE *************** */
265
266 /* load editNurb in object */
267 void load_editNurb(Object *obedit)
268 {
269         ListBase *editnurb= curve_get_editcurve(obedit);
270
271         if(obedit==NULL) return;
272
273         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
274                 Curve *cu= obedit->data;
275                 Nurb *nu, *newnu;
276                 KeyBlock *actkey;
277                 int totvert= count_curveverts(editnurb);
278
279                 /* are there keys? */
280                 actkey = ob_get_keyblock(obedit);
281                 if(actkey) {
282                         /* active key: the vertices */
283                         
284                         if(totvert) {
285                                 if(actkey->data) MEM_freeN(actkey->data);
286                         
287                                 actkey->data= MEM_callocN(cu->key->elemsize*totvert, "actkey->data");
288                                 actkey->totelem= totvert;
289                 
290                                 curve_to_key(cu, actkey, editnurb);
291                         }
292                 }
293                 
294                 if(cu->key && actkey!=cu->key->refkey) {
295                         ;
296                 }
297                 else {
298                         freeNurblist(&(cu->nurb));
299                         
300                         for(nu= editnurb->first; nu; nu= nu->next) {
301                                 newnu= duplicateNurb(nu);
302                                 BLI_addtail(&(cu->nurb), newnu);
303                                 
304                                 if((nu->type & 7)==CU_NURBS) {
305                                         clamp_nurb_order_u(nu);
306                                 }
307                         }
308                 }
309         }
310         
311         set_actNurb(obedit, NULL);
312 }
313
314 /* make copy in cu->editnurb */
315 void make_editNurb(Object *obedit)
316 {
317         ListBase *editnurb= curve_get_editcurve(obedit);
318         Nurb *nu, *newnu;
319         KeyBlock *actkey;
320
321         if(obedit==NULL) return;
322
323         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
324                 Curve *cu= obedit->data;
325                 
326                 if(editnurb)
327                         freeNurblist(editnurb);
328                 else
329                         editnurb= cu->editnurb= MEM_callocN(sizeof(ListBase), "editnurb");
330                 
331                 nu= cu->nurb.first;
332                 cu->lastselbp= NULL;   /* for select row */
333                 
334                 while(nu) {
335                         newnu= duplicateNurb(nu);
336                         test2DNurb(newnu);      // after join, or any other creation of curve
337                         BLI_addtail(editnurb, newnu);
338                         nu= nu->next;
339                 }
340                 
341                 actkey = ob_get_keyblock(obedit);
342                 if(actkey) {
343                         // XXX strcpy(G.editModeTitleExtra, "(Key) ");
344                         key_to_curve(actkey, cu, editnurb);
345                 }
346         }
347         
348         set_actNurb(obedit, NULL);
349 }
350
351 void free_editNurb(Object *obedit)
352 {
353         Curve *cu= obedit->data;
354
355         if(cu->editnurb) {
356                 freeNurblist(cu->editnurb);
357                 MEM_freeN(cu->editnurb);
358                 cu->editnurb= NULL;
359         }
360 }
361
362 /******************** separate operator ***********************/
363
364 static int separate_exec(bContext *C, wmOperator *op)
365 {
366         Scene *scene= CTX_data_scene(C);
367         Nurb *nu, *nu1;
368         Object *oldob, *newob;
369         Base *oldbase, *newbase;
370         Curve *oldcu, *newcu;
371         ListBase *oldedit, *newedit;
372
373         oldbase= CTX_data_active_base(C);
374         oldob= oldbase->object;
375         oldcu= oldob->data;
376         oldedit= oldcu->editnurb;
377
378         if(oldcu->key) {
379                 BKE_report(op->reports, RPT_ERROR, "Can't separate a curve with vertex keys.");
380                 return OPERATOR_CANCELLED;
381         }
382
383         WM_cursor_wait(1);
384         
385         /* 1. duplicate the object and data */
386         newbase= ED_object_add_duplicate(scene, oldbase, 0);    /* 0 = fully linked */
387         ED_base_object_select(newbase, BA_DESELECT);
388         newob= newbase->object;
389
390         newcu= newob->data= copy_curve(oldcu);
391         newcu->editnurb= NULL;
392         oldcu->id.us--; /* because new curve is a copy: reduce user count */
393
394         /* 2. put new object in editmode and clear it */
395         make_editNurb(newob);
396         newedit= newcu->editnurb;
397         freeNurblist(newedit);
398
399         /* 3. move over parts from old object */
400         for(nu= oldedit->first; nu; nu=nu1) {
401                 nu1= nu->next;
402
403                 if(isNurbsel(nu)) {
404                         BLI_remlink(oldedit, nu);
405                         BLI_addtail(newedit, nu);
406                 }
407         }
408
409         /* 4. put old object out of editmode */
410         load_editNurb(newob);
411         free_editNurb(newob);
412
413         DAG_object_flush_update(scene, oldob, OB_RECALC_DATA);  /* this is the original one */
414         DAG_object_flush_update(scene, newob, OB_RECALC_DATA);  /* this is the separated one */
415
416         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, oldob);
417
418         WM_cursor_wait(0);
419
420         return OPERATOR_FINISHED;
421 }
422
423 void CURVE_OT_separate(wmOperatorType *ot)
424 {
425         /* identifiers */
426         ot->name= "Separate";
427         ot->idname= "CURVE_OT_separate";
428         
429         /* api callbacks */
430         ot->exec= separate_exec;
431         ot->poll= ED_operator_editsurfcurve;
432         
433         /* flags */
434         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
435 }
436
437 /* ******************* FLAGS ********************* */
438
439 static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
440 {
441         /* return u!=-1:     1 row in u-direction selected. U has value between 0-pntsv 
442      * return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu 
443      */
444         BPoint *bp;
445         int a, b, sel;
446
447         *u= *v= -1;
448
449         bp= nu->bp;
450         for(b=0; b<nu->pntsv; b++) {
451                 sel= 0;
452                 for(a=0; a<nu->pntsu; a++, bp++) {
453                         if(bp->f1 & flag) sel++;
454                 }
455                 if(sel==nu->pntsu) {
456                         if(*u== -1) *u= b;
457                         else return 0;
458                 }
459                 else if(sel>1) return 0;    /* because sel==1 is still ok */
460         }
461
462         for(a=0; a<nu->pntsu; a++) {
463                 sel= 0;
464                 bp= nu->bp+a;
465                 for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
466                         if(bp->f1 & flag) sel++;
467                 }
468                 if(sel==nu->pntsv) {
469                         if(*v== -1) *v= a;
470                         else return 0;
471                 }
472                 else if(sel>1) return 0;
473         }
474
475         if(*u==-1 && *v>-1) return 1;
476         if(*v==-1 && *u>-1) return 1;
477         return 0;
478 }
479
480 static void setflagsNurb(ListBase *editnurb, short flag)
481 {
482         Nurb *nu;
483         BezTriple *bezt;
484         BPoint *bp;
485         int a;
486
487         for(nu= editnurb->first; nu; nu= nu->next) {
488                 if( (nu->type & 7)==CU_BEZIER) {
489                         a= nu->pntsu;
490                         bezt= nu->bezt;
491                         while(a--) {
492                                 bezt->f1= bezt->f2= bezt->f3= flag;
493                                 bezt++;
494                         }
495                 }
496                 else {
497                         a= nu->pntsu*nu->pntsv;
498                         bp= nu->bp;
499                         while(a--) {
500                                 bp->f1= flag;
501                                 bp++;
502                         }
503                 }
504         }
505 }
506
507 static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[][3])
508 {
509         /* all verts with (flag & 'flag') rotate */
510         Nurb *nu;
511         BPoint *bp;
512         int a;
513
514         for(nu= editnurb->first; nu; nu= nu->next) {
515                 if((nu->type & 7)==CU_NURBS) {
516                         bp= nu->bp;
517                         a= nu->pntsu*nu->pntsv;
518
519                         while(a--) {
520                                 if(bp->f1 & flag) {
521                                         bp->vec[0]-=cent[0];
522                                         bp->vec[1]-=cent[1];
523                                         bp->vec[2]-=cent[2];
524                                         Mat3MulVecfl(rotmat, bp->vec);
525                                         bp->vec[0]+=cent[0];
526                                         bp->vec[1]+=cent[1];
527                                         bp->vec[2]+=cent[2];
528                                 }
529                                 bp++;
530                         }
531                 }
532         }
533 }
534
535 static void translateflagNurb(ListBase *editnurb, short flag, float *vec)
536 {
537         /* all verts with ('flag' & flag) translate */
538         Nurb *nu;
539         BezTriple *bezt;
540         BPoint *bp;
541         int a;
542
543         for(nu= editnurb->first; nu; nu= nu->next) {
544                 if( (nu->type & 7)==CU_BEZIER) {
545                         a= nu->pntsu;
546                         bezt= nu->bezt;
547                         while(a--) {
548                                 if(bezt->f1 & flag) VecAddf(bezt->vec[0], bezt->vec[0], vec);
549                                 if(bezt->f2 & flag) VecAddf(bezt->vec[1], bezt->vec[1], vec);
550                                 if(bezt->f3 & flag) VecAddf(bezt->vec[2], bezt->vec[2], vec);
551                                 bezt++;
552                         }
553                 }
554                 else {
555                         a= nu->pntsu*nu->pntsv;
556                         bp= nu->bp;
557                         while(a--) {
558                                 if(bp->f1 & flag) VecAddf(bp->vec, bp->vec, vec);
559                                 bp++;
560                         }
561                 }
562
563                 test2DNurb(nu);
564         }
565 }
566
567 static void weightflagNurb(ListBase *editnurb, short flag, float w, int mode)   /* mode==0: replace, mode==1: multiply */
568 {
569         Nurb *nu;
570         BPoint *bp;
571         int a;
572
573         for(nu= editnurb->first; nu; nu= nu->next) {
574                 if((nu->type & 7)==CU_NURBS) {
575                         a= nu->pntsu*nu->pntsv;
576                         bp= nu->bp;
577                         while(a--) {
578                                 if(bp->f1 & flag) {
579                                         if(mode==1) bp->vec[3]*= w;
580                                         else bp->vec[3]= w;
581                                 }
582                                 bp++;
583                         }
584                 }
585         }
586 }
587
588 static int deleteflagNurb(bContext *C, wmOperator *op, int flag)
589 {
590         Object *obedit= CTX_data_edit_object(C);
591         Curve *cu= obedit->data;
592         ListBase *editnurb= curve_get_editcurve(obedit);
593         Nurb *nu, *next;
594         BPoint *bp, *bpn, *newbp;
595         int a, b, newu, newv, sel;
596
597         if(obedit && obedit->type==OB_SURF);
598         else return OPERATOR_CANCELLED;
599
600         cu->lastselbp= NULL;
601
602         nu= editnurb->first;
603         while(nu) {
604                 next= nu->next;
605
606                 /* is entire nurb selected */
607                 bp= nu->bp;
608                 a= nu->pntsu*nu->pntsv;
609                 while(a) {
610                         a--;
611                         if(bp->f1 & flag);
612                         else break;
613                         bp++;
614                 }
615                 if(a==0) {
616                         BLI_remlink(editnurb, nu);
617                         freeNurb(nu); nu=NULL;
618                 }
619                 else {
620                         /* is nurb in U direction selected */
621                         newv= nu->pntsv;
622                         bp= nu->bp;
623                         for(b=0; b<nu->pntsv; b++) {
624                                 sel= 0;
625                                 for(a=0; a<nu->pntsu; a++, bp++) {
626                                         if(bp->f1 & flag) sel++;
627                                 }
628                                 if(sel==nu->pntsu) {
629                                         newv--;
630                                 }
631                                 else if(sel>=1) {
632                                         /* don't delete */
633                                         break;
634                                 }
635                         }
636                         if(newv!=nu->pntsv && b==nu->pntsv)     {
637                                 /* delete */
638                                 bp= nu->bp;
639                                 bpn = newbp =
640                                         (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
641                                 for(b=0; b<nu->pntsv; b++) {
642                                         if((bp->f1 & flag)==0) {
643                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
644                                                 bpn+= nu->pntsu;
645                                         }
646                                         bp+= nu->pntsu;
647                                 }
648                                 nu->pntsv= newv;
649                                 MEM_freeN(nu->bp);
650                                 nu->bp= newbp;
651                                 clamp_nurb_order_v(nu);
652
653                                 makeknots(nu, 2);
654                         }
655                         else {
656                                 /* is the nurb in V direction selected */
657                                 newu= nu->pntsu;
658                                 for(a=0; a<nu->pntsu; a++) {
659                                         bp= nu->bp+a;
660                                         sel= 0;
661                                         for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
662                                                 if(bp->f1 & flag) sel++;
663                                         }
664                                         if(sel==nu->pntsv) {
665                                                 newu--;
666                                         }
667                                         else if(sel>=1) {
668                                                 /* don't delete */
669                                                 break;
670                                         }
671                                 }
672                                 if(newu!=nu->pntsu && a==nu->pntsu)     {
673                                         /* delete */
674                                         bp= nu->bp;
675                                         bpn = newbp =
676                                                 (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
677                                         for(b=0; b<nu->pntsv; b++) {
678                                                 for(a=0; a<nu->pntsu; a++, bp++) {
679                                                         if((bp->f1 & flag)==0) {
680                                                                 *bpn= *bp;
681                                                                 bpn++;
682                                                         }
683                                                 }
684                                         }
685                                         MEM_freeN(nu->bp);
686                                         nu->bp= newbp;
687                                         if(newu==1 && nu->pntsv>1) {    /* make a U spline */
688                                                 nu->pntsu= nu->pntsv;
689                                                 nu->pntsv= 1;
690                                                 SWAP(short, nu->orderu, nu->orderv);
691                                                 clamp_nurb_order_u(nu);
692                                                 if(nu->knotsv) MEM_freeN(nu->knotsv);
693                                                 nu->knotsv= NULL;
694                                         }
695                                         else {
696                                                 nu->pntsu= newu;
697                                                 clamp_nurb_order_u(nu);
698                                         }
699                                         makeknots(nu, 1);
700                                 }
701                         }
702                 }
703                 nu= next;
704         }
705
706         return OPERATOR_FINISHED;
707 }
708
709 /* only for OB_SURF */
710 static short extrudeflagNurb(ListBase *editnurb, int flag)
711 {
712         Nurb *nu;
713         BPoint *bp, *bpn, *newbp;
714         int ok= 0, a, u, v, len;
715
716         nu= editnurb->first;
717         while(nu) {
718
719                 if(nu->pntsv==1) {
720                         bp= nu->bp;
721                         a= nu->pntsu;
722                         while(a) {
723                                 if(bp->f1 & flag);
724                                 else break;
725                                 bp++;
726                                 a--;
727                         }
728                         if(a==0) {
729                                 ok= 1;
730                                 newbp =
731                                         (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
732                                 memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
733                                 bp= newbp+ nu->pntsu;
734                                 memcpy(bp, nu->bp, nu->pntsu*sizeof(BPoint) );
735                                 MEM_freeN(nu->bp);
736                                 nu->bp= newbp;
737                                 a= nu->pntsu;
738                                 while(a--) {
739                                         select_bpoint(bp, SELECT, flag, HIDDEN);
740                                         select_bpoint(newbp, DESELECT, flag, HIDDEN);
741                                         bp++; 
742                                         newbp++;
743                                 }
744
745                                 nu->pntsv= 2;
746                                 nu->orderv= 2;
747                                 makeknots(nu, 2);
748                         }
749                 }
750                 else {
751                         /* which row or collumn is selected */
752
753                         if( isNurbselUV(nu, &u, &v, flag) ) {
754
755                                 /* deselect all */
756                                 bp= nu->bp;
757                                 a= nu->pntsu*nu->pntsv;
758                                 while(a--) {
759                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
760                                         bp++;
761                                 }
762
763                                 if(u==0 || u== nu->pntsv-1) {       /* row in u-direction selected */
764                                         ok= 1;
765                                         newbp =
766                                                 (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
767                                                                                   * sizeof(BPoint), "extrudeNurb1");
768                                         if(u==0) {
769                                                 len= nu->pntsv*nu->pntsu;
770                                                 memcpy(newbp+nu->pntsu, nu->bp, len*sizeof(BPoint) );
771                                                 memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
772                                                 bp= newbp;
773                                         }
774                                         else {
775                                                 len= nu->pntsv*nu->pntsu;
776                                                 memcpy(newbp, nu->bp, len*sizeof(BPoint) );
777                                                 memcpy(newbp+len, nu->bp+len-nu->pntsu, nu->pntsu*sizeof(BPoint) );
778                                                 bp= newbp+len;
779                                         }
780
781                                         a= nu->pntsu;
782                                         while(a--) {
783                                                 select_bpoint(bp, SELECT, flag, HIDDEN);
784                                                 bp++;
785                                         }
786
787                                         MEM_freeN(nu->bp);
788                                         nu->bp= newbp;
789                                         nu->pntsv++;
790                                         makeknots(nu, 2);
791                                 }
792                                 else if(v==0 || v== nu->pntsu-1) {          /* collumn in v-direction selected */
793                                         ok= 1;
794                                         bpn = newbp =
795                                                 (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
796                                         bp= nu->bp;
797
798                                         for(a=0; a<nu->pntsv; a++) {
799                                                 if(v==0) {
800                                                         *bpn= *bp;
801                                                         bpn->f1 |= flag;
802                                                         bpn++;
803                                                 }
804                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
805                                                 bp+= nu->pntsu;
806                                                 bpn+= nu->pntsu;
807                                                 if(v== nu->pntsu-1) {
808                                                         *bpn= *(bp-1);
809                                                         bpn->f1 |= flag;
810                                                         bpn++;
811                                                 }
812                                         }
813
814                                         MEM_freeN(nu->bp);
815                                         nu->bp= newbp;
816                                         nu->pntsu++;
817                                         makeknots(nu, 1);
818                                 }
819                         }
820                 }
821                 nu= nu->next;
822         }
823
824         return ok;
825 }
826
827 static void adduplicateflagNurb(Object *obedit, short flag)
828 {
829         ListBase *editnurb= curve_get_editcurve(obedit);
830         Nurb *nu, *newnu;
831         BezTriple *bezt, *bezt1;
832         BPoint *bp, *bp1;
833         int a, b, starta, enda, newu, newv;
834         char *usel;
835
836         nu= editnurb->last;
837         while(nu) {
838                 if( (nu->type & 7)==CU_BEZIER) {
839                         bezt= nu->bezt;
840                         for(a=0; a<nu->pntsu; a++) {
841                                 enda= -1;
842                                 starta= a;
843                                 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
844                                         select_beztriple(bezt, DESELECT, flag, HIDDEN);
845                                         enda=a;
846                                         if(a>=nu->pntsu-1) break;
847                                         a++;
848                                         bezt++;
849                                 }
850                                 if(enda>=starta) {
851                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");  
852                                         memcpy(newnu, nu, sizeof(Nurb));
853                                         BLI_addtail(editnurb, newnu);
854                                         set_actNurb(obedit, newnu);
855                                         newnu->pntsu= enda-starta+1;
856                                         newnu->bezt=
857                                                 (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");  
858                                         memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
859
860                                         b= newnu->pntsu;
861                                         bezt1= newnu->bezt;
862                                         while(b--) {
863                                                 select_beztriple(bezt1, SELECT, flag, HIDDEN);
864                                                 bezt1++;
865                                         }
866
867                                         if(nu->flagu & CU_CYCLIC) {
868                                                 if(starta!=0 || enda!=nu->pntsu-1) {
869                                                         newnu->flagu &= ~CU_CYCLIC;
870                                                 }
871                                         }
872                                 }
873                                 bezt++;
874                         }
875                 }
876                 else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
877                         bp= nu->bp;
878                         for(a=0; a<nu->pntsu; a++) {
879                                 enda= -1;
880                                 starta= a;
881                                 while(bp->f1 & flag) {
882                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
883                                         enda= a;
884                                         if(a>=nu->pntsu-1) break;
885                                         a++;
886                                         bp++;
887                                 }
888                                 if(enda>=starta) {
889                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");  
890                                         memcpy(newnu, nu, sizeof(Nurb));
891                                         set_actNurb(obedit, newnu);
892                                         BLI_addtail(editnurb, newnu);
893                                         newnu->pntsu= enda-starta+1;
894                                         newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
895                                         memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
896
897                                         b= newnu->pntsu;
898                                         bp1= newnu->bp;
899                                         while(b--) {
900                                                 select_bpoint(bp1, SELECT, flag, HIDDEN);
901                                                 bp1++;
902                                         }
903
904                                         if(nu->flagu & CU_CYCLIC) {
905                                                 if(starta!=0 || enda!=nu->pntsu-1) {
906                                                         newnu->flagu &= ~CU_CYCLIC;
907                                                 }
908                                         }
909
910                                         /* knots */
911                                         newnu->knotsu= NULL;
912                                         makeknots(newnu, 1);
913                                 }
914                                 bp++;
915                         }
916                 }
917                 else {
918                         /* a rectangular area in nurb has to be selected */
919                         if(isNurbsel(nu)) {
920                                 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
921                                 bp= nu->bp;
922                                 for(a=0; a<nu->pntsv; a++) {
923                                         for(b=0; b<nu->pntsu; b++, bp++) {
924                                                 if(bp->f1 & flag) usel[b]++;
925                                         }
926                                 }
927                                 newu= 0;
928                                 newv= 0;
929                                 for(a=0; a<nu->pntsu; a++) {
930                                         if(usel[a]) {
931                                                 if(newv==0 || usel[a]==newv) {
932                                                         newv= usel[a];
933                                                         newu++;
934                                                 }
935                                                 else {
936                                                         newv= 0;
937                                                         break;
938                                                 }
939                                         }
940                                 }
941                                 if(newu==0 || newv==0) {
942                                         printf("Can't duplicate Nurb\n");
943                                 }
944                                 else {
945
946                                         if(newu==1) SWAP(short, newu, newv);
947
948                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
949                                         memcpy(newnu, nu, sizeof(Nurb));
950                                         BLI_addtail(editnurb, newnu);
951                                         set_actNurb(obedit, newnu);
952                                         newnu->pntsu= newu;
953                                         newnu->pntsv= newv;
954                                         newnu->bp =
955                                                 (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
956                                         clamp_nurb_order_u(newnu);
957                                         clamp_nurb_order_v(newnu);
958                                         
959                                         newnu->knotsu= newnu->knotsv= NULL;
960                                         
961                                         bp= newnu->bp;
962                                         bp1= nu->bp;
963                                         for(a=0; a<nu->pntsv; a++) {
964                                                 for(b=0; b<nu->pntsu; b++, bp1++) {
965                                                         if(bp1->f1 & flag) {
966                                                                 memcpy(bp, bp1, sizeof(BPoint));
967                                                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
968                                                                 bp++;
969                                                         }
970                                                 }
971                                         }
972                                         if (check_valid_nurb_u(newnu)) {
973                                                 if(nu->pntsu==newnu->pntsu && nu->knotsu) {
974                                                         newnu->knotsu= MEM_dupallocN( nu->knotsu );
975                                                 } else {
976                                                         makeknots(newnu, 1);
977                                                 }
978                                         }
979                                         if (check_valid_nurb_v(newnu)) {
980                                                 if(nu->pntsv==newnu->pntsv && nu->knotsv) {
981                                                         newnu->knotsv= MEM_dupallocN( nu->knotsv );
982                                                 } else {
983                                                         makeknots(newnu, 2);
984                                                 }
985                                         }
986                                 }
987                                 MEM_freeN(usel);
988                         }
989                 }
990
991                 nu= nu->prev;
992         }
993         
994         /* actnu changed */
995 }
996
997 /**************** switch direction operator ***************/
998
999 static int switch_direction_exec(bContext *C, wmOperator *op)
1000 {
1001         Object *obedit= CTX_data_edit_object(C);
1002         ListBase *editnurb= curve_get_editcurve(obedit);
1003         Nurb *nu;
1004         
1005         for(nu= editnurb->first; nu; nu= nu->next)
1006                 if(isNurbsel(nu))
1007                         switchdirectionNurb(nu);
1008         
1009         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1010         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1011
1012         return OPERATOR_FINISHED;
1013 }
1014
1015 void CURVE_OT_switch_direction(wmOperatorType *ot)
1016 {
1017         /* identifiers */
1018         ot->name= "Switch Direction";
1019         ot->idname= "CURVE_OT_switch_direction";
1020         
1021         /* api callbacks */
1022         ot->exec= switch_direction_exec;
1023         ot->poll= ED_operator_editsurfcurve;
1024
1025         /* flags */
1026         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1027 }
1028
1029 /****************** set weight operator *******************/
1030
1031 static int set_weight_exec(bContext *C, wmOperator *op)
1032 {
1033         Object *obedit= CTX_data_edit_object(C);
1034         ListBase *editnurb= curve_get_editcurve(obedit);
1035         Nurb *nu;
1036         BezTriple *bezt;
1037         BPoint *bp;
1038         float weight= RNA_float_get(op->ptr, "weight");
1039         int a;
1040                                 
1041         for(nu= editnurb->first; nu; nu= nu->next) {
1042                 if(nu->bezt) {
1043                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1044                                 if(bezt->f2 & SELECT)
1045                                         bezt->weight= weight;
1046                         }
1047                 }
1048                 else if(nu->bp) {
1049                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1050                                 if(bp->f1 & SELECT)
1051                                         bp->weight= weight;
1052                         }
1053                 }
1054         }       
1055
1056         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1057         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1058
1059         return OPERATOR_FINISHED;
1060 }
1061
1062 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
1063 {
1064         /* identifiers */
1065         ot->name= "Set Curve Weight";
1066         ot->idname= "CURVE_OT_spline_weight_set";
1067         
1068         /* api callbacks */
1069         ot->exec= set_weight_exec;
1070         ot->invoke= WM_operator_props_popup;
1071         ot->poll= ED_operator_editsurfcurve;
1072
1073         /* flags */
1074         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1075
1076         /* properties */
1077         RNA_def_float_percentage(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
1078 }
1079
1080 /******************* set radius operator ******************/
1081
1082 static int set_radius_exec(bContext *C, wmOperator *op)
1083 {
1084         Object *obedit= CTX_data_edit_object(C);
1085         ListBase *editnurb= curve_get_editcurve(obedit);
1086         Nurb *nu;
1087         BezTriple *bezt;
1088         BPoint *bp;
1089         float radius= RNA_float_get(op->ptr, "radius");
1090         int a;
1091         
1092         for(nu= editnurb->first; nu; nu= nu->next) {
1093                 if(nu->bezt) {
1094                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1095                                 if(bezt->f2 & SELECT)
1096                                         bezt->radius= radius;
1097                         }
1098                 }
1099                 else if(nu->bp) {
1100                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1101                                 if(bp->f1 & SELECT)
1102                                         bp->radius= radius;
1103                         }
1104                 }
1105         }       
1106
1107         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1108         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1109
1110         return OPERATOR_FINISHED;
1111 }
1112
1113 void CURVE_OT_radius_set(wmOperatorType *ot)
1114 {
1115         /* identifiers */
1116         ot->name= "Set Curve Radius";
1117         ot->idname= "CURVE_OT_radius_set";
1118         
1119         /* api callbacks */
1120         ot->exec= set_radius_exec;
1121         ot->invoke= WM_operator_props_popup;
1122         ot->poll= ED_operator_editsurfcurve;
1123
1124         /* flags */
1125         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1126
1127         /* properties */
1128         RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
1129 }
1130
1131 /********************* smooth operator ********************/
1132
1133 static int smooth_exec(bContext *C, wmOperator *op)
1134 {
1135         Object *obedit= CTX_data_edit_object(C);
1136         ListBase *editnurb= curve_get_editcurve(obedit);
1137         Nurb *nu;
1138         BezTriple *bezt, *beztOrig;
1139         BPoint *bp, *bpOrig;
1140         float val, newval, offset;
1141         int a, i, change = 0;
1142         
1143         for(nu= editnurb->first; nu; nu= nu->next) {
1144                 if(nu->bezt) {
1145                         change = 0;
1146                         beztOrig = MEM_dupallocN( nu->bezt );
1147                         for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
1148                                 if(bezt->f2 & SELECT) {
1149                                         for(i=0; i<3; i++) {
1150                                                 val = bezt->vec[1][i];
1151                                                 newval = ((beztOrig+(a-1))->vec[1][i] * 0.5) + ((beztOrig+(a+1))->vec[1][i] * 0.5);
1152                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1153                                                 /* offset handles */
1154                                                 bezt->vec[1][i] += offset;
1155                                                 bezt->vec[0][i] += offset;
1156                                                 bezt->vec[2][i] += offset;
1157                                         }
1158                                         change = 1;
1159                                 }
1160                         }
1161                         MEM_freeN(beztOrig);
1162                         if (change)
1163                                 calchandlesNurb(nu);
1164                 } else if (nu->bp) {
1165                         bpOrig = MEM_dupallocN( nu->bp );
1166                         /* Same as above, keep these the same! */
1167                         for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
1168                                 if(bp->f1 & SELECT) {
1169                                         for(i=0; i<3; i++) {
1170                                                 val = bp->vec[i];
1171                                                 newval = ((bpOrig+(a-1))->vec[i] * 0.5) + ((bpOrig+(a+1))->vec[i] * 0.5);
1172                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1173                                         
1174                                                 bp->vec[i] += offset;
1175                                         }
1176                                 }
1177                         }
1178                         MEM_freeN(bpOrig);
1179                 }
1180         }
1181
1182         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1183         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1184
1185         return OPERATOR_FINISHED;
1186 }
1187
1188 void CURVE_OT_smooth(wmOperatorType *ot)
1189 {
1190         /* identifiers */
1191         ot->name= "Smooth";
1192         ot->idname= "CURVE_OT_smooth";
1193         
1194         /* api callbacks */
1195         ot->exec= smooth_exec;
1196         ot->poll= ED_operator_editsurfcurve;
1197
1198         /* flags */
1199         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1200 }
1201
1202 /**************** smooth curve radius operator *************/
1203
1204 /* TODO, make smoothing distance based */
1205 static int smooth_radius_exec(bContext *C, wmOperator *op)
1206 {
1207         Object *obedit= CTX_data_edit_object(C);
1208         ListBase *editnurb= curve_get_editcurve(obedit);
1209         Nurb *nu;
1210         BezTriple *bezt;
1211         BPoint *bp;
1212         int a;
1213         
1214         /* use for smoothing */
1215         int last_sel;
1216         int start_sel, end_sel; /* selection indicies, inclusive */
1217         float start_rad, end_rad, fac, range;
1218         
1219         for(nu= editnurb->first; nu; nu= nu->next) {
1220                 if(nu->bezt) {
1221                         
1222                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1223                                 /* loop over selection segments of a curve, smooth each */
1224                                 
1225                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1226                                 start_sel = end_sel = -1;
1227                                 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
1228                                         if(bezt->f2 & SELECT) {
1229                                                 start_sel = a;
1230                                                 break;
1231                                         }
1232                                 }
1233                                 /* incase there are no other selected verts */
1234                                 end_sel = start_sel;
1235                                 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
1236                                         if((bezt->f2 & SELECT)==0) {
1237                                                 break;
1238                                         }
1239                                         end_sel = a;
1240                                 }
1241                                 
1242                                 if (start_sel == -1) {
1243                                         last_sel = nu->pntsu; /* next... */
1244                                 } else {
1245                                         last_sel = end_sel; /* before we modify it */
1246                                         
1247                                         /* now blend between start and end sel */
1248                                         start_rad = end_rad = -1.0;
1249                                         
1250                                         if (start_sel == end_sel) {
1251                                                 /* simple, only 1 point selected */
1252                                                 if (start_sel>0)                                                start_rad = (nu->bezt+start_sel-1)->radius;
1253                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
1254                                                 
1255                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
1256                                                 else if (start_rad >= 0.0)                              (nu->bezt+start_sel)->radius = start_rad;
1257                                                 else if (end_rad >= 0.0)                                (nu->bezt+start_sel)->radius = end_rad;
1258                                         } else {
1259                                                 /* if endpoints selected, then use them */
1260                                                 if (start_sel==0) {
1261                                                         start_rad = (nu->bezt+start_sel)->radius;
1262                                                         start_sel++; /* we dont want to edit the selected endpoint */
1263                                                 } else {
1264                                                         start_rad = (nu->bezt+start_sel-1)->radius;
1265                                                 }
1266                                                 if (end_sel==nu->pntsu-1) {
1267                                                         end_rad = (nu->bezt+end_sel)->radius;
1268                                                         end_sel--; /* we dont want to edit the selected endpoint */
1269                                                 } else {
1270                                                         end_rad = (nu->bezt+end_sel+1)->radius;
1271                                                 }
1272                                                 
1273                                                 /* Now Blend between the points */
1274                                                 range = (float)(end_sel - start_sel) + 2.0f;
1275                                                 for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
1276                                                         fac = (float)(1+a-start_sel) / range;
1277                                                         bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
1278                                                 }
1279                                         }
1280                                 }
1281                         }
1282                 } else if (nu->bp) {
1283                         /* Same as above, keep these the same! */
1284                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1285                                 /* loop over selection segments of a curve, smooth each */
1286                                 
1287                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1288                                 start_sel = end_sel = -1;
1289                                 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
1290                                         if(bp->f1 & SELECT) {
1291                                                 start_sel = a;
1292                                                 break;
1293                                         }
1294                                 }
1295                                 /* incase there are no other selected verts */
1296                                 end_sel = start_sel;
1297                                 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
1298                                         if((bp->f1 & SELECT)==0) {
1299                                                 break;
1300                                         }
1301                                         end_sel = a;
1302                                 }
1303                                 
1304                                 if (start_sel == -1) {
1305                                         last_sel = nu->pntsu; /* next... */
1306                                 } else {
1307                                         last_sel = end_sel; /* before we modify it */
1308                                         
1309                                         /* now blend between start and end sel */
1310                                         start_rad = end_rad = -1.0;
1311                                         
1312                                         if (start_sel == end_sel) {
1313                                                 /* simple, only 1 point selected */
1314                                                 if (start_sel>0)                                                start_rad = (nu->bp+start_sel-1)->radius;
1315                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
1316                                                 
1317                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
1318                                                 else if (start_rad >= 0.0)                              (nu->bp+start_sel)->radius = start_rad;
1319                                                 else if (end_rad >= 0.0)                                (nu->bp+start_sel)->radius = end_rad;
1320                                         } else {
1321                                                 /* if endpoints selected, then use them */
1322                                                 if (start_sel==0) {
1323                                                         start_rad = (nu->bp+start_sel)->radius;
1324                                                         start_sel++; /* we dont want to edit the selected endpoint */
1325                                                 } else {
1326                                                         start_rad = (nu->bp+start_sel-1)->radius;
1327                                                 }
1328                                                 if (end_sel==nu->pntsu-1) {
1329                                                         end_rad = (nu->bp+end_sel)->radius;
1330                                                         end_sel--; /* we dont want to edit the selected endpoint */
1331                                                 } else {
1332                                                         end_rad = (nu->bp+end_sel+1)->radius;
1333                                                 }
1334                                                 
1335                                                 /* Now Blend between the points */
1336                                                 range = (float)(end_sel - start_sel) + 2.0f;
1337                                                 for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
1338                                                         fac = (float)(1+a-start_sel) / range;
1339                                                         bp->radius = start_rad*(1.0-fac) + end_rad*fac;
1340                                                 }
1341                                         }
1342                                 }
1343                         }
1344                 }
1345         }
1346
1347         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1348         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1349
1350         return OPERATOR_FINISHED;
1351 }
1352
1353 void CURVE_OT_smooth_radius(wmOperatorType *ot)
1354 {
1355         /* identifiers */
1356         ot->name= "Smooth Curve Radius";
1357         ot->idname= "CURVE_OT_smooth_radius";
1358         
1359         /* api clastbacks */
1360         ot->exec= smooth_radius_exec;
1361         ot->poll= ED_operator_editsurfcurve;
1362         
1363         /* flags */
1364         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1365 }
1366
1367 /***************** selection utility *************************/
1368
1369 /* next == 1 -> select next             */
1370 /* next == -1 -> select previous        */
1371 /* cont == 1 -> select continuously     */
1372 /* selstatus, inverts behaviour         */
1373 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
1374 {
1375         Nurb *nu;
1376         BezTriple *bezt;
1377         BPoint *bp;
1378         int a;
1379         short lastsel= 0, sel=0;
1380         
1381         if(next==0) return;
1382         
1383         for(nu= editnurb->first; nu; nu= nu->next) {
1384                 lastsel=0;
1385                 if((nu->type & 7)==CU_BEZIER) {                 
1386                         a= nu->pntsu;
1387                         bezt= nu->bezt;
1388                         if(next < 0) bezt= (nu->bezt + (a-1));
1389                         while(a--) {
1390                                 if(a-abs(next) < 0) break;
1391                                 sel= 0;
1392                                 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
1393                                         bezt+=next;
1394                                         if(!(bezt->f2 & SELECT) || (selstatus==0)) {
1395                                                 sel= select_beztriple(bezt, selstatus, 1, VISIBLE);     
1396                                                 if((sel==1) && (cont==0)) lastsel= 1;
1397                                         }                                                       
1398                                 }
1399                                 else {
1400                                         bezt+=next;
1401                                         lastsel= 0;
1402                                 }
1403                                 /* move around in zigzag way so that we go through each */                              
1404                                 bezt-=(next-next/abs(next));                            
1405                         }
1406                 }
1407                 else {
1408                         a= nu->pntsu*nu->pntsv;
1409                         bp= nu->bp;
1410                         if(next < 0) bp= (nu->bp + (a-1));
1411                         while(a--) {
1412                                 if(a-abs(next) < 0) break;
1413                                 sel=0;
1414                                 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
1415                                         bp+=next;
1416                                         if(!(bp->f1 & SELECT) || (selstatus==0)) {
1417                                                 sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1418                                                 if((sel==1) && (cont==0)) lastsel= 1;
1419                                         }                       
1420                                 }
1421                                 else {
1422                                         bp+=next;
1423                                         lastsel= 0;
1424                                 }
1425                                 /* move around in zigzag way so that we go through each */
1426                                 bp-=(next-next/abs(next));                              
1427                         }
1428                 }
1429         }
1430 }
1431
1432 /**************** select start/end operators **************/
1433
1434 /* (de)selects first or last of visible part of each Nurb depending on selFirst     */
1435 /* selFirst: defines the end of which to select                                     */
1436 /* doswap: defines if selection state of each first/last control point is swapped   */
1437 /* selstatus: selection status in case doswap is false                              */
1438 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus)
1439 {
1440         ListBase *editnurb= curve_get_editcurve(obedit);
1441         Nurb *nu;
1442         BPoint *bp;
1443         BezTriple *bezt;
1444         int a;
1445         short sel;
1446         
1447         if(obedit==0) return;
1448         
1449         for(nu= editnurb->first; nu; nu= nu->next) {
1450                 sel= 0;
1451                 if((nu->type & 7)==CU_BEZIER) {
1452                         a= nu->pntsu;
1453                         
1454                         /* which point? */
1455                         if(selfirst==0) { /* select last */ 
1456                                 bezt= (nu->bezt + (a-1));
1457                         }
1458                         else { /* select first */
1459                                 bezt= nu->bezt;
1460                         }
1461                         
1462                         while(a--) {
1463                                 if(doswap) sel= swap_selection_beztriple(bezt);
1464                                 else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
1465                                 
1466                                 if(sel==1) break;
1467                         }
1468                 }
1469                 else {
1470                         a= nu->pntsu*nu->pntsv;
1471                         
1472                         /* which point? */
1473                         if(selfirst==0) { /* select last */
1474                                 bp= (nu->bp + (a-1));
1475                         }
1476                         else{ /* select first */
1477                                 bp= nu->bp;
1478                         }
1479
1480                         while(a--) {
1481                                 if (bp->hide == 0) {
1482                                         if(doswap) sel= swap_selection_bpoint(bp);
1483                                         else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1484                                         
1485                                         if(sel==1) break;
1486                                 }
1487                         }
1488                 }
1489         }
1490 }
1491
1492 static int de_select_first_exec(bContext *C, wmOperator *op)
1493 {
1494         Object *obedit= CTX_data_edit_object(C);
1495
1496         selectend_nurb(obedit, FIRST, 1, DESELECT);
1497         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1498
1499         return OPERATOR_FINISHED;
1500 }
1501
1502 void CURVE_OT_de_select_first(wmOperatorType *ot)
1503 {
1504         /* identifiers */
1505         ot->name= "Select or Deselect First";
1506         ot->idname= "CURVE_OT_de_select_first";
1507         
1508         /* api cfirstbacks */
1509         ot->exec= de_select_first_exec;
1510         ot->poll= ED_operator_editcurve;
1511         
1512         /* flags */
1513         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1514 }
1515
1516 static int de_select_last_exec(bContext *C, wmOperator *op)
1517 {
1518         Object *obedit= CTX_data_edit_object(C);
1519
1520         selectend_nurb(obedit, LAST, 1, DESELECT);
1521         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1522
1523         return OPERATOR_FINISHED;
1524 }
1525
1526 void CURVE_OT_de_select_last(wmOperatorType *ot)
1527 {
1528         /* identifiers */
1529         ot->name= "Select or Deselect Last";
1530         ot->idname= "CURVE_OT_de_select_last";
1531         
1532         /* api clastbacks */
1533         ot->exec= de_select_last_exec;
1534         ot->poll= ED_operator_editcurve;
1535         
1536         /* flags */
1537         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1538 }
1539
1540 /******************* de select all operator ***************/
1541
1542 static short nurb_has_selected_cps(ListBase *editnurb)
1543 {
1544         Nurb *nu;
1545         BezTriple *bezt;
1546         BPoint *bp;
1547         int a;
1548
1549         for(nu= editnurb->first; nu; nu= nu->next) {
1550                 if((nu->type & 7)==CU_BEZIER) {
1551                         a= nu->pntsu;
1552                         bezt= nu->bezt;
1553                         while(a--) {
1554                                 if(bezt->hide==0) {
1555                                         if((bezt->f1 & SELECT)
1556                                         || (bezt->f2 & SELECT)
1557                                         || (bezt->f3 & SELECT)) return 1;
1558                                 }
1559                                 bezt++;
1560                         }
1561                 }
1562                 else {
1563                         a= nu->pntsu*nu->pntsv;
1564                         bp= nu->bp;
1565                         while(a--) {
1566                                 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
1567                                 bp++;
1568                         }
1569                 }
1570         }
1571         
1572         return 0;
1573 }
1574
1575 static int de_select_all_exec(bContext *C, wmOperator *op)
1576 {
1577         Object *obedit= CTX_data_edit_object(C);
1578         ListBase *editnurb= curve_get_editcurve(obedit);
1579         
1580         if(nurb_has_selected_cps(editnurb)) { /* deselect all */
1581                 selectend_nurb(obedit, FIRST, 0, DESELECT); /* set first control points as unselected */
1582                 select_adjacent_cp(editnurb, 1, 1, DESELECT); /* cascade selection */   
1583         }
1584         else { /* select all */
1585                 selectend_nurb(obedit, FIRST, 0, SELECT); /* set first control points as selected */
1586                 select_adjacent_cp(editnurb, 1, 1, SELECT); /* cascade selection */
1587         }
1588         
1589         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1590
1591         return OPERATOR_FINISHED;
1592 }
1593
1594 void CURVE_OT_select_all_toggle(wmOperatorType *ot)
1595 {
1596         /* identifiers */
1597         ot->name= "Select or Deselect All";
1598         ot->idname= "CURVE_OT_select_all_toggle";
1599         
1600         /* api callbacks */
1601         ot->exec= de_select_all_exec;
1602         ot->poll= ED_operator_editsurfcurve;
1603         
1604         /* flags */
1605         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1606 }
1607
1608 /********************** hide operator *********************/
1609
1610 static int hide_exec(bContext *C, wmOperator *op)
1611 {
1612         Object *obedit= CTX_data_edit_object(C);
1613         ListBase *editnurb= curve_get_editcurve(obedit);
1614         Nurb *nu;
1615         BPoint *bp;
1616         BezTriple *bezt;
1617         int a, sel, invert= RNA_boolean_get(op->ptr, "unselected");
1618
1619         for(nu= editnurb->first; nu; nu= nu->next) {
1620                 if((nu->type & 7)==CU_BEZIER) {
1621                         bezt= nu->bezt;
1622                         a= nu->pntsu;
1623                         sel= 0;
1624                         while(a--) {
1625                                 if(invert == 0 && BEZSELECTED_HIDDENHANDLES(bezt)) {
1626                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
1627                                         bezt->hide= 1;
1628                                 }
1629                                 else if(invert && !BEZSELECTED_HIDDENHANDLES(bezt)) {
1630                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
1631                                         bezt->hide= 1;
1632                                 }
1633                                 if(bezt->hide) sel++;
1634                                 bezt++;
1635                         }
1636                         if(sel==nu->pntsu) nu->hide= 1;
1637                 }
1638                 else {
1639                         bp= nu->bp;
1640                         a= nu->pntsu*nu->pntsv;
1641                         sel= 0;
1642                         while(a--) {
1643                                 if(invert==0 && (bp->f1 & SELECT)) {
1644                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
1645                                         bp->hide= 1;
1646                                 }
1647                                 else if(invert && (bp->f1 & SELECT)==0) {
1648                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
1649                                         bp->hide= 1;
1650                                 }
1651                                 if(bp->hide) sel++;
1652                                 bp++;
1653                         }
1654                         if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
1655                 }
1656         }
1657
1658         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1659         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1660
1661         return OPERATOR_FINISHED;       
1662 }
1663
1664 void CURVE_OT_hide(wmOperatorType *ot)
1665 {
1666         /* identifiers */
1667         ot->name= "Hide Selected";
1668         ot->idname= "CURVE_OT_hide";
1669         
1670         /* api callbacks */
1671         ot->exec= hide_exec;
1672         ot->poll= ED_operator_editsurfcurve;
1673         
1674         /* flags */
1675         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1676         
1677         /* props */
1678         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1679 }
1680
1681 /********************** reveal operator *********************/
1682
1683 static int reveal_exec(bContext *C, wmOperator *op)
1684 {
1685         Object *obedit= CTX_data_edit_object(C);
1686         ListBase *editnurb= curve_get_editcurve(obedit);
1687         Nurb *nu;
1688         BPoint *bp;
1689         BezTriple *bezt;
1690         int a;
1691
1692         for(nu= editnurb->first; nu; nu= nu->next) {
1693                 nu->hide= 0;
1694                 if((nu->type & 7)==CU_BEZIER) {
1695                         bezt= nu->bezt;
1696                         a= nu->pntsu;
1697                         while(a--) {
1698                                 if(bezt->hide) {
1699                                         select_beztriple(bezt, SELECT, 1, HIDDEN);
1700                                         bezt->hide= 0;
1701                                 }
1702                                 bezt++;
1703                         }
1704                 }
1705                 else {
1706                         bp= nu->bp;
1707                         a= nu->pntsu*nu->pntsv;
1708                         while(a--) {
1709                                 if(bp->hide) {
1710                                         select_bpoint(bp, SELECT, 1, HIDDEN);
1711                                         bp->hide= 0;
1712                                 }
1713                                 bp++;
1714                         }
1715                 }
1716         }
1717
1718         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1719         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1720
1721         return OPERATOR_FINISHED;       
1722 }
1723
1724 void CURVE_OT_reveal(wmOperatorType *ot)
1725 {
1726         /* identifiers */
1727         ot->name= "Reveal Hidden";
1728         ot->idname= "CURVE_OT_reveal";
1729         
1730         /* api callbacks */
1731         ot->exec= reveal_exec;
1732         ot->poll= ED_operator_editsurfcurve;
1733         
1734         /* flags */
1735         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1736 }
1737
1738 /********************** select invert operator *********************/
1739
1740 static int select_invert_exec(bContext *C, wmOperator *op)
1741 {
1742         Object *obedit= CTX_data_edit_object(C);
1743         ListBase *editnurb= curve_get_editcurve(obedit);
1744         Nurb *nu;
1745         BPoint *bp;
1746         BezTriple *bezt;
1747         int a;
1748
1749         for(nu= editnurb->first; nu; nu= nu->next) {
1750                 if((nu->type & 7)==CU_BEZIER) {
1751                         bezt= nu->bezt;
1752                         a= nu->pntsu;
1753                         while(a--) {
1754                                 if(bezt->hide==0) {
1755                                         bezt->f2 ^= SELECT; /* always do the center point */
1756                                         if ((G.f & G_HIDDENHANDLES)==0) {
1757                                                 bezt->f1 ^= SELECT;
1758                                                 bezt->f3 ^= SELECT;
1759                                         }
1760                                 }
1761                                 bezt++;
1762                         }
1763                 }
1764                 else {
1765                         bp= nu->bp;
1766                         a= nu->pntsu*nu->pntsv;
1767                         while(a--) {
1768                                 swap_selection_bpoint(bp);
1769                                 bp++;
1770                         }
1771                 }
1772         }
1773
1774         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1775
1776         return OPERATOR_FINISHED;       
1777 }
1778
1779 void CURVE_OT_select_invert(wmOperatorType *ot)
1780 {
1781         /* identifiers */
1782         ot->name= "Select Invert";
1783         ot->idname= "CURVE_OT_select_invert";
1784         
1785         /* api callbacks */
1786         ot->exec= select_invert_exec;
1787         ot->poll= ED_operator_editsurfcurve;
1788         
1789         /* flags */
1790         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1791 }
1792
1793 /********************** subdivide operator *********************/
1794
1795 /** Divide the line segments associated with the currently selected
1796  * curve nodes (Bezier or NURB). If there are no valid segment
1797  * selections within the current selection, nothing happens.
1798  *
1799  * @deffunc subdividenurb subdivideNurb(void)
1800  * @return Nothing
1801  * @param  None
1802 */
1803
1804 static int subdivide_exec(bContext *C, wmOperator *op)
1805 {
1806         Object *obedit= CTX_data_edit_object(C);
1807         ListBase *editnurb= curve_get_editcurve(obedit);
1808         Nurb *nu;
1809         BezTriple *prevbezt, *bezt, *beztnew, *beztn;
1810         BPoint *bp, *prevbp, *bpnew, *bpn;
1811         float vec[15];
1812         int a, b, sel, amount, *usel, *vsel;
1813
1814    // printf("*** subdivideNurb: entering subdivide\n");
1815
1816         for(nu= editnurb->first; nu; nu= nu->next) {
1817                 amount= 0;
1818                 if((nu->type & 7)==CU_BEZIER) {
1819         /* 
1820            Insert a point into a 2D Bezier curve. 
1821            Endpoints are preserved. Otherwise, all selected and inserted points are 
1822            newly created. Old points are discarded.
1823         */
1824                         /* count */
1825                         if(nu->flagu & CU_CYCLIC) {
1826                                 a= nu->pntsu;
1827                                 bezt= nu->bezt;
1828                                 prevbezt= bezt+(a-1);
1829                         }
1830                         else {
1831                                 a= nu->pntsu-1;
1832                                 prevbezt= nu->bezt;
1833                                 bezt= prevbezt+1;
1834                         }
1835                         while(a--) {
1836                                 if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) amount++;
1837                                 prevbezt= bezt;
1838                                 bezt++;
1839                         }
1840
1841                         if(amount) {
1842                                 /* insert */
1843                                 beztnew =
1844                                         (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
1845                                 beztn= beztnew;
1846                                 if(nu->flagu & CU_CYCLIC) {
1847                                         a= nu->pntsu;
1848                                         bezt= nu->bezt;
1849                                         prevbezt= bezt+(a-1);
1850                                 }
1851                                 else {
1852                                         a= nu->pntsu-1;
1853                                         prevbezt= nu->bezt;
1854                                         bezt= prevbezt+1;
1855                                 }
1856                                 while(a--) {
1857                                         memcpy(beztn, prevbezt, sizeof(BezTriple));
1858                                         beztn++;
1859
1860                                         if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) {
1861                                                 memcpy(beztn, bezt, sizeof(BezTriple));
1862                                                 
1863                                                 /* midpoint subdividing */
1864                                                 VecMidf(vec, prevbezt->vec[1], prevbezt->vec[2]);
1865                                                 VecMidf(vec+3, prevbezt->vec[2], bezt->vec[0]);
1866                                                 VecMidf(vec+6, bezt->vec[0], bezt->vec[1]);
1867                                                 
1868                                                 VecMidf(vec+9, vec, vec+3);
1869                                                 VecMidf(vec+12, vec+3, vec+6);
1870                                                 
1871                                                 /* change handle of prev beztn */
1872                                                 VECCOPY((beztn-1)->vec[2], vec);
1873                                                 /* new point */
1874                                                 VECCOPY(beztn->vec[0], vec+9);
1875                                                 VecMidf(beztn->vec[1], vec+9, vec+12);
1876                                                 VECCOPY(beztn->vec[2], vec+12);
1877                                                 /* handle of next bezt */
1878                                                 if(a==0 && (nu->flagu & CU_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
1879                                                 else {VECCOPY(bezt->vec[0], vec+6);}
1880                                                 
1881                                                 beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
1882                                                 beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
1883                                                 
1884                                                 beztn++;
1885                                         }
1886
1887                                         prevbezt= bezt;
1888                                         bezt++;
1889                                 }
1890                                 /* last point */
1891                                 if((nu->flagu & CU_CYCLIC)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
1892
1893                                 MEM_freeN(nu->bezt);
1894                                 nu->bezt= beztnew;
1895                                 nu->pntsu+= amount;
1896
1897                                 calchandlesNurb(nu);
1898                         }
1899                 } /* End of 'if((nu->type & 7)==CU_BEZIER)' */
1900                 else if (nu->pntsv==1) {
1901         /* 
1902            All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
1903            are handled together with the regular NURB plane division, as it 
1904            should be. I split it off just now, let's see if it is
1905            stable... nzc 30-5-'00
1906          */
1907                         /* count */
1908                         if(nu->flagu & CU_CYCLIC) {
1909                                 a= nu->pntsu;
1910                                 bp= nu->bp;
1911                                 prevbp= bp+(a-1);
1912                         }
1913                         else {
1914                                 a= nu->pntsu-1;
1915                                 prevbp= nu->bp;
1916                                 bp= prevbp+1;
1917                         }
1918                         while(a--) {
1919                                 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount++;
1920                                 prevbp= bp;
1921                                 bp++;
1922                         }
1923
1924                         if(amount) {
1925                                 /* insert */
1926                                 bpnew =
1927                                         (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
1928                                 bpn= bpnew;
1929
1930                                 if(nu->flagu & CU_CYCLIC) {
1931                                         a= nu->pntsu;
1932                                         bp= nu->bp;
1933                                         prevbp= bp+(a-1);
1934                                 }
1935                                 else {
1936                                         a= nu->pntsu-1;
1937                                         prevbp= nu->bp;
1938                                         bp= prevbp+1;
1939                                 }
1940                                 while(a--) {
1941                                         memcpy(bpn, prevbp, sizeof(BPoint));
1942                                         bpn++;
1943
1944                                         if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
1945                  // printf("*** subdivideNurb: insert 'linear' point\n");
1946                                                 memcpy(bpn, bp, sizeof(BPoint));
1947                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1948                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1949                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1950                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1951                                                 bpn++;
1952
1953                                         }
1954                                         prevbp= bp;
1955                                         bp++;
1956                                 }
1957                                 if((nu->flagu & CU_CYCLIC)==0) memcpy(bpn, prevbp, sizeof(BPoint));     /* last point */
1958
1959                                 MEM_freeN(nu->bp);
1960                                 nu->bp= bpnew;
1961                                 nu->pntsu+= amount;
1962
1963                                 if(nu->type & CU_NURBS) {
1964                                         makeknots(nu, 1);
1965                                 }
1966                         }
1967                 } /* End of 'else if(nu->pntsv==1)' */
1968                 else if((nu->type & 7)==CU_NURBS) {
1969         /* This is a very strange test ... */
1970         /** 
1971            Subdivide NURB surfaces - nzc 30-5-'00 -
1972            
1973              Subdivision of a NURB curve can be effected by adding a 
1974            control point (insertion of a knot), or by raising the
1975            degree of the functions used to build the NURB. The
1976            expression 
1977
1978                degree = #knots - #controlpoints + 1 (J Walter piece)
1979                degree = #knots - #controlpoints     (Blender
1980                                                       implementation)
1981                  ( this is confusing.... what is true? Another concern
1982                  is that the JW piece allows the curve to become
1983                  explicitly 1st order derivative discontinuous, while
1984                  this is not what we want here... )
1985
1986            is an invariant for a single NURB curve. Raising the degree
1987            of the NURB is done elsewhere; the degree is assumed
1988            constant during this opration. Degree is a property shared
1989            by all controlpoints in a curve (even though it is stored
1990            per control point - this can be misleading).
1991              Adding a knot is done by searching for the place in the
1992            knot vector where a certain knot value must be inserted, or
1993            by picking an appropriate knot value between two existing
1994            ones. The number of controlpoints that is influenced by the
1995            insertion depends on the order of the curve. A certain
1996            minimum number of knots is needed to form high-order
1997            curves, as can be seen from the equation above. In Blender,
1998            currently NURBs may be up to 6th order, so we modify at
1999            most 6 points. One point is added. For an n-degree curve,
2000            n points are discarded, and n+1 points inserted
2001            (so effectively, n points are modified).  (that holds for
2002            the JW piece, but it seems not for our NURBs)
2003               In practice, the knot spacing is copied, but the tail
2004            (the points following the insertion point) need to be
2005            offset to keep the knot series ascending. The knot series
2006            is always a series of monotonically ascending integers in
2007            Blender. When not enough control points are available to
2008            fit the order, duplicates of the endpoints are added as
2009            needed. 
2010         */
2011                         /* selection-arrays */
2012                         usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
2013                         vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
2014                         sel= 0;
2015
2016          /* Count the number of selected points. */
2017                         bp= nu->bp;
2018                         for(a=0; a<nu->pntsv; a++) {
2019                                 for(b=0; b<nu->pntsu; b++) {
2020                                         if(bp->f1 & SELECT) {
2021                                                 usel[b]++;
2022                                                 vsel[a]++;
2023                                                 sel++;
2024                                         }
2025                                         bp++;
2026                                 }
2027                         }
2028                         if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
2029            /* Global subdivision is a special case of partial
2030               subdivision. Strange it is considered separately... */
2031                                 bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
2032                                 bp= nu->bp;
2033                                 /* first subdivide rows */
2034                                 for(a=0; a<nu->pntsv; a++) {
2035                                         for(b=0; b<nu->pntsu; b++) {
2036                                                 *bpn= *bp;
2037                                                 bpn++; 
2038                                                 bp++;
2039                                                 if(b<nu->pntsu-1) {
2040                                                         *bpn= *bp;
2041                                                         prevbp= bp-1;
2042                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2043                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2044                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2045                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2046                                                         bpn++;
2047                                                 }
2048                                         }
2049                                         bpn+= (2*nu->pntsu-1);
2050                                 }
2051                                 /* now insert new */
2052                                 bpn= bpnew+(2*nu->pntsu-1);
2053                                 bp= bpnew+(4*nu->pntsu-2);
2054                                 prevbp= bpnew;
2055                                 for(a=1; a<nu->pntsv; a++) {
2056
2057                                         for(b=0; b<2*nu->pntsu-1; b++) {
2058                                                 *bpn= *bp;
2059                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2060                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2061                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2062                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2063                                                 bpn++; 
2064                                                 bp++; 
2065                                                 prevbp++;
2066                                         }
2067                                         bp+= (2*nu->pntsu-1);
2068                                         bpn+= (2*nu->pntsu-1);
2069                                         prevbp+= (2*nu->pntsu-1);
2070                                 }
2071                                 MEM_freeN(nu->bp);
2072                                 nu->bp= bpnew;
2073                                 nu->pntsu= 2*nu->pntsu-1;
2074                                 nu->pntsv= 2*nu->pntsv-1;
2075                                 makeknots(nu, 1);
2076                                 makeknots(nu, 2);
2077                         } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
2078                         else {
2079                                 /* subdivide in v direction? */
2080                                 sel= 0;
2081                                 for(a=0; a<nu->pntsv-1; a++) {
2082                                         if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
2083                                 }
2084
2085                                 if(sel) {   /* V ! */
2086                                         bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
2087                                         bp= nu->bp;
2088                                         for(a=0; a<nu->pntsv; a++) {
2089                                                 for(b=0; b<nu->pntsu; b++) {
2090                                                         *bpn= *bp;
2091                                                         bpn++; 
2092                                                         bp++;
2093                                                 }
2094                                                 if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
2095                                                         prevbp= bp- nu->pntsu;
2096                                                         for(b=0; b<nu->pntsu; b++) {
2097                        /* 
2098                           This simple bisection must be replaces by a
2099                           subtle resampling of a number of points. Our 
2100                           task is made slightly easier because each
2101                           point in our curve is a separate data
2102                           node. (is it?)
2103                        */
2104                                                                 *bpn= *prevbp;
2105                                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2106                                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2107                                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2108                                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2109                                                                 bpn++;
2110                                                                 prevbp++;
2111                                                                 bp++;
2112                                                         }
2113                                                         bp-= nu->pntsu;
2114                                                 }
2115                                         }
2116                                         MEM_freeN(nu->bp);
2117                                         nu->bp= bpnew;
2118                                         nu->pntsv+= sel;
2119                                         makeknots(nu, 2);
2120                                 }
2121                                 else {
2122                                         /* or in u direction? */
2123                                         sel= 0;
2124                                         for(a=0; a<nu->pntsu-1; a++) {
2125                                                 if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
2126                                         }
2127
2128                                         if(sel) {       /* U ! */
2129                  /* Inserting U points is sort of 'default' Flat curves only get */
2130                  /* U points inserted in them.                                   */
2131                                                 bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
2132                                                 bp= nu->bp;
2133                                                 for(a=0; a<nu->pntsv; a++) {
2134                                                         for(b=0; b<nu->pntsu; b++) {
2135                                                                 *bpn= *bp;
2136                                                                 bpn++; 
2137                                                                 bp++;
2138                                                                 if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
2139                           /* 
2140                              One thing that bugs me here is that the
2141                              orders of things are not the same as in
2142                              the JW piece. Also, this implies that we
2143                              handle at most 3rd order curves? I miss
2144                              some symmetry here...
2145                           */
2146                                                                         prevbp= bp- 1;
2147                                                                         *bpn= *prevbp;
2148                                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2149                                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2150                                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2151                                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2152                                                                         bpn++;
2153                                                                 }
2154                                                         }
2155                                                 }
2156                                                 MEM_freeN(nu->bp);
2157                                                 nu->bp= bpnew;
2158                                                 nu->pntsu+= sel;
2159                                                 makeknots(nu, 1); /* shift knots
2160                                                      forward */
2161                                         }
2162                                 }
2163                         }
2164                         MEM_freeN(usel); 
2165                         MEM_freeN(vsel);
2166
2167                 } /* End of 'if((nu->type & 7)==CU_NURBS)'  */
2168         }
2169
2170         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
2171         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
2172
2173         return OPERATOR_FINISHED;       
2174 }
2175
2176 void CURVE_OT_subdivide(wmOperatorType *ot)
2177 {
2178         /* identifiers */
2179         ot->name= "Subdivide";
2180         ot->idname= "CURVE_OT_subdivide";
2181         
2182         /* api callbacks */
2183         ot->exec= subdivide_exec;
2184         ot->poll= ED_operator_editsurfcurve;
2185         
2186         /* flags */
2187         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2188 }
2189
2190 /******************** find nearest ************************/
2191
2192 static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
2193 {
2194         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; int dist, hpoint, select, mval[2]; } *data = userData;
2195
2196         short flag;
2197         short temp;
2198
2199         if (bp) {
2200                 flag = bp->f1;
2201         } else {
2202                 if (beztindex==0) {
2203                         flag = bezt->f1;
2204                 } else if (beztindex==1) {
2205                         flag = bezt->f2;
2206                 } else {
2207                         flag = bezt->f3;
2208                 }
2209         }
2210
2211         temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
2212         if ((flag&1)==data->select) temp += 5;
2213         if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
2214
2215         if (temp<data->dist) {
2216                 data->dist = temp;
2217
2218                 data->bp = bp;
2219                 data->bezt = bezt;
2220                 data->nurb = nu;
2221                 data->hpoint = bezt?beztindex:0;
2222         }
2223 }
2224
2225 static short findnearestNurbvert(ViewContext *vc, short sel, int mval[2], Nurb **nurb, BezTriple **bezt, BPoint **bp)
2226 {
2227                 /* sel==1: selected gets a disadvantage */
2228                 /* in nurb and bezt or bp the nearest is written */
2229                 /* return 0 1 2: handlepunt */
2230         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; int dist, hpoint, select, mval[2]; } data = {0};
2231
2232         data.dist = 100;
2233         data.hpoint = 0;
2234         data.select = sel;
2235         data.mval[0] = mval[0];
2236         data.mval[1] = mval[1];
2237
2238         nurbs_foreachScreenVert(vc, findnearestNurbvert__doClosest, &data);
2239
2240         *nurb = data.nurb;
2241         *bezt = data.bezt;
2242         *bp = data.bp;
2243
2244         return data.hpoint;
2245 }
2246
2247 static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt, BPoint **bp)
2248 {
2249         /* in nu and (bezt or bp) selected are written if there's 1 sel.  */
2250         /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
2251         Nurb *nu1;
2252         BezTriple *bezt1;
2253         BPoint *bp1;
2254         int a;
2255
2256         *nu= 0;
2257         *bezt= 0;
2258         *bp= 0;
2259         for(nu1= editnurb->first; nu1; nu1= nu1->next) {
2260                 if((nu1->type & 7)==CU_BEZIER) {
2261                         bezt1= nu1->bezt;
2262                         a= nu1->pntsu;
2263                         while(a--) {
2264                                 if( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
2265                                         if(*nu!=0 && *nu!= nu1) {
2266                                                 *nu= 0;
2267                                                 *bp= 0;
2268                                                 *bezt= 0;
2269                                                 return;
2270                                         }
2271                                         else if(*bezt || *bp) {
2272                                                 *bp= 0;
2273                                                 *bezt= 0;
2274                                         }
2275                                         else {
2276                                                 *bezt= bezt1;
2277                                                 *nu= nu1;
2278                                         }
2279                                 }
2280                                 bezt1++;
2281                         }
2282                 }
2283                 else {
2284                         bp1= nu1->bp;
2285                         a= nu1->pntsu*nu1->pntsv;
2286                         while(a--) {
2287                                 if( bp1->f1 & 1 ) {
2288                                         if(*nu!=0 && *nu!= nu1) {
2289                                                 *bp= 0;
2290                                                 *bezt= 0;
2291                                                 *nu= 0;
2292                                                 return;
2293                                         }
2294                                         else if(*bezt || *bp) {
2295                                                 *bp= 0;
2296                                                 *bezt= 0;
2297                                         }
2298                                         else {
2299                                                 *bp= bp1;
2300                                                 *nu= nu1;
2301                                         }
2302                                 }
2303                                 bp1++;
2304                         }
2305                 }
2306         }
2307 }
2308
2309 /***************** set spline type operator *******************/
2310
2311 static int convertspline(short type, Nurb *nu)
2312 {
2313         BezTriple *bezt;
2314         BPoint *bp;
2315         int a, c, nr;
2316
2317         if((nu->type & 7)==CU_POLY) {
2318                 if(type==CU_BEZIER) {                       /* to Bezier with vecthandles  */
2319                         nr= nu->pntsu;
2320                         bezt =
2321                                 (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2322                         nu->bezt= bezt;
2323                         a= nr;
2324                         bp= nu->bp;
2325                         while(a--) {
2326                                 VECCOPY(bezt->vec[1], bp->vec);
2327                                 bezt->f1=bezt->f2=bezt->f3= bp->f1;
2328                                 bezt->h1= bezt->h2= HD_VECT;
2329                                 bezt->weight= bp->weight;
2330                                 bezt->radius= bp->radius;
2331                                 bp++;
2332                                 bezt++;
2333                         }
2334                         MEM_freeN(nu->bp);
2335                         nu->bp= 0;
2336                         nu->pntsu= nr;
2337                         nu->type &= ~7;
2338                         nu->type |= CU_BEZIER;
2339                         calchandlesNurb(nu);
2340                 }
2341                 else if(type==CU_NURBS) {
2342                         nu->type &= ~7;
2343                         nu->type |= CU_NURBS;
2344                         nu->orderu= 4;
2345                         nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2346                         nu->flagu += 4;
2347                         makeknots(nu, 1);
2348                         a= nu->pntsu*nu->pntsv;
2349                         bp= nu->bp;
2350                         while(a--) {
2351                                 bp->vec[3]= 1.0;
2352                                 bp++;
2353                         }
2354                 }
2355         }
2356         else if((nu->type & 7)==CU_BEZIER) {    /* Bezier */
2357                 if(type==0 || type==4) {            /* to Poly or Nurb */
2358                         nr= 3*nu->pntsu;
2359                         nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
2360                         a= nu->pntsu;
2361                         bezt= nu->bezt;
2362                         bp= nu->bp;
2363                         while(a--) {
2364                                 if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
2365                                         /* vector handle becomes 1 poly vertice */
2366                                         VECCOPY(bp->vec, bezt->vec[1]);
2367                                         bp->vec[3]= 1.0;
2368                                         bp->f1= bezt->f2;
2369                                         nr-= 2;
2370                                         bp->radius= bezt->radius;
2371                                         bp->weight= bezt->weight;
2372                                         bp++;
2373                                 }
2374                                 else {
2375                                         for(c=0;c<3;c++) {
2376                                                 VECCOPY(bp->vec, bezt->vec[c]);
2377                                                 bp->vec[3]= 1.0;
2378                                                 if(c==0) bp->f1= bezt->f1;
2379                                                 else if(c==1) bp->f1= bezt->f2;
2380                                                 else bp->f1= bezt->f3;
2381                                                 bp->radius= bezt->radius;
2382                                                 bp->weight= bezt->weight;
2383                                                 bp++;
2384                                         }
2385                                 }
2386                                 bezt++;
2387                         }
2388                         MEM_freeN(nu->bezt); 
2389                         nu->bezt= 0;
2390                         nu->pntsu= nr;
2391                         nu->pntsv= 1;
2392                         nu->orderu= 4;
2393                         nu->orderv= 1;
2394                         nu->type &= ~7;
2395                         nu->type+= type;
2396                         if(nu->flagu & CU_CYCLIC) c= nu->orderu-1; 
2397                         else c= 0;
2398                         if(type== 4) {
2399                                 nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2400                                 nu->flagu += 4;
2401                                 makeknots(nu, 1);
2402                         }
2403                 }
2404         }
2405         else if((nu->type & 7)==CU_NURBS) {
2406                 if(type==0) {                   /* to Poly */
2407                         nu->type &= ~7;
2408                         if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
2409                         nu->knotsu= NULL;
2410                         if(nu->knotsv) MEM_freeN(nu->knotsv);
2411                         nu->knotsv= NULL;
2412                 }
2413                 else if(type==CU_BEZIER) {              /* to Bezier */
2414                         nr= nu->pntsu/3;
2415
2416                         if(nr<2) 
2417                                 return 1;       /* conversion impossible */
2418                         else {
2419                                 bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2420                                 nu->bezt= bezt;
2421                                 a= nr;
2422                                 bp= nu->bp;
2423                                 while(a--) {
2424                                         VECCOPY(bezt->vec[0], bp->vec);
2425                                         bezt->f1= bp->f1;
2426                                         bp++;
2427                                         VECCOPY(bezt->vec[1], bp->vec);
2428                                         bezt->f2= bp->f1;
2429                                         bp++;
2430                                         VECCOPY(bezt->vec[2], bp->vec);
2431                                         bezt->f3= bp->f1;
2432                                         bezt->radius= bp->radius;
2433                                         bezt->weight= bp->weight;
2434                                         bp++;
2435                                         bezt++;
2436                                 }
2437                                 MEM_freeN(nu->bp);
2438                                 nu->bp= 0;
2439                                 MEM_freeN(nu->knotsu);
2440                                 nu->knotsu= NULL;
2441                                 nu->pntsu= nr;
2442                                 nu->type &= ~7;
2443                                 nu->type |= CU_BEZIER;
2444                         }
2445                 }
2446         }
2447
2448         return 0;
2449 }
2450
2451 static int set_spline_type_exec(bContext *C, wmOperator *op)
2452 {
2453         Object *obedit= CTX_data_edit_object(C);
2454         ListBase *editnurb= curve_get_editcurve(obedit);
2455         Nurb *nu;
2456         int changed=0, type= RNA_enum_get(op->ptr, "type");
2457
2458         if(type==CU_CARDINAL || type==CU_BSPLINE) {
2459                 BKE_report(op->reports, RPT_ERROR, "Not implemented yet");
2460                 return OPERATOR_CANCELLED;
2461         }
2462         
2463         for(nu= editnurb->first; nu; nu= nu->next) {
2464                 if(isNurbsel(nu)) {
2465                         if(convertspline(type, nu))
2466                                 BKE_report(op->reports, RPT_ERROR, "No conversion possible");
2467                         else
2468                                 changed= 1;
2469                 }
2470         }
2471
2472         return (changed)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
2473 }
2474
2475 void CURVE_OT_spline_type_set(wmOperatorType *ot)
2476 {
2477         static EnumPropertyItem type_items[]= {
2478                 {CU_POLY, "POLY", 0, "Poly", ""},
2479                 {CU_BEZIER, "BEZIER", 0, "Bezier", ""},
2480                 {CU_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
2481                 {CU_BSPLINE, "B_SPLINE", 0, "B-Spline", ""},
2482                 {CU_NURBS, "NURBS", 0, "NURBS", ""},
2483                 {0, NULL, 0, NULL, NULL}};
2484
2485         /* identifiers */
2486         ot->name= "Set Spline Type";
2487         ot->idname= "CURVE_OT_spline_type_set";
2488         
2489         /* api callbacks */
2490         ot->exec= set_spline_type_exec;
2491         ot->poll= ED_operator_editcurve;
2492         
2493         /* flags */
2494         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2495
2496         /* properties */
2497         RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
2498 }
2499
2500 /***************** set handle type operator *******************/
2501
2502 static int set_handle_type_exec(bContext *C, wmOperator *op)
2503 {
2504         Scene *scene= CTX_data_scene(C);
2505         Object *obedit= CTX_data_edit_object(C);
2506         ListBase *editnurb= curve_get_editcurve(obedit);
2507
2508         sethandlesNurb(editnurb, RNA_enum_get(op->ptr, "type"));
2509
2510         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
2511         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2512
2513         return OPERATOR_FINISHED;
2514 }
2515
2516 void CURVE_OT_handle_type_set(wmOperatorType *ot)
2517 {
2518         static EnumPropertyItem type_items[]= {
2519                 {1, "AUTOMATIC", 0, "Automatic", ""},
2520                 {2, "VECTOR", 0, "Vector", ""},
2521                 {3, "TOGGLE_FREE_ALIGN", 0, "Toggle Free/Align", ""},
2522                 {5, "ALIGN", 0, "Align", ""},
2523                 {6, "FREE_ALIGN", 0, "Free Align", ""},
2524                 {0, NULL, 0, NULL, NULL}};
2525
2526         /* identifiers */
2527         ot->name= "Set Handle Type";
2528         ot->idname= "CURVE_OT_handle_type_set";
2529         
2530         /* api callbacks */
2531         ot->exec= set_handle_type_exec;
2532         ot->poll= ED_operator_editcurve;
2533         
2534         /* flags */
2535         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2536
2537         /* properties */
2538         RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
2539 }
2540
2541 /***************** make segment operator **********************/
2542
2543 /* ******************** SKINNING LOFTING!!! ******************** */
2544
2545 static void switchdirection_knots(float *base, int tot)
2546 {
2547         float *fp1, *fp2, *tempf;
2548         int a;
2549         
2550         if(base==NULL || tot==0) return;
2551         
2552         /* reverse knots */
2553         a= tot;
2554         fp1= base;
2555         fp2= fp1+(a-1);
2556         a/= 2;
2557         while(fp1!=fp2 && a>0) {
2558                 SWAP(float, *fp1, *fp2);
2559                 a--;
2560                 fp1++; 
2561                 fp2--;
2562         }
2563         /* and make in increasing order again */
2564         a= tot;
2565         fp1= base;
2566         fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
2567         while(a--) {
2568                 fp2[0]= fabs(fp1[1]-fp1[0]);
2569                 fp1++;
2570                 fp2++;
2571         }
2572
2573         a= tot-1;
2574         fp1= base;
2575         fp2= tempf;
2576         fp1[0]= 0.0;
2577         fp1++;
2578         while(a--) {
2579                 fp1[0]= fp1[-1]+fp2[0];
2580                 fp1++;
2581                 fp2++;
2582         }
2583         MEM_freeN(tempf);
2584 }
2585
2586 static void rotate_direction_nurb(Nurb *nu)
2587 {
2588         BPoint *bp1, *bp2, *temp;
2589         int u, v;
2590         
2591         SWAP(short, nu->pntsu, nu->pntsv);
2592         SWAP(short, nu->orderu, nu->orderv);
2593         SWAP(short, nu->resolu, nu->resolv);
2594         SWAP(short, nu->flagu, nu->flagv);
2595         
2596         SWAP(float *, nu->knotsu, nu->knotsv);
2597         switchdirection_knots(nu->knotsv, KNOTSV(nu) );
2598         
2599         temp= MEM_dupallocN(nu->bp);
2600         bp1= nu->bp;
2601         for(v=0; v<nu->pntsv; v++) {
2602                 for(u=0; u<nu->pntsu; u++, bp1++) {
2603                         bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
2604                         *bp1= *bp2;
2605                 }
2606         }
2607
2608         MEM_freeN(temp);
2609 }
2610
2611 static int is_u_selected(Nurb *nu, int u)
2612 {
2613         BPoint *bp;
2614         int v;
2615         
2616         /* what about resolu == 2? */
2617         bp= nu->bp+u;
2618         for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
2619                 if(v) if(bp->f1 & SELECT) return 1;
2620         }
2621         
2622         return 0;
2623 }
2624
2625 typedef struct NurbSort {
2626         struct NurbSort *next, *prev;
2627         Nurb *nu;
2628         float vec[3];
2629 } NurbSort;
2630
2631 static ListBase nsortbase= {0, 0};
2632 /*  static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
2633
2634 static void make_selection_list_nurb(ListBase *editnurb)
2635 {
2636         ListBase nbase= {0, 0};
2637         NurbSort *nus, *nustest, *headdo, *taildo;
2638         Nurb *nu;
2639         BPoint *bp;
2640         float dist, headdist, taildist;
2641         int a;
2642         
2643         for(nu= editnurb->first; nu; nu= nu->next) {
2644                 if( isNurbsel(nu) ) {
2645                         
2646                         nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
2647                         BLI_addhead(&nbase, nus);
2648                         nus->nu= nu;
2649                         
2650                         bp= nu->bp;
2651                         a= nu->pntsu;
2652                         while(a--) {
2653                                 VecAddf(nus->vec, nus->vec, bp->vec);
2654                                 bp++;
2655                         }
2656                         VecMulf(nus->vec, 1.0/(float)nu->pntsu);
2657                         
2658                         
2659                 }
2660         }
2661
2662         /* just add the first one */
2663         nus= nbase.first;
2664         BLI_remlink(&nbase, nus);
2665         BLI_addtail( &nsortbase, nus);
2666         
2667         /* now add, either at head or tail, the closest one */
2668         while(nbase.first) {
2669         
2670                 headdist= taildist= 1.0e30;
2671                 headdo= taildo= 0;
2672
2673                 nustest= nbase.first;
2674                 while(nustest) {
2675                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
2676
2677                         if(dist<headdist) {
2678                                 headdist= dist;
2679                                 headdo= nustest;
2680                         }
2681                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
2682
2683                         if(dist<taildist) {
2684                                 taildist= dist;
2685                                 taildo= nustest;
2686                         }
2687                         nustest= nustest->next;
2688                 }
2689                 
2690                 if(headdist<taildist) {
2691                         BLI_remlink(&nbase, headdo);
2692                         BLI_addhead(&nsortbase, headdo);
2693                 }
2694                 else {
2695                         BLI_remlink(&nbase, taildo);
2696                         BLI_addtail(&nsortbase, taildo);
2697                 }
2698         }
2699 }
2700
2701 static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
2702 {
2703         BPoint *bp, *bp1, *bp2, *temp;
2704         float  len1, len2;
2705         int    origu, u, v;
2706         
2707         /* first nurbs will be changed to make u = resolu-1 selected */
2708         /* 2nd nurbs will be changed to make u = 0 selected */
2709
2710         /* first nurbs: u = resolu-1 selected */
2711         
2712         if( is_u_selected(nu1, nu1->pntsu-1) );
2713         else {
2714                 rotate_direction_nurb(nu1);
2715                 if( is_u_selected(nu1, nu1->pntsu-1) );
2716                 else {
2717                         rotate_direction_nurb(nu1);
2718                         if( is_u_selected(nu1, nu1->pntsu-1) );
2719                         else {
2720                                 rotate_direction_nurb(nu1);
2721                                 if( is_u_selected(nu1, nu1->pntsu-1) );
2722                                 else {
2723                                         /* rotate again, now its OK! */
2724                                         if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
2725                                         return;
2726                                 }
2727                         }
2728                 }
2729         }
2730         
2731         /* 2nd nurbs: u = 0 selected */
2732         if( is_u_selected(nu2, 0) );
2733         else {
2734                 rotate_direction_nurb(nu2);
2735                 if( is_u_selected(nu2, 0) );
2736                 else {
2737                         rotate_direction_nurb(nu2);
2738                         if( is_u_selected(nu2, 0) );
2739                         else {
2740                                 rotate_direction_nurb(nu2);
2741                                 if( is_u_selected(nu2, 0) );
2742                                 else {
2743                                         /* rotate again, now its OK! */
2744                                         if(nu1->pntsu==1) rotate_direction_nurb(nu1);
2745                                         if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
2746                                         return;
2747                                 }
2748                         }
2749                 }
2750         }
2751         
2752         if( nu1->pntsv != nu2->pntsv ) {
2753                 BKE_report(op->reports, RPT_ERROR, "Resolution doesn't match");
2754                 return;
2755         }
2756         
2757         /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
2758         /* maybe we need a 'v' flip of nu2? */
2759         
2760         bp1= nu1->bp+nu1->pntsu-1;
2761         bp2= nu2->bp;
2762         len1= 0.0;
2763         
2764         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
2765                 len1+= VecLenf(bp1->vec, bp2->vec);
2766         }
2767
2768         bp1= nu1->bp + nu1->pntsu-1;
2769         bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
2770         len2= 0.0;
2771         
2772         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
2773                 len2+= VecLenf(bp1->vec, bp2->vec);
2774         }
2775
2776         /* merge */
2777         origu= nu1->pntsu;
2778         nu1->pntsu+= nu2->pntsu;
2779         if(nu1->orderu<3) nu1->orderu++;
2780         if(nu1->orderv<3) nu1->orderv++;
2781         temp= nu1->bp;
2782         nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
2783         
2784         bp= nu1->bp;
2785         bp1= temp;
2786         
2787         for(v=0; v<nu1->pntsv; v++) {
2788                 
2789                 /* switch direction? */
2790                 if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
2791                 else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
2792
2793                 for(u=0; u<nu1->pntsu; u++, bp++) {
2794                         if(u<origu) {
2795                                 *bp= *bp1; bp1++;
2796                                 select_bpoint(bp, SELECT, 1, HIDDEN);
2797                         }
2798                         else {
2799                                 *bp= *bp2; bp2++;
2800                         }
2801                 }
2802         }
2803
2804         if((nu1->type & 7)==CU_NURBS) {
2805                 /* merge knots */
2806                 makeknots(nu1, 1);
2807         
2808                 /* make knots, for merged curved for example */
2809                 makeknots(nu1, 2);
2810         }
2811         
2812         MEM_freeN(temp);
2813         BLI_remlink(editnurb, nu2);
2814         freeNurb(nu2);
2815 }
2816
2817 static int merge_nurb(bContext *C, wmOperator *op)
2818 {
2819         Object *obedit= CTX_data_edit_object(C);
2820         ListBase *editnurb= curve_get_editcurve(obedit);
2821         NurbSort *nus1, *nus2;
2822         int ok= 1;
2823         
2824         make_selection_list_nurb(editnurb);
2825         
2826         if(nsortbase.first == nsortbase.last) {
2827                 BLI_freelistN(&nsortbase);
2828                 BKE_report(op->reports, RPT_ERROR, "Too few selections to merge.");
2829                 return OPERATOR_CANCELLED;
2830         }
2831         
2832         nus1= nsortbase.first;
2833         nus2= nus1->next;
2834
2835         /* resolution match, to avoid uv rotations */
2836         if(nus1->nu->pntsv==1) {
2837                 if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
2838                 else ok= 0;
2839         }
2840         else if(nus2->nu->pntsv==1) {