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