Пример #1
0
int rc_clip_line(rc_line_t line, rc_rectangle_t clip)
{
    rc_code_t C0, C1, C;
    float x, y;

    assert(line != NULL);
    assert(clip != NULL);
    
    C0 = rc_compute_code(line->x0, line->y0, clip);
    C1 = rc_compute_code(line->x1, line->y1, clip);
    
    for (;;) {
	/* trivial accept: both ends in rectangle */
	if ((C0 | C1) == 0) {
	    return 1;
	}
	
	/* trivial reject: both ends on the external side of the rectangle */
	if ((C0 & C1) != 0)
	    return 0;
	
	/* normal case: clip end outside rectangle */
	C = C0 ? C0 : C1;
	if (C & RCF_TOP) {
	    x = line->x0 + (line->x1 - line->x0) *
		(clip->ymax - line->y0) / (line->y1 - line->y0);
	    y = clip->ymax;
	} else if (C & RCF_BOTTOM) {
	    x = line->x0 + (line->x1 - line->x0) *
		(clip->ymin - line->y0) / (line->y1 - line->y0);
	    y = clip->ymin;
	} else if (C & RCF_RIGHT) {
	    x = clip->xmax;
	    y = line->y0 + (line->y1 - line->y0) *
		(clip->xmax - line->x0) / (line->x1 - line->x0);
	} else {
	    x = clip->xmin;
	    y = line->y0 + (line->y1 - line->y0) *
		(clip->xmin - line->x0) / (line->x1 - line->x0);
	}
	
	/* set new end point and iterate */
	if (C == C0) {
	    line->x0 = x; line->y0 = y;
	    C0 = rc_compute_code(line->x0, line->y0, clip);
	} else {
	    line->x1 = x; line->y1 = y;
	    C1 = rc_compute_code(line->x1, line->y1, clip);
	}
    }
    
    /* notreached */
    assert(0);
}
Пример #2
0
pp_point_type_t pp_point_identify(struct robot_position *rpoint,
                                  struct obstacle_config *oc)
{
    /* determine the point type of rpoint */
    
    pp_point_type_t retval;
    robot_position this_cp;

    assert(rpoint != NULL);
    assert(oc != NULL);

    if (rc_compute_code(rpoint->x, rpoint->y, oc) == 0)
	retval = PPT_INTERNAL;
    else
	retval = PPT_DETACHED;
    
    /* is this a corner point? Check each corner of this obstacle */
    if (PP_TOL > pp_point_distance(
	rpoint, rc_corner(RCF_TOP|RCF_LEFT, &this_cp, oc))) {
	retval = PPT_CORNERPOINT;
    }
    else if (PP_TOL > pp_point_distance(
	rpoint, rc_corner(RCF_TOP|RCF_RIGHT, &this_cp, oc))) {
	retval = PPT_CORNERPOINT;
    }
    else if (PP_TOL > pp_point_distance(
	rpoint, rc_corner(RCF_BOTTOM|RCF_RIGHT, &this_cp, oc))) {
	retval = PPT_CORNERPOINT;
    }
    else if (PP_TOL > pp_point_distance(
	rpoint, rc_corner(RCF_BOTTOM|RCF_LEFT, &this_cp, oc))) {
	retval = PPT_CORNERPOINT;
    }
    
    /* is this point in bounds? */
    if (!(pp_point_in_bounds(rpoint->x, rpoint->y))) {
	retval = PPT_OUTOFBOUNDS;
	if (debug > 1)
	    info("pp_point_identify says this point is out of bounds\n");
    }
    
    /* debugging output */
    if (PPT_CORNERPOINT == retval) {
	if (debug > 1)
	    info("pp_point_identify says this point is a corner point\n");
    }

    return retval;
}
Пример #3
0
/**
 * Check that a point is not only in bounds, but also reachable by the robot.
 * A point is not reachable if it is out of bounds or if the robot would have
 * to travel through the center of the obstacle to reach it.
 *
 * @param pp A plan with the pp_actual_pos and pp_obstacle fields initialized.
 * The pp_obstacle field should contain the obstacle that must be navigated
 * around.
 * @param rp The point to check.
 * @return True if the point is reachable, false otherwise.
 */
static int pp_point_reachable(struct path_plan *pp, struct robot_position *rp)
{
    int retval = 0;

    assert(pp != NULL);
    assert(rp != NULL);

    if (pp_point_in_bounds(rp->x, rp->y)) {
	struct obstacle_config oc;
	struct rc_line rl;

	rl.x0 = pp->pp_actual_pos.x;
	rl.y0 = pp->pp_actual_pos.y;
	rl.x1 = rp->x;
	rl.y1 = rp->y;
	oc = pp->pp_obstacle;
	if (rc_compute_code(rl.x0, rl.y0, &oc) == 0) {
	    float xlen, ylen;

	    /*
	     * The point is inside the obstacle, shrink the size of the
	     * obstacle so the point is on the outside.
	     */
	    xlen = min(fabs(rl.x0 - pp->pp_obstacle.xmin),
		       fabs(rl.x0 - pp->pp_obstacle.xmax));
	    ylen = min(fabs(rl.y0 - pp->pp_obstacle.ymin),
		       fabs(rl.y0 - pp->pp_obstacle.ymax));
	    if (xlen < ylen) {
		if (fabs(rl.x0 - pp->pp_obstacle.xmin) <
		    fabs(rl.x0 - pp->pp_obstacle.xmax)) {
		    oc.xmin = rl.x0 + 0.01;
		    oc.xmax = pp->pp_obstacle.xmax;
		}
		else {
		    oc.xmin = pp->pp_obstacle.xmin;
		    oc.xmax = rl.x0 - 0.01;
		}
	    }
	    else {
		if (fabs(rl.y0 - pp->pp_obstacle.ymin) <
		    fabs(rl.y0 - pp->pp_obstacle.ymax)) {
		    oc.ymin = rl.y0 + 0.01;
		    oc.ymax = pp->pp_obstacle.ymax;
		}
		else {
		    oc.ymin = pp->pp_obstacle.ymin;
		    oc.ymax = rl.y0 - 0.01;
		}
	    }
	}
	
	if (debug > 1) {
	    info("reachable %.2f %.2f - %.2f %.2f %.2f %.2f\n",
		 rp->x, rp->y, oc.xmin, oc.ymin, oc.xmax, oc.ymax);
	}

	/*
	 * Check if the path to the point is completely outside the obstacle
	 * or intersects just at one of the corners.
	 */
	if ((rc_clip_line(&rl, &oc) == 0) ||
	    ((rl.x0 == rl.x1) && (rl.y0 == rl.y1))) {
	    retval = 1;
	}
    }

    return retval;
}
Пример #4
0
pp_plot_code_t pp_plot_waypoint(struct path_plan *pp)
{
    struct lnMinList dextra, sextra, intersections;
    float distance, cross, theta;
    pp_plot_code_t retval;
    int in_ob = 0;
    
    assert(pp != NULL);

    if (debug > 0) {
	info(" plot %.2f %.2f -> %.2f %.2f\n",
	     pp->pp_actual_pos.x, pp->pp_actual_pos.y,
	     pp->pp_goal_pos.x, pp->pp_goal_pos.y);
    }
    
    lnNewList(&dextra);
    lnNewList(&sextra);
    lnNewList(&intersections);
    
    retval = PPC_NO_WAYPOINT; /* if nothing else */
    
    /*
     * We have to iterate over one or more waypoints, so we start with the
     * Initial waypoint is the goal point.
     */
    pp->pp_waypoint = pp->pp_goal_pos;
    
    do {
	struct obstacle_node *on, *min_on = NULL;
	int goal_in_ob = 0, robot_ob = 0;
	float min_distance = FLT_MAX;

	/*
	 * The path doesn't cross enough of the obstacle box for us to worry
	 * about it so we dump it on the extra list so the intersect doesn't
	 * return it again.  XXX The number is partially a guess and
	 * empirically derived.
	 */
	cross = PP_MIN_OBSTACLE_CROSS;
	/*
	 * First we find all of the obstacles that intersect with this path
	 * and locate the minimum distance to an obstacle.
	 */
	if (debug)
	    info("wp %.2f %.2f\n", pp->pp_waypoint.x, pp->pp_waypoint.y);
	while ((on = ob_find_intersect2(&pp->pp_actual_pos,
					&pp->pp_waypoint,
					&distance,
					&cross)) != NULL) {
#if 0
	    info("intr %d %.2f %.2f\n",
		 on->on_natural.id,
		 distance,
		 cross);
#endif
	    
	    if (on->on_type == OBT_ROBOT)
		robot_ob = 1;

	    switch (pp_point_identify(&pp->pp_actual_pos, &on->on_expanded)) {
	    case PPT_INTERNAL:
	    case PPT_CORNERPOINT:
	    case PPT_OUTOFBOUNDS:
		in_ob = 1;
		break;
	    default:
		break;
	    }

	    if (rc_compute_code(pp->pp_goal_pos.x,
				pp->pp_goal_pos.y,
				&on->on_expanded) == 0) {
		goal_in_ob = 1;
	    }
	    
	    lnRemove(&on->on_link);
	    /* Record the intersection and */
	    lnAddTail(&intersections, &on->on_link);
	    /* ... check if this is the closest obstacle. */
	    if (distance < min_distance) {
		min_distance = distance;
		min_on = on;
	    }
	    
	    cross = PP_MIN_OBSTACLE_CROSS;
	}
	
	/* Check if there was an actual intersection. */
	if (min_on != NULL) {
	    if (debug > 1)
		info("closest %d\n", min_on->on_natural.id);
	    
	    pp->pp_flags |= PPF_HAS_OBSTACLE;
	    lnRemove(&min_on->on_link); // from the intersections list
	    lnAddTail(min_on->on_type == OBT_STATIC ? &sextra : &dextra,
		      &min_on->on_link);
	    pp->pp_obstacle = min_on->on_expanded;

	    /*
	     * Find all obstacles that the path intersects with and overlap the
	     * closest one.  The rest of the obstacles will be dealt with after
	     * we get around the closest one.
	     */
	    while ((on = (struct obstacle_node *)
		    lnRemHead(&intersections)) != NULL) {
		if (rc_rect_intersects(&pp->pp_obstacle, &on->on_expanded)) {
		    if (debug > 1)
			info("merging %d\n", on->on_natural.id);
		    
		    ob_merge_obstacles(&pp->pp_obstacle, &on->on_expanded);
		}
		lnAddTail(on->on_type == OBT_STATIC ? &sextra : &dextra,
			  &on->on_link);
	    }
	    
	    if (goal_in_ob) {
		struct robot_position rp;
		struct rc_line rl;
		float r;
		
		mtp_polar(&pp->pp_goal_pos, &pp->pp_actual_pos, &r, &theta);
		if (robot_ob)
		    theta += M_PI_2;
		mtp_cartesian(&pp->pp_goal_pos, r + 1000.0, theta, &rp);
		rl.x0 = pp->pp_goal_pos.x;
		rl.y0 = pp->pp_goal_pos.y;
		rl.x1 = rp.x;
		rl.y1 = rp.y;
		rc_clip_line(&rl, &pp->pp_obstacle);
		pp->pp_waypoint.x = rl.x1;
		pp->pp_waypoint.y = rl.y1;
		if (pp_point_distance(&pp->pp_waypoint,
				      &pp->pp_actual_pos) > 0.075) {
		    if (pp_point_reachable(pp, &pp->pp_waypoint))
			retval = PPC_WAYPOINT;
		    else if (pp_next_cornerpoint(pp))
			retval = PPC_WAYPOINT;
		    else
			retval = PPC_BLOCKED;
		}
		else {
		    retval = PPC_GOAL_IN_OBSTACLE;
		}
	    }
	    else if (pp_next_cornerpoint(pp)) {
		retval = PPC_WAYPOINT;
	    }
	    else {
		retval = PPC_BLOCKED;
	    }
	}

	/* Restore the active obstacle list.  XXX Shouldn't do this here. */
	lnPrependList(&ob_data.od_active, &dextra); // dynamics first
	lnAppendList(&ob_data.od_active, &sextra); // statics last
	
	/* Check for obstacles on the path to our new waypoint. */
	cross = PP_MIN_OBSTACLE_CROSS;
    } while ((retval == PPC_WAYPOINT) &&
	     (ob_find_intersect2(&pp->pp_actual_pos,
				 &pp->pp_waypoint,
				 &distance,
				 &cross) != NULL) &&
	     !in_ob);
    
    /* And make sure it is still sane. */
    assert(ob_data_invariant());
    
    /* restrict final waypoint to MAX_DISTANCE */
    mtp_polar(&pp->pp_actual_pos,
	      (retval == PPC_WAYPOINT) ? &pp->pp_waypoint : &pp->pp_goal_pos,
	      &distance,
	      &theta);
    if (distance > pp_data.ppd_max_distance) {
	mtp_cartesian(&pp->pp_actual_pos,
		      pp_data.ppd_max_distance,
		      theta,
		      &pp->pp_waypoint);
	retval = PPC_WAYPOINT;
    }

    switch (retval) {
    case PPC_WAYPOINT:
	info("set waypoint(%s) %.2f %.2f\n",
	     pp->pp_robot->hostname,
	     pp->pp_waypoint.x,
	     pp->pp_waypoint.y);
	break;
    case PPC_NO_WAYPOINT:
	info("set waypoint(%s) NONE\n", pp->pp_robot->hostname);
	break;
    case PPC_BLOCKED:
	info("set waypoint(%s) BLOCKED\n", pp->pp_robot->hostname);
	break;
    case PPC_GOAL_IN_OBSTACLE:
	info("set waypoint(%s) GOAL_IN_OBSTACLE\n", pp->pp_robot->hostname);
	break;
    }
    
    return retval;
}