Automatically add sleepers to 12V tracks.

This commit is contained in:
Leonardo Zide
2025-02-22 13:08:24 -08:00
parent fbc0150855
commit eff843c9eb
4 changed files with 131 additions and 43 deletions
+33 -19
View File
@@ -2281,12 +2281,12 @@ lcMatrix33 lcModel::GetRelativeRotation() const
return lcMatrix33Identity();
}
lcPiece* lcModel::AddPiece(PieceInfo* PieceInfo, quint32 Section)
lcPiece* lcModel::AddPiece(PieceInfo* Info, quint32 Section)
{
if (!PieceInfo)
PieceInfo = gMainWindow->GetCurrentPieceInfo();
if (!Info)
Info = gMainWindow->GetCurrentPieceInfo();
if (!PieceInfo)
if (!Info)
return nullptr;
lcPiece* Last = mPieces.empty() ? nullptr : mPieces.back().get();
@@ -2300,43 +2300,57 @@ lcPiece* lcModel::AddPiece(PieceInfo* PieceInfo, quint32 Section)
}
}
lcMatrix44 WorldMatrix;
const lcBoundingBox& PieceInfoBoundingBox = PieceInfo->GetBoundingBox();
const lcBoundingBox& PieceInfoBoundingBox = Info->GetBoundingBox();
lcPiece* Piece = nullptr;
auto CreatePiece=[this, &Piece](PieceInfo* Info, const lcMatrix44& WorldMatrix, int ColorIndex)
{
Piece = new lcPiece(Info);
Piece->Initialize(WorldMatrix, mCurrentStep);
Piece->SetColorIndex(ColorIndex);
AddPiece(Piece);
};
if (Last)
{
bool TransformValid = false;
std::vector<lcTrainTrackInsert> TrainTracks;
if (PieceInfo->GetTrainTrackInfo() && Last->mPieceInfo->GetTrainTrackInfo())
if (Info->GetTrainTrackInfo() && Last->mPieceInfo->GetTrainTrackInfo())
{
std::optional<lcMatrix44> TrainTrackTransform = lcTrainTrackInfo::GetPieceInsertTransform(Last, PieceInfo, Section);
quint32 FocusSection = Last->GetFocusSection();
if (TrainTrackTransform)
if (FocusSection != LC_PIECE_SECTION_INVALID && FocusSection >= LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST)
Section = FocusSection;
TrainTracks = lcTrainTrackInfo::GetPieceInsertTransforms(Last, Info, Section);
for (const lcTrainTrackInsert& TrainTrack : TrainTracks)
{
TransformValid = true;
WorldMatrix = TrainTrackTransform.value();
int ColorIndex = TrainTrack.ColorCode == 16 ? gMainWindow->mColorIndex : lcGetColorIndex(TrainTrack.ColorCode);
CreatePiece(TrainTrack.Info, TrainTrack.Transform, ColorIndex);
}
}
if (!TransformValid)
if (TrainTracks.empty())
{
const lcBoundingBox& LastBoundingBox = Last->GetBoundingBox();
lcVector3 Dist(0, 0, LastBoundingBox.Max.z - PieceInfoBoundingBox.Min.z);
Dist = SnapPosition(Dist);
WorldMatrix = Last->mModelWorld;
lcMatrix44 WorldMatrix = Last->mModelWorld;
WorldMatrix.SetTranslation(lcMul31(Dist, Last->mModelWorld));
CreatePiece(Info, WorldMatrix, gMainWindow->mColorIndex);
}
}
else
{
WorldMatrix = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -PieceInfoBoundingBox.Min.z));
lcMatrix44 WorldMatrix = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -PieceInfoBoundingBox.Min.z));
CreatePiece(Info, WorldMatrix, gMainWindow->mColorIndex);
}
lcPiece* Piece = new lcPiece(PieceInfo);
Piece->Initialize(WorldMatrix, mCurrentStep);
Piece->SetColorIndex(gMainWindow->mColorIndex);
AddPiece(Piece);
gMainWindow->UpdateTimeline(false, false);
ClearSelectionAndSetFocus(Piece, LC_PIECE_SECTION_POSITION, false);
+46 -19
View File
@@ -7,6 +7,9 @@
// todo:
// add the rest of the 9v and 12v tracks, look into 4.5v
// see if we should remove some of the 12v tracks to avoid bloat
// data driven sleepers
// lcView::GetPieceInsertTransform should use track connections when dragging a new track over an existing one
// better insert gizmo mouse detection
// auto replace cross when going over a straight section
// set focus connection after adding
@@ -53,20 +56,20 @@ void lcTrainTrackInit(lcPiecesLibrary* Library)
float Rotation = JsonConnection["Rotation"].toDouble() * LC_DTOR;
QString ConnectionGroup = JsonConnection["Type"].toString();
int ConnectionDirection = 0;
lcTrainTrackConnectionSleeper ConnectionSleeper = lcTrainTrackConnectionSleeper::None;
if (ConnectionGroup.startsWith('+'))
{
ConnectionDirection = 1;
ConnectionSleeper = lcTrainTrackConnectionSleeper::NeedsSleeper;
ConnectionGroup = ConnectionGroup.mid(1);
}
else if (ConnectionGroup.startsWith('-'))
{
ConnectionDirection = -1;
ConnectionSleeper = lcTrainTrackConnectionSleeper::HasSleeper;
ConnectionGroup = ConnectionGroup.mid(1);
}
TrainTrackInfo->AddConnection(lcMatrix44(lcMatrix33RotationZ(Rotation), Position), { qHash(ConnectionGroup), ConnectionDirection } );
TrainTrackInfo->AddConnection(lcMatrix44(lcMatrix33RotationZ(Rotation), Position), { qHash(ConnectionGroup), ConnectionSleeper } );
}
}
}
@@ -97,21 +100,17 @@ int lcTrainTrackInfo::GetPieceConnectionIndex(const lcPiece* Piece1, int Connect
return -1;
}
std::optional<lcMatrix44> lcTrainTrackInfo::GetPieceInsertTransform(lcPiece* CurrentPiece, PieceInfo* Info, quint32 Section)
std::vector<lcTrainTrackInsert> lcTrainTrackInfo::GetPieceInsertTransforms(lcPiece* CurrentPiece, PieceInfo* Info, quint32 Section)
{
std::vector<lcTrainTrackInsert> Pieces;
const lcTrainTrackInfo* CurrentTrackInfo = CurrentPiece->mPieceInfo->GetTrainTrackInfo();
if (!CurrentTrackInfo || CurrentTrackInfo->GetConnections().empty())
return std::nullopt;
return Pieces;
const quint32 FocusSection = CurrentPiece->GetFocusSection();
quint32 ConnectionIndex = 0;
if (FocusSection != LC_PIECE_SECTION_INVALID && FocusSection >= LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST)
{
ConnectionIndex = FocusSection - LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST;
}
else if (Section != LC_PIECE_SECTION_INVALID && Section >= LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST)
if (Section != LC_PIECE_SECTION_INVALID && Section >= LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST)
{
ConnectionIndex = Section - LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST;
}
@@ -122,7 +121,7 @@ std::optional<lcMatrix44> lcTrainTrackInfo::GetPieceInsertTransform(lcPiece* Cur
break;
if (ConnectionIndex == CurrentTrackInfo->GetConnections().size())
return std::nullopt;
return Pieces;
}
const lcTrainTrackConnectionType& CurrentConnectionType = CurrentTrackInfo->GetConnections()[ConnectionIndex].Type;
@@ -134,17 +133,45 @@ std::optional<lcMatrix44> lcTrainTrackInfo::GetPieceInsertTransform(lcPiece* Cur
break;
if (NewConnectionIndex == NewConnections.size())
return std::nullopt;
return Pieces;
return GetConnectionTransform(CurrentPiece, ConnectionIndex, Info, NewConnectionIndex);
if (CurrentConnectionType.Sleeper == lcTrainTrackConnectionSleeper::NeedsSleeper && NewConnections[NewConnectionIndex].Type.Sleeper == lcTrainTrackConnectionSleeper::NeedsSleeper)
{
PieceInfo* SleeperInfo = lcGetPiecesLibrary()->FindPiece("4166a.dat", nullptr, false, false); // todo: data driven
if (!SleeperInfo)
return Pieces;
std::optional<lcMatrix44> SleeperTransform = GetConnectionTransform(CurrentPiece->mPieceInfo, CurrentPiece->mModelWorld, ConnectionIndex, SleeperInfo, 0);
if (!SleeperTransform)
return Pieces;
std::optional<lcMatrix44> Transform = GetConnectionTransform(SleeperInfo, SleeperTransform.value(), 1, Info, NewConnectionIndex);
if (Transform)
{
Pieces.emplace_back(lcTrainTrackInsert{ SleeperInfo, SleeperTransform.value(), 8 });
Pieces.emplace_back(lcTrainTrackInsert{ Info, Transform.value(), 16 });
}
}
else
{
std::optional<lcMatrix44> Transform = GetConnectionTransform(CurrentPiece->mPieceInfo, CurrentPiece->mModelWorld, ConnectionIndex, Info, NewConnectionIndex);
if (Transform)
Pieces.emplace_back(lcTrainTrackInsert{ Info, Transform.value(), 16 });
}
return Pieces;
}
std::optional<lcMatrix44> lcTrainTrackInfo::GetConnectionTransform(lcPiece* CurrentPiece, quint32 CurrentConnectionIndex, PieceInfo* Info, quint32 NewConnectionIndex)
std::optional<lcMatrix44> lcTrainTrackInfo::GetConnectionTransform(PieceInfo* CurrentInfo, const lcMatrix44& CurrentTransform, quint32 CurrentConnectionIndex, PieceInfo* Info, quint32 NewConnectionIndex)
{
if (!CurrentPiece || !Info)
if (!CurrentInfo || !Info)
return std::nullopt;
const lcTrainTrackInfo* CurrentTrackInfo = CurrentPiece->mPieceInfo->GetTrainTrackInfo();
const lcTrainTrackInfo* CurrentTrackInfo = CurrentInfo->GetTrainTrackInfo();
if (!CurrentTrackInfo || CurrentTrackInfo->GetConnections().empty())
return std::nullopt;
@@ -168,7 +195,7 @@ std::optional<lcMatrix44> lcTrainTrackInfo::GetConnectionTransform(lcPiece* Curr
// }
Transform = lcMul(Transform, CurrentTrackInfo->GetConnections()[CurrentConnectionIndex].Transform);
Transform = lcMul(Transform, CurrentPiece->mModelWorld);
Transform = lcMul(Transform, CurrentTransform);
return Transform;
}
+34 -4
View File
@@ -4,11 +4,19 @@
class lcPiece;
class lcPiecesLibrary;
class PieceInfo;
enum class lcTrainTrackConnectionSleeper
{
None,
HasSleeper,
NeedsSleeper
};
struct lcTrainTrackConnectionType
{
quint32 Group;
int Format;
lcTrainTrackConnectionSleeper Sleeper;
};
struct lcTrainTrackConnection
@@ -17,13 +25,20 @@ struct lcTrainTrackConnection
lcTrainTrackConnectionType Type;
};
struct lcTrainTrackInsert
{
PieceInfo* Info;
lcMatrix44 Transform;
int ColorCode;
};
class lcTrainTrackInfo
{
public:
lcTrainTrackInfo() = default;
static std::optional<lcMatrix44> GetPieceInsertTransform(lcPiece* CurrentPiece, PieceInfo* Info, quint32 Section);
static std::optional<lcMatrix44> GetConnectionTransform(lcPiece* CurrentPiece, quint32 CurrentConnectionIndex, PieceInfo* Info, quint32 NewConnectionIndex);
static std::vector<lcTrainTrackInsert> GetPieceInsertTransforms(lcPiece* CurrentPiece, PieceInfo* Info, quint32 Section);
static std::optional<lcMatrix44> GetConnectionTransform(PieceInfo* CurrentInfo, const lcMatrix44& CurrentTransform, quint32 CurrentConnectionIndex, PieceInfo* Info, quint32 NewConnectionIndex);
static std::optional<lcMatrix44> CalculateTransformToConnection(const lcMatrix44& ConnectionTransform, PieceInfo* Info, quint32 ConnectionIndex);
static int GetPieceConnectionIndex(const lcPiece* Piece1, int ConnectionIndex1, const lcPiece* Piece2);
@@ -49,7 +64,22 @@ public:
protected:
static bool AreConnectionsCompatible(const lcTrainTrackConnectionType& a, const lcTrainTrackConnectionType& b)
{
return a.Group == b.Group && a.Format + b.Format == 0;
if (a.Group != b.Group)
return false;
switch (a.Sleeper)
{
case lcTrainTrackConnectionSleeper::None:
return b.Sleeper == lcTrainTrackConnectionSleeper::None;
case lcTrainTrackConnectionSleeper::HasSleeper:
return b.Sleeper == lcTrainTrackConnectionSleeper::NeedsSleeper;
case lcTrainTrackConnectionSleeper::NeedsSleeper:
return b.Sleeper == lcTrainTrackConnectionSleeper::HasSleeper || b.Sleeper == lcTrainTrackConnectionSleeper::NeedsSleeper;
}
return false;
}
std::vector<lcTrainTrackConnection> mConnections;
+18 -1
View File
@@ -126,7 +126,7 @@
},
"Train Track Sleeper Plate 2 x 8":
{
"Parts": [ "4166a.dat" ],
"Parts": [ "4166a.dat", "4166b.dat" ],
"Connections":
[
{
@@ -279,6 +279,23 @@
"Type": "+12V"
}
]
},
"Train Track 4.5V Slotted Straight Without End Sleepers":
{
"Parts": [ "3228bc02.dat" ],
"Connections":
[
{
"Position": [ 160.0, 0.0, 0.0 ],
"Rotation": 0.0,
"Type": "+4.5V"
},
{
"Position": [ -160.0, 0.0, 0.0 ],
"Rotation": -180.0,
"Type": "+4.5V"
}
]
}
}
}