Changeset 49


Ignore:
Timestamp:
Nov 26, 2017, 12:32:16 AM (6 years ago)
Author:
chronos
Message:
  • Modified: Use generic object list instead of TObjectList.
  • Fixed: Avoid division by zero in line intersection calculation.
Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/BigMetro.lpr

    r41 r49  
    88  {$ENDIF}
    99  Interfaces, // this includes the LCL widgetset
    10   Forms, SysUtils, UFormMain, UEngine, UGeometric, UTrack, UMetaCanvas,
    11 UFormImages;
     10  Forms, SysUtils, UFormMain, UFormImages;
    1211
    1312{$R *.res}
  • trunk/UEngine.pas

    r44 r49  
    66
    77uses
    8   Classes, SysUtils, Contnrs, Graphics, Controls, ExtCtrls, Math, DateUtils,
    9   UMetaCanvas;
     8  Classes, SysUtils, Graphics, Controls, ExtCtrls, Math, DateUtils,
     9  UMetaCanvas, fgl;
    1010
    1111type
     
    4646  { TMapStations }
    4747
    48   TMapStations = class(TObjectList)
     48  TMapStations = class(TFPGObjectList<TMapStation>)
    4949    Engine: TEngine;
    5050    function GetRect: TRect;
     
    6060  { TLineStations }
    6161
    62   TLineStations = class(TObjectList)
     62  TLineStations = class(TFPGObjectList<TLineStation>)
    6363    Line: TMetroLine;
    6464    function SearchMapStation(Station: TMapStation): TLineStation;
     
    9494  { TTrackPoints }
    9595
    96   TTrackPoints = class(TObjectList)
     96  TTrackPoints = class(TFPGObjectList<TTrackPoint>)
    9797    Track: TTrack;
    9898    function AddNew: TTrackPoint;
     
    111111  { TTrackLinks }
    112112
    113   TTrackLinks = class(TObjectList)
     113  TTrackLinks = class(TFPGObjectList<TTrackLink>)
    114114    Track: TTrack;
    115115    function SearchPoints(Point1, Point2: TTrackPoint): TTrackLink;
     
    129129  { TTracks }
    130130
    131   TTracks = class(TObjectList)
     131  TTracks = class(TFPGObjectList<TTrackLink>)
    132132    function SearchPointUp(TrackPoint: TTrackPoint; Skip: TTrackLink): TTrackLink;
    133133    function SearchPointDown(TrackPoint: TTrackPoint; Skip: TTrackLink): TTrackLink;
     
    145145  { TTrackPointsAngleGroup }
    146146
    147   TTrackPointsAngleGroup = class(TObjectList)
     147  TTrackPointsAngleGroup = class(TFPGObjectList<TTrackPointsAngle>)
    148148    function SearchAngle(Angle: Double): TTrackPointsAngle;
    149149  end;
     
    171171  { TMetroLines }
    172172
    173   TMetroLines = class(TObjectList)
     173  TMetroLines = class(TFPGObjectList<TMetroLine>)
    174174    Engine: TEngine;
    175175    function AddNew: TMetroLine;
     
    204204  { TMetroTrains }
    205205
    206   TMetroTrains = class(TObjectList)
     206  TMetroTrains = class(TFPGObjectList<TMetroTrain>)
    207207    function GetUnusedTrain: TMetroTrain;
    208208    function GetUnusedCount: Integer;
     
    219219  { TMetroPassengers }
    220220
    221   TMetroPassengers = class(TObjectList)
     221  TMetroPassengers = class(TFPGObjectList<TMetroPassenger>)
    222222    Engine: TEngine;
    223223    function AddNew: TMetroPassenger;
     
    231231  end;
    232232
    233   TRivers = class(TObjectList)
     233  TRivers = class(TFPGObjectList<TRiver>)
    234234  end;
    235235
     
    414414begin
    415415  Points := TTrackPoints.Create;
    416   Points.OwnsObjects := False;
     416  Points.FreeObjects := False;
    417417end;
    418418
     
    542542begin
    543543  TrackLinks := TTrackLinks.Create;
    544   TrackLinks.OwnsObjects := False;
     544  TrackLinks.FreeObjects := False;
    545545end;
    546546
     
    667667begin
    668668  NeighPoints := TTrackPoints.Create;
    669   NeighPoints.OwnsObjects := False;
     669  NeighPoints.FreeObjects := False;
    670670  NeighLinks := TTrackLinks.Create;
    671   NeighLinks.OwnsObjects := False;
     671  NeighLinks.FreeObjects := False;
    672672end;
    673673
     
    10161016begin
    10171017  LineStations := TLineStations.Create;
    1018   LineStations.OwnsObjects := True;
     1018  LineStations.FreeObjects := True;
    10191019  Trains := TMetroTrains.Create;
    1020   Trains.OwnsObjects := False;
     1020  Trains.FreeObjects := False;
    10211021  Track := TTrack.Create;
    10221022  Track.Line := Self;
     
    11131113begin
    11141114  Passengers := TMetroPassengers.Create;
    1115   Passengers.OwnsObjects := False;
     1115  Passengers.FreeObjects := False;
    11161116  Direction := 1;
    11171117  Line := nil;
     
    11441144begin
    11451145  TrackLinks := TTrackLinks.Create;
    1146   TrackLinks.OwnsObjects := False;
     1146  TrackLinks.FreeObjects := False;
    11471147
    11481148  // Collect all near track points as track links
     
    12131213  end;
    12141214
    1215   TPAngleGroup.Free;
    1216   TrackLinks.Free;
    1217 end;
    1218 
    1219 function MapStationCompareLine(Item1, Item2: Pointer): Integer;
    1220 begin
    1221   if TMetroLine(Item1).Index > TMetroLine(Item2).Index then Result := 1
    1222   else if TMetroLine(Item1).Index < TMetroLine(Item2).Index then Result := -1
     1215  FreeAndNil(TPAngleGroup);
     1216  FreeAndNil(TrackLinks);
     1217end;
     1218
     1219function MapStationCompareLine(const Item1, Item2: TMetroLine): Integer;
     1220begin
     1221  if Item1.Index > Item2.Index then Result := 1
     1222  else if Item1.Index < Item2.Index then Result := -1
    12231223  else Result := 0;
    12241224end;
     
    12901290begin
    12911291  Passengers := TMetroPassengers.Create;
    1292   Passengers.OwnsObjects := False;
     1292  Passengers.FreeObjects := False;
    12931293  Lines := TMetroLines.Create;
    1294   Lines.OwnsObjects := False;
     1294  Lines.FreeObjects := False;
    12951295end;
    12961296
    12971297destructor TMapStation.Destroy;
    12981298begin
    1299   Lines.Free;
    1300   Passengers.Free;
     1299  FreeAndNil(Lines);
     1300  FreeAndNil(Passengers);
    13011301  inherited Destroy;
    13021302end;
     
    13231323var
    13241324  I: Integer;
     1325  Station: TMapStation;
    13251326begin
    13261327  Result := [];
    1327   for I := 0 to Stations.Count - 1 do
    1328   with TMapStation(Stations[I]) do begin
    1329     Result := Result + [Shape];
    1330   end;
     1328  for Station in Stations do
     1329    Result := Result + [Station.Shape];
    13311330end;
    13321331
     
    15331532  I: Integer;
    15341533  S: TStationShape;
     1534  Station: TMapStation;
    15351535begin
    15361536  // Reset all distances
    1537   for I := 0 to Stations.Count - 1 do
    1538   with TMapStation(Stations[I]) do begin
     1537  for Station in Stations do
     1538  with Station do begin
    15391539    for S := Low(ShapeDistance) to High(ShapeDistance) do
    15401540      ShapeDistance[S] := -1;
     
    15431543  // Propagate shape distance for all stations
    15441544  // Distace 0 means that station is final target
    1545   for I := 0 to Stations.Count - 1 do
    1546   with TMapStation(Stations[I]) do begin
    1547     ComputeShapeDistanceStation(TMapStation(Stations[I]), Shape, 0);
     1545  for Station in Stations do
     1546  with Station do begin
     1547    ComputeShapeDistanceStation(Station, Shape, 0);
    15481548  end;
    15491549end;
     
    17731773  I: Integer;
    17741774  J: Integer;
    1775   L: Integer;
    17761775  Link1, Link2: TPoint;
    17771776  NewPoint: TPoint;
     1777  MetroLine: TMetroLine;
     1778  TrackPoint: TTrackPoint;
     1779  MapStation: TMapStation;
    17781780begin
    17791781  // Reset all trackpoints position shift
    1780   for I := 0 to Lines.Count - 1 do
    1781   with TMetroLine(Lines[I]) do
     1782  for MetroLine in Lines do
     1783    for TrackPoint in MetroLine.Track.Points do
     1784      TrackPoint.Position := TrackPoint.PositionDesigned;
     1785
     1786  // Calculate new position shifts
     1787  for MapStation in Stations do
     1788    MapStation.ShiftTrackPoints;
     1789
     1790  // Compute track points from track shift
     1791  for MetroLine in Lines do
     1792  with MetroLine do begin
     1793    if Track.Points.Count > 1 then begin
     1794      Track.Points[0].Position := Track.Points[0].PositionDesigned +
     1795        Track.Points[0].LinkUp.Shift;
     1796    end;
     1797    for I := 1 to Track.Points.Count - 1 do
     1798    with Track.Points[I] do
     1799    if Assigned(Track.Points[I].LinkDown) and Assigned(Track.Points[I].LinkUp) then begin
     1800      Link1 := (Track.Points[I].PositionDesigned + Track.Points[I].LinkDown.Shift) -
     1801        (Track.Points[I - 1].PositionDesigned + Track.Points[I].LinkDown.Shift);
     1802      if (I + 1) < Track.Points.Count then
     1803        Link2 := (Track.Points[I + 1].PositionDesigned + Track.Points[I].LinkUp.Shift) -
     1804          (Track.Points[I].PositionDesigned + Track.Points[I].LinkUp.Shift)
     1805        else Link2 := Link1;
     1806
     1807{      if ArcTanPoint(Link1) = ArcTanPoint(Link2) then begin
     1808        // Parallel lines
     1809        NewPoint := Track.Points[I].PositionDesigned + Track.Points[I].LinkDown.Shift;
     1810        Track.Points[I].Position := NewPoint;
     1811      end else begin}
     1812        // Intersected lines
     1813        if LineIntersect(Track.Points[I - 1].PositionDesigned + Track.Points[I].LinkDown.Shift,
     1814          Track.Points[I].PositionDesigned + Track.Points[I].LinkDown.Shift,
     1815          Track.Points[I].PositionDesigned + Track.Points[I].LinkUp.Shift,
     1816          Track.Points[I + 1].PositionDesigned + Track.Points[I].LinkUp.Shift, NewPoint) then
     1817          Track.Points[I].Position := NewPoint
     1818          else begin
     1819            // Parallel lines
     1820            NewPoint := Track.Points[I].PositionDesigned + Track.Points[I].LinkDown.Shift;
     1821            Track.Points[I].Position := NewPoint;
     1822          end;
     1823//      end;
     1824    end;
     1825  end;
     1826
     1827  // Remove all temporal links
     1828  for MetroLine in Lines do
     1829  with MetroLine do
    17821830    for J := 0 to Track.Points.Count - 1 do
    1783     TTrackPoint(Track.Points[J]).Position := TTrackPoint(Track.Points[J]).PositionDesigned;
    1784 
    1785   // Calculate new position shifts
    1786   for I := 0 to Stations.Count - 1 do
    1787     TMapStation(Stations[I]).ShiftTrackPoints;
    1788 
    1789   // Compute track points from track shift
    1790   for L := 0 to Lines.Count - 1 do
    1791   with TMetroLine(Lines[L]) do begin
    1792     if Track.Points.Count > 1 then begin
    1793       TTrackPoint(Track.Points[0]).Position := AddPoint(TTrackPoint(Track.Points[0]).PositionDesigned,
    1794         TTrackPoint(Track.Points[0]).LinkUp.Shift);
    1795     end;
    1796     for I := 1 to Track.Points.Count - 1 do
    1797     with TTrackPoint(Track.Points[I]) do
    1798     if Assigned(TTrackPoint(Track.Points[I]).LinkDown) and Assigned(TTrackPoint(Track.Points[I]).LinkUp) then begin
    1799       Link1 := SubPoint(AddPoint(TTrackPoint(Track.Points[I]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkDown.Shift),
    1800         AddPoint(TTrackPoint(Track.Points[I - 1]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkDown.Shift));
    1801       if (I + 1) < Track.Points.Count then
    1802         Link2 := SubPoint(AddPoint(TTrackPoint(Track.Points[I + 1]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkUp.Shift),
    1803           AddPoint(TTrackPoint(Track.Points[I]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkUp.Shift))
    1804         else Link2 := Link1;
    1805 
    1806       if ArcTanPoint(Link1) = ArcTanPoint(Link2) then begin
    1807         // Parallel lines
    1808         NewPoint := AddPoint(TTrackPoint(Track.Points[I]).PositionDesigned,
    1809           TTrackPoint(Track.Points[I]).LinkDown.Shift);
    1810         TTrackPoint(Track.Points[I]).Position := NewPoint;
    1811       end else begin
    1812         // Intersected lines
    1813         NewPoint := LineIntersect(AddPoint(TTrackPoint(Track.Points[I - 1]).PositionDesigned,
    1814           TTrackPoint(Track.Points[I]).LinkDown.Shift),
    1815           AddPoint(TTrackPoint(Track.Points[I]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkDown.Shift),
    1816           AddPoint(TTrackPoint(Track.Points[I]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkUp.Shift),
    1817           AddPoint(TTrackPoint(Track.Points[I + 1]).PositionDesigned, TTrackPoint(Track.Points[I]).LinkUp.Shift));
    1818         TTrackPoint(Track.Points[I]).Position := NewPoint;
    1819       end;
    1820     end;
    1821   end;
    1822 
    1823   // Remove all temporal links
    1824   for I := 0 to Lines.Count - 1 do
    1825   with TMetroLine(Lines[I]) do
    1826     for J := 0 to Track.Points.Count - 1 do
    1827     if Assigned(TTrackPoint(Track.Points[J]).LinkUp) then begin
    1828       TTrackPoint(Track.Points[J]).LinkUp.Free;
    1829       TTrackPoint(Track.Points[J]).LinkUp := nil;
    1830       TTrackPoint(Track.Points[J + 1]).LinkDown := nil;
     1831    if Assigned(Track.Points[J].LinkUp) then begin
     1832      Track.Points[J].LinkUp.Free;
     1833      Track.Points[J].LinkUp := nil;
     1834      Track.Points[J + 1].LinkDown := nil;
    18311835    end;
    18321836end;
     
    18631867procedure TEngine.DrawTrains(Canvas: TCanvas);
    18641868var
    1865   I: Integer;
    18661869  P: Integer;
    18671870  Pos: TPoint;
     
    18691872  Angle: Double;
    18701873  ShapePos: TPoint;
     1874  Train: TMetroTrain;
     1875  Passenger: TMetroPassenger;
    18711876begin
    18721877  // Draw trains
    1873   for I := 0 to Trains.Count - 1 do
    1874   with TMetroTrain(Trains[I]) do begin
     1878  for Train in Trains do
     1879  with Train do begin
    18751880    if Assigned(Line) then begin
    18761881      Canvas.Brush.Color := Line.Color;
     
    18871892      Canvas.Polygon(Points);
    18881893      Canvas.Brush.Color := clWhite;
    1889       for P := 0 to Passengers.Count - 1 do
    1890       with TMetroPassenger(Passengers[P]) do begin
     1894      P := 0;
     1895      for Passenger in Passengers do
     1896      with Passenger do begin
    18911897        ShapePos := Point(Pos.X - Trunc(TrainSize div 3 * 1) + (P mod 3) * TrainSize div 3,
    18921898          Pos.Y - Trunc(TrainSize div 6 * 1) + (P div 3) * TrainSize div 3);
    18931899        ShapePos := RotatePoint(Pos, ShapePos, Angle);
    18941900        DrawShape(Canvas, ShapePos, Shape, TrainSize div 3, Angle + Pi / 2);
     1901        Inc(P);
    18951902      end;
    18961903    end;
     
    19011908var
    19021909  Passenger: TMetroPassenger;
    1903   I: Integer;
     1910  MapStation: TMapStation;
    19041911begin
    19051912  if State = gsRunning then begin
     
    19331940  if (Time - LastNewPassengerTime) > NewPassengerPeriod then begin
    19341941    LastNewPassengerTime := Time;
    1935     for I := 0 to Stations.Count - 1 do
    1936     with TMapStation(Stations[I]) do
     1942    for MapStation in Stations do
     1943    with MapStation do
    19371944    if Random < NewPassengerProbability then begin
    19381945      Passenger := Self.Passengers.AddNew;
    1939       Passenger.Station := TMapStation(Stations[I]);
     1946      Passenger.Station := MapStation;
    19401947      Passengers.Add(Passenger);
    19411948
    19421949      // Passenger is not allowed to have same shape
    1943       while (Passenger.Shape = Passenger.Station.Shape) or not (Passenger.Shape in GetExistStationShapes) do
     1950      while (Passenger.Shape = Passenger.Station.Shape) or
     1951      not (Passenger.Shape in GetExistStationShapes) do
    19441952        Passenger.Shape := TStationShape((Integer(Passenger.Shape) + 1) mod Integer(ShapeCount));
    19451953      Redraw;
     
    19481956
    19491957  // Check station passenger overload state
    1950   for I := 0 to Stations.Count - 1 do
    1951   with TMapStation(Stations[I]) do begin
     1958  for MapStation in Stations do
     1959  with MapStation do begin
    19521960    if Passengers.Count > MaxWaitingPassengers then begin
    19531961      OverloadDuration := OverloadDuration + (FTime - FLastTime);
     
    19681976
    19691977  // Game over
    1970   for I := 0 to Stations.Count - 1 do
    1971   with TMapStation(Stations[I]) do begin
     1978  for MapStation in Stations do
     1979  with MapStation do begin
    19721980    if OverloadDuration >= MaxPassengersOveloadTime then begin
    19731981      State := gsGameOver;
     
    22232231destructor TEngine.Destroy;
    22242232begin
    2225   MetaCanvas.Free;
    2226   Trains.Free;
    2227   ImageLocomotive.Free;
    2228   ImagePassenger.Free;
    2229   View.Free;
    2230   Map.Free;
    2231   Passengers.Free;
    2232   Stations.Free;
    2233   Lines.Free;
     2233  FreeAndNil(MetaCanvas);
     2234  FreeAndNil(Trains);
     2235  FreeAndNil(ImageLocomotive);
     2236  FreeAndNil(ImagePassenger);
     2237  FreeAndNil(View);
     2238  FreeAndNil(Map);
     2239  FreeAndNil(Passengers);
     2240  FreeAndNil(Stations);
     2241  FreeAndNil(Lines);
    22342242  inherited Destroy;
    22352243end;
     
    22402248  S: Integer;
    22412249  Size: Integer;
    2242   P: Integer;
    22432250  Pos: TPoint;
    22442251  Text: string;
     
    22482255  Points: array of TPoint;
    22492256  Canvas: TMetaCanvas;
     2257  MetroLine: TMetroLine;
     2258  MapStation: TMapStation;
     2259  Passenger: TMetroPassenger;
    22502260const
    22512261  GameOverText = 'Game Over';
     
    22582268
    22592269  // Draw station passenger overload
    2260   for I := 0 to Stations.Count - 1 do
    2261   with TMapStation(Stations[I]) do begin
     2270  for MapStation in Stations do
     2271  with MapStation do begin
    22622272    if OverloadDuration > 0 then begin
    22632273      Canvas.Brush.Color := clSilver;
     
    22742284
    22752285  // Draw lines
    2276   for I := 0 to Lines.Count - 1 do
    2277   with TMetroLine(Lines[I]) do begin
     2286  for MetroLine in Lines do
     2287  with MetroLine do begin
    22782288    Canvas.Pen.Color := Color;
    22792289    Canvas.Pen.Style := psSolid;
    22802290    Canvas.Pen.Width := MetroLineThickness;
    2281     if Track.Points.Count > 0 then Canvas.MoveTo(TTrackPoint(Track.Points[0]).Position);
     2291    if Track.Points.Count > 0 then Canvas.MoveTo(Track.Points[0].Position);
    22822292    for S := 1 to Track.Points.Count - 1 do begin
    2283       Canvas.LineTo(TTrackPoint(Track.Points[S]).Position);
     2293      Canvas.LineTo(Track.Points[S].Position);
    22842294{      if (S = TrackPoints.Count - 1) then begin
    22852295        Canvas.Pen.EndCap := pecSquare;
     
    23492359  // Draw stations
    23502360  Canvas.Pen.Width := 5;
    2351   for I := 0 to Stations.Count - 1 do
    2352   with TMapStation(Stations[I]) do begin
     2361  for MapStation in Stations do
     2362  with MapStation do begin
    23532363    Canvas.Pen.Style := psSolid;
    23542364    if Assigned(SelectedLine) and (Lines.IndexOf(SelectedLine) <> -1) then begin
     
    23682378    PassengerPos := Point(0, 0);
    23692379    Direction := 1;
    2370     for P := 0 to Passengers.Count - 1 do
    2371     with TMetroPassenger(Passengers[P]) do begin
     2380    for Passenger in Passengers do
     2381    with Passenger do begin
    23722382      DrawShape(Canvas, Point(Position.X + StationSize + PassengerPos.X,
    23732383        Position.Y - StationSize div 2 + PassengerPos.Y),
  • trunk/UGeometric.pas

    r44 r49  
    1919function RotatePoint(Center, P: TPoint; Angle: Double): TPoint;
    2020function RotatePoints(Center: TPoint; P: TPointArray; Angle: Double): TPointArray;
    21 function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint): TPoint;
     21function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint;
     22  out Intersection: TPoint): Boolean;
    2223function ArcTan2Point(Point: TPoint): Float;
    2324function ArcTanPoint(Point: TPoint): Float;
     
    100101end;
    101102
    102 function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint): TPoint;
     103function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint;
     104  out Intersection: TPoint): Boolean;
    103105Var
    104106  LDetLineA, LDetLineB, LDetDivInv: Double;
    105107  LDiffLA, LDiffLB: TPoint;
     108  D: Double;
    106109begin
     110  if (LineAP1 = LineAP2) or (LineBP1 = LineBP2) then begin
     111    Result := False;
     112    Exit;
     113  end;
    107114  LDetLineA := LineAP1.X * LineAP2.Y - LineAP1.Y * LineAP2.X;
    108115  LDetLineB := LineBP1.X * LineBP2.Y - LineBP1.Y * LineBP2.X;
     
    111118  LDiffLB := SubPoint(LineBP1, LineBP2);
    112119
    113   LDetDivInv := 1 / ((LDiffLA.X * LDiffLB.Y) - (LDiffLA.Y * LDiffLB.X));
     120  D := ((LDiffLA.X * LDiffLB.Y) - (LDiffLA.Y * LDiffLB.X));
     121  if D = 0 then begin
     122    // Parallel lines without intersection
     123    Result := False;
     124    Exit;
     125  end;
     126  LDetDivInv := 1 / D;
    114127
    115   Result.X := Trunc(((LDetLineA * LDiffLB.X) - (LDiffLA.X * LDetLineB)) * LDetDivInv);
    116   Result.Y := Trunc(((LDetLineA * LDiffLB.Y) - (LDiffLA.Y * LDetLineB)) * LDetDivInv);
     128  Intersection.X := Trunc(((LDetLineA * LDiffLB.X) - (LDiffLA.X * LDetLineB)) * LDetDivInv);
     129  Intersection.Y := Trunc(((LDetLineA * LDiffLB.Y) - (LDiffLA.Y * LDetLineB)) * LDetDivInv);
     130  Result := True;
    117131end;
    118132
Note: See TracChangeset for help on using the changeset viewer.