📄 car.cs
字号:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
namespace WindowsApplication2
{
/// <summary>
/// Each Car object represents an individual car. It contains the
/// Drive() function and is designed to store data on its movements
/// which can be used for later reporting.
/// </summary>
public class Car
{
public const int WRONG_DIRECTION = -1;
public const int STUCK_AT_INTERSECTION = 1;
public const int GOAL_REACHED = 2;
public const int NEW_SEGMENT = 3;
public const int FINAL_BLOCK = 4;
private Point location; //Where the Car is
private readonly Point start, goal; //Where the Car started and is going
private int segID,lastStep; //Sement Car is on and last tick car was driven on
private readonly int endID; //Index number of the target segment
private readonly int myID; //Car's ID number
private double distTravelled; //Semi-accurate accounting of distance driven
private readonly double totalDist; //Distance(start,goal)
private SolidBrush carColor; //Used to draw cars, never changed from Blue
private readonly MapSeg startSeg,endSeg; //Segments car starts and ends on
private ArrayList shortestPath; //Ordered list of intersections car must visit
public Car(CityMap myMap, int carID)
{
myID = carID;
lastStep = 0;
segID = myMap.getRandomMapSeg();
startSeg = myMap.getSegment(segID);
location = startSeg.getRandomPoint();
start = new Point(location.X,location.Y);
endID = myMap.getRandomMapSeg();
endSeg = myMap.getSegment(endID);
goal = endSeg.getRandomPoint();
distTravelled = 0;
carColor = new SolidBrush (Color.Blue);
totalDist = Distance(start,goal);
shortestPath = new ArrayList();
}
private double Distance(Point a, Point b)
{
double xdiff = a.X - b.X;
double ydiff = a.Y - b.Y;
return Math.Sqrt(xdiff * xdiff + ydiff * ydiff);
}
#region Simple Properties
public Point getStartPoint
{
get {return start;}
}
public int getDriveCount
{
get {return lastStep;}
}
public Point getGoalPoint
{
get {return goal;}
}
public MapSeg getStartSeg
{
get{return startSeg;}
}
public MapSeg getGoalSeg
{
get{return endSeg;}
}
public Point getLocation
{
get{return location;}
}
public ArrayList path
{
get {return shortestPath;}
set
{
shortestPath = value;
if (value != null)
startSeg.PushCar(this, getFromTo(startSeg));
}
}
public int getID
{
get {return myID;}
}
public int getNextIntersection
{
get {return (int)shortestPath[0];}
}
#endregion
public void Draw (Graphics g, Scaler myScale)
{
PointF myPoint = myScale.translate(location);
g.FillEllipse(carColor,myPoint.X-3,myPoint.Y-3,6.0f,6.0f);
}
public int Drive (CityMap myMap)
{//Allows simple calling from Form1, internal function is for recursion
return Drive(myMap,-1);
}
private int Drive (CityMap myMap, double dist)
{
lastStep++;
MapSeg currSeg = myMap.getSegment(segID);
currSeg.drivePreviousCars(myID,lastStep,getFromTo(myMap),myMap);
if (dist < 0)
{//called from Form1
dist = (1/52.8/25)* currSeg.SpeedLimit * myMap.scale.UnitsPerMile;
dist = CongestionAdjust(dist, getFromTo(myMap), myMap.getSegment(segID));
}
//check if on last block
if (shortestPath.Count == 0)
{
if (Distance(location,goal) <= dist)
return GOAL_REACHED;
else
location = moveInSeg(location,goal,currSeg,dist);
}
else
{
Point target = (currSeg.From_Intersection==(int)shortestPath[0])? currSeg.from:currSeg.to;
//Intersection Reached
if (Distance(location,target) < dist)
{
Intersection at = (Intersection)myMap.getIntersectionList[(int)shortestPath[0]];
bool thru = at.isThru(segID, (int)shortestPath[0]);
int passable = at.canGo(segID,lastStep);
if (thru && passable == 1)
{//Keep on truckin'
currSeg.RemoveCar(segID,getFromTo(myMap));
if (shortestPath.Count > 1)
segID = at.findSeg(myMap,(int)shortestPath[1]);
else
segID = endID;
currSeg = myMap.getSegment(segID);
shortestPath.RemoveAt(0);
location = getFromTo(myMap)? currSeg.from : currSeg.to;
currSeg.PushCar(this,getFromTo(myMap));
return Drive(myMap, dist - Distance(location,target));
}
else if (passable == -1)
{//Red Light, don't bother going back
location = getFromTo(myMap)? currSeg.to : currSeg.from;
return 0;
}
else
{//Either turning or stop sign (or both)
location = getFromTo(myMap)? currSeg.to : currSeg.from;
return STUCK_AT_INTERSECTION;
}
}
else //On an intermediate block out of reach of an intersection
location = moveInSeg(location,target,currSeg,dist);
}
distTravelled += dist;
return 0;
}
public void passThruIntersection(CityMap myMap)
{//Called on phase 2 of Form1's timer_tick function, passes the car through
// the intersection it is stuck on.
MapSeg currSeg = myMap.getSegment(segID);
Intersection at = (Intersection)myMap.getIntersectionList[(int)shortestPath[0]];
currSeg.RemoveCar(myID,getFromTo(myMap));
if (shortestPath.Count > 1)
segID = at.findSeg(myMap,(int)shortestPath[1]);
else
segID = endID;
currSeg = myMap.getSegment(segID);
shortestPath.RemoveAt(0);
location = getFromTo(myMap)? currSeg.from : currSeg.to;
currSeg.PushCar(this,getFromTo(myMap));
}
private Point moveInSeg(Point loc, Point goal, MapSeg curr, double dist)
{//Advances the car along the line defined by curr
// The function appears to fail occasionally, as the commented exception does fire
Point newLoc = new Point();
double Z = dist/Math.Sqrt((curr.to.X - curr.from.X)*(curr.to.X - curr.from.X)
+ (curr.to.Y - curr.from.Y)*(curr.to.Y - curr.from.Y));
newLoc.X = (int)(loc.X + Z * (curr.to.X - curr.from.X));
newLoc.Y = (int)(loc.Y + Z * (curr.to.Y - curr.from.Y));
if (Distance(newLoc,goal) > Distance(loc,goal))
{
newLoc.X = (int)(loc.X - Z * (curr.to.X - curr.from.X));
newLoc.Y = (int)(loc.Y - Z * (curr.to.Y - curr.from.Y));
}
double inline = Distance (loc, newLoc) + Distance (newLoc, goal);
if (inline * 1.1 > Distance (loc, goal) && inline * 0.9 < Distance (loc,goal))
return newLoc;
else
//throw (new Exception("New location is not on the appropriate block: "+inline+" vs "+Distance (loc, goal)));
return newLoc;
}
private double CongestionAdjust (double dist, bool fromTo, MapSeg mySeg)
{//Limits the car's movement so that it doesn't run over the cars in front of it
Point max_move = mySeg.getCarPosition(myID, fromTo);
if (max_move.X == 0 && max_move.Y == 0)
return dist;
return Math.Min(Math.Max(Distance (max_move,location)-15,0),dist);
}
private bool getFromTo(CityMap myMap)
{//Decides which direction the car is moving on the current map segment
return getFromTo(myMap.getSegment(segID));
}
private bool getFromTo(MapSeg s)
{
if (shortestPath.Count >= 1)
return (s.To_Intersection == (int)shortestPath[0]);
return (Distance(s.from,location) < Distance (s.from,goal));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -