/** * This is region handler for a polygon region. * @author Pinkfish * @started Mon Apr 1 12:15:24 PST 2002 */ inherit "/std/room/inherit/terrain_map/geometry"; class vertex { int x; int y; } private mixed *_feature_direcs = ({ ({ "southwest", "south", "southeast" }), ({ "west", "Oops", "east" }), ({ "northwest", "north", "northeast" }) }); private class vertex* _vertexes = ({ }); /** * This method sets the position of the feature. * @param x the x coordinate of the feature * @param y the y coordinate of the feature * @param width the width of the feature * @param height the height of the feature */ void add_vertex(int x, int y) { class vertex vertex; vertex = new(class vertex, x : x, y : y); _vertexes += ({ vertex }); } /** * This is the function that finds the distance and direction to the * current region. * @param x the x-coordinate * @param y the y-coordinate * @param z the z-coordinate * @return ({ direction, distance [, direc2, dist2, [...]] }) */ mapping query_feature_desc_from(int x, int y, int z) { class vertex vert1; class vertex vert2; int i; float v1_x; float v1_y; float v2_x; float v2_y; float vm_x; float vm_y; float b; float dot1; float dot2; float min_distance; float distance; float xmod; float ymod; int xd; int yd; string direc; mapping dirs; class point p; dirs = ([ ]); // With a series of line segments we don't count the implied return segment for (i = 0; i < sizeof(_vertexes) - 1; i++) { vert1 = _vertexes[i]; vert2 = _vertexes[(i + 1) % sizeof(_vertexes)]; v1_x = to_float(vert1->x - vert2->x); v1_y = to_float(vert1->y - vert2->y); v2_x = to_float(x - vert2->x); v2_y = to_float(y - vert2->y); dot1 = v1_x * v2_x + v1_y * v2_y; if (dot1 <= 0.0) { // Distance to p1 distance = sqrt(pow(vert2->x - x, 2) + pow(vert2->y - y, 2)); //printf("1) %O\n", distance); if ((!min_distance || distance < min_distance) && distance > 0.0001) { xmod = ((vert2->x - x) < 0) ? -0.5 : 0.5; ymod = ((vert2->y - y) < 0) ? -0.5 : 0.5; xd = to_int(xmod + to_float(vert2->x - x) / distance) + 1; yd = to_int(ymod + to_float(vert2->y - y) / distance) + 1; direc = _feature_direcs[yd][xd]; min_distance = distance; } } else { dot2 = v1_x * v1_x + v1_y * v1_y; if (dot2 <= dot1) { // Distance to p2. distance = sqrt(pow(vert1->x - x, 2) + pow(vert1->y - y, 2)); if ((!min_distance || distance < min_distance) && distance > 0.0001) { //printf("2) %O\n", distance); xmod = ((vert1->x - x) < 0) ? -0.5 : 0.5; ymod = ((vert1->y - y) < 0) ? -0.5 : 0.5; xd = to_int(xmod + to_float(vert1->x - x) / distance) + 1; yd = to_int(ymod + to_float(vert1->y - y) / distance) + 1; direc = _feature_direcs[yd][xd]; min_distance = distance; } } else { b = dot1 / dot2; vm_x = to_float(vert2->x) + b * v1_x; vm_y = to_float(vert2->y) + b * v1_y; // Distance to vm. distance = sqrt(pow(vm_x - x, 2) + pow(vm_y - y, 2)); //printf("3) (%O, %O) %O\n", vm_x, vm_y, distance); if ((!min_distance || distance < min_distance) && distance > 0.0001) { xmod = ((vm_x - x) < 0) ? -0.5 : 0.5; ymod = ((vm_y - y) < 0) ? -0.5 : 0.5; xd = to_int(xmod + to_float(vm_x - x) / distance) + 1; yd = to_int(ymod + to_float(vm_y - y) / distance) + 1; direc = _feature_direcs[yd][xd]; min_distance = distance; } } } // Do specific direction checks. p = intersection_of_line_and_segment(0,0, 1,0, vert1->x, vert1->y, vert2->x, vert2->y); if (p) { if (p->x > x) { if (dirs["east"] && dirs["east"] > p->x) { dirs["east"] = p->x; } } else { if (dirs["west"] && dirs["west"] > p->x) { dirs["west"] = p->x; } } } p = intersection_of_line_and_segment(0,0, 0,1, vert1->x, vert1->y, vert2->x, vert2->y); if (p) { if (p->y > y) { if (dirs["north"] && dirs["north"] > p->y) { dirs["north"] = to_int(p->y); } } else { if (dirs["south"] && dirs["south"] > p->y) { dirs["south"] = to_int(p->y); } } } p = intersection_of_line_and_segment(0,0, 1,1, vert1->x, vert1->y, vert2->x, vert2->y); if (p) { if (p->x > x) { if (dirs["northeast"] && dirs["northeast"] > p->x) { dirs["northeast"] = to_int(p->x); } } else { if (dirs["southwest"] && dirs["southwest"] > p->x) { dirs["southwest"] = to_int(p->x); } } } p = intersection_of_line_and_segment(0,0, 1,-1, vert1->x, vert1->y, vert2->x, vert2->y); if (p) { if (p->y > y) { if (dirs["northwest"] && dirs["northwest"] > p->y) { dirs["northwest"] = p->y; } } else { if (dirs["southeast"] && dirs["southeast"] > p->y) { dirs["southeast"] = p->y; } } } //printf("%O of %O: %O %O\n", i, sizeof(_vertexes), direc, min_distance); } dirs[direc] = to_int(min_distance); /* ret = ({ direc, to_int(min_distance) }); foreach (direc, i in dirs) { ret += ({ direc, i }); } */ return dirs; } /** * Find out if this polygon is inside the region, given the specified range * at which it can be seen. This will work by adding the ranges onto the * lines and checking for distance from the points of the polygon to the line * bordering the region and also checking for intersection with the bordering * line. It also checks to see if all of the points are inside the region. * @param x1 the top x * @param y1 the top y * @param x2 the bottom x * @param y2 the bottom y */ int is_inside_region(int x1, int y1, int x2, int y2, int range) { class vertex vertex; class vertex vert1; class vertex vert2; int i; foreach (vertex in _vertexes) { if (vertex->x >= x1 && vertex->x <= x2 && vertex->y >= y1 && vertex->y <= y2) { return 1; } } // Now check distances to the edges of the polygon. for (i = 0; i < sizeof(_vertexes); i++) { vert1 = _vertexes[i]; vert2 = _vertexes[(i + 1) % sizeof(_vertexes)]; if (distance_between_two_line_segments(x1, y1, x1, y2, vert1->x, vert1->y, vert2->x, vert2->y) < range) { return 1; } if (distance_between_two_line_segments(x1, y1, x2, y1, vert1->x, vert1->y, vert2->x, vert2->y) < range) { return 1; } if (distance_between_two_line_segments(x2, y1, x2, y2, vert1->x, vert1->y, vert2->x, vert2->y) < range) { return 1; } if (distance_between_two_line_segments(x1, y2, x2, y2, vert1->x, vert1->y, vert2->x, vert2->y) < range) { return 1; } } return 0; } /** @ignore yes */ void dest_me() { destruct(this_object()); }