/** for a pair (p, q) of points, add the edge pq if their are visible to each other */ void handle(struct Point *p, struct Point *q, struct Map_info *out) { /* if it's a point without segments, just report the edge */ if (segment1(q) == NULL && segment2(q) == NULL && before(p, q, p->vis)) { report(p, q, out); } else if (segment1(p) != NULL && q == other1(p)) { /* we need to check if there is another segment at q so it can be set to the vis */ if (segment1(q) == segment1(p) && segment2(q) != NULL && left_turn(p, q, other2(q))) { p->vis = segment2(q); } else if (segment2(q) == segment1(p) && segment1(q) != NULL && left_turn(p, q, other1(q))) { p->vis = segment1(q); } else p->vis = q->vis; report(p, q, out); } else if (segment2(p) != NULL && q == other2(p)) { /* we need to check if there is another segment at q so it can be set to the vis */ if (segment1(q) == segment2(p) && segment2(q) != NULL && left_turn(p, q, other2(q))) { p->vis = segment2(q); } else if (segment2(q) == segment2(p) && segment1(q) != NULL && left_turn(p, q, other1(q))) { p->vis = segment1(q); } else p->vis = q->vis; report(p, q, out); } else if (segment1(q) == p->vis && segment1(q) != NULL) { /* we need to check if there is another segment at q so it can be set to the vis */ if (segment2(q) != NULL && left_turn(p, q, other2(q))) p->vis = segment2(q); else p->vis = q->vis; /* check that p and q are not on the same boundary and that the edge pq is inside the boundary */ if (p->cat == -1 || p->cat != q->cat || !point_inside(p, (p->x + q->x) * 0.5, (p->y + q->y) * 0.5)) report(p, q, out); } else if (segment2(q) == p->vis && segment2(q) != NULL) { /* we need to check if there is another segment at q so it can be set to the vis */ if (segment1(q) != NULL && left_turn(p, q, other1(q))) p->vis = segment1(q); else p->vis = q->vis; /* check that p and q are not on the same boundary and that the edge pq is inside the boundary */ if (p->cat == -1 || p->cat != q->cat || !point_inside(p, (p->x + q->x) * 0.5, (p->y + q->y) * 0.5)) report(p, q, out); } else if (before(p, q, p->vis)) { /* if q only has one segment, then this is the new vis */ if (segment2(q) == NULL) p->vis = segment1(q); else if (segment1(q) == NULL) p->vis = segment2(q); /* otherwise take the one with biggest slope */ else if (left_turn(p, q, other1(q)) && !left_turn(p, q, other2(q))) p->vis = segment1(q); else if (!left_turn(p, q, other1(q)) && left_turn(p, q, other2(q))) p->vis = segment2(q); else if (left_turn(q, other2(q), other1(q))) p->vis = segment1(q); else p->vis = segment2(q); /* check that p and q are not on the same boundary and that the edge pq is inside the boundary */ if (p->cat == -1 || p->cat != q->cat || !point_inside(p, (p->x + q->x) * 0.5, (p->y + q->y) * 0.5)) report(p, q, out); } }
/** for all points initiate their vis line to the one directly below */ void init_vis(struct Point *points, int num_points, struct Line *lines, int num_lines) { int i; double d; struct avl_table *tree = avl_create(cmp_points, NULL, NULL); struct avl_traverser it; struct Point *p; double y1, y2; struct Point *s1, *s2; for (i = 0; i < num_points; i++) { points[i].vis = NULL; d = PORT_DOUBLE_MAX; avl_t_init(&it, tree); /* loop through the tree */ while ((p = avl_t_next(&it)) != NULL) { if (segment1(p) == NULL && segment2(p) == NULL) continue; /* test for intersection and get the intersecting point */ if (segment1(p) != NULL && segment_intersect(segment1(p), &points[i], &y1) > -1) { /* find the closest one below */ if (y1 < points[i].y && (points[i].y - y1) < d) { d = points[i].y - y1; points[i].vis = segment1(p); } } if (segment2(p) != NULL && segment_intersect(segment2(p), &points[i], &y2) > -1) { if (y2 < points[i].y && (points[i].y - y2) < d) { d = points[i].y - y2; points[i].vis = segment2(p); } } } /* end loop */ s1 = s2 = NULL; /* now if the other point is on the right, we can delete it */ if (segment1(&points[i]) != NULL && cmp_points(&points[i], other1(&points[i]), NULL) > 0) { p = other1(&points[i]); /* unless the other point of it is on the left */ if (segment1(p) != NULL && other1(p) != &points[i] && cmp_points(&points[i], other1(p), NULL) > 0) s1 = avl_delete(tree, p); else if (segment2(p) != NULL && other2(p) != &points[i] && cmp_points(&points[i], other2(p), NULL) > 0) s1 = avl_delete(tree, p); } /* now if the other point is on the right, we can delete it */ if (segment2(&points[i]) != NULL && cmp_points(&points[i], other2(&points[i]), NULL) > 0) { p = other2(&points[i]); /* unless the other point of it is on the left */ if (segment1(p) != NULL && other1(p) != &points[i] && cmp_points(&points[i], other1(p), NULL) > 0) s2 = avl_delete(tree, p); else if (segment2(p) != NULL && other2(p) != &points[i] && cmp_points(&points[i], other2(p), NULL) > 0) s2 = avl_delete(tree, p); } /* if both weren't deleted, it means there is at least one other point on the left, so add the current */ /* also there is no point adding the point if there is no segment attached to it */ if ((s1 == NULL || s2 == NULL)) { avl_insert(tree, &points[i]); } } avl_destroy(tree, NULL); }
size_t BVH4MB::rotate(Base* nodeID, size_t depth) { /*! nothing to rotate if we reached a leaf node. */ if (nodeID->isLeaf()) return 0; Node* parent = nodeID->node(); /*! rotate all children first */ ssei cdepth; for (size_t c=0; c<4; c++) cdepth[c] = (int)rotate(parent->child[c],depth+1); /* compute current area of all children */ ssef sizeX = parent->upper_x-parent->lower_x; ssef sizeY = parent->upper_y-parent->lower_y; ssef sizeZ = parent->upper_z-parent->lower_z; ssef childArea = sizeX*(sizeY + sizeZ) + sizeY*sizeZ; /*! transpose node bounds */ ssef plower0,plower1,plower2,plower3; transpose(parent->lower_x,parent->lower_y,parent->lower_z,ssef(zero),plower0,plower1,plower2,plower3); ssef pupper0,pupper1,pupper2,pupper3; transpose(parent->upper_x,parent->upper_y,parent->upper_z,ssef(zero),pupper0,pupper1,pupper2,pupper3); BBox<ssef> other0(plower0,pupper0), other1(plower1,pupper1), other2(plower2,pupper2), other3(plower3,pupper3); /*! Find best rotation. We pick a target child of a first child, and swap this with an other child. We perform the best such swap. */ float bestCost = pos_inf; int bestChild = -1, bestTarget = -1, bestOther = -1; for (size_t c=0; c<4; c++) { /*! ignore leaf nodes as we cannot descent into */ if (parent->child[c]->isLeaf()) continue; Node* child = parent->child[c]->node(); /*! transpose child bounds */ ssef clower0,clower1,clower2,clower3; transpose(child->lower_x,child->lower_y,child->lower_z,ssef(zero),clower0,clower1,clower2,clower3); ssef cupper0,cupper1,cupper2,cupper3; transpose(child->upper_x,child->upper_y,child->upper_z,ssef(zero),cupper0,cupper1,cupper2,cupper3); BBox<ssef> target0(clower0,cupper0), target1(clower1,cupper1), target2(clower2,cupper2), target3(clower3,cupper3); /*! put other0 at each target position */ float cost00 = halfArea3f(merge(other0 ,target1,target2,target3)); float cost01 = halfArea3f(merge(target0,other0 ,target2,target3)); float cost02 = halfArea3f(merge(target0,target1,other0 ,target3)); float cost03 = halfArea3f(merge(target0,target1,target2,other0 )); ssef cost0 = ssef(cost00,cost01,cost02,cost03); ssef min0 = vreduce_min(cost0); int pos0 = (int)__bsf(movemask(min0 == cost0)); /*! put other1 at each target position */ float cost10 = halfArea3f(merge(other1 ,target1,target2,target3)); float cost11 = halfArea3f(merge(target0,other1 ,target2,target3)); float cost12 = halfArea3f(merge(target0,target1,other1 ,target3)); float cost13 = halfArea3f(merge(target0,target1,target2,other1 )); ssef cost1 = ssef(cost10,cost11,cost12,cost13); ssef min1 = vreduce_min(cost1); int pos1 = (int)__bsf(movemask(min1 == cost1)); /*! put other2 at each target position */ float cost20 = halfArea3f(merge(other2 ,target1,target2,target3)); float cost21 = halfArea3f(merge(target0,other2 ,target2,target3)); float cost22 = halfArea3f(merge(target0,target1,other2 ,target3)); float cost23 = halfArea3f(merge(target0,target1,target2,other2 )); ssef cost2 = ssef(cost20,cost21,cost22,cost23); ssef min2 = vreduce_min(cost2); int pos2 = (int)__bsf(movemask(min2 == cost2)); /*! put other3 at each target position */ float cost30 = halfArea3f(merge(other3 ,target1,target2,target3)); float cost31 = halfArea3f(merge(target0,other3 ,target2,target3)); float cost32 = halfArea3f(merge(target0,target1,other3 ,target3)); float cost33 = halfArea3f(merge(target0,target1,target2,other3 )); ssef cost3 = ssef(cost30,cost31,cost32,cost33); ssef min3 = vreduce_min(cost3); int pos3 = (int)__bsf(movemask(min3 == cost3)); /*! find best other child */ ssef otherCost = ssef(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)); int pos[4] = { pos0,pos1,pos2,pos3 }; sseb valid = ssei(int(depth+1))+cdepth <= ssei(maxDepth); // only select swaps that fulfill depth constraints if (none(valid)) continue; size_t n = select_min(valid,otherCost); float cost = otherCost[n]-childArea[c]; //< increasing the original child bound is bad, decreasing good /*! accept a swap when it reduces cost and is not swapping a node with itself */ if (cost < bestCost && n != c) { bestCost = cost; bestChild = (int)c; bestOther = (int)n; bestTarget = pos[n]; } } /*! if we did not find a swap that improves the SAH then do nothing */ if (bestCost >= 0) return 1+reduce_max(cdepth); /*! perform the best found tree rotation */ Node* child = parent->child[bestChild]->node(); swap(parent,bestOther,child,bestTarget); parent->lower_x[bestChild] = reduce_min(child->lower_x); parent->lower_y[bestChild] = reduce_min(child->lower_y); parent->lower_z[bestChild] = reduce_min(child->lower_z); parent->upper_x[bestChild] = reduce_max(child->upper_x); parent->upper_y[bestChild] = reduce_max(child->upper_y); parent->upper_z[bestChild] = reduce_max(child->upper_z); parent->lower_dx[bestChild] = reduce_min(child->lower_dx); parent->lower_dy[bestChild] = reduce_min(child->lower_dy); parent->lower_dz[bestChild] = reduce_min(child->lower_dz); parent->upper_dx[bestChild] = reduce_max(child->upper_dx); parent->upper_dy[bestChild] = reduce_max(child->upper_dy); parent->upper_dz[bestChild] = reduce_max(child->upper_dz); /*! This returned depth is conservative as the child that was * pulled up in the tree could have been on the critical path. */ cdepth[bestOther]++; // bestOther was pushed down one level return 1+reduce_max(cdepth); }