From 7a55f52b1bddc389dca1d456dafb79751abcc9c1 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sun, 22 Jun 2008 23:21:29 +0000 Subject: Transform Snapping Snap to edges and vertice without have to go through faces. This means you can import floor plans and use the edges as snapping guides and other sort of fun things. The bounding box test still needs padding though. --- source/blender/src/transform_snap.c | 551 +++++++++++++++++++++--------------- 1 file changed, 328 insertions(+), 223 deletions(-) (limited to 'source/blender/src') diff --git a/source/blender/src/transform_snap.c b/source/blender/src/transform_snap.c index 04ca5b08755..d16308f17ae 100644 --- a/source/blender/src/transform_snap.c +++ b/source/blender/src/transform_snap.c @@ -737,136 +737,6 @@ void TargetSnapClosest(TransInfo *t) } /*================================================================*/ - -/* find snapping point on face, return 1 on success */ -int snapFace(MFace *face, EditFace *efa, MVert *verts, float *intersect, float *loc, float *no) -{ - MVert *v[4]; - EditVert *eve[4]; - int totvert; - int result = 0; - - v[0] = verts + face->v1; - v[1] = verts + face->v2; - v[2] = verts + face->v3; - - if (face->v4) - { - v[3] = verts + face->v4; - totvert = 4; - } - else - { - v[3] = NULL; - totvert = 3; - } - - if (efa) - { - eve[0] = efa->v1; - eve[1] = efa->v2; - eve[2] = efa->v3; - eve[3] = efa->v4; - } - - switch(G.scene->snap_mode) - { - case SCE_SNAP_MODE_VERTEX: - { - float min_dist = FLT_MAX; - int i; - - for(i = 0; i < totvert; i++) - { - - if (efa == NULL || (eve[i]->f1 & SELECT) == 0) - { - float vert_dist = VecLenf(v[i]->co, intersect); - - if (vert_dist < min_dist) - { - result = 1; - - min_dist = vert_dist; - - VECCOPY(loc, v[i]->co); - NormalShortToFloat(no, v[i]->no); - } - } - } - break; - } - case SCE_SNAP_MODE_EDGE: - { - float min_dist = FLT_MAX; - int i; - - for(i = 0; i < totvert; i++) - { - MVert *v1, *v2; - EditVert *eve1, *eve2; - - v1 = v[i]; - v2 = v[(i + 1) % totvert]; - - eve1 = eve[i]; - eve2 = eve[(i + 1) % totvert]; - - if (efa == NULL || ((eve1->f1 & SELECT) == 0 && (eve2->f1 & SELECT) == 0)) - { - float edge_loc[3]; - float vec[3]; - float mul; - float edge_dist; - - VecSubf(edge_loc, v2->co, v1->co); - VecSubf(vec, intersect, v1->co); - - mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc); - - VecMulf(edge_loc, mul); - VecAddf(edge_loc, edge_loc, v1->co); - - edge_dist = VecLenf(edge_loc, intersect); - - if (edge_dist < min_dist) - { - float n1[3], n2[3]; - result = 1; - - min_dist = edge_dist; - - VECCOPY(loc, edge_loc); - - NormalShortToFloat(n1, v1->no); - NormalShortToFloat(n2, v2->no); - VecLerpf(no, n1, n2, mul); - Normalize(no); - } - } - } - break; - } - case SCE_SNAP_MODE_FACE: - { - if (efa == NULL || ((efa->f1 & SELECT) == 0)) - { - result = 1; - - VECCOPY(loc, intersect); - - if (totvert == 4) - CalcNormFloat4(v[0]->co, v[1]->co, v[2]->co, v[3]->co, no); - else - CalcNormFloat(v[0]->co, v[1]->co, v[2]->co, no); - } - break; - } - } - - return result; -} - int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth, short EditMesh) { int retval = 0; @@ -891,7 +761,7 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta Mat4Mul3Vecfl(imat, ray_normal_local); - /* If number of vert is more than an arbitrary limit, + /* If number of vert is more than an arbitrary limit, * test against boundbox first * */ if (totface > 16) { @@ -900,117 +770,219 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta } if (test == 1) { - MVert *verts = dm->getVertArray(dm); - MFace *faces = dm->getFaceArray(dm); - int *index_array = NULL; - int index = 0; - int i; - if (EditMesh) + switch (G.scene->snap_mode) { - index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(0, 0, 1); - } - - for( i = 0; i < totface; i++) { - EditFace *efa = NULL; - MFace *f = faces + i; - float lambda; - int result; - - test = 1; /* reset for every face */ - - if (EditMesh) - { - if (index_array) - { - index = index_array[i]; - } - else - { - index = i; - } + case SCE_SNAP_MODE_FACE: + { + MVert *verts = dm->getVertArray(dm); + MFace *faces = dm->getFaceArray(dm); + int *index_array = NULL; + int index = 0; + int i; - if (index == ORIGINDEX_NONE) + if (EditMesh) { - test = 0; + index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); + EM_init_index_arrays(0, 0, 1); } - else - { - efa = EM_get_face_for_index(index); + + for( i = 0; i < totface; i++) { + EditFace *efa = NULL; + MFace *f = faces + i; + float lambda; + int result; - if (efa && efa->f1 & SELECT) + test = 1; /* reset for every face */ + + if (EditMesh) { - test = 0; + if (index_array) + { + index = index_array[i]; + } + else + { + index = i; + } + + if (index == ORIGINDEX_NONE) + { + test = 0; + } + else + { + efa = EM_get_face_for_index(index); + + if (efa && efa->f & SELECT) + { + test = 0; + } + } } - } - } - - - if (test) - { - result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL); - - if (result) { - float location[3], normal[3]; - float intersect[3]; - VECCOPY(intersect, ray_normal_local); - VecMulf(intersect, lambda); - VecAddf(intersect, intersect, ray_start_local); - if (snapFace(f, efa, verts, intersect, location, normal)) - { - float new_depth; - int screen_loc[2]; - int new_dist; - - Mat4MulVecfl(obmat, location); - - new_depth = VecLenf(location, ray_start); - - project_int(location, screen_loc); - new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + if (test) + { + result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL); - if (new_dist <= *dist && new_depth < *depth) - { - *depth = new_depth; - retval = 1; + if (result) { + float location[3], normal[3]; + float intersect[3]; + float new_depth; + int screen_loc[2]; + int new_dist; - VECCOPY(loc, location); - VECCOPY(no, normal); + VECCOPY(intersect, ray_normal_local); + VecMulf(intersect, lambda); + VecAddf(intersect, intersect, ray_start_local); - Mat3MulVecfl(timat, no); - Normalize(no); - - project_int(loc, screen_loc); + VECCOPY(location, intersect); + + if (f->v4) + CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal); + else + CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + *depth = new_depth; + retval = 1; + + VECCOPY(loc, location); + VECCOPY(no, normal); + + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } + } + + if (f->v4 && result == 0) + { + result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL); - *dist = new_dist; - } + if (result) { + float location[3], normal[3]; + float intersect[3]; + float new_depth; + int screen_loc[2]; + int new_dist; + + VECCOPY(intersect, ray_normal_local); + VecMulf(intersect, lambda); + VecAddf(intersect, intersect, ray_start_local); + + VECCOPY(location, intersect); + + if (f->v4) + CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal); + else + CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + *depth = new_depth; + retval = 1; + + VECCOPY(loc, location); + VECCOPY(no, normal); + + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } + } + } } } - - if (f->v4 && result == 0) + + if (EditMesh) { - result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL); + EM_free_index_arrays(); + } + break; + } + case SCE_SNAP_MODE_VERTEX: + { + MVert *verts = dm->getVertArray(dm); + int *index_array = NULL; + int index = 0; + int i; + + if (EditMesh) + { + index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); + EM_init_index_arrays(1, 0, 0); + } + + for( i = 0; i < totvert; i++) { + EditVert *eve = NULL; + MVert *v = verts + i; - if (result) { - float location[3], normal[3]; - float intersect[3]; + test = 1; /* reset for every vert */ + + if (EditMesh) + { + if (index_array) + { + index = index_array[i]; + } + else + { + index = i; + } - VECCOPY(intersect, ray_normal_local); - VecMulf(intersect, lambda); - VecAddf(intersect, intersect, ray_start_local); - - if (snapFace(f, efa, verts, intersect, location, normal)) - { + if (index == ORIGINDEX_NONE) + { + test = 0; + } + else + { + eve = EM_get_vert_for_index(index); + + if (eve && eve->f & SELECT) + { + test = 0; + } + } + } + + + if (test) + { + float dvec[3]; + + VecSubf(dvec, v->co, ray_start_local); + + if (Inpf(ray_normal_local, dvec) > 0) + { + float location[3]; float new_depth; int screen_loc[2]; int new_dist; + VECCOPY(location, v->co); + Mat4MulVecfl(obmat, location); - new_depth = VecLenf(location, ray_start); + new_depth = VecLenf(location, ray_start); project_int(location, screen_loc); new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); @@ -1021,8 +993,8 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta retval = 1; VECCOPY(loc, location); - VECCOPY(no, normal); + NormalShortToFloat(no, v->no); Mat3MulVecfl(timat, no); Normalize(no); @@ -1031,12 +1003,145 @@ int snapDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta } } } + + if (EditMesh) + { + EM_free_index_arrays(); + } + break; + } + case SCE_SNAP_MODE_EDGE: + { + MVert *verts = dm->getVertArray(dm); + MEdge *edges = dm->getEdgeArray(dm); + int totedge = dm->getNumEdges(dm); + int *index_array = NULL; + int index = 0; + int i; + + if (EditMesh) + { + index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); + EM_init_index_arrays(0, 1, 0); + } + + for( i = 0; i < totedge; i++) { + EditEdge *eed = NULL; + MEdge *e = edges + i; + + test = 1; /* reset for every vert */ + + if (EditMesh) + { + if (index_array) + { + index = index_array[i]; + } + else + { + index = i; + } + + if (index == ORIGINDEX_NONE) + { + test = 0; + } + else + { + eed = EM_get_edge_for_index(index); + + if (eed && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT))) + { + test = 0; + } + } + } + + + if (test) + { + float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; + int result; + + VECCOPY(ray_end, ray_normal_local); + VecMulf(ray_end, 2000); + VecAddf(ray_end, ray_start_local, ray_end); + + result = LineIntersectLine(verts[e->v1].co, verts[e->v2].co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */ + + if (result) + { + float edge_loc[3], vec[3]; + float mul; + + /* check for behind ray_start */ + VecSubf(dvec, intersect, ray_start_local); + + VecSubf(edge_loc, verts[e->v1].co, verts[e->v2].co); + VecSubf(vec, intersect, verts[e->v2].co); + + mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc); + + if (mul > 1) { + mul = 1; + VECCOPY(intersect, verts[e->v1].co); + } + else if (mul < 0) { + mul = 0; + VECCOPY(intersect, verts[e->v2].co); + } + + if (Inpf(ray_normal_local, dvec) > 0) + { + float location[3]; + float new_depth; + int screen_loc[2]; + int new_dist; + + VECCOPY(location, intersect); + + Mat4MulVecfl(obmat, location); + + new_depth = VecLenf(location, ray_start); + + project_int(location, screen_loc); + new_dist = abs(screen_loc[0] - mval[0]) + abs(screen_loc[1] - mval[1]); + + if (new_dist <= *dist && new_depth < *depth) + { + float n1[3], n2[3]; + + *depth = new_depth; + retval = 1; + + VecSubf(edge_loc, verts[e->v1].co, verts[e->v2].co); + VecSubf(vec, intersect, verts[e->v2].co); + + mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc); + + NormalShortToFloat(n1, verts[e->v1].no); + NormalShortToFloat(n2, verts[e->v2].no); + VecLerpf(no, n2, n1, mul); + Normalize(no); + + VECCOPY(loc, location); + + Mat3MulVecfl(timat, no); + Normalize(no); + + *dist = new_dist; + } + } + } + } + } + + if (EditMesh) + { + EM_free_index_arrays(); + } + break; } - } - - if (EditMesh) - { - EM_free_index_arrays(); } } } -- cgit v1.2.3