Beispiel #1
0
std::vector<glm::vec3> getConvexHull(std::vector<glm::vec3> &pts){
    std::vector<glm::vec3> hull;
    glm::vec3 h1,h2,h3;
    
    if (pts.size() < 3) {
        std::cout << "Error: you need at least three points to calculate the convex hull" << std::endl;
        return hull;
    }
    
    std::sort(pts.begin(), pts.end(), &lexicalComparison);
    
    hull.push_back(pts.at(0));
    hull.push_back(pts.at(1));
    
    int currentPoint = 2;
    int direction = 1;
    
    for (int i=0; i<3000; i++) { //max 1000 tries
        
        hull.push_back(pts.at(currentPoint));
        
        // look at the turn direction in the last three points
        h1 = hull.at(hull.size()-3);
        h2 = hull.at(hull.size()-2);
        h3 = hull.at(hull.size()-1);
        
        // while there are more than two points in the hull
        // and the last three points do not make a right turn
        while (!isRightTurn(h1, h2, h3) && hull.size() > 2) {
            
            // remove the middle of the last three points
            hull.erase(hull.end() - 2);
            
            if (hull.size() >= 3) {
                h1 = hull.at(hull.size()-3);
            }
            h2 = hull.at(hull.size()-2);
            h3 = hull.at(hull.size()-1);
        }
        
        // going through left-to-right calculates the top hull
        // when we get to the end, we reverse direction
        // and go back again right-to-left to calculate the bottom hull
        if (currentPoint == pts.size() -1 || currentPoint == 0) {
            direction = direction * -1;
        }
        
        currentPoint+=direction;
        
        if (hull.front()==hull.back()) {
            if(currentPoint == 3 && direction == 1){
                currentPoint = 4;
            } else {
                break;
            }
        }
    }
    
    return hull;
}
Beispiel #2
0
int TicTacToe::play(bool _xTurn, int pos) {
	bool win;
	
	if(!isRightTurn(_xTurn)) {
		return INVALID_TURN;
	}
	
	if(!isValidMove(pos)) {
		return INVALID_MOVE;
	}
	
	placeMove(_xTurn,pos);
	
	plotGame();
	
	win = won(_xTurn);
	xTurn = !xTurn;
	
	if(win) {
		resetGame();
		return WIN;
	}
	else if(isFull()){
		resetGame();
		return OVER;
	}
	else {
		return NO_WIN;
	}
}
Beispiel #3
0
//vector<ofPoint>
ofPolyline ofxGetConvexHull(vector<ofPoint> points) {
  if (points.size()<3) return ofPolyline();

  ofPoint h1,h2,h3;

  sort(points.begin(), points.end(), lexicalComparison);

  vector<ofPoint> hull;

  hull.push_back(points.at(0));
  hull.push_back(points.at(1));

  int currentPoint = 2;
  int direction = 1;

  for (int i=0; i<1000; i++) { //max 1000 tries

    hull.push_back(points.at(currentPoint));

    // look at the turn direction in the last three points
    h1 = hull.at(hull.size()-3);
    h2 = hull.at(hull.size()-2);
    h3 = hull.at(hull.size()-1);

    // while there are more than two points in the hull
    // and the last three points do not make a right turn
    while (!isRightTurn(h1, h2, h3) && hull.size() > 2) {

      // remove the middle of the last three points
      hull.erase(hull.end() - 2);

      if (hull.size() >= 3) {
        h1 = hull.at(hull.size()-3);
      }
      h2 = hull.at(hull.size()-2);
      h3 = hull.at(hull.size()-1);
    }

    // going through left-to-right calculates the top hull
    // when we get to the end, we reverse direction
    // and go back again right-to-left to calculate the bottom hull
    if (currentPoint == points.size() -1 || currentPoint == 0) {
      direction = direction * -1;
    }

    currentPoint+= direction;

    if (hull.front()==hull.back()) break;
  }

  return ofPolyline(hull);
}
std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
                                            const double min_duration_needed_for_lane_change)
{
    // Lane anticipation works on contiguous ranges of quick steps that have lane information
    const auto is_quick_has_lanes = [&](const RouteStep &step) {
        const auto is_quick = step.duration < min_duration_needed_for_lane_change;
        const auto has_lanes = step.intersections.front().lanes.lanes_in_turn > 0;
        return has_lanes && is_quick;
    };

    using StepIter = decltype(steps)::iterator;
    using StepIterRange = std::pair<StepIter, StepIter>;

    std::vector<StepIterRange> quick_lanes_ranges;

    const auto range_back_inserter = [&](StepIterRange range) {
        if (std::distance(range.first, range.second) > 1)
            quick_lanes_ranges.push_back(std::move(range));
    };

    util::group_by(begin(steps), end(steps), is_quick_has_lanes, range_back_inserter);

    // The lanes for a keep straight depend on the next left/right turn. Tag them in advance.
    std::unordered_set<const RouteStep *> is_straight_left;
    std::unordered_set<const RouteStep *> is_straight_right;

    // Walk backwards over all turns, constraining possible turn lanes.
    // Later turn lanes constrain earlier ones: we have to anticipate lane changes.
    const auto constrain_lanes = [&](const StepIterRange &turns) {
        const std::reverse_iterator<StepIter> rev_first{turns.second};
        const std::reverse_iterator<StepIter> rev_last{turns.first};

        // We're walking backwards over all adjacent turns:
        // the current turn lanes constrain the lanes we have to take in the previous turn.
        util::for_each_pair(rev_first, rev_last, [&](RouteStep &current, RouteStep &previous) {
            const auto current_inst = current.maneuver.instruction;
            const auto current_lanes = current.intersections.front().lanes;

            // Constrain the previous turn's lanes
            auto &previous_lanes = previous.intersections.front().lanes;
            const auto previous_inst = previous.maneuver.instruction;

            // Lane mapping (N:M) from previous lanes (N) to current lanes (M), with:
            //  N > M, N > 1   fan-in situation, constrain N lanes to min(N,M) shared lanes
            //  otherwise      nothing to constrain
            const bool lanes_to_constrain = previous_lanes.lanes_in_turn > 1;
            const bool lanes_fan_in = previous_lanes.lanes_in_turn > current_lanes.lanes_in_turn;

            if (!lanes_to_constrain || !lanes_fan_in)
                return;

            // We do not have a mapping from lanes to lanes. All we have is the lanes in the turn
            // and all the lanes at that situation. To perfectly handle lane anticipation in cases
            // where lanes in the turn fan in but for example the overall lanes at that location
            // fan out, we would have to know the asymmetric mapping of lanes. This is currently
            // not possible at the moment. In the following we implement a heuristic instead.
            const LaneID current_num_lanes_right_of_turn = current.numLanesToTheRight();
            const LaneID current_num_lanes_left_of_turn = current.numLanesToTheLeft();

            const LaneID num_shared_lanes = std::min(current_lanes.lanes_in_turn,   //
                                                     previous_lanes.lanes_in_turn); //

            // 0/ Tag keep straight with the next turn's direction if available
            const auto previous_is_straight =
                !isLeftTurn(previous_inst) && !isRightTurn(previous_inst);

            if (previous_is_straight)
            {
                if (isLeftTurn(current_inst) || is_straight_left.count(&current) > 0)
                    is_straight_left.insert(&previous);
                else if (isRightTurn(current_inst) || is_straight_right.count(&current) > 0)
                    is_straight_right.insert(&previous);
            }

            // 1/ How to anticipate left, right:
            const auto anticipate_for_left_turn = [&] {
                // Current turn is left turn, already keep left during previous turn.
                // This implies constraining the rightmost lanes in previous step.
                LaneID new_first_lane_from_the_right =
                    previous_lanes.first_lane_from_the_right // start from rightmost lane
                    + previous_lanes.lanes_in_turn           // one past leftmost lane
                    - num_shared_lanes;                      // back number of new lanes

                // The leftmost target lanes might not be involved in the turn. Figure out
                // how many lanes are to the left and not in the turn.
                new_first_lane_from_the_right -=
                    std::min(current_num_lanes_left_of_turn, num_shared_lanes);

                previous_lanes = {num_shared_lanes, new_first_lane_from_the_right};
            };

            const auto anticipate_for_right_turn = [&] {
                // Current turn is right turn, already keep right during the previous turn.
                // This implies constraining the leftmost lanes in the previous turn step.
                LaneID new_first_lane_from_the_right = previous_lanes.first_lane_from_the_right;

                // The rightmost target lanes might not be involved in the turn. Figure out
                // how many lanes are to the right and not in the turn.
                new_first_lane_from_the_right +=
                    std::min(current_num_lanes_right_of_turn, num_shared_lanes);

                previous_lanes = {num_shared_lanes, new_first_lane_from_the_right};
            };

            // 2/ When to anticipate a left, right turn
            if (isLeftTurn(current_inst))
                anticipate_for_left_turn();
            else if (isRightTurn(current_inst))
                anticipate_for_right_turn();
            else // keepStraight
            {
                // Heuristic: we do not have a from-lanes -> to-lanes mapping. What we use
                // here instead in addition is the number of all lanes (not only the lanes
                // in a turn):
                //
                // -v-v v-v-        straight follows
                //  | | | |
                // <- v v ->        keep straight here
                //    | |
                //  <-| |->
                //
                // A route from the top left to the bottom right here goes over a keep
                // straight. If we handle all keep straights as right turns (in right-sided
                // driving), we wrongly guide the user to the rightmost lanes in the first turn.
                // Not only is this wrong but the opposite of what we expect.
                //
                // The following implements a heuristic to determine a keep straight's
                // direction in relation to the next step. In the above example we would get:
                //
                // coming from right, going to left (in direction of way) -> handle as left turn

                if (is_straight_left.count(&current) > 0)
                    anticipate_for_left_turn();
                else if (is_straight_right.count(&current) > 0)
                    anticipate_for_right_turn();
                else // FIXME: right-sided driving
                    anticipate_for_right_turn();
            }

            // We might have constrained the previous step in a way that makes it compatible
            // with the current step. If we did so we collapse it here and mark the current
            // step as invalid, scheduled for later removal.
            if (collapsable(previous, current))
            {
                previous = elongate(previous, current);
                current.maneuver.instruction = TurnInstruction::NO_TURN();
            }
        });
    };

    std::for_each(begin(quick_lanes_ranges), end(quick_lanes_ranges), constrain_lanes);

    // Lane Anticipation might have collapsed steps after constraining lanes. Remove invalid steps.
    steps = removeNoTurnInstructions(std::move(steps));

    return steps;
}
Beispiel #5
0
std::vector<RouteStep> anticipateLaneChange(std::vector<RouteStep> steps,
                                            const double min_duration_needed_for_lane_change)
{
    // Postprocessing does not strictly guarantee for only turns
    const auto is_turn = [](const RouteStep &step) {
        return step.maneuver.instruction.type != TurnType::NewName &&
               step.maneuver.instruction.type != TurnType::Notification;
    };

    const auto is_quick = [min_duration_needed_for_lane_change](const RouteStep &step) {
        return step.duration < min_duration_needed_for_lane_change;
    };

    const auto is_quick_turn = [&](const RouteStep &step) {
        return is_turn(step) && is_quick(step);
    };

    // Determine range of subsequent quick turns, candidates for possible lane anticipation
    using StepIter = decltype(steps)::iterator;
    using StepIterRange = std::pair<StepIter, StepIter>;

    std::vector<StepIterRange> subsequent_quick_turns;

    const auto keep_turn_range = [&](StepIterRange range) {
        if (std::distance(range.first, range.second) > 1)
            subsequent_quick_turns.push_back(std::move(range));
    };

    util::group_by(begin(steps), end(steps), is_quick_turn, keep_turn_range);

    // Walk backwards over all turns, constraining possible turn lanes.
    // Later turn lanes constrain earlier ones: we have to anticipate lane changes.
    const auto constrain_lanes = [](const StepIterRange &turns) {
        const std::reverse_iterator<StepIter> rev_first{turns.second};
        const std::reverse_iterator<StepIter> rev_last{turns.first};

        // We're walking backwards over all adjacent turns:
        // the current turn lanes constrain the lanes we have to take in the previous turn.
        util::for_each_pair(rev_first, rev_last, [](RouteStep &current, RouteStep &previous) {
            const auto current_inst = current.maneuver.instruction;
            const auto current_lanes = current.intersections.front().lanes;

            // Constrain the previous turn's lanes
            auto &previous_lanes = previous.intersections.front().lanes;
            // Lane mapping (N:M) from previous lanes (N) to current lanes (M), with:
            //  N > M, N > 1   fan-in situation, constrain N lanes to min(N,M) shared lanes
            //  otherwise      nothing to constrain
            const bool lanes_to_constrain = previous_lanes.lanes_in_turn > 1;
            const bool lanes_fan_in = previous_lanes.lanes_in_turn > current_lanes.lanes_in_turn;

            if (!lanes_to_constrain || !lanes_fan_in)
                return;

            // In case there is no lane information we work with one artificial lane
            const auto current_adjusted_lanes = std::max(current_lanes.lanes_in_turn, LaneID{1});

            const auto num_shared_lanes = std::min(current_adjusted_lanes, //
                                                   previous_lanes.lanes_in_turn);

            if (isRightTurn(current_inst))
            {
                // Current turn is right turn, already keep right during the previous turn.
                // This implies constraining the leftmost lanes in the previous turn step.
                previous_lanes = {num_shared_lanes, previous_lanes.first_lane_from_the_right};
            }
            else if (isLeftTurn(current_inst))
            {
                // Current turn is left turn, already keep left during previous turn.
                // This implies constraining the rightmost lanes in the previous turn step.
                const LaneID shared_lane_delta = previous_lanes.lanes_in_turn - num_shared_lanes;
                const LaneID previous_adjusted_lanes =
                    std::min(current_adjusted_lanes, shared_lane_delta);
                const LaneID constraint_first_lane_from_the_right =
                    previous_lanes.first_lane_from_the_right + previous_adjusted_lanes;

                previous_lanes = {num_shared_lanes, constraint_first_lane_from_the_right};
            }
        });
    };

    std::for_each(begin(subsequent_quick_turns), end(subsequent_quick_turns), constrain_lanes);
    return steps;
}