Revision: 55802
http://sourceforge.net/p/brlcad/code/55802
Author: starseeker
Date: 2013-06-19 20:29:22 +0000 (Wed, 19 Jun 2013)
Log Message:
-----------
Start trying to figure out how to speed up the sparse bot wireframe drawing
Modified Paths:
--------------
brlcad/trunk/src/librt/primitives/bot/bot_wireframe.cpp
Modified: brlcad/trunk/src/librt/primitives/bot/bot_wireframe.cpp
===================================================================
--- brlcad/trunk/src/librt/primitives/bot/bot_wireframe.cpp 2013-06-19
20:08:41 UTC (rev 55801)
+++ brlcad/trunk/src/librt/primitives/bot/bot_wireframe.cpp 2013-06-19
20:29:22 UTC (rev 55802)
@@ -1,52 +1,12 @@
#include "common.h"
-#include <map>
-#include <set>
#include <queue>
-#include <list>
-#include <vector>
#include "vmath.h"
#include "raytrace.h"
#include "wdb.h"
-/*************************
- * Utility functions
- *************************/
-#if 0
-// Make an edge id using the Szudzik pairing function:
-long unsigned int edge_id(size_t pt_A, size_t pt_B)
-{
- return (pt_A >= pt_B) ? (pt_A * pt_A + pt_A + pt_B) : (pt_B * pt_B + pt_A);
-}
-
-// shift one of the vertex index numbers up to form a unique ID. Offset is
-// log10(bot->num_vertices) + 1
-long unsigned int edge_id(size_t pt_A, size_t pt_B, int offset)
-{
- return (pt_A <= pt_B) ? (pt_A * pow(10,offset) + pt_B) : (pt_B *
pow(10,offset) + pt_A);
-}
-
-void breakout(long unsigned int id, int offset, size_t *A, size_t *B)
-{
- (*B) = (size_t)((long)id % (int)pow(10,offset));
- (*A) = (size_t)(id - (*B))/ (int)(pow(10, offset));
-}
-#endif
-
-// Make an edge using consistent vertex ordering
-static std::pair<size_t, size_t>
-mk_edge(size_t pt_A, size_t pt_B)
-{
- if (pt_A <= pt_B) {
- return std::make_pair(pt_A, pt_B);
- } else {
- return std::make_pair(pt_B, pt_A);
- }
-}
-
-
// Calculate area of a face
static double
face_area(struct rt_bot_internal *bot, size_t face_num)
@@ -65,49 +25,6 @@
return area;
}
-// Given a BoT face, return the three other faces that share an edge with that
face
-static void
-get_connected_faces(struct rt_bot_internal *bot, size_t face_num,
std::map<size_t, std::set<size_t> > *vert_to_face, std::set<size_t> *faces)
-{
- std::map<size_t, size_t> face_cnt;
- size_t points[3];
- points[0] = bot->faces[face_num*3+0]*3;
- points[1] = bot->faces[face_num*3+1]*3;
- points[2] = bot->faces[face_num*3+2]*3;
- std::set<size_t>::iterator it;
- for (int i = 0; i < 3; ++i) {
- for (it = (*vert_to_face)[points[i]].begin(); it !=
(*vert_to_face)[points[i]].end(); it++) {
- face_cnt[(*it)] += 1;
- }
- }
- std::map<size_t, size_t>::iterator mit;
- for (mit = face_cnt.begin(); mit != face_cnt.end(); ++mit) {
- if ((*mit).second > 1) {
- faces->insert((*mit).first);
- }
- }
-}
-
-/* To avoid drawing duplicate lines, build the final vlist using a set */
-static void
-plot_patch_borders(std::vector<std::map<std::pair<size_t, size_t>, size_t> >
*patch_edge_cnt, struct rt_bot_internal *bot, struct bu_list *vhead)
-{
- std::set<std::pair<size_t, size_t> > final_edge_set;
- std::set<std::pair<size_t, size_t> >::iterator fe_it;
- std::map<std::pair<size_t, size_t>, size_t>::iterator e_it;
- for (int i = 0; i < patch_edge_cnt->size(); i++) {
- for (e_it = (*patch_edge_cnt)[i].begin(); e_it !=
(*patch_edge_cnt)[i].end(); e_it++) {
- if ((*e_it).second == 1) {
- final_edge_set.insert((*e_it).first);
- }
- }
- }
- for (fe_it = final_edge_set.begin(); fe_it != final_edge_set.end();
fe_it++) {
- RT_ADD_VLIST(vhead, &(bot->vertices[(*fe_it).first]),
BN_VLIST_LINE_MOVE);
- RT_ADD_VLIST(vhead, &(bot->vertices[(*fe_it).second]),
BN_VLIST_LINE_DRAW);
- }
-}
-
/**********************************************************
* Code for identifying semi-flat patches in bots
* and creating wireframe edges
@@ -120,32 +37,7 @@
BU_CK_LIST_HEAD(info->vhead);
bot = (struct rt_bot_internal *)ip->idb_ptr;
RT_BOT_CK_MAGIC(bot);
-
- if (bot->num_vertices <= 0 || !bot->vertices || bot->num_faces <= 0 ||
!bot->faces)
- return 0;
-
- /* Declare key containers */
vect_t gvects[6];
- std::vector<double> face_areas;
- std::vector<double> face_normals;
- std::vector<std::vector<size_t> > groups;
- std::vector<std::map<std::pair<size_t, size_t>, size_t> >
groups_edge_face_cnt;
- std::vector<std::vector<size_t> > categorization_results;
- std::vector<int> face_to_plane;
- std::vector<std::set<size_t> > patches;
- std::map<size_t, std::set<size_t> > vert_to_face;
-
- /* Initialize containers */
- face_areas.resize(bot->num_faces);
- face_to_plane.resize(bot->num_faces);
- face_normals.resize(bot->num_faces*3);
- groups.resize(6);
- groups_edge_face_cnt.resize(6);
- categorization_results.resize(6);
- for (int i = 0; i < 6; ++i) {
- categorization_results[i].resize(bot->num_faces); //categories can hold
at most all faces in bot
- }
- patches.resize(bot->num_faces*3); // Max number of patches should be the
same as the face cnt, but it isn't always
VSET(gvects[0], -1,0,0);
VSET(gvects[1], 0,-1,0);
VSET(gvects[2], 0,0,-1);
@@ -153,118 +45,140 @@
VSET(gvects[4], 0,1,0);
VSET(gvects[5], 0,0,1);
- // Calculate face normals dot product with bounding rpp planes
- for (size_t i=0; i < bot->num_faces; ++i) {
- size_t pt_A, pt_B, pt_C;
- size_t result_max;
- double vdot = 0.0;
- double result = 0.0;
+ if (bot->num_vertices <= 0 || !bot->vertices || bot->num_faces <= 0 ||
!bot->faces)
+ return 0;
+
+ /* Declare key containers */
+ double *face_areas= (double *)bu_calloc(bot->num_faces, sizeof(double),
"areas");
+ double *face_normals= (double *)bu_calloc(bot->num_faces * 3,
sizeof(double), "normals");
+ /* Stash all the initial categorization test results - can be re-used
later */
+// unsigned int *categorization_results = (unsigned int
*)bu_calloc(sizeof(unsigned int) * bot->num_faces * 6, "categorization
results");
+ /* Initial group assignments */
+ unsigned int *groups = (unsigned int *)bu_calloc(bot->num_faces,
sizeof(unsigned int), "groups");
+ /* Initially, patch breakdown is made in a faces -> patch_id map */
+ unsigned int *patches= (unsigned int *)bu_calloc(bot->num_faces,
sizeof(unsigned int), "patch_id_numbers");
+ /* Don't know yet how big this needs to be */
+ unsigned int *vert_to_face = NULL;
+
+ /* Sanity check vertex indicies in face definitions */
+ for (unsigned int i = 0; i < bot->num_faces; ++i) {
+ if ((unsigned int)bot->faces[i*3+0] > (unsigned
int)(bot->num_vertices)) bu_log("bot->faces[%d*3+0]: %d, bot->num_vertices:
%d", i, bot->faces[i*3+0], bot->num_vertices);
+ if ((unsigned int)bot->faces[i*3+1] > (unsigned
int)(bot->num_vertices)) bu_log("bot->faces[%d*3+1]: %d, bot->num_vertices:
%d", i, bot->faces[i*3+1], bot->num_vertices);
+ if ((unsigned int)bot->faces[i*3+2] > (unsigned
int)(bot->num_vertices)) bu_log("bot->faces[%d*3+2]: %d, bot->num_vertices:
%d", i, bot->faces[i*3+2], bot->num_vertices);
+ }
+ /* Pre-compute face areas once */
+ for (unsigned int i = 0; i < bot->num_faces; i++) {
+ face_areas[i] = face_area(bot, i);
+ }
+ /* Pre-compute face normals once */
+ for (unsigned int i = 0; i < bot->num_faces; i++) {
vect_t a, b, norm_dir;
- // Add vert -> edge and edge -> face mappings to global map.
- pt_A = bot->faces[i*3+0]*3;
- pt_B = bot->faces[i*3+1]*3;
- pt_C = bot->faces[i*3+2]*3;
- vert_to_face[pt_A].insert(i);
- vert_to_face[pt_B].insert(i);
- vert_to_face[pt_C].insert(i);
- // Categorize face
VSUB2(a, &bot->vertices[bot->faces[i*3+1]*3],
&bot->vertices[bot->faces[i*3]*3]);
VSUB2(b, &bot->vertices[bot->faces[i*3+2]*3],
&bot->vertices[bot->faces[i*3]*3]);
VCROSS(norm_dir, a, b);
VUNITIZE(norm_dir);
- face_normals[i*3]=norm_dir[0];
- face_normals[i*3+1]=norm_dir[1];
- face_normals[i*3+2]=norm_dir[2];
- for (int j=0; j < 6; j++) {
+ face_normals[i*3]=norm_dir[0];
+ face_normals[i*3+1]=norm_dir[1];
+ face_normals[i*3+2]=norm_dir[2];
+ }
+ /* Calculate categorization results and assign groups */
+ for (unsigned int i = 0; i < bot->num_faces; i++) {
+ int result_max = 0;
+ double result = 0.0;
+ double vdot = 0.0;
+ vect_t norm_dir;
+ VSET(norm_dir, face_normals[i*3], face_normals[i*3+1],
face_normals[i*3+2]);
+ for (unsigned int j=0; j < 6; j++) {
vdot = VDOT(gvects[j],norm_dir);
- categorization_results[j][i] = vdot;
+ //categorization_results[i*j] = vdot;
if (vdot > result) {
result_max = j;
result = vdot;
}
}
- groups[result_max].push_back(i);
- face_to_plane[i]=result_max;
- face_areas[i] = face_area(bot, i);
+ groups[i] = result_max;
}
-
- // Order the groups by number of bots
- std::vector<int> ordered_groups;
- int group_ids[] = {0, 1, 2, 3, 4, 5};
- std::set<int> group_bin (group_ids, group_ids+6);
- std::set<int>::iterator fg_it;
- while (!group_bin.empty()) {
- int largest_group = 0;
- int max = 0;
- for (fg_it = group_bin.begin(); fg_it != group_bin.end(); fg_it++) {
- if (groups[(*fg_it)].size() == 0) {
- group_bin.erase((*fg_it));
- } else {
- if (groups[(*fg_it)].size() > max) {
- max = groups[(*fg_it)].size();
- largest_group = (*fg_it);
- }
- }
+ /* Determine the maximun number of faces associated with any one vertex */
+ unsigned int *vert_face_cnt = (unsigned int *)bu_calloc(bot->num_vertices,
sizeof(unsigned int), "vert face cnt");
+ for (unsigned int i = 0; i < bot->num_faces; i++) {
+ vert_face_cnt[bot->faces[i*3+0]]++;
+ vert_face_cnt[bot->faces[i*3+1]]++;
+ vert_face_cnt[bot->faces[i*3+2]]++;
+ }
+ unsigned int max_face_cnt = 0;
+ for (unsigned int i = 0; i < bot->num_vertices; i++) {
+ if (vert_face_cnt[i] > max_face_cnt)
+ max_face_cnt = vert_face_cnt[i];
+ }
+ /* Now, allocate a 2D array that can hold the full vert->face map
+ * and populate it */
+ vert_to_face = (unsigned int *)bu_calloc(bot->num_vertices * max_face_cnt,
sizeof(unsigned int), "map");
+ for (unsigned int i = 0; i < bot->num_faces; i++) {
+ for (unsigned int j = 0; j < 3; j++) {
+ unsigned int k = 0;
+ unsigned int vert = bot->faces[i*3+j];
+ /* rows are vertex indexes, columns hold the faces */
+ while (vert_to_face[max_face_cnt * vert + k] && k < max_face_cnt)
k++;
+ /* Need to increment face index by one so we can reference
+ * the first face and still use the true/false test that 0 allows */
+ vert_to_face[max_face_cnt * vert + k] = i + 1;
+ //bu_log("vert_to_face(%d,%d)[%d] = %d\n", vert, k, max_face_cnt *
vert + k, i + 1);
}
- if (max > 0)
- ordered_groups.push_back(largest_group);
- group_bin.erase(largest_group);
}
+
+ /* Order the groups by number of bots */
+ unsigned int group_cnt[6] = {0};
+ unsigned int ordered_groups[6] = {0};
+ for (unsigned int i = 0; i < bot->num_faces; i++) {
+ group_cnt[groups[i]]++;
+ }
+ for (unsigned int i = 0; i < 6; i++) {
+ unsigned int more = 5;
+ for (unsigned int j = 0; j < 6; j++) {
+ if (group_cnt[j] > group_cnt[i]) more--;
+ }
+ ordered_groups[more] = i;
+ }
+
+
// All faces must belong to some patch - continue until all faces are
processed
- std::vector<int> face_pool (bot->num_faces, 1);
- std::vector<int> face_to_patch (bot->num_faces, -1);
- int patch_cnt = -1;
- for (int i = 0; i < ordered_groups.size(); i++) {
+ unsigned int patch_cnt = 0;
+ for (unsigned int i = 0; i < 6; i++) {
int largest_face = 0;
- int curr_group = ordered_groups[i];
while (largest_face != -1) {
// Start a new patch
vect_t largest_face_normal;
largest_face = -1;
- patch_cnt++;
+ patch_cnt++;
// Find largest remaining face in group
double face_size_criteria = 0.0;
- for (int f_it = 0; f_it < groups[curr_group].size(); f_it++) {
- if (face_pool[groups[curr_group][f_it]]) {
- double fa = face_areas[groups[curr_group][f_it]];
- if (fa > face_size_criteria) {
- largest_face = groups[curr_group][f_it];
- face_size_criteria = fa;
- }
+ for (unsigned int j = 0; j < bot->num_faces; j++) {
+ if (ordered_groups[i] == groups[j] && !patches[j] &&
(face_areas[j] > face_size_criteria)) {
+ largest_face = j;
+ face_size_criteria = face_areas[j];
}
}
if (largest_face != -1) {
- std::queue<int> face_queue;
+ std::queue<unsigned int> face_queue;
face_queue.push(largest_face);
-
+ patches[largest_face] = patch_cnt;
VSET(largest_face_normal, face_normals[largest_face*3],
face_normals[largest_face*3+1], face_normals[largest_face*3+2]);
- face_pool[largest_face] = 0;
while (!face_queue.empty()) {
- size_t pt_A, pt_B, pt_C;
- int face_num = face_queue.front();
+ unsigned int face_num = face_queue.front();
face_queue.pop();
- patches[patch_cnt].insert(face_num);
- face_to_patch[face_num] = patch_cnt;
- pt_A = bot->faces[face_num*3+0]*3;
- pt_B = bot->faces[face_num*3+1]*3;
- pt_C = bot->faces[face_num*3+2]*3;
- groups_edge_face_cnt[curr_group][mk_edge(pt_A, pt_B)] += 1;
- groups_edge_face_cnt[curr_group][mk_edge(pt_B, pt_C)] += 1;
- groups_edge_face_cnt[curr_group][mk_edge(pt_C, pt_A)] += 1;
-
- std::set<size_t> connected_faces;
- std::set<size_t>::iterator cf_it;
- get_connected_faces(bot, face_num, &(vert_to_face),
&connected_faces);
- for (cf_it = connected_faces.begin(); cf_it !=
connected_faces.end() ; cf_it++) {
- if (face_pool[(*cf_it)]) {
- double curr_face_area = face_areas[(*cf_it)];
- if (curr_face_area < (face_size_criteria*10) &&
curr_face_area > (face_size_criteria*0.1)) {
- vect_t face_normal;
- VSET(face_normal, face_normals[face_num*3],
face_normals[face_num*3+1], face_normals[face_num*3+2]);
- if (VDOT(largest_face_normal, face_normal) >
0.85) {
- face_queue.push((*cf_it));
- face_pool[(*cf_it)] = 0;
+ for (unsigned int k = 0; k < 3; k++) {
+ unsigned int vert_id = bot->faces[face_num*3+k];
+ for (unsigned int l = 0; l < vert_face_cnt[vert_id];
l++) {
+ unsigned int new_face = vert_to_face[max_face_cnt *
vert_id + l] - 1;
+ if (groups[new_face] == ordered_groups[i] &&
!patches[new_face]) {
+ if (face_areas[new_face] >
face_areas[largest_face] * 0.1) {
+ vect_t new_face_normal;
+ VSET(new_face_normal,
face_normals[new_face*3], face_normals[new_face*3+1],
face_normals[new_face*3+2]);
+ if (VDOT(largest_face_normal,
new_face_normal) > 0.65) {
+ face_queue.push(new_face);
+ patches[new_face] = patch_cnt;
+ }
}
}
}
@@ -273,8 +187,48 @@
}
}
}
- plot_patch_borders(&(groups_edge_face_cnt), bot, info->vhead);
+ bu_log("patch_cnt: %d\n", patch_cnt);
+ bu_free(face_areas, "face_areas");
+ bu_free(face_normals, "face_normals");
+ bu_free(groups, "groups");
+ bu_free(vert_to_face, "vert_to_face");
+ unsigned int *patch_vert_cnt = (unsigned int *)bu_malloc(sizeof(unsigned
int) * bot->num_vertices, "patch_vert_cnt");
+ unsigned int *vert_edge_status = (unsigned int
*)bu_calloc(bot->num_vertices, sizeof(unsigned int), "vert status");
+ for (unsigned int i = 0; i < patch_cnt; i++) {
+ for (unsigned int j = 0; j < bot->num_vertices; j++) patch_vert_cnt[j]
= 0;
+ for (unsigned int j = 0; j < bot->num_faces; j++) {
+ if (patches[j] == i+1) {
+ patch_vert_cnt[bot->faces[j*3+0]]++;
+ patch_vert_cnt[bot->faces[j*3+1]]++;
+ patch_vert_cnt[bot->faces[j*3+2]]++;
+ }
+ }
+ for (unsigned int j = 0; j < bot->num_vertices; j++) {
+ if (patch_vert_cnt[j] && patch_vert_cnt[j] != vert_face_cnt[j])
vert_edge_status[j]++;
+ }
+ }
+ bu_free(patches, "patches");
+ bu_free(patch_vert_cnt, "patch_vert_cnt");
+ bu_free(vert_face_cnt, "vert_face_cnt");
+
+ for (unsigned int j = 0; j < bot->num_faces; j++) {
+ if (vert_edge_status[bot->faces[j*3+0]] &&
vert_edge_status[bot->faces[j*3+1]]) {
+ RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+0]*3]),
BN_VLIST_LINE_MOVE);
+ RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+1]*3]),
BN_VLIST_LINE_DRAW);
+ }
+ if (vert_edge_status[bot->faces[j*3+1]] &&
vert_edge_status[bot->faces[j*3+2]]) {
+ RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+1]*3]),
BN_VLIST_LINE_MOVE);
+ RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+2]*3]),
BN_VLIST_LINE_DRAW);
+ }
+ if (vert_edge_status[bot->faces[j*3+2]] &&
vert_edge_status[bot->faces[j*3+0]]) {
+ RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+2]*3]),
BN_VLIST_LINE_MOVE);
+ RT_ADD_VLIST(info->vhead, &(bot->vertices[bot->faces[j*3+0]*3]),
BN_VLIST_LINE_DRAW);
+ }
+ }
+
+ bu_free(vert_edge_status, "vert status");
+
return 0;
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits