diff --git a/areas.cpp b/areas.cpp index 5c47ac5..ea8c8f0 100644 --- a/areas.cpp +++ b/areas.cpp @@ -7,6 +7,7 @@ #include "geometry.h" #include "areas.h" +#include "segment_tree.h" Unit get_area_union(std::vector rectangles) { @@ -15,9 +16,6 @@ Unit get_area_union(std::vector rectangles) { assert(rect.bottom_left.x <= rect.top_right.x); assert(rect.bottom_left.y <= rect.top_right.y); } - // entry i will describe coverage of the interval (x_points[i], x_points[i+1]) - std::vector coverage_numbers; - coverage_numbers.reserve(2*rectangles.size() -1); //sorted vector of all x coordinates of all rectangles std::vector x_points; @@ -48,39 +46,33 @@ Unit get_area_union(std::vector rectangles) { } std::sort(y_points.begin(), y_points.end()); - // run sweepline - Unit current_cross_section_length = 0; + // init data and run sweepline Unit total_area = 0; + SegmentTree segmentTree(x_points); + for(Index y_index = 0 ; y_index < y_points.size() ; ++y_index) { // first, update cross section if (y_points[y_index].rect->bottom_left.y == y_points[y_index].coord) { // rectangle is starting now, add its cross section - for (Index index = y_points[y_index].rect->i_left; index < y_points[y_index].rect->i_right; ++index) { - ++coverage_numbers[index]; - if (coverage_numbers[index] == 1) { - current_cross_section_length += (x_points[index + 1].coord - x_points[index].coord); - } - } + segmentTree.add_interval( + {x_points[y_points[y_index].rect->i_left].coord, + x_points[y_points[y_index].rect->i_right].coord} + ); } else { assert(y_points[y_index].rect->top_right.y == y_points[y_index].coord); // rectangle stopping, remove its cross section - for (Index index = y_points[y_index].rect->i_left; index < y_points[y_index].rect->i_right; ++index) { - --coverage_numbers[index]; - if (coverage_numbers[index] == 0) { - current_cross_section_length -= (x_points[index + 1].coord - x_points[index].coord); - } - } + segmentTree.remove_interval( + {x_points[y_points[y_index].rect->i_left].coord, + x_points[y_points[y_index].rect->i_right].coord} + ); } //cross section is now up to date if(y_index + 1 < y_points.size()) { // add area up to next y point - total_area += current_cross_section_length * (y_points[y_index+1].coord - y_points[y_index].coord); + total_area += segmentTree.length_covered_intervals(); } } - // sanity check that nothing is covered when arriving at the end - for(auto coverage : coverage_numbers) { - assert(coverage == 0); - } + // TODO: sanity check that nothing is covered when arriving at the end return total_area; } diff --git a/segment_tree.cpp b/segment_tree.cpp index 6d89a67..c0811d8 100644 --- a/segment_tree.cpp +++ b/segment_tree.cpp @@ -15,7 +15,7 @@ SegmentTree::SegmentTree(const std::vector &coords): size_t num_meta_nodes = std::bit_ceil(num_leaf_nodes) - 1; // Initialize all nodes with zero coverage and dummy interval - _nodes.resize(2 * num_meta_nodes - 1, {0, coords[num_leaf_nodes].coord, coords[num_leaf_nodes].coord}); + _nodes.resize(2 * num_meta_nodes + 1, {0, coords[num_leaf_nodes].coord, coords[num_leaf_nodes].coord}); // We initialize the tree from bottom up, keeping track of the index ranges // and the length of the corresponding segment @@ -25,7 +25,7 @@ SegmentTree::SegmentTree(const std::vector &coords): _nodes[leaf_node_idx + num_meta_nodes].right_coord = coords[leaf_node_idx +1].coord; } // Note that there are remaining leafs that represent dummy ranges - for(Index node_idx = num_meta_nodes - 1; node_idx >= 0; ++node_idx) { + for(Index node_idx = num_meta_nodes - 1; node_idx != -1 ; --node_idx) { _nodes[node_idx].left_coord = left_child(node_idx).left_coord; _nodes[node_idx].right_coord = right_child(node_idx).right_coord; }