/* getRotation: * The function determines how much the block should be rotated * for best positioning with parent, assuming its center is at x and y * relative to the parent. * angle gives the angle of the new position, i.e., tan(angle) = y/x. * If sn has 2 nodes, we arrange the line of the 2 normal to angle. * If sn has 1 node, parent_pos has already been set to the * correct angle assuming no rotation. * Otherwise, we find the node in sn connected to the parent and rotate * the block so that it is closer or at least visible to its node in the * parent. * * For COALESCED blocks, if neighbor is in left half plane, * use unCOALESCED case. * Else let theta be angle, R = LEN(x,y), pho the radius of actual * child block, phi be angle of neighbor in actual child block, * and r the distance from center of coalesced block to center of * actual block. Then, the angle to rotate the coalesced block to * that the edge from the parent is tangent to the neighbor on the * actual child block circle is * alpha = theta + M_PI/2 - phi - arcsin((l/R)*(sin B)) * where l = r - rho/(cos phi) and beta = M_PI/2 + phi. * Thus, * alpha = theta + M_PI/2 - phi - arcsin((l/R)*(cos phi)) */ static double getRotation(block_t * sn, Agraph_t * g, double x, double y, double theta) { double mindist2; Agraph_t *subg; /* Agedge_t* e; */ Agnode_t *n, *closest_node, *neighbor; nodelist_t *list; double len2, newX, newY; int count; subg = sn->sub_graph; #ifdef OLD parent = sn->parent; #endif list = sn->circle_list; if (sn->parent_pos >= 0) { theta += M_PI - sn->parent_pos; if (theta < 0) theta += 2 * M_PI; return theta; } count = sizeNodelist(list); if (count == 2) { return (theta - M_PI / 2.0); } /* Find node in block connected to block's parent */ neighbor = CHILD(sn); #ifdef OLD for (e = agfstedge(g, parent); e; e = agnxtedge(g, e, parent)) { n = e->head; if (n == parent) n = e->tail; if ((BLOCK(n) == sn) && (PARENT(n) == parent)) { neighbor = n; break; } } #endif newX = ND_pos(neighbor)[0] + x; newY = ND_pos(neighbor)[1] + y; mindist2 = LEN2(newX, newY); /* save sqrts by using sqr of dist to find min */ closest_node = neighbor; for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { if (n == neighbor) continue; newX = ND_pos(n)[0] + x; newY = ND_pos(n)[1] + y; len2 = LEN2(newX, newY); if (len2 < mindist2) { mindist2 = len2; closest_node = n; } } /* if((neighbor != closest_node) && !ISPARENT(neighbor)) { */ if (neighbor != closest_node) { double rho = sn->rad0; double r = sn->radius - rho; double n_x = ND_pos(neighbor)[0]; if (COALESCED(sn) && (-r < n_x)) { double R = LEN(x, y); double n_y = ND_pos(neighbor)[1]; double phi = atan2(n_y, n_x + r); double l = r - rho / (cos(phi)); theta += M_PI / 2.0 - phi - asin((l / R) * (cos(phi))); } else { /* Origin still at center of this block */ double phi = atan2(ND_pos(neighbor)[1], ND_pos(neighbor)[0]); theta += M_PI - phi - PSI(neighbor); if (theta > 2 * M_PI) theta -= 2 * M_PI; } } else theta = 0; return theta; }
//查找比较长的线段 const line *longer_line(const line *p_line1, const line *p_line2) { return LEN2(p_line1) > LEN2(p_line2) ? p_line1 : p_line2; }