// Implementation of the Intersection class // CSE143 Spring '01 // Homework 6 #include "intersection.h" #include "road_segment.h" #include "vehicle.h" #include "gp142display.h" #include #include int swapEntryExit(int entryOrExit) { assert (entryOrExit == Entry || entryOrExit == Exit); if (entryOrExit == Entry) return Exit; else return Entry; } // Construct an uninitialized intersection Intersection::Intersection() { } // Construct an intersection centered at (x,y) Intersection::Intersection(Position center) { this->center = center; Direction dir; int i; for (i = 0, dir = North; i < NumDirections; i++, dir = nextDir(dir)) { segments[dir][Entry] = segments[dir][Exit] = NULL; } } // Destructor: does NOT deallocate any of the segments, but does deallocate // the vehicle(s) currently in the intersection (if any). Intersection::~Intersection() { // This starter implementation doesn't hold any vehicles, so no need // for destructor. } // Draw the intersection on the screen. // Precondition: the intersection was initialized with a position. void Intersection::draw(GP142Display& gp) { gp.drawRectangle(getBorder(West), getBorder(South), getBorder(East), getBorder(North), Black, 0); } // Update the intersection, moving vehicles if necessary. // Each vehicle exits the intersection through the segment opposite its entry. // If there is no segment there, the vehicle "disappears". void Intersection::tick() { // For each entering segment, need to dequeue waiting vehicles Direction dir; int i; for (i = 0, dir = North; i < NumDirections; i++, dir = nextDir(dir)) { RoadSegment *cur = segments[dir][Entry]; if (cur != NULL && cur->vehicleWaiting()) { Vehicle *v; // waiting vehicle bool go; // true if the vehicle should be moved // Move vehicle to opposite segment, if possible RoadSegment *opp = segments[oppositeDir(dir)][Exit]; go = ((opp == NULL) || opp->canEnqueue()); if (go) { v = cur->dequeue(); if (opp != NULL) opp->enqueue(v); else delete v; } } } } // Set the position of the intersection. // This must be done before any other operation (unless the x,y constructor // was used, in which case the position is already set). // Precondition: the position was not set yet. void Intersection::setCenter(Position center) { this->center = center; } // Connects the given road segment as entry or exit at the given direction. // Precondition: there is no segment connected there already. void Intersection::connectRoad(RoadSegment *roadSeg, Direction dir, int entryOrExit) { assert (roadSeg != NULL); assert (entryOrExit == Entry || entryOrExit == Exit); assert (validDir(dir)); assert (segments[dir][entryOrExit] == NULL); // do the necessary connections segments[dir][entryOrExit] = roadSeg; roadSeg->setIntersection(this, swapEntryExit(entryOrExit)); // Place new road segment. // Do all computations as if direction is North. We'll fix it later. int x; // entry or exit corner X coordinate (assuming dir = North). x = center.getX(); if (entryOrExit == Exit) x = getBorder(East); // Fix corner position to match segment direction, and place segment. Position corner = Position(x, getBorder(North)); corner.rotate(center, dir); roadSeg->setCorner(corner, swapEntryExit(entryOrExit)); } // Returns the x or y coordinate at the intersection's border on the // specified direction. E.g. if dir = NORTH, returns the y value for the // northern border of the intersection; if dir = EAST, returns the x value // for the eastern border. int Intersection::getBorder(Direction dir) const { assert (validDir(dir)); switch (dir) { case North: return center.getY() + RoadWidth; case East: return center.getX() + RoadWidth; case South: return center.getY() - RoadWidth; case West: return center.getX() - RoadWidth; } return 0; // for compiler's benefit. should never get here. } // Returns the center of this intersection Position Intersection::getCenter() const { return center; }