void test_bsp__tree_can_clip_tree(void) { klist_t(poly) *polys = kl_init(poly); float3 tr1[] = {{-0.2, 0.0, 0.0}, {0.2, 0.0, 0.0}, {0.0, 0.2, 0.0}}; float3 tr2[] = {{-0.2, 0.0, 100.0}, {0.2, 0.0, 100.0}, {0.0, 0.2, 1000.0}}; *kl_pushp(poly, polys) = poly_make_triangle(tr1[0], tr1[1], tr1[2]); *kl_pushp(poly, polys) = poly_make_triangle(tr2[0], tr2[1], tr2[2]); cl_assert_equal_i(polys->size, 2); bsp_node_t *tr_bsp = bsp_build(NULL, polys, 1); cl_assert(tr_bsp != NULL); cl_assert(bsp_clip(tr_bsp, cube_bsp) != NULL); klist_t(poly) *clipped = bsp_to_polygons(tr_bsp, 0, NULL); cl_assert_equal_i(clipped->size, 1); // Make sure we clipped the poly inside the cube, and kept // the poly outside float3 *v = &kl_val(kl_begin(clipped))->vertices[0]; cl_assert_((*v)[2] >= 99.0, "Should have kept the vertex outside the cube, not inside."); kl_destroy(poly, polys); }
void test_bsp__initialize(void) { bsp = alloc_bsp_node(); poly_t *poly = NULL; polygons = kl_init(poly); float3 fs[] = {{-0.5, 0.0, 0.0}, {0.5, 0.0, 0.0}, {0.0, 0.5, 0.0}}; poly = poly_make_triangle(fs[0], fs[1], fs[2]); cl_assert_(poly != NULL, "Out of memory"); *kl_pushp(poly, polygons) = poly; float3 fs2[] = {{-0.5, 0.0, -0.5}, {0.5, 0.0, -0.5}, {0.0, 0.5, -0.5}}; poly = poly_make_triangle(fs2[0], fs2[1], fs2[2]); cl_assert_(poly != NULL, "Out of memory"); *kl_pushp(poly, polygons) = poly; float3 fs3[] = {{-0.5, 0.0, 0.5}, {0.5, 0.0, 0.5}, {0.0, 0.5, 0.5}}; poly = poly_make_triangle(fs3[0], fs3[1], fs3[2]); cl_assert_(poly != NULL, "Out of memory"); *kl_pushp(poly, polygons) = poly; float3 fs4[] = {{0.0, 0.0, -1.0}, {0.0, 0.0, 1.0}, {0.0, 1.0, 0.0}}; poly = poly_make_triangle(fs4[0], fs4[1], fs4[2]); cl_assert_(poly != NULL, "Out of memory"); *kl_pushp(poly, polygons) = poly; cl_assert_(bsp != NULL, "Out of memory"); cl_assert_(bsp_build(bsp, polygons, 1) != NULL, "Failed to build bsp tree"); stl_object *stl_cube = stl_read_file(cube_stl_file, 1); cl_assert(stl_cube != NULL); klist_t(poly) *cube_polys = kl_init(poly); for(int i = 0; i < stl_cube->facet_count; i++) { poly_t *p = poly_make_triangle(stl_cube->facets[i].vertices[0], stl_cube->facets[i].vertices[1], stl_cube->facets[i].vertices[2]); cl_assert(p != NULL); *kl_pushp(poly, cube_polys) = p; } cube_bsp = bsp_build(NULL, cube_polys, 1); kl_destroy(poly, cube_polys); cl_assert(cube_bsp != NULL); }
void test_bsp__cube_bsp_can_return_poly_list_of_equal_length(void) { // We test that when we get a list of polygons from a BSP tree of a cube // and assert that we have the same number of polygons as when we started. // // A cube is nice here because no faces need to be split, so polygon // counts before and after remain the same. char cube_path[] = CLAR_FIXTURE_PATH "cube.stl"; stl_object *stl_cube = stl_read_file(cube_path, 0); klist_t(poly) *cube_polys = kl_init(poly); cl_assert(stl_cube != NULL); cl_assert(stl_cube->facet_count > 0); for(int i = 0; i < stl_cube->facet_count; i++) { stl_facet *face = &stl_cube->facets[i]; poly_t *poly = poly_make_triangle(face->vertices[0], face->vertices[1], face->vertices[2]); *kl_pushp(poly, cube_polys) = poly; cl_assert(poly); } bsp_node_t *cube_bsp = alloc_bsp_node(); cl_assert(cube_bsp != NULL); cl_assert(bsp_build(cube_bsp, cube_polys, 1) == cube_bsp); klist_t(poly) *results = bsp_to_polygons(cube_bsp, 0, NULL); cl_assert_equal_i(results->size, stl_cube->facet_count); if(stl_cube) stl_free(stl_cube); if(results) kl_destroy(poly, results); kl_destroy(poly, cube_polys); }
void test_bsp__tree_can_produce_triangles_from_quads(void) { klist_t(poly) *quad = kl_init(poly); // I'll make a quad by making a triangle with a missing // vertex, then pushing the extra vertex after and recomputing float3 quad_verts[] = {{-1.0, 1.0, 0.0}, {-1.0, -1.0, 0.0}, {1.0, -1.0, 0.0}, {1.0, 1.0, 0.0}}; poly_t *poly = poly_make_triangle(quad_verts[0], quad_verts[1], quad_verts[2]); cl_assert_(poly != NULL, "Can't make triangle for test"); poly_push_vertex(poly, quad_verts[3]); cl_assert_(poly_vertex_count(poly) == 4, "Failed to add vertex into quad"); poly_update(poly); // Build a tree of the quad klist_t(poly) *lpoly = kl_init(poly); *kl_pushp(poly, lpoly) = poly; bsp_node_t *quad_bsp = bsp_build(NULL, lpoly, 1); cl_assert(quad_bsp); klist_t(poly) *tris = bsp_to_polygons(quad_bsp, 1, NULL); cl_assert_equal_i(tris->size, 2); kl_destroy(poly, quad); kl_destroy(poly, lpoly); if(tris) kl_destroy(poly, tris); }
bsp_node_t *clone_bsp_tree(bsp_node_t *tree) { bsp_node_t *copy = alloc_bsp_node(); check_mem(copy); kliter_t(poly) *iter = kl_begin(tree->polygons); for(; iter != kl_end(tree->polygons); iter = kl_next(iter)) { poly_t *poly_copy = clone_poly(kl_val(iter)); check_mem(poly_copy); *kl_pushp(poly, copy->polygons) = poly_copy; } free_poly(copy->divider, 1); if(tree->divider) { copy->divider = clone_poly(tree->divider); check_mem(copy->divider); } else { copy->divider = NULL; } if(tree->front != NULL) { copy->front = clone_bsp_tree(tree->front); check_mem(copy->front); } if(tree->back != NULL) { copy->back = clone_bsp_tree(tree->back); check_mem(copy->back); } return copy; error: if(copy != NULL) free_bsp_tree(copy); return NULL; }
// Called when the manager sends a complete message void messageArrivedFromManager() { printf ("Message arrived: >%s< for >%s<\r\n", commandMessage, commandClientId); // See if the client is connected, if so immediately forward khiter_t k = kh_get(clientStatuses, clientStatuses, (char*)commandClientId); // Find it in the hash if (k != kh_end(clientStatuses)) { // Was it in the hash? clientStatus* status = kh_value(clientStatuses, k); // Grab the clientStatus from the hash snprintf(httpResponse, HTTP_RESPONSE_SIZE, HTTP_TEMPLATE, commandMessageLen, commandMessage); // Compose the response message write(status->io.fd, httpResponse, strlen(httpResponse)); // Send it closeConnection((ev_io*)status); // Close the conn return; } // If not, add to a queue khiter_t q = kh_get(queue, queue, (char*)commandClientId); // See if this client is already in the queue if (q == kh_end(queue)) { printf("Creating queue for %s\r\n", commandClientId); // This client needs to be added to the queue // First make a new list klist_t(messages) *newMessageList = kl_init(messages); *kl_pushp(messages, newMessageList) = strdup((char*)commandMessage); // Add the message to the list // Now make a new hash entry pointing to this new list int ret; q = kh_put(queue, queue, strdup((char*)commandClientId), &ret); kh_value(queue, q) = newMessageList; } else { printf("Adding to the queue for %s\r\n", commandClientId); // This client is in the queue already eg it has a hash entry // Pushp puts this message at the end of the queue, so that shift will grab the oldest first (like a FIFO) *kl_pushp(messages, kh_value(queue, q)) = strdup((char*)commandMessage); } // Now do a printout of the hash list for (khiter_t qi = kh_begin(queue); qi < kh_end(queue); qi++) { if (kh_exist(queue, qi)) { printf("Queue for %s\n", kh_key(queue,qi)); klist_t(messages) *list = kh_value(queue, qi); kliter_t(messages) *li; for (li = kl_begin(list); li != kl_end(list); li = kl_next(li)) printf("%s\n", kl_val(li)); printf("----\n"); } } }
// Queue an event void event_push(Event event, bool deferred) { // Sometimes libuv will run pending callbacks(timer for example) before // blocking for a poll. If this happens and the callback pushes a event to one // of the queues, the event would only be processed after the poll // returns(user hits a key for example). To avoid this scenario, we call // uv_stop when a event is enqueued. uv_stop(uv_default_loop()); *kl_pushp(Event, deferred ? deferred_events : immediate_events) = event; }
void test_polygon__initialize(void) { faces = kl_init(poly); // Set up three triangles, one on top of each other // stored in list `faces` for easy cleanup // and refferenced in `top` and `bottom`, and `square` // used for inversion testing and area checking. // And a square for non-triangular area tests and float3 square_faces[] = {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}}; square = alloc_poly(); cl_assert(square != NULL); for(int i = 0; i < 3; i++) { cl_assert_(poly_push_vertex(square, square_faces[i]), "Failed to add square vertex"); } cl_assert_equal_i(poly_vertex_count(square), 3); *kl_pushp(poly, faces) = square; // Set up a quad quad = alloc_poly(); cl_assert(quad != NULL); for(int i = 0; i < 4; i++) { cl_assert_(poly_push_vertex(quad, square_faces[i]), "Failed to add quad vertex."); } cl_assert_equal_i(poly_vertex_count(quad), 4); *kl_pushp(poly, faces) = quad; // Set up an invalid polygon which is just a line line = alloc_poly(); cl_assert(line != NULL); cl_assert(poly_push_vertex(line, square_faces[0])); cl_assert(poly_push_vertex(line, square_faces[1])); cl_assert(poly_push_vertex(line, square_faces[2])); // Force the last vertex to be square_faces[0], then force a recompute line->vertices[2][0] = line->vertices[0][0]; line->vertices[2][1] = line->vertices[0][1]; line->vertices[2][2] = line->vertices[0][2]; cl_assert(poly_update(line) == 0); *kl_pushp(poly, faces) = line; // Set up two triangles, one on top of each other float3 fs[] = {{-0.5, 0.0, 0.0}, {0.5, 0.0, 0.0}, {0.0, 0.5, 0.0}}; bottom = poly_make_triangle(fs[0], fs[1], fs[2]); cl_assert_(bottom != NULL, "Out of memory"); *kl_pushp(poly, faces) = bottom; for(int i = 0; i < 3; i++) { fs[i][2] += 1.0; } top = poly_make_triangle(fs[0], fs[1], fs[2]); cl_assert_(top != NULL, "Out of memory"); *kl_pushp(poly, faces) = top; cl_assert_equal_i(poly_classify_poly(top, bottom), BACK); cl_assert_equal_i(poly_classify_poly(bottom, top), FRONT); }
static void trans_tbl_init(bam_hdr_t* out, bam_hdr_t* translate, trans_tbl_t* tbl, bool merge_rg, bool merge_pg) { tbl->n_targets = translate->n_targets; tbl->tid_trans = (int*)calloc(translate->n_targets, sizeof(int)); tbl->rg_trans = kh_init(c2c); tbl->pg_trans = kh_init(c2c); if (!tbl->tid_trans || !tbl->rg_trans || !tbl->pg_trans) { perror("out of memory"); exit(-1); } int32_t out_len = out->l_text; while (out_len > 0 && out->text[out_len-1] == '\n') {--out_len; } // strip trailing \n's kstring_t out_text = { 0, 0, NULL }; kputsn(out->text, out_len, &out_text); int i, min_tid = -1; tbl->lost_coord_sort = false; khash_t(c2i) *out_tid = kh_init(c2i); for (i = 0; i < out->n_targets; ++i) { int ret; khiter_t iter = kh_put(c2i, out_tid, out->target_name[i], &ret); if (ret <= 0) abort(); kh_value(out_tid, iter) = i; } for (i = 0; i < translate->n_targets; ++i) { khiter_t iter = kh_get(c2i, out_tid, translate->target_name[i]); if (iter == kh_end(out_tid)) { // Append missing entries to out tbl->tid_trans[i] = out->n_targets++; out->target_name = (char**)realloc(out->target_name, sizeof(char*)*out->n_targets); out->target_name[out->n_targets-1] = strdup(translate->target_name[i]); out->target_len = (uint32_t*)realloc(out->target_len, sizeof(uint32_t)*out->n_targets); out->target_len[out->n_targets-1] = translate->target_len[i]; // grep line with regex '^@SQ.*\tSN:%s(\t.*$|$)', translate->target_name[i] // from translate->text regex_t sq_id; regmatch_t* matches = (regmatch_t*)calloc(2, sizeof(regmatch_t)); if (matches == NULL) { perror("out of memory"); exit(-1); } kstring_t seq_regex = { 0, 0, NULL }; ksprintf(&seq_regex, "^@SQ.*\tSN:%s(\t.*$|$)", translate->target_name[i]); regcomp(&sq_id, seq_regex.s, REG_EXTENDED|REG_NEWLINE); free(seq_regex.s); if (regexec(&sq_id, translate->text, 1, matches, 0) != 0) { fprintf(pysamerr, "[trans_tbl_init] @SQ SN (%s) found in binary header but not text header.\n",translate->target_name[i]); exit(1); } regfree(&sq_id); // Produce our output line and append it to out_text kputc('\n', &out_text); kputsn(translate->text+matches[0].rm_so, matches[0].rm_eo-matches[0].rm_so, &out_text); free(matches); } else { tbl->tid_trans[i] = kh_value(out_tid, iter); } if (tbl->tid_trans[i] > min_tid) { min_tid = tbl->tid_trans[i]; } else { tbl->lost_coord_sort = true; } } kh_destroy(c2i, out_tid); // grep @RG id's regex_t rg_id; regmatch_t* matches = (regmatch_t*)calloc(2, sizeof(regmatch_t)); if (matches == NULL) { perror("out of memory"); exit(-1); } regcomp(&rg_id, "^@RG.*\tID:([!-)+-<>-~][ !-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE); char* text = translate->text; klist_t(hdrln) *rg_list = kl_init(hdrln); while(1) { // foreach rg id in translate's header if (regexec(&rg_id, text, 2, matches, 0) != 0) break; // matches[0] is the whole @RG line; matches[1] is the ID field value kstring_t match_id = { 0, 0, NULL }; kputsn(text+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &match_id); // is our matched ID in our output list already regex_t rg_id_search; kstring_t rg_regex = { 0, 0, NULL }; ksprintf(&rg_regex, "^@RG.*\tID:%s(\t.*$|$)", match_id.s); regcomp(&rg_id_search, rg_regex.s, REG_EXTENDED|REG_NEWLINE|REG_NOSUB); free(rg_regex.s); kstring_t transformed_id = { 0, 0, NULL }; bool transformed_equals_match; if (regexec(&rg_id_search, out->text, 0, NULL, 0) != 0 || merge_rg) { // Not in there so can add it as 1-1 mapping kputs(match_id.s, &transformed_id); transformed_equals_match = true; } else { // It's in there so we need to transform it by appending random number to id ksprintf(&transformed_id, "%s-%0lX", match_id.s, lrand48()); transformed_equals_match = false; } regfree(&rg_id_search); // Insert it into our translation map int in_there = 0; khiter_t iter = kh_put(c2c, tbl->rg_trans, ks_release(&match_id), &in_there); char *transformed_id_s = ks_release(&transformed_id); kh_value(tbl->rg_trans,iter) = transformed_id_s; // take matched line and replace ID with transformed_id kstring_t transformed_line = { 0, 0, NULL }; if (transformed_equals_match) { kputsn(text+matches[0].rm_so, matches[0].rm_eo-matches[0].rm_so, &transformed_line); } else { kputsn(text+matches[0].rm_so, matches[1].rm_so-matches[0].rm_so, &transformed_line); kputs(transformed_id_s, &transformed_line); kputsn(text+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line); } if (!(transformed_equals_match && merge_rg)) { // append line to linked list for PG processing char** ln = kl_pushp(hdrln, rg_list); *ln = ks_release(&transformed_line); // Give away to linked list } else free(transformed_line.s); text += matches[0].rm_eo; // next! } regfree(&rg_id); // Do same for PG id's regex_t pg_id; regcomp(&pg_id, "^@PG.*\tID:([!-)+-<>-~][ !-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE); text = translate->text; klist_t(hdrln) *pg_list = kl_init(hdrln); while(1) { // foreach pg id in translate's header if (regexec(&pg_id, text, 2, matches, 0) != 0) break; kstring_t match_id = { 0, 0, NULL }; kputsn(text+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &match_id); // is our matched ID in our output list already regex_t pg_id_search; kstring_t pg_regex = { 0, 0, NULL }; ksprintf(&pg_regex, "^@PG.*\tID:%s(\t.*$|$)", match_id.s); regcomp(&pg_id_search, pg_regex.s, REG_EXTENDED|REG_NEWLINE|REG_NOSUB); free(pg_regex.s); kstring_t transformed_id = { 0, 0, NULL }; bool transformed_equals_match; if (regexec(&pg_id_search, out->text, 0, NULL, 0) != 0 || merge_pg) { // Not in there so can add it as 1-1 mapping kputs(match_id.s, &transformed_id); transformed_equals_match = true; } else { // It's in there so we need to transform it by appending random number to id ksprintf(&transformed_id, "%s-%0lX", match_id.s, lrand48()); transformed_equals_match = false; } regfree(&pg_id_search); // Insert it into our translation map int in_there = 0; khiter_t iter = kh_put(c2c, tbl->pg_trans, ks_release(&match_id), &in_there); char *transformed_id_s = ks_release(&transformed_id); kh_value(tbl->pg_trans,iter) = transformed_id_s; // take matched line and replace ID with transformed_id kstring_t transformed_line = { 0, 0, NULL }; if (transformed_equals_match) { kputsn(text+matches[0].rm_so, matches[0].rm_eo-matches[0].rm_so, &transformed_line); } else { kputsn(text+matches[0].rm_so, matches[1].rm_so-matches[0].rm_so, &transformed_line); kputs(transformed_id_s, &transformed_line); kputsn(text+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line); } if (!(transformed_equals_match && merge_pg)) { // append line to linked list for PP processing char** ln = kl_pushp(hdrln, pg_list); *ln = ks_release(&transformed_line); // Give away to linked list } else free(transformed_line.s); text += matches[0].rm_eo; // next! } regfree(&pg_id); // need to translate PP's on the fly in second pass because they may not be in correct order and need complete tbl->pg_trans to do this // for each line { // with ID replaced with tranformed_id and PP's transformed using the translation table // } regex_t pg_pp; regcomp(&pg_pp, "^@PG.*\tPP:([!-)+-<>-~][!-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE); kliter_t(hdrln) *iter = kl_begin(pg_list); while (iter != kl_end(pg_list)) { char* data = kl_val(iter); kstring_t transformed_line = { 0, 0, NULL }; // Find PP tag if (regexec(&pg_pp, data, 2, matches, 0) == 0) { // Lookup in hash table kstring_t pp_id = { 0, 0, NULL }; kputsn(data+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &pp_id); khiter_t k = kh_get(c2c, tbl->pg_trans, pp_id.s); free(pp_id.s); char* transformed_id = kh_value(tbl->pg_trans,k); // Replace kputsn(data, matches[1].rm_so-matches[0].rm_so, &transformed_line); kputs(transformed_id, &transformed_line); kputsn(data+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line); } else { kputs(data, &transformed_line); } // Produce our output line and append it to out_text kputc('\n', &out_text); kputsn(transformed_line.s, transformed_line.l, &out_text); free(transformed_line.s); free(data); iter = kl_next(iter); } regfree(&pg_pp); // Need to also translate @RG PG's on the fly too regex_t rg_pg; regcomp(&rg_pg, "^@RG.*\tPG:([!-)+-<>-~][!-~]*)(\t.*$|$)", REG_EXTENDED|REG_NEWLINE); kliter_t(hdrln) *rg_iter = kl_begin(rg_list); while (rg_iter != kl_end(rg_list)) { char* data = kl_val(rg_iter); kstring_t transformed_line = { 0, 0, NULL }; // Find PG tag if (regexec(&rg_pg, data, 2, matches, 0) == 0) { // Lookup in hash table kstring_t pg_id = { 0, 0, NULL }; kputsn(data+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so, &pg_id); khiter_t k = kh_get(c2c, tbl->pg_trans, pg_id.s); free(pg_id.s); char* transformed_id = kh_value(tbl->pg_trans,k); // Replace kputsn(data, matches[1].rm_so-matches[0].rm_so, &transformed_line); kputs(transformed_id, &transformed_line); kputsn(data+matches[1].rm_eo, matches[0].rm_eo-matches[1].rm_eo, &transformed_line); } else { kputs(data, &transformed_line); } // Produce our output line and append it to out_text kputc('\n', &out_text); kputsn(transformed_line.s, transformed_line.l, &out_text); free(transformed_line.s); free(data); rg_iter = kl_next(rg_iter); } regfree(&rg_pg); kl_destroy(hdrln,pg_list); kl_destroy(hdrln,rg_list); free(matches); // Add trailing \n and write back to header free(out->text); kputc('\n', &out_text); out->l_text = out_text.l; out->text = ks_release(&out_text); }
// Push an event to the queue void event_push(Event event) { *kl_pushp(Event, event_queue) = event; }