static inline void edges_start_or_continue (cairo_bo_edge_t *left, cairo_bo_edge_t *right, int top, cairo_polygon_t *polygon) { assert (right->deferred.other == NULL); if (left->deferred.other == right) return; if (left->deferred.other != NULL) { if (right != NULL && edges_colinear (left->deferred.other, right)) { cairo_bo_edge_t *old = left->deferred.other; /* continuation on right, extend right to cover both */ assert (old->deferred.other == NULL); assert (old->edge.line.p2.y > old->edge.line.p1.y); if (old->edge.line.p1.y < right->edge.line.p1.y) right->edge.line.p1 = old->edge.line.p1; if (old->edge.line.p2.y > right->edge.line.p2.y) right->edge.line.p2 = old->edge.line.p2; left->deferred.other = right; return; } edges_end (left, top, polygon); } if (right != NULL && ! edges_colinear (left, right)) { left->deferred.top = top; left->deferred.other = right; } }
static inline void active_edges (cairo_bo_edge_t *left, int32_t top, cairo_polygon_t *polygon) { cairo_bo_edge_t *right; int winding[2] = {0, 0}; /* Yes, this is naive. Consider this a placeholder. */ while (left != NULL) { assert (is_zero (winding)); do { winding[left->a_or_b] += left->edge.dir; if (! is_zero (winding)) break; if unlikely ((left->deferred.other)) edges_end (left, top, polygon); left = left->next; if (! left) return; } while (1); right = left->next; do { if unlikely ((right->deferred.other)) edges_end (right, top, polygon); winding[right->a_or_b] += right->edge.dir; if (is_zero (winding)) { if (right->next == NULL || ! edges_colinear (right, right->next)) break; } right = right->next; } while (1); edges_start_or_continue (left, right, top, polygon); left = right->next; } }
bool Boundary::contour_is_complete (contour_iterator cit) const { edge_iterator eit = edges_begin (cit); edge_iterator end = edges_end (cit); for (; eit != end; ++eit) if (!edge_has_successor (eit)) return false; return true; }
void Boundary::reverse_contour (Boundary::contour_iterator cit) { edge_iterator eit = edges_begin (cit); edge_iterator eit_end = edges_end (cit); for (; eit != eit_end; ++eit) { edge_t &E = edge (eit); std::swap (E.prev, E.next); std::swap (E.vert0, E.vert1); } }
void Boundary::fix_contours (bool silent) { assert_boundary (*this); if (!silent) std::cerr << "fix_contours"; int deg_edges = 0; int deg_spikes = 0; std::vector <int> deg_con_indices; Boundary::contour_iterator cit = contours_begin (); Boundary::contour_iterator cit_end = contours_end (); Boundary::edge_iterator eit, eit_end; while (cit != cit_end) { bool fixed_something = false; eit = edges_begin (cit); eit_end = edges_end (cit); // remove spikes with exterior angle = pi while (eit != eit_end) { edge_iterator eit_next = eit; ++eit_next; vec_t d = edge_vertex1 (eit_next); d -= edge_vertex0 (eit); if (d.norm () < VERTEX_MERGE_TOLERANCE) { if (is_self_referential (eit)) { // further processing is dangerous goto deg_contour; } // remove spike. the norm-zero edge created by this // operation is removed later eit = remove_vertex1 (eit); ++deg_spikes; --eit; // remove_vertex1 could have removed our end eit_end = edges_end (cit); fixed_something = true; } else { eit = eit_next; } } eit = edges_begin (cit); // remove norm-zero edges while (eit != eit_end) { double len = edge_length (eit); if (len < VERTEX_MERGE_TOLERANCE) { if (is_self_referential (eit)) { // further processing is dangerous goto deg_contour; } ++deg_edges; eit = remove_vertex1 (eit); // remove_vertex1 could have removed our end eit_end = edges_end (cit); fixed_something = true; } else { ++eit; } } if (!fixed_something) ++cit; continue; deg_contour: // current contour has been reduced to or was a single-vertex // contour. we mark it for later removal. deg_con_indices.push_back (cit - contours_begin ()); ++cit; } int deg_contours = (int)deg_con_indices.size (); // remove degenerate contours { std::vector <int>::reverse_iterator it; it = deg_con_indices.rbegin (); for (; it != deg_con_indices.rend (); ++it) { erase_contour_by_index (*it); } } // final "status report" if (!silent) { std::cerr << "\n" << std::setw (4) << deg_contours << " deg. contours (removed)\n" << std::setw (4) << deg_spikes << " deg. spikes (removed)\n" << std::setw (4) << deg_edges << " deg. edges (removed)\n"; } assert_boundary (*this); }
static cairo_status_t intersection_sweep (cairo_bo_event_t **start_events, int num_events, cairo_polygon_t *polygon) { cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */ cairo_bo_event_queue_t event_queue; cairo_bo_sweep_line_t sweep_line; cairo_bo_event_t *event; cairo_bo_edge_t *left, *right; cairo_bo_edge_t *e1, *e2; _cairo_bo_event_queue_init (&event_queue, start_events, num_events); _cairo_bo_sweep_line_init (&sweep_line); while ((event = _cairo_bo_event_dequeue (&event_queue))) { if (event->point.y.ordinate != sweep_line.current_y) { active_edges (sweep_line.head, sweep_line.current_y, polygon); sweep_line.current_y = event->point.y.ordinate; } switch (event->type) { case CAIRO_BO_EVENT_TYPE_START: e1 = &((cairo_bo_start_event_t *) event)->edge; status = sweep_line_insert (&sweep_line, e1); if (unlikely (status)) goto unwind; status = event_queue_insert_stop (&event_queue, e1); if (unlikely (status)) goto unwind; left = e1->prev; right = e1->next; if (left != NULL) { status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1); if (unlikely (status)) goto unwind; } if (right != NULL) { status = event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); if (unlikely (status)) goto unwind; } break; case CAIRO_BO_EVENT_TYPE_STOP: e1 = ((cairo_bo_queue_event_t *) event)->e1; _cairo_bo_event_queue_delete (&event_queue, event); if (e1->deferred.other) edges_end (e1, sweep_line.current_y, polygon); left = e1->prev; right = e1->next; _cairo_bo_sweep_line_delete (&sweep_line, e1); if (left != NULL && right != NULL) { status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); if (unlikely (status)) goto unwind; } break; case CAIRO_BO_EVENT_TYPE_INTERSECTION: e1 = ((cairo_bo_queue_event_t *) event)->e1; e2 = ((cairo_bo_queue_event_t *) event)->e2; _cairo_bo_event_queue_delete (&event_queue, event); /* skip this intersection if its edges are not adjacent */ if (e2 != e1->next) break; if (e1->deferred.other) edges_end (e1, sweep_line.current_y, polygon); if (e2->deferred.other) edges_end (e2, sweep_line.current_y, polygon); left = e1->prev; right = e2->next; _cairo_bo_sweep_line_swap (&sweep_line, e1, e2); /* after the swap e2 is left of e1 */ if (left != NULL) { status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2); if (unlikely (status)) goto unwind; } if (right != NULL) { status = event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); if (unlikely (status)) goto unwind; } break; } } unwind: _cairo_bo_event_queue_fini (&event_queue); return status; }
struct Edge* find_MST_parallel_star(Graph g){ omp_set_num_threads(THREADS); int n = get_num_nodes(g); //store the edge index of the min weight edge incident on node i struct Edge* min_edges = new struct Edge[n]; struct set *components = new struct set[n]; struct Edge* mst_edges = new struct Edge[n]; bool *coin_flips = new bool[n]; //bool not_one_component = true; //keeps track of which tails have been contracted bool *is_contracted = new bool[n]; //bool not_one_component = true; //this is a hacky way to accommodate the fact that we look at every edge //even though we're contracting bool is_first_passes[n]; //loop guard - did the graph get smaller - only needs to be set by //at least one thread so it should work in the parallel version bool can_be_contracted = true; #pragma omp parallel for schedule(static) for(int i = 0; i < n; i++){ components[i].parent = i; components[i].rank = 0; is_first_passes[i] = true; } double startTimeFind, endTimeFind; double findTotal = 0.0; double startTimeContract, endTimeContract; double contractTotal = 0.0; //continue looping until there's only 1 component //in the case of a disconnected graph, until num_components doesn't change //TODO is it better to have one condition here and not have to deal with //not_one_component (you would go one extra iteration but it could be worth //it instad of having to loop through the components list every iteration - //but one iteration could be just as expensive so we'll have to see) while(can_be_contracted){ startTimeFind = CycleTimer::currentSeconds(); #pragma omp parallel for schedule(dynamic, CHUNKSIZE) for(int j = 0; j < n; j++){ if(find_parallel(components, j) == j){ //find minimum weight edge out of each componenet for(int i = 0; i < n; i++){ int set1 = find_parallel(components, i); if(set1 == j){ const Vertex* start = edges_begin(g, i); const Vertex* end = edges_end(g, i); int weight_offset = -1; for(const Vertex* v = start; v < end; v++){ weight_offset++; //get representative nodes int set2 = find_parallel(components, *v); //this edge has already been contracted (endpoints in same component) if(set1 != set2){ Edge e; e.src = i; e.dest = *v; e.weight = g->weights[g->offsets[i] + weight_offset]; if(is_first_passes[set1]){ min_edges[set1] = e; is_first_passes[set1] = false; } else if (min_edges[set1].weight > e.weight) min_edges[set1] = e; } } } } } } endTimeFind = CycleTimer::currentSeconds(); findTotal += (endTimeFind - startTimeFind); startTimeContract = CycleTimer::currentSeconds(); //TODO: need to rewrite union find so that it always contract the edge that we want //it to - this is necessary in star contraction so we contract into the HEAD //determine which vertices will be star centers and which are satellites //we make 0 mean you are a satellite (false) and 1 mean you are a star center (true) #pragma omp parallel for schedule(static) for(int i = 0; i < n; i++){ coin_flips[i] = ((rand() % 2) == 1); } //do this so we can see if any thread sets to true meaning something got contracted can_be_contracted = false; //star contraction - we'll say 1 is HEADS and 0 is TAILS #pragma omp parallel for schedule(dynamic, CHUNKSIZE) for(int i = 0; i < n; i++){ int src = min_edges[i].src; int dest = min_edges[i].dest; int root1 = find_parallel(components, src); int root2 = find_parallel(components, dest); if(root1 == root2){ continue; } can_be_contracted = true; //you wouldn't contract in case of both heads or both tails if((coin_flips[root1] == coin_flips[root2])){ continue; } //try to contract, but if you fail, that means someone has contracted already //I think this should be correct by how CAS works //mark the tail as having been contracted if(coin_flips[root1]){ if(!__sync_bool_compare_and_swap(&is_contracted[root2],false,true)) continue; } else{ if(!__sync_bool_compare_and_swap(&is_contracted[root1],false,true)) continue; } if(coin_flips[root1]){ union_parallel(components, root2, root1); mst_edges[root2] = min_edges[i]; } else{ union_parallel(components, root1, root2); mst_edges[root1] = min_edges[i]; } } #pragma omp parallel for schedule(static) for(int i = 0; i < n; i++){ is_first_passes[i] = true; is_contracted[i] = false; } endTimeContract = CycleTimer::currentSeconds(); contractTotal += (endTimeContract - startTimeContract); } /* for(int i = 0; i < n; i++){ if(mst_edges[i].src == 0 && mst_edges[i].dest == 0) continue; if(mst_edges[i].src < 0 || mst_edges[i].src > n || mst_edges[i].dest < 0 || mst_edges[i].dest > n) continue; printf("%d, %d\n", mst_edges[i].src, mst_edges[i].dest); } */ printf("find time parallel comp star: %.20f\n", findTotal); printf("contract time parallel comp star: %.20f\n", contractTotal); delete[] min_edges; delete[] components; return mst_edges; }