📄 citymap.cs
字号:
using System;
using System.IO;
using System.Collections;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization.Formatters.Binary;
namespace WindowsApplication2
{
/// <summary>
/// The object that stores, loads, and saves map data.
/// </summary>
public class CityMap
{
private Scaler Map_Scale = new Scaler();
private ArrayList streetSegs = new ArrayList();
private IntersectionList intersections;
private Random r;
private int segCount, min_X, min_Y, max_X, max_Y;
public CityMap()
{
//Initialize here to take advantage of good pseudo-random series
//Seed is different for each map
r = new Random();
segCount = 0;
min_X = Int32.MaxValue;
min_Y = Int32.MaxValue;
max_X = Int32.MinValue;
max_Y = Int32.MinValue;
}
#region FHB file manipulation
public void SaveMap(string fileName)
{//Saves the Map and all associated data in a binary format that can be easily loaded
ArrayList array = new ArrayList();
array.Add(streetSegs);
array.Add(intersections);
array.Add(r);
array.Add(segCount);
array.Add(new Point(min_X,min_Y));
array.Add(new Point(max_X,max_Y));
array.Add(Map_Scale);
Stream stream = File.Open(fileName, FileMode.OpenOrCreate);
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, array); // serialize the arraylist to the output stream here
stream.Close();
}
public void LoadMap(string fileName)
{//Load from a file created as above
Stream stream = File.Open(fileName, FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
ArrayList array = (ArrayList) bf.Deserialize(stream); // deserialize the file to the object (must cast)
stream.Close();
streetSegs = (ArrayList)array[0];
intersections = (IntersectionList)array[1];
r = (Random)array[2];
segCount = (int)array[3];
min_X = ((Point)array[4]).X;
min_Y = ((Point)array[4]).Y;
max_X = ((Point)array[5]).X;
max_Y = ((Point)array[5]).Y;
Map_Scale = (Scaler)array[6];
}
#endregion
#region CSV file manipulation
public void ImportMap(StreamReader data)
{//Needs expansion (and a helper form) to allow flexibility
string myInputstring;
try
{
myInputstring = data.ReadLine();
//Help align if file is a CSV
//First line is ignored because it contains headers in my CSV file
myInputstring = data.ReadLine();
while (myInputstring != null)
{
string[] dataCells = myInputstring.Split(",".ToCharArray());
MapSeg toAdd = new MapSeg(ParseInt(dataCells[1]),
ParseInt(dataCells[2]), ParseInt(dataCells[3]),ParseInt(dataCells[4]));
toAdd.StreetName = dataCells[5];
if (Math.Max(toAdd.from.X,toAdd.to.X)>max_X)
max_X = Math.Max(toAdd.from.X,toAdd.to.X);
if (Math.Min(toAdd.from.X,toAdd.to.X)<min_X)
min_X = Math.Min(toAdd.from.X,toAdd.to.X);
if (Math.Max(toAdd.from.Y,toAdd.to.Y)>max_Y)
max_Y = Math.Max(toAdd.from.Y,toAdd.to.Y);
if (Math.Min(toAdd.from.Y,toAdd.to.Y)<min_Y)
min_Y = Math.Min(toAdd.from.Y,toAdd.to.Y);
streetSegs.Add(toAdd);
segCount++;
myInputstring = data.ReadLine();
}
MessageBox.Show("CitySim has successfully loaded "+segCount+" Street Segments."+Environment.NewLine
+"Data Range: ("+min_X+","+min_Y+") to ("+max_X+","+max_Y+")","Load Successful");
}
catch(Exception exc)
{
// Show the error to the user.
MessageBox.Show("File could not be opened or read." + Environment.NewLine +
"Please verify that the filename is correct, and that it is properly formatted." + Environment.NewLine +
"Exception: " + exc.Message);
}
finally
{
// Close the object if it has been created.
if (data != null)
{
data.Close();
}
}
//All segments have been added, and Intersections must be discovered
intersections = new IntersectionList(max_X,min_X);
for (int i=0;i<segCount;i++)
{
MapSeg toLoad = (MapSeg)streetSegs[i];
int index = intersections.pointSearch(toLoad.from);
if (index < 0)
{
intersections.Add(new Intersection(toLoad.from,i));
toLoad.From_Intersection = intersections.Count-1;
}
else
{
Intersection found = (Intersection)intersections[index];
found.addConnection(i);
toLoad.From_Intersection = index;
}
index = intersections.pointSearch(toLoad.to);
if (index < 0)
{
intersections.Add(new Intersection(toLoad.to,i));
toLoad.To_Intersection = intersections.Count-1;
}
else
{
Intersection found = (Intersection)intersections[index];
found.addConnection(i);
toLoad.To_Intersection = index;
}
}
MessageBox.Show("Intersections successfully discovered."+Environment.NewLine+
"City Sim has discovered and logged "+intersections.Count+" intersections."+Environment.NewLine+
"");//"The shortest distance between two intersections is: "+intersections.shortestDist());
Map_Scale.setRange(max_X,max_Y,min_X,min_Y);
//Finally, intersections must be analyzed for thruStreets. Reporting is currently commented out.
int [] totals = new int [30];
int [] results = new int [30];
for (int i=0;i<intersections.Count;i++)
{
Intersection toComplete = (Intersection)intersections[i];
totals[toComplete.getConnections.Count]++;
results[toComplete.analyze(this)]++;
}
/*string toDisplay = "Intersections Analyzed"+Environment.NewLine+"Successes: "+results[0]+Environment.NewLine;
toDisplay += "Failures:"+Environment.NewLine;
for (int i=1; i<totals.Length;i++)
{
toDisplay += i+": "+results[i]+" of "+totals[i]+Environment.NewLine;
}
MessageBox.Show (toDisplay);*/
}
#endregion
#region Simple Properties
public int getRandomMapSeg()
{
return r.Next(segCount);
}
public IntersectionList getIntersectionList
{
get {return intersections;}
}
public Scaler scale
{
get{return Map_Scale;}
set{Map_Scale = value;}
}
public MapSeg getSegment (int id)
{
return (MapSeg)streetSegs[id];
}
#endregion
public void PrepareSim()
{//Initalize values, so multiple simulations can be run each session
for (int i=0;i<streetSegs.Count;i++)
{
((MapSeg)streetSegs[i]).visits = 0;
((MapSeg)streetSegs[i]).clearCars();
}
}
public void SortCars()
{//Allows the Drive function to assume that cars in MapSegs are sorted
for (int i=0;i<streetSegs.Count;i++)
this.getSegment(i).SortCars();
}
public void TestConnections()
{//Debug only: Proves that maps are imported correctly
int from = 0;
int to = 0;
for (int i=0; i<streetSegs.Count;i++)
{
MapSeg cur = (MapSeg)streetSegs[i];
Intersection f_int = (Intersection)intersections[(int)cur.From_Intersection];
Intersection t_int = (Intersection)intersections[(int)cur.To_Intersection];
if(!f_int.checkConnection(i)){from++;}
if(!t_int.checkConnection(i)){to++;}
}
MessageBox.Show("Errors: From = "+from+" and To = "+to);
}
public void drawMap (Graphics g, bool colorLines)
{//Draws the map, Colors post-simulation report appropriately
int MaxVisits = 0;
Pen myPen = new Pen (Color.White,2);
if (colorLines)
{
for (int i=0;i<streetSegs.Count;i++)
{
MapSeg toCheck = getSegment(i);
if (toCheck.visits > MaxVisits)
MaxVisits = toCheck.visits;
}
myPen.Width = 4;
}
g.SmoothingMode = SmoothingMode.HighQuality;
for(int i=0;i<segCount;i++)
{
MapSeg needToDraw = (MapSeg)streetSegs[i];
if (colorLines)
{
double percentage = needToDraw.visits/(double)MaxVisits;
if (percentage == 0)
continue;
else if (percentage <=0.1)
myPen.Color = Color.LightGray;
else if (percentage <= 0.25)
myPen.Color = Color.Orange;
else if (percentage <= 0.5)
myPen.Color = Color.Green;
else
myPen.Color = Color.Red;
}
g.DrawLine(myPen,Map_Scale.translate(needToDraw.from),Map_Scale.translate(needToDraw.to));
}
}
public ArrayList getBlocks (PointF Oldp1, PointF Oldp2, int mode)
{//Generates the list of blocks analyzed by the City_Blocks Form
ArrayList toReturn = new ArrayList();
Point p1 = scale.revert(Oldp1);
Point p2 = scale.revert(Oldp2);
int MXX = Math.Max(p1.X,p2.X);
int MXY = Math.Max(p1.Y,p2.Y);
int MNX = Math.Min(p1.X,p2.X);
int MNY = Math.Min(p1.Y,p2.Y);
double slope = (p1.Y - p2.Y)/(double)(p1.X - p2.X);
int fudge = 1000;
for (int i=0; i<streetSegs.Count;i++)
{
MapSeg cur = (MapSeg)streetSegs[i];
switch(mode)
{
case Form1.SELECT_BOX:
if (cur.max_X() <= MXX && cur.max_Y() <= MXY && cur.min_X() >= MNX
&& cur.min_Y() >= MNY)
{
toReturn.Add (i);
}
break;
case Form1.SELECT_LINE:
double yVal = slope * (cur.from.X - p1.X) + p1.Y;
if (cur.max_X() <= MXX && cur.max_Y() <= MXY && cur.min_X() >= MNX
&& cur.min_Y() >= MNY)
{
/*MessageBox.Show("From: ("+p1.X+","+p1.Y+")"+Environment.NewLine+
"To: ("+p2.X+","+p2.Y+")"+Environment.NewLine+
"Slope: "+slope+Environment.NewLine+
"yVal 1: "+yVal+Environment.NewLine+
"Real Y: "+cur.from.Y+Environment.NewLine+
"Real X: "+cur.from.X+Environment.NewLine);*/
if (cur.from.Y <= yVal + fudge && cur.from.Y >= yVal - fudge)
{
toReturn.Add (i);
break;
}
yVal = slope * (cur.to.X - p1.X) + p1.Y;
if (cur.to.Y <= yVal + fudge && cur.to.Y >= yVal - fudge)
{toReturn.Add (i);}
}
break;
}
}
MessageBox.Show ("Found "+toReturn.Count+" City Blocks");
return toReturn;
}
public ArrayList getIntersections (PointF Oldp1, PointF Oldp2, int mode)
{//Generates the list of intersections to be analyzed by one of the other two forms
ArrayList toReturn = new ArrayList();
Point p1 = scale.revert(Oldp1);
Point p2 = scale.revert(Oldp2);
int MXX = Math.Max(p1.X,p2.X);
int MXY = Math.Max(p1.Y,p2.Y);
int MNX = Math.Min(p1.X,p2.X);
int MNY = Math.Min(p1.Y,p2.Y);
double slope = (p1.Y - p2.Y)/(double)(p1.X - p2.X);
int fudge = 1000;
double min_dist = Double.MaxValue;
for (int i=0; i<intersections.Count;i++)
{
Intersection cur = (Intersection)intersections[i];
switch(mode)
{
case Form1.SELECT_BOX:
if (cur.getPoint.X <= MXX && cur.getPoint.Y <= MXY && cur.getPoint.X >= MNX
&& cur.getPoint.Y >= MNY)
{
toReturn.Add (i);
}
break;
case Form1.SELECT_LINE:
double yVal = slope * (cur.getPoint.X - p1.X) + p1.Y;
if (cur.getPoint.X <= MXX && cur.getPoint.Y <= MXY && cur.getPoint.X >= MNX
&& cur.getPoint.Y >= MNY)
{
/*MessageBox.Show("From: ("+p1.X+","+p1.Y+")"+Environment.NewLine+
"To: ("+p2.X+","+p2.Y+")"+Environment.NewLine+
"Slope: "+slope+Environment.NewLine+
"yVal 1: "+yVal+Environment.NewLine+
"Real Y: "+cur.from.Y+Environment.NewLine+
"Real X: "+cur.from.X+Environment.NewLine);*/
if (cur.getPoint.Y <= yVal + fudge && cur.getPoint.Y >= yVal - fudge)
{toReturn.Add (i);}
}
break;
case Form1.SELECT_POINT:
double xdiff = cur.getPoint.X - p2.X;
double ydiff = cur.getPoint.Y - p2.Y;
double dist = Math.Sqrt(xdiff * xdiff + ydiff * ydiff);
if (dist < min_dist)
{
//MessageBox.Show("Dist: "+dist+" Min: "+min_dist);
min_dist = dist;
toReturn.Clear();
toReturn.Add(i);
}
break;
}
}
MessageBox.Show ("Found "+toReturn.Count+" Intersections");
return toReturn;
}
public void reRandomize()
{//Because the randomization object is saved in .FHB files, this is the way to
//run new random simulations on a previously saved map.
r = new Random();
}
#region Integer Parsing
private int ParseInt(string str)
{
char[] chars = str.ToCharArray();
string numeric = "";
int round = 0;
for(int i=0; i<chars.Length; i++)
{
if (chars[i] == '.')
{
try
{
if (CharIsNumeric(chars[i+1])&& Convert.ToInt32(chars[i+1]) >= 53)
round = 1;
}
catch {;}//if there is no following character, round down
break;
}
else if(CharIsNumeric(chars[i]))
{
numeric += Convert.ToString(chars[i]);
}
}
if(numeric != "")
return Convert.ToInt32(numeric)+round;
else
return 0;
}
private bool CharIsNumeric(char c)
{
int charCode = Convert.ToInt32(c);
if(charCode > 47 && charCode < 58)
return true;
else
return false;
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -