- Timestamp:
- Apr 12, 2015, 12:08:05 AM (10 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/BigMetro.lpi
r24 r25 69 69 </Item1> 70 70 </RequiredPackages> 71 <Units Count=" 4">71 <Units Count="5"> 72 72 <Unit0> 73 73 <Filename Value="BigMetro.lpr"/> … … 92 92 <UnitName Value="UGeometric"/> 93 93 </Unit3> 94 <Unit4> 95 <Filename Value="UTrack.pas"/> 96 <IsPartOfProject Value="True"/> 97 <UnitName Value="UTrack"/> 98 </Unit4> 94 99 </Units> 95 100 </ProjectOptions> … … 119 124 <StackChecks Value="True"/> 120 125 </Checks> 121 <VerifyObjMethodCallValidity Value="True"/>122 126 </CodeGeneration> 123 127 <Linking> -
trunk/BigMetro.lpr
r20 r25 8 8 {$ENDIF}{$ENDIF} 9 9 Interfaces, // this includes the LCL widgetset 10 Forms, SysUtils, UFormMain, UEngine, UGeometric 10 Forms, SysUtils, UFormMain, UEngine, UGeometric, UTrack 11 11 { you can add units after this }; 12 12 -
trunk/UEngine.pas
r24 r25 24 24 TMapStation = class 25 25 private 26 procedure ShiftTrackPoints; 27 procedure SortLines; 26 28 public 27 29 Engine: TEngine; … … 63 65 LineStation: TLineStation; 64 66 Point: TPoint; 67 PointShift: TPoint; 68 DesignedPoint: TPoint; 65 69 Pending: Boolean; 66 70 function GetDown: TTrackPoint; … … 72 76 end; 73 77 74 TTrack = record78 TTrack = class 75 79 PointDown: TTrackPoint; 76 80 PointUp: TTrackPoint; 81 Line: TMetroLine; 82 Shift: TPoint; 83 end; 84 85 { TTracks } 86 87 TTracks = class(TObjectList) 88 function SearchPointUp(TrackPoint: TTrackPoint; Skip: TTrack): TTrack; 89 function SearchPointDown(TrackPoint: TTrackPoint; Skip: TTrack): TTrack; 90 end; 91 92 { TTrackPointsAngle } 93 94 TTrackPointsAngle = class 95 Angle: Double; 96 Tracks: TTracks; 97 constructor Create; 98 destructor Destroy; override; 99 end; 100 101 { TTrackPointsAngleGroup } 102 103 TTrackPointsAngleGroup = class(TObjectList) 104 function SearchAngle(Angle: Double): TTrackPointsAngle; 77 105 end; 78 106 … … 83 111 procedure UpdateEndingLines; 84 112 public 113 Index: Integer; 85 114 Engine: TEngine; 86 115 Color: TColor; … … 189 218 procedure TrainMovement; 190 219 function GetUnusedLine: TMetroLine; 220 procedure ShiftTrackPoints; 191 221 public 192 222 Passengers: TMetroPassengers; … … 231 261 StationMaxDistance = 300; 232 262 MaxWaitingPassengers = 10; 233 MaxPassengersOveloadTime = 1;263 MaxPassengersOveloadTime = 2; 234 264 MetroLineThickness = 13; 235 265 TrackClickDistance = 20; … … 238 268 //TimePerSecond = (60 * OneMinute); 239 269 TimePerSecond = (60 * OneMinute); 270 NewStationPeriod = 1; 271 NewShapePeriod = 10; 272 NewTrainPeriod = 7; // Each week 273 NewPassengerPeriod = 0.3 * OneSecond; 274 NewPassengerProbability = 0.002; 240 275 241 276 implementation … … 243 278 uses 244 279 UGeometric; 280 281 { TTracks } 282 283 function TTracks.SearchPointUp(TrackPoint: TTrackPoint; Skip: TTrack): TTrack; 284 var 285 I: Integer; 286 begin 287 I := 0; 288 while (I < Count) and (TTrack(Items[I]).PointUp <> TrackPoint) and (TTrack(Items[I]) <> Skip) do Inc(I); 289 if I < Count then Result := TTrack(Items[I]) 290 else Result := nil; 291 end; 292 293 function TTracks.SearchPointDown(TrackPoint: TTrackPoint; Skip: TTrack): TTrack; 294 var 295 I: Integer; 296 begin 297 I := 0; 298 while (I < Count) and (TTrack(Items[I]).PointDown <> TrackPoint) and (TTrack(Items[I]) <> Skip) do Inc(I); 299 if I < Count then Result := TTrack(Items[I]) 300 else Result := nil; 301 end; 302 303 { TTrackPointsAngleGroup } 304 305 function TTrackPointsAngleGroup.SearchAngle(Angle: Double): TTrackPointsAngle; 306 var 307 I: Integer; 308 begin 309 I := 0; 310 while (I < Count) and (TTrackPointsAngle(Items[I]).Angle <> Angle) do Inc(I); 311 if I < Count then Result := TTrackPointsAngle(Items[I]) 312 else Result := nil; 313 end; 314 315 { TTrackPointsAngle } 316 317 constructor TTrackPointsAngle.Create; 318 begin 319 Tracks := TTracks.Create; 320 Tracks.OwnsObjects := False; 321 end; 322 323 destructor TTrackPointsAngle.Destroy; 324 begin 325 Tracks.Free; 326 inherited Destroy; 327 end; 245 328 246 329 { TTrackPoint } … … 357 440 Result.Color := LineColors[Count]; 358 441 Result.Engine := Engine; 442 Result.Index := Count; 359 443 Add(Result); 360 444 end; … … 398 482 Round(TTrackPoint(TrackPoints[1]).Point.Y - EndStationLength * Sin(Angle))); 399 483 TTrackPoint(TrackPoints.First).Point := EndPoint; 484 TTrackPoint(TrackPoints.First).DesignedPoint := EndPoint; 400 485 401 486 Angle := arctan2((TTrackPoint(TrackPoints[TrackPoints.Count - 2]).Point.Y - TTrackPoint(TrackPoints[TrackPoints.Count - 3]).Point.Y), … … 404 489 Round(TTrackPoint(TrackPoints[TrackPoints.Count - 2]).Point.Y + EndStationLength * Sin(Angle))); 405 490 TTrackPoint(TrackPoints.Last).Point := EndPoint; 491 TTrackPoint(TrackPoints.Last).DesignedPoint := EndPoint; 406 492 end; 407 493 end; … … 430 516 NewTrackPoint.LineStation := NewLineStation; 431 517 NewTrackPoint.Point := Station.Position; 518 NewTrackPoint.DesignedPoint := NewTrackPoint.Point; 432 519 NewTrackPoint.Line := TrackPoints.Line; 433 520 Index := 0; … … 453 540 UpdateEndingLines; 454 541 Engine.ComputeShapeDistance; 542 Engine.ShiftTrackPoints; 455 543 end; 456 544 … … 491 579 UpdateEndingLines; 492 580 Engine.ComputeShapeDistance; 581 Engine.ShiftTrackPoints; 493 582 end; 494 583 … … 510 599 if Abs(Delta.X) > Abs(Delta.Y) then begin 511 600 NewTrackPoint.Point := Point(P2.X - Sign(Delta.X) * Abs(Delta.Y), P1.Y); 601 NewTrackPoint.DesignedPoint := NewTrackPoint.Point; 512 602 end else begin 513 603 NewTrackPoint.Point := Point(P1.X, P2.Y - Sign(Delta.Y) * Abs(Delta.X)); 604 NewTrackPoint.DesignedPoint := NewTrackPoint.Point; 514 605 end; 515 606 TrackPoints.Insert(Index1 + 1, NewTrackPoint); … … 650 741 651 742 { TMapStation } 743 744 procedure TMapStation.ShiftTrackPoints; 745 var 746 Tracks: TTracks; 747 I: Integer; 748 J: Integer; 749 Index: Integer; 750 TP: TTrackPoint; 751 LS: TLineStation; 752 Line: TMetroLine; 753 Angle: Double; 754 TPAngleGroup: TTrackPointsAngleGroup; 755 GroupItem: TTrackPointsAngle; 756 NewTrack: TTrack; 757 HAngle: Double; 758 PairTrack: TTrack; 759 NewPoint: TPoint; 760 begin 761 Tracks := TTracks.Create; 762 763 // Collect all near track points as track 764 SortLines; 765 for I := 0 to Lines.Count - 1 do begin 766 Line := TMetroLine(Lines[I]); 767 LS := Line.LineStations.SearchMapStation(Self); 768 TP := LS.TrackPoint; 769 Index := Line.TrackPoints.IndexOf(TP); 770 if Index > 0 then begin 771 NewTrack := TTrack.Create; 772 NewTrack.PointDown := TTrackPoint(Line.TrackPoints[Index - 1]); 773 NewTrack.PointUp := TTrackPoint(Line.TrackPoints[Index]); 774 Tracks.Add(NewTrack); 775 end; 776 if Index < (Line.TrackPoints.Count - 1) then begin 777 NewTrack := TTrack.Create; 778 NewTrack.PointDown := TTrackPoint(Line.TrackPoints[Index + 1]); 779 NewTrack.PointUp := TTrackPoint(Line.TrackPoints[Index]); 780 Tracks.Add(NewTrack); 781 end; 782 end; 783 784 // Make groups of tracks with same angle 785 TPAngleGroup := TTrackPointsAngleGroup.Create; 786 for I := 0 to Tracks.Count - 1 do begin 787 Angle := ArcTan2(TTrack(Tracks[I]).PointDown.DesignedPoint.Y - Position.Y, 788 TTrack(Tracks[I]).PointDown.DesignedPoint.X - Position.X); 789 GroupItem := TPAngleGroup.SearchAngle(Angle); 790 if not Assigned(GroupItem) then begin 791 GroupItem := TTrackPointsAngle.Create; 792 GroupItem.Angle := Angle; 793 TPAngleGroup.Add(GroupItem); 794 end; 795 GroupItem.Tracks.Add(TTrack(Tracks[I])) 796 end; 797 798 // Shift tracks according number of lines in group 799 for I := 0 to TPAngleGroup.Count - 1 do 800 with TTrackPointsAngle(TPAngleGroup[I]) do begin 801 for J := 0 to Tracks.Count - 1 do 802 with TTrack(Tracks[J]) do begin 803 // Get orthogonal angle 804 HAngle := Angle + Pi / 2; 805 if HAngle > Pi then HAngle := Hangle - Pi; 806 Shift.X := Trunc(MetroLineThickness * Cos(HAngle) * (J - (Tracks.Count - 1) / 2)); 807 Shift.Y := Trunc(MetroLineThickness * Sin(HAngle) * (J - (Tracks.Count - 1) / 2)); 808 PointDown.PointShift := Shift; 809 PointUp.PointShift := Shift; 810 end; 811 end; 812 813 TPAngleGroup.Free; 814 Tracks.Free; 815 end; 816 817 function MapStationCompareLine(Item1, Item2: Pointer): Integer; 818 begin 819 if TMetroLine(Item1).Index > TMetroLine(Item2).Index then Result := 1 820 else if TMetroLine(Item1).Index < TMetroLine(Item2).Index then Result := -1 821 else Result := 0; 822 end; 823 824 procedure TMapStation.SortLines; 825 begin 826 Lines.Sort(MapStationCompareLine); 827 end; 652 828 653 829 function TMapStation.IsBestStationForShape(Shape: TStationShape; … … 756 932 MinD: Integer; 757 933 begin 934 Result := TTrack.Create; 758 935 Result.PointDown := nil; 759 936 Result.PointUp := nil; … … 926 1103 if DirectionUp then begin 927 1104 if StationIndex = 0 then 928 ComputeShapeDistanceStation(TLineStation(LineStations[ Stations.Count - 2]).MapStation,1105 ComputeShapeDistanceStation(TLineStation(LineStations[LineStations.Count - 2]).MapStation, 929 1106 UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1); 930 1107 if StationIndex > 0 then … … 1063 1240 end; 1064 1241 1242 procedure TEngine.ShiftTrackPoints; 1243 var 1244 I: Integer; 1245 J: Integer; 1246 L: Integer; 1247 Link1, Link2: TPoint; 1248 NewPoint: TPoint; 1249 begin 1250 // Reset all trackpoints position shift 1251 for I := 0 to Lines.Count - 1 do 1252 with TMetroLine(Lines[I]) do 1253 for J := 0 to TrackPoints.Count - 1 do 1254 TTrackPoint(TrackPoints[J]).Point := TTrackPoint(TrackPoints[J]).DesignedPoint; 1255 1256 // Calculate new position shifts 1257 for I := 0 to Stations.Count - 1 do 1258 TMapStation(Stations[I]).ShiftTrackPoints; 1259 1260 // Compute track points from track shift 1261 for L := 0 to Lines.Count - 1 do 1262 with TMetroLine(Lines[L]) do begin 1263 if TrackPoints.Count > 0 then 1264 TTrackPoint(TrackPoints[0]).Point := AddPoint(TTrackPoint(TrackPoints[0]).DesignedPoint, 1265 TTrackPoint(TrackPoints[0]).PointShift); 1266 for I := 1 to TrackPoints.Count - 1 do 1267 with TTrackPoint(TrackPoints[I]) do begin 1268 Link1 := SubPoint(AddPoint(TTrackPoint(TrackPoints[I]).DesignedPoint, TTrackPoint(TrackPoints[I]).PointShift), 1269 AddPoint(TTrackPoint(TrackPoints[I - 1]).DesignedPoint, TTrackPoint(TrackPoints[I - 1]).PointShift)); 1270 if (I + 1) < TrackPoints.Count then 1271 Link2 := SubPoint(AddPoint(TTrackPoint(TrackPoints[I + 1]).DesignedPoint, TTrackPoint(TrackPoints[I + 1]).PointShift), 1272 AddPoint(TTrackPoint(TrackPoints[I]).DesignedPoint, TTrackPoint(TrackPoints[I]).PointShift)) 1273 else Link2 := Link1; 1274 1275 if ArcTanPoint(Link1) = ArcTanPoint(Link2) then begin 1276 // Parallel lines 1277 TTrackPoint(TrackPoints[I]).Point := AddPoint(TTrackPoint(TrackPoints[I]).DesignedPoint, 1278 TTrackPoint(TrackPoints[I]).PointShift); 1279 end else begin 1280 // Intersected lines 1281 NewPoint := LineIntersect(AddPoint(TTrackPoint(TrackPoints[I - 1]).DesignedPoint, TTrackPoint(TrackPoints[I - 1]).PointShift), 1282 AddPoint(TTrackPoint(TrackPoints[I]).DesignedPoint, TTrackPoint(TrackPoints[I]).PointShift), 1283 AddPoint(TTrackPoint(TrackPoints[I]).DesignedPoint, TTrackPoint(TrackPoints[I]).PointShift), 1284 AddPoint(TTrackPoint(TrackPoints[I + 1]).DesignedPoint, TTrackPoint(TrackPoints[I + 1]).PointShift)); 1285 TTrackPoint(TrackPoints[I]).Point := NewPoint; 1286 end; 1287 end; 1288 end; 1289 1290 end; 1291 1065 1292 procedure TEngine.DrawClock(Canvas: TCanvas); 1066 1293 var … … 1130 1357 1131 1358 procedure TEngine.Tick; 1132 const1133 NewStationPeriod = 1;1134 NewShapePeriod = 10;1135 NewTrainPeriod = 7; // Each week1136 NewPassengerPeriod = 0.3 * OneSecond;1137 NewPassengerProbability = 0.005;1138 1359 var 1139 1360 Passenger: TMetroPassenger; … … 1235 1456 Line.DisconnectStation(CurrentTrackPoint.LineStation); 1236 1457 end else 1237 if Assigned(Line) and ((Line.LineStations.SearchMapStation(FocusedStation) = nil) or 1458 if Assigned(Line) and ((not Line.IsCircular) or ((TrackStationDown <> nil) and (TrackStationUp <> nil))) and 1459 ((Line.LineStations.SearchMapStation(FocusedStation) = nil) or 1238 1460 ((Line.LineStations.Count > 0) and 1239 1461 ((TLineStation(Line.LineStations.First).MapStation = FocusedStation) or 1240 (TLineStation(Line.LineStations.Last).MapStation = FocusedStation)))) then begin 1462 (TLineStation(Line.LineStations.Last).MapStation = FocusedStation)) and 1463 ((TrackStationDown = nil) or (TrackStationUp = nil)) and 1464 (not Line.IsCircular))) then begin 1241 1465 if Assigned(TrackStationDown) then LineStationDown := TrackStationDown.LineStation 1242 1466 else LineStationDown := nil; … … 1299 1523 // Line selection 1300 1524 Track := GetTrackOnPos(Position); 1301 if Assigned(Track .PointDown) and Assigned(Track.PointUp) then begin1525 if Assigned(Track) and Assigned(Track.PointDown) and Assigned(Track.PointUp) then begin 1302 1526 SelectedLine := Track.PointDown.Line; 1303 1527 … … 1317 1541 else TrackStationUp := nil; 1318 1542 end; 1319 1543 Track.Free; 1320 1544 Exit; 1321 1545 end; -
trunk/UGeometric.pas
r13 r25 13 13 function Distance(P1, P2: TPoint): Integer; 14 14 function Dot(const P1, P2: TPoint): Double; 15 function AddPoint(const P1, P2: TPoint): TPoint; 15 16 function SubPoint(const P1, P2: TPoint): TPoint; 16 17 function PointToLineDistance(const P, V, W: TPoint): Integer; … … 18 19 function RotatePoint(Center, P: TPoint; Angle: Double): TPoint; 19 20 function RotatePoints(Center: TPoint; P: TPointArray; Angle: Double): TPointArray; 21 function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint): TPoint; 22 function ArcTan2Point(Point: TPoint): Float; 23 function ArcTanPoint(Point: TPoint): Float; 20 24 21 25 implementation … … 29 33 begin 30 34 Result := P1.X * P2.X + P1.Y * P2.Y; 35 end; 36 37 function AddPoint(const P1, P2: TPoint): TPoint; 38 begin 39 Result.X := P1.X + P2.X; 40 Result.Y := P1.Y + P2.Y; 31 41 end; 32 42 … … 88 98 end; 89 99 100 function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint): TPoint; 101 Var 102 LDetLineA, LDetLineB, LDetDivInv: Double; 103 LDiffLA, LDiffLB: TPoint; 104 begin 105 LDetLineA := LineAP1.X * LineAP2.Y - LineAP1.Y * LineAP2.X; 106 LDetLineB := LineBP1.X * LineBP2.Y - LineBP1.Y * LineBP2.X; 107 108 LDiffLA := SubPoint(LineAP1, LineAP2); 109 LDiffLB := SubPoint(LineBP1, LineBP2); 110 111 LDetDivInv := 1 / ((LDiffLA.X * LDiffLB.Y) - (LDiffLA.Y * LDiffLB.X)); 112 113 Result.X := Trunc(((LDetLineA * LDiffLB.X) - (LDiffLA.X * LDetLineB)) * LDetDivInv); 114 Result.Y := Trunc(((LDetLineA * LDiffLB.Y) - (LDiffLA.Y * LDetLineB)) * LDetDivInv); 115 end; 116 117 function ArcTan2Point(Point: TPoint): Float; 118 begin 119 Result := ArcTan2(Point.Y, Point.X); 120 end; 121 122 function ArcTanPoint(Point: TPoint): Float; 123 begin 124 Result := ArcTan(Point.Y / Point.X); 125 end; 90 126 91 127 end.
Note:
See TracChangeset
for help on using the changeset viewer.