Blender V2.61 - r43446

transform_orientations.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Martin Poirier
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00028 #include <string.h>
00029 #include <ctype.h>
00030 
00031 #include "MEM_guardedalloc.h"
00032 
00033 #include "DNA_armature_types.h"
00034 #include "DNA_curve_types.h"
00035 #include "DNA_object_types.h"
00036 #include "DNA_scene_types.h"
00037 #include "DNA_screen_types.h"
00038 #include "DNA_view3d_types.h"
00039 
00040 
00041 #include "BKE_armature.h"
00042 #include "BKE_curve.h"
00043 #include "BKE_context.h"
00044 #include "BKE_report.h"
00045 
00046 #include "BLI_math.h"
00047 #include "BLI_blenlib.h"
00048 #include "BLI_editVert.h"
00049 #include "BLI_utildefines.h"
00050 
00051 #include "BLF_translation.h"
00052 
00053 //#include "BIF_editmesh.h"
00054 //#include "BIF_interface.h"
00055 //#include "BIF_space.h"
00056 //#include "BIF_toolbox.h"
00057 
00058 #include "ED_armature.h"
00059 #include "ED_mesh.h"
00060 
00061 #include "RNA_define.h"
00062 
00063 #include "UI_interface.h"
00064 
00065 #include "transform.h"
00066 
00067 /* *********************** TransSpace ************************** */
00068 
00069 void BIF_clearTransformOrientation(bContext *C)
00070 {
00071     View3D *v3d = CTX_wm_view3d(C);
00072 
00073     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00074     BLI_freelistN(transform_spaces);
00075     
00076     // Need to loop over all view3d
00077     if(v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
00078         v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
00079     }
00080 }
00081 
00082 static TransformOrientation* findOrientationName(ListBase *lb, const char *name)
00083 {
00084     TransformOrientation *ts= NULL;
00085 
00086     for (ts= lb->first; ts; ts = ts->next) {
00087         if (strncmp(ts->name, name, sizeof(ts->name)-1) == 0) {
00088             return ts;
00089         }
00090     }
00091     
00092     return NULL;
00093 }
00094 
00095 static int uniqueOrientationNameCheck(void *arg, const char *name)
00096 {
00097     return findOrientationName((ListBase *)arg, name) != NULL;
00098 }
00099 
00100 static void uniqueOrientationName(ListBase *lb, char *name)
00101 {
00102     BLI_uniquename_cb(uniqueOrientationNameCheck, lb, "Space", '.', name, sizeof(((TransformOrientation *)NULL)->name));
00103 }
00104 
00105 void BIF_createTransformOrientation(bContext *C, ReportList *reports, char *name, int use, int overwrite)
00106 {
00107     Object *obedit = CTX_data_edit_object(C);
00108     Object *ob = CTX_data_active_object(C);
00109     TransformOrientation *ts = NULL;
00110     
00111     if (obedit) {
00112         if (obedit->type == OB_MESH)
00113             ts = createMeshSpace(C, reports, name, overwrite);
00114         else if (obedit->type == OB_ARMATURE)
00115             ts = createBoneSpace(C, reports, name, overwrite);
00116     }
00117     else if (ob && (ob->mode & OB_MODE_POSE)) {
00118             ts = createBoneSpace(C, reports, name, overwrite);
00119     }
00120     else {
00121         ts = createObjectSpace(C, reports, name, overwrite);
00122     }
00123     
00124     if (use && ts != NULL)
00125     {
00126         BIF_selectTransformOrientation(C, ts);
00127     }
00128 }
00129 
00130 TransformOrientation *createObjectSpace(bContext *C, ReportList *UNUSED(reports), char *name, int overwrite)
00131 {
00132     Base *base = CTX_data_active_base(C);
00133     Object *ob;
00134     float mat[3][3];
00135 
00136     if (base == NULL)
00137         return NULL;
00138 
00139 
00140     ob = base->object;
00141     
00142     copy_m3_m4(mat, ob->obmat);
00143     normalize_m3(mat);
00144 
00145     /* use object name if no name is given */
00146     if (name[0] == 0)
00147     {
00148         strncpy(name, ob->id.name+2, MAX_ID_NAME-2);
00149     }
00150 
00151     return addMatrixSpace(C, mat, name, overwrite); 
00152 }
00153 
00154 TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, char *name, int overwrite)
00155 {
00156     float mat[3][3];
00157     float normal[3], plane[3];
00158 
00159     getTransformOrientation(C, normal, plane, 0);
00160 
00161     if (createSpaceNormalTangent(mat, normal, plane) == 0) {
00162         BKE_reports_prepend(reports, "Cannot use zero-length bone");
00163         return NULL;
00164     }
00165 
00166     if (name[0] == 0)
00167     {
00168         strcpy(name, "Bone");
00169     }
00170 
00171     return addMatrixSpace(C, mat, name, overwrite);
00172 }
00173 
00174 TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *name, int overwrite)
00175 {
00176     float mat[3][3];
00177     float normal[3], plane[3];
00178     int type;
00179 
00180     type = getTransformOrientation(C, normal, plane, 0);
00181     
00182     switch (type)
00183     {
00184         case ORIENTATION_VERT:
00185             if (createSpaceNormal(mat, normal) == 0) {
00186                 BKE_reports_prepend(reports, "Cannot use vertex with zero-length normal");
00187                 return NULL;
00188             }
00189     
00190             if (name[0] == 0)
00191             {
00192                 strcpy(name, "Vertex");
00193             }
00194             break;
00195         case ORIENTATION_EDGE:
00196             if (createSpaceNormalTangent(mat, normal, plane) == 0) {
00197                 BKE_reports_prepend(reports, "Cannot use zero-length edge");
00198                 return NULL;
00199             }
00200     
00201             if (name[0] == 0)
00202             {
00203                 strcpy(name, "Edge");
00204             }
00205             break;
00206         case ORIENTATION_FACE:
00207             if (createSpaceNormalTangent(mat, normal, plane) == 0) {
00208                 BKE_reports_prepend(reports, "Cannot use zero-area face");
00209                 return NULL;
00210             }
00211     
00212             if (name[0] == 0)
00213             {
00214                 strcpy(name, "Face");
00215             }
00216             break;
00217         default:
00218             return NULL;
00219             break;
00220     }
00221 
00222     return addMatrixSpace(C, mat, name, overwrite);
00223 }
00224 
00225 int createSpaceNormal(float mat[3][3], float normal[3])
00226 {
00227     float tangent[3] = {0.0f, 0.0f, 1.0f};
00228     
00229     copy_v3_v3(mat[2], normal);
00230     if (normalize_v3(mat[2]) == 0.0f) {
00231         return 0; /* error return */
00232     }
00233 
00234     cross_v3_v3v3(mat[0], mat[2], tangent);
00235     if (dot_v3v3(mat[0], mat[0]) == 0.0f) {
00236         tangent[0] = 1.0f;
00237         tangent[1] = tangent[2] = 0.0f;
00238         cross_v3_v3v3(mat[0], tangent, mat[2]);
00239     }
00240 
00241     cross_v3_v3v3(mat[1], mat[2], mat[0]);
00242 
00243     normalize_m3(mat);
00244     
00245     return 1;
00246 }
00247 
00248 int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
00249 {
00250     copy_v3_v3(mat[2], normal);
00251     if (normalize_v3(mat[2]) == 0.0f) {
00252         return 0; /* error return */
00253     }
00254     
00255     /* preempt zero length tangent from causing trouble */
00256     if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0)
00257     {
00258         tangent[2] = 1;
00259     }
00260 
00261     cross_v3_v3v3(mat[0], mat[2], tangent);
00262     if (normalize_v3(mat[0]) == 0.0f) {
00263         return 0; /* error return */
00264     }
00265     
00266     cross_v3_v3v3(mat[1], mat[2], mat[0]);
00267 
00268     normalize_m3(mat);
00269     
00270     return 1;
00271 }
00272 
00273 TransformOrientation* addMatrixSpace(bContext *C, float mat[3][3], char name[], int overwrite)
00274 {
00275     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00276     TransformOrientation *ts = NULL;
00277 
00278     if (overwrite)
00279     {
00280         ts = findOrientationName(transform_spaces, name);
00281     }
00282     else
00283     {
00284         uniqueOrientationName(transform_spaces, name);
00285     }
00286 
00287     /* if not, create a new one */
00288     if (ts == NULL)
00289     {
00290         ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
00291         BLI_addtail(transform_spaces, ts);
00292         strncpy(ts->name, name, sizeof(ts->name));
00293     }
00294 
00295     /* copy matrix into transform space */
00296     copy_m3_m3(ts->mat, mat);
00297 
00298     return ts;
00299 }
00300 
00301 void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target)
00302 {
00303     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00304     TransformOrientation *ts;
00305     int i;
00306     
00307     for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
00308         if (ts == target) {
00309             View3D *v3d = CTX_wm_view3d(C);
00310             if(v3d) {
00311                 int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
00312                 
00313                 // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
00314                 if (selected_index == i) {
00315                     v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
00316                 }
00317                 else if (selected_index > i) {
00318                     v3d->twmode--;
00319                 }
00320                 
00321             }
00322 
00323             BLI_freelinkN(transform_spaces, ts);
00324             break;
00325         }
00326     }
00327 }
00328 
00329 void BIF_removeTransformOrientationIndex(bContext *C, int index)
00330 {
00331     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00332     TransformOrientation *ts= BLI_findlink(transform_spaces, index);
00333 
00334     if (ts) {
00335         View3D *v3d = CTX_wm_view3d(C);
00336         if(v3d) {
00337             int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
00338             
00339             // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
00340             if (selected_index == index) {
00341                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
00342             }
00343             else if (selected_index > index) {
00344                 v3d->twmode--;
00345             }
00346             
00347         }
00348 
00349         BLI_freelinkN(transform_spaces, ts);
00350     }
00351 }
00352 
00353 void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
00354 {
00355     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00356     View3D *v3d = CTX_wm_view3d(C);
00357     TransformOrientation *ts;
00358     int i;
00359     
00360     for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
00361         if (ts == target) {
00362             v3d->twmode = V3D_MANIP_CUSTOM + i;
00363             break;
00364         }
00365     }
00366 }
00367 
00368 void BIF_selectTransformOrientationValue(bContext *C, int orientation)
00369 {
00370     View3D *v3d = CTX_wm_view3d(C);
00371     if(v3d) /* currently using generic poll */
00372         v3d->twmode = orientation;
00373 }
00374 
00375 EnumPropertyItem *BIF_enumTransformOrientation(bContext *C)
00376 {
00377     Scene *scene;
00378     ListBase *transform_spaces;
00379     TransformOrientation *ts= NULL;
00380 
00381     EnumPropertyItem global = {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""};
00382     EnumPropertyItem normal = {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""};
00383     EnumPropertyItem local = {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""};
00384     EnumPropertyItem view = {V3D_MANIP_VIEW, "VIEW", 0, "View", ""};
00385     EnumPropertyItem tmp = {0, "", 0, "", ""};
00386     EnumPropertyItem *item= NULL;
00387     int i = V3D_MANIP_CUSTOM, totitem= 0;
00388 
00389     RNA_enum_item_add(&item, &totitem, &global);
00390     RNA_enum_item_add(&item, &totitem, &normal);
00391     RNA_enum_item_add(&item, &totitem, &local);
00392     RNA_enum_item_add(&item, &totitem, &view);
00393 
00394     if(C) {
00395         scene= CTX_data_scene(C);
00396 
00397         if(scene) {
00398             transform_spaces = &scene->transform_spaces;
00399             ts = transform_spaces->first;
00400         }
00401     }
00402         
00403     if(ts)
00404         RNA_enum_item_add_separator(&item, &totitem);
00405 
00406     for(; ts; ts = ts->next) {
00407         tmp.identifier = "CUSTOM";
00408         tmp.name= ts->name;
00409         tmp.value = i++;
00410         RNA_enum_item_add(&item, &totitem, &tmp);
00411     }
00412 
00413     RNA_enum_item_end(&item, &totitem);
00414 
00415     return item;
00416 }
00417 
00418 const char * BIF_menustringTransformOrientation(const bContext *C, const char *title)
00419 {
00420     const char* menu = IFACE_("%t|Global%x0|Local%x1|Gimbal%x4|Normal%x2|View%x3");
00421     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00422     TransformOrientation *ts;
00423     int i = V3D_MANIP_CUSTOM;
00424     char *str_menu, *p;
00425     const int elem_size = MAX_NAME + 4;
00426 
00427     title = IFACE_(title);
00428 
00429     str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + elem_size * BIF_countTransformOrientation(C), TIP_("UserTransSpace from matrix"));
00430     p = str_menu;
00431     
00432     p += sprintf(str_menu, "%s", title);
00433     p += sprintf(p, "%s", menu);
00434     
00435     for (ts = transform_spaces->first; ts; ts = ts->next) {
00436         p += sprintf(p, "|%s%%x%d", ts->name, i++);
00437     }
00438     
00439     return str_menu;
00440 }
00441 
00442 int BIF_countTransformOrientation(const bContext *C)
00443 {
00444     ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00445     TransformOrientation *ts;
00446     int count = 0;
00447 
00448     for (ts = transform_spaces->first; ts; ts = ts->next) {
00449         count++;
00450     }
00451     
00452     return count;
00453 }
00454 
00455 void applyTransformOrientation(const bContext *C, float mat[3][3], char *name)
00456 {
00457     TransformOrientation *ts;
00458     View3D *v3d = CTX_wm_view3d(C);
00459     int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
00460     int i;
00461     
00462     if (selected_index >= 0) {
00463         for (i = 0, ts = CTX_data_scene(C)->transform_spaces.first; ts; ts = ts->next, i++) {
00464             if (selected_index == i) {
00465                 
00466                 if (name)
00467                     strcpy(name, ts->name);
00468                 
00469                 copy_m3_m3(mat, ts->mat);
00470                 break;
00471             }
00472         }
00473       }
00474 }
00475 
00476 static int count_bone_select(bArmature *arm, ListBase *lb, int do_it) 
00477 {
00478     Bone *bone;
00479     int do_next;
00480     int total = 0;
00481     
00482     for(bone= lb->first; bone; bone= bone->next) {
00483         bone->flag &= ~BONE_TRANSFORM;
00484         do_next = do_it;
00485         if(do_it) {
00486             if(bone->layer & arm->layer) {
00487                 if (bone->flag & BONE_SELECTED) {
00488                     bone->flag |= BONE_TRANSFORM;
00489                     total++;
00490                     do_next= 0; // no transform on children if one parent bone is selected
00491                 }
00492             }
00493         }
00494         total += count_bone_select(arm, &bone->childbase, do_next);
00495     }
00496     
00497     return total;
00498 }
00499 
00500 void initTransformOrientation(bContext *C, TransInfo *t)
00501 {
00502     View3D *v3d = CTX_wm_view3d(C);
00503     Object *ob = CTX_data_active_object(C);
00504     Object *obedit = CTX_data_active_object(C);
00505 
00506     switch(t->current_orientation) {
00507     case V3D_MANIP_GLOBAL:
00508         unit_m3(t->spacemtx);
00509         strcpy(t->spacename, "global");
00510         break;
00511 
00512     case V3D_MANIP_GIMBAL:
00513         unit_m3(t->spacemtx);
00514         if (gimbal_axis(ob, t->spacemtx)) {
00515             strcpy(t->spacename, "gimbal");
00516             break;
00517         }
00518         /* no gimbal fallthrough to normal */
00519     case V3D_MANIP_NORMAL:
00520         if(obedit || (ob && ob->mode & OB_MODE_POSE)) {
00521             strcpy(t->spacename, "normal");
00522             ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE));
00523             break;
00524         }
00525         /* no break we define 'normal' as 'local' in Object mode */
00526     case V3D_MANIP_LOCAL:
00527         strcpy(t->spacename, "local");
00528         
00529         if(ob) {
00530             copy_m3_m4(t->spacemtx, ob->obmat);
00531             normalize_m3(t->spacemtx);
00532         } else {
00533             unit_m3(t->spacemtx);
00534         }
00535         
00536         break;
00537         
00538     case V3D_MANIP_VIEW:
00539         if (t->ar->regiontype == RGN_TYPE_WINDOW)
00540         {
00541             RegionView3D *rv3d = t->ar->regiondata;
00542             float mat[3][3];
00543 
00544             strcpy(t->spacename, "view");
00545             copy_m3_m4(mat, rv3d->viewinv);
00546             normalize_m3(mat);
00547             copy_m3_m3(t->spacemtx, mat);
00548         }
00549         else
00550         {
00551             unit_m3(t->spacemtx);
00552         }
00553         break;
00554     default: /* V3D_MANIP_CUSTOM */
00555         applyTransformOrientation(C, t->spacemtx, t->spacename);
00556         break;
00557     }
00558 }
00559 
00560 int getTransformOrientation(const bContext *C, float normal[3], float plane[3], int activeOnly)
00561 {
00562     Scene *scene = CTX_data_scene(C);
00563     View3D *v3d = CTX_wm_view3d(C);
00564     Object *obedit= CTX_data_edit_object(C);
00565     Base *base;
00566     Object *ob = OBACT;
00567     int result = ORIENTATION_NONE;
00568 
00569     normal[0] = normal[1] = normal[2] = 0;
00570     plane[0] = plane[1] = plane[2] = 0;
00571 
00572     if(obedit)
00573     {
00574         float imat[3][3], mat[3][3];
00575         
00576         /* we need the transpose of the inverse for a normal... */
00577         copy_m3_m4(imat, ob->obmat);
00578         
00579         invert_m3_m3(mat, imat);
00580         transpose_m3(mat);
00581 
00582         ob= obedit;
00583 
00584         if(ob->type==OB_MESH)
00585         {
00586             Mesh *me= ob->data;
00587             EditMesh *em = me->edit_mesh;
00588             EditVert *eve;
00589             EditSelection ese;
00590             float vec[3]= {0,0,0};
00591             
00592             /* USE LAST SELECTED WITH ACTIVE */
00593             if (activeOnly && EM_get_actSelection(em, &ese))
00594             {
00595                 EM_editselection_normal(normal, &ese);
00596                 EM_editselection_plane(plane, &ese);
00597                 
00598                 switch (ese.type)
00599                 {
00600                     case EDITVERT:
00601                         result = ORIENTATION_VERT;
00602                         break;
00603                     case EDITEDGE:
00604                         result = ORIENTATION_EDGE;
00605                         break;
00606                     case EDITFACE:
00607                         result = ORIENTATION_FACE;
00608                         break;
00609                 }
00610             }
00611             else
00612             {
00613                 if (em->totfacesel >= 1)
00614                 {
00615                     EditFace *efa;
00616                     
00617                     for(efa= em->faces.first; efa; efa= efa->next)
00618                     {
00619                         if(efa->f & SELECT)
00620                         {
00621                             add_v3_v3(normal, efa->n);
00622                             sub_v3_v3v3(vec, efa->v2->co, efa->v1->co);
00623                             add_v3_v3(plane, vec);
00624                         }
00625                     }
00626                     
00627                     result = ORIENTATION_FACE;
00628                 }
00629                 else if (em->totvertsel == 3)
00630                 {
00631                     EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
00632                     float cotangent[3];
00633                     
00634                     for (eve = em->verts.first; eve; eve = eve->next)
00635                     {
00636                         if ( eve->f & SELECT ) {
00637                             if (v1 == NULL) {
00638                                 v1 = eve; 
00639                             }
00640                             else if (v2 == NULL) {
00641                                 v2 = eve;
00642                             }
00643                             else {
00644                                 v3 = eve;
00645 
00646                                 sub_v3_v3v3(plane, v2->co, v1->co);
00647                                 sub_v3_v3v3(cotangent, v3->co, v2->co);
00648                                 cross_v3_v3v3(normal, cotangent, plane);
00649                                 break;
00650                             }
00651                         }
00652                     }
00653 
00654                     /* if there's an edge available, use that for the tangent */
00655                     if (em->totedgesel >= 1)
00656                     {
00657                         EditEdge *eed = NULL;
00658     
00659                         for(eed= em->edges.first; eed; eed= eed->next) {
00660                             if(eed->f & SELECT) {
00661                                 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
00662                                 break;
00663                             }
00664                         }
00665                     }
00666 
00667                     result = ORIENTATION_FACE;
00668                 }
00669                 else if (em->totedgesel == 1)
00670                 {
00671                     EditEdge *eed;
00672 
00673                     for(eed= em->edges.first; eed; eed= eed->next) {
00674                         if(eed->f & SELECT) {
00675                             /* use average vert normals as plane and edge vector as normal */
00676                             copy_v3_v3(plane, eed->v1->no);
00677                             add_v3_v3(plane, eed->v2->no);
00678                             sub_v3_v3v3(normal, eed->v2->co, eed->v1->co);
00679                             break;
00680                         }
00681                     }
00682                     result = ORIENTATION_EDGE;
00683                 }
00684                 else if (em->totvertsel == 2)
00685                 {
00686                     EditVert *v1 = NULL, *v2 = NULL;
00687         
00688                     for (eve = em->verts.first; eve; eve = eve->next)
00689                     {
00690                         if ( eve->f & SELECT ) {
00691                             if (v1 == NULL) {
00692                                 v1 = eve; 
00693                             }
00694                             else {
00695                                 v2 = eve;
00696                                 
00697                                 copy_v3_v3(plane, v1->no);
00698                                 add_v3_v3(plane, v2->no);
00699                                 sub_v3_v3v3(normal, v2->co, v1->co);
00700                                 break; 
00701                             }
00702                         }
00703                     }
00704                     result = ORIENTATION_EDGE;
00705                 }
00706                 else if (em->totvertsel == 1)
00707                 {
00708                     for (eve = em->verts.first; eve; eve = eve->next)
00709                     {
00710                         if ( eve->f & SELECT ) {
00711                             copy_v3_v3(normal, eve->no);
00712                             break;
00713                         }
00714                     }
00715                     result = ORIENTATION_VERT;
00716                 }
00717                 else if (em->totvertsel > 3)
00718                 {
00719                     normal[0] = normal[1] = normal[2] = 0;
00720                     
00721                     for (eve = em->verts.first; eve; eve = eve->next)
00722                     {
00723                         if ( eve->f & SELECT ) {
00724                             add_v3_v3(normal, eve->no);
00725                         }
00726                     }
00727                     normalize_v3(normal);
00728                     result = ORIENTATION_VERT;
00729                 }
00730             }
00731         } /* end editmesh */
00732         else if ELEM(obedit->type, OB_CURVE, OB_SURF)
00733         {
00734             Curve *cu= obedit->data;
00735             Nurb *nu;
00736             BezTriple *bezt;
00737             int a;
00738             ListBase *nurbs= curve_editnurbs(cu);
00739 
00740             for (nu = nurbs->first; nu; nu = nu->next)
00741             {
00742                 /* only bezier has a normal */
00743                 if(nu->type == CU_BEZIER)
00744                 {
00745                     bezt= nu->bezt;
00746                     a= nu->pntsu;
00747                     while(a--)
00748                     {
00749                         /* exception */
00750                         if ( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT )
00751                         {
00752                             sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
00753                         }
00754                         else
00755                         {
00756                             if(bezt->f1)
00757                             {
00758                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[1]);
00759                             }
00760                             if(bezt->f2)
00761                             {
00762                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
00763                             }
00764                             if(bezt->f3)
00765                             {
00766                                 sub_v3_v3v3(normal, bezt->vec[1], bezt->vec[2]);
00767                             }
00768                         }
00769                         bezt++;
00770                     }
00771                 }
00772             }
00773             
00774             if (normal[0] != 0 || normal[1] != 0 || normal[2] != 0)
00775             {
00776                 result = ORIENTATION_NORMAL;
00777             }
00778         }
00779         else if(obedit->type==OB_MBALL)
00780         {
00781 #if 0 // XXX
00782             /* editmball.c */
00783             extern ListBase editelems;  /* go away ! */
00784             MetaElem *ml, *ml_sel = NULL;
00785     
00786             /* loop and check that only one element is selected */  
00787             for (ml = editelems.first; ml; ml = ml->next)
00788             {
00789                 if (ml->flag & SELECT) {
00790                     if (ml_sel == NULL)
00791                     {
00792                         ml_sel = ml;
00793                     }
00794                     else
00795                     {
00796                         ml_sel = NULL;
00797                         break;
00798                     }
00799                 }
00800             }
00801             
00802             if (ml_sel)
00803             {   
00804                 float mat[4][4];
00805 
00806                 /* Rotation of MetaElem is stored in quat */
00807                 quat_to_mat4( mat,ml_sel->quat);
00808 
00809                 copy_v3_v3(normal, mat[2]);
00810 
00811                 negate_v3_v3(plane, mat[1]);
00812                 
00813                 result = ORIENTATION_NORMAL;
00814             }
00815 #endif
00816             
00817         }
00818         else if (obedit->type == OB_ARMATURE)
00819         {
00820             bArmature *arm = obedit->data;
00821             EditBone *ebone;
00822             
00823             for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
00824                 if (arm->layer & ebone->layer)
00825                 {
00826                     if (ebone->flag & BONE_SELECTED)
00827                     {
00828                         float tmat[3][3];
00829                         float vec[3];
00830                         sub_v3_v3v3(vec, ebone->tail, ebone->head);
00831                         normalize_v3(vec);
00832                         add_v3_v3(normal, vec);
00833                         
00834                         vec_roll_to_mat3(vec, ebone->roll, tmat);
00835                         add_v3_v3(plane, tmat[2]);
00836                     }
00837                 }
00838             }
00839             
00840             normalize_v3(normal);
00841             normalize_v3(plane);
00842 
00843             if (plane[0] != 0 || plane[1] != 0 || plane[2] != 0)
00844             {
00845                 result = ORIENTATION_EDGE;
00846             }
00847 
00848         }
00849 
00850         /* Vectors from edges don't need the special transpose inverse multiplication */
00851         if (result == ORIENTATION_EDGE)
00852         {
00853             mul_mat3_m4_v3(ob->obmat, normal);
00854             mul_mat3_m4_v3(ob->obmat, plane);
00855         }
00856         else
00857         {
00858             mul_m3_v3(mat, normal);
00859             mul_m3_v3(mat, plane);
00860         }
00861     }
00862     else if(ob && (ob->mode & OB_MODE_POSE))
00863     {
00864         bArmature *arm= ob->data;
00865         bPoseChannel *pchan;
00866         int totsel;
00867         
00868         totsel = count_bone_select(arm, &arm->bonebase, 1);
00869         if(totsel) {
00870             float imat[3][3], mat[3][3];
00871 
00872             /* use channels to get stats */
00873             for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00874                 if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
00875                     add_v3_v3(normal, pchan->pose_mat[2]);
00876                     add_v3_v3(plane, pchan->pose_mat[1]);
00877                 }
00878             }
00879             negate_v3(plane);
00880             
00881             /* we need the transpose of the inverse for a normal... */
00882             copy_m3_m4(imat, ob->obmat);
00883             
00884             invert_m3_m3(mat, imat);
00885             transpose_m3(mat);
00886             mul_m3_v3(mat, normal);
00887             mul_m3_v3(mat, plane);
00888             
00889             result = ORIENTATION_EDGE;
00890         }
00891     }
00892     else if(ob && (ob->mode & (OB_MODE_ALL_PAINT|OB_MODE_PARTICLE_EDIT)))
00893     {
00894     }
00895     else {
00896         /* we need the one selected object, if its not active */
00897         ob = OBACT;
00898         if(ob && !(ob->flag & SELECT)) ob = NULL;
00899         
00900         for(base= scene->base.first; base; base= base->next) {
00901             if TESTBASELIB(v3d, base) {
00902                 if(ob == NULL) { 
00903                     ob= base->object;
00904                     break;
00905                 }
00906             }
00907         }
00908         
00909         if (ob) {
00910             copy_v3_v3(normal, ob->obmat[2]);
00911             copy_v3_v3(plane, ob->obmat[1]);
00912         }
00913         result = ORIENTATION_NORMAL;
00914     }
00915     
00916     return result;
00917 }
00918 
00919 void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[][3], int activeOnly)
00920 {
00921     float normal[3]={0.0, 0.0, 0.0};
00922     float plane[3]={0.0, 0.0, 0.0};
00923 
00924     int type;
00925 
00926     type = getTransformOrientation(C, normal, plane, activeOnly);
00927 
00928     switch (type)
00929     {
00930         case ORIENTATION_NORMAL:
00931             if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0)
00932             {
00933                 type = ORIENTATION_NONE;
00934             }
00935             break;
00936         case ORIENTATION_VERT:
00937             if (createSpaceNormal(orientation_mat, normal) == 0)
00938             {
00939                 type = ORIENTATION_NONE;
00940             }
00941             break;
00942         case ORIENTATION_EDGE:
00943             if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0)
00944             {
00945                 type = ORIENTATION_NONE;
00946             }
00947             break;
00948         case ORIENTATION_FACE:
00949             if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0)
00950             {
00951                 type = ORIENTATION_NONE;
00952             }
00953             break;
00954     }
00955 
00956     if (type == ORIENTATION_NONE)
00957     {
00958         unit_m3(orientation_mat);
00959     }
00960 }