From 54eb20d3c5cd73cff2c13bcb4d66b30fa19c8465 Mon Sep 17 00:00:00 2001 From: cambrialas Date: Wed, 23 Oct 2024 14:37:12 +0200 Subject: [PATCH] New feature, dialog to edit train track system in an easy way. --- common/lc_commands.cpp | 7 + common/lc_commands.h | 1 + common/lc_mainwindow.cpp | 6 + common/lc_model.cpp | 40 +++ common/lc_model.h | 2 + common/lc_partselectionwidget.cpp | 25 ++ common/lc_partselectionwidget.h | 2 + common/lc_traintracksystemdialog.cpp | 224 ++++++++++++++++ common/lc_traintracksystemdialog.h | 62 +++++ common/lc_traintracksystemdialog.ui | 86 +++++++ common/lc_viewwidget.cpp | 26 +- common/lc_viewwidget.h | 4 + common/traintracksystem.cpp | 365 +++++++++++++++++++++++++++ common/traintracksystem.h | 105 ++++++++ leocad.pro | 5 + 15 files changed, 956 insertions(+), 4 deletions(-) create mode 100644 common/lc_traintracksystemdialog.cpp create mode 100644 common/lc_traintracksystemdialog.h create mode 100644 common/lc_traintracksystemdialog.ui create mode 100644 common/traintracksystem.cpp create mode 100644 common/traintracksystem.h diff --git a/common/lc_commands.cpp b/common/lc_commands.cpp index 00d5620b..e2143946 100644 --- a/common/lc_commands.cpp +++ b/common/lc_commands.cpp @@ -1369,6 +1369,13 @@ const lcCommand gCommands[] = QT_TRANSLATE_NOOP("Status", "Add a new minifig to the model"), "" }, + // LC_PIECE_TRAIN_TRACK_WIZARD + { + QT_TRANSLATE_NOOP("Action", "Piece.TrainTrackSystemWizard"), + QT_TRANSLATE_NOOP("Menu", "Train track network wizard..."), + QT_TRANSLATE_NOOP("Status", "Add a new train track network to the model"), + "Ctrl+T" + }, // LC_PIECE_ARRAY { QT_TRANSLATE_NOOP("Action", "Piece.Array"), diff --git a/common/lc_commands.h b/common/lc_commands.h index f88091ca..9ac7e01f 100644 --- a/common/lc_commands.h +++ b/common/lc_commands.h @@ -211,6 +211,7 @@ enum lcCommandId LC_PIECE_ROTATE_PLUSZ, LC_PIECE_ROTATE_MINUSZ, LC_PIECE_MINIFIG_WIZARD, + LC_PIECE_TRAIN_TRACK_WIZARD, LC_PIECE_ARRAY, LC_PIECE_VIEW_SELECTED_MODEL, LC_PIECE_MOVE_SELECTION_TO_MODEL, diff --git a/common/lc_mainwindow.cpp b/common/lc_mainwindow.cpp index aecd719e..6ecd548e 100644 --- a/common/lc_mainwindow.cpp +++ b/common/lc_mainwindow.cpp @@ -557,6 +557,7 @@ void lcMainWindow::CreateMenus() PieceMenu->addAction(mActions[LC_PIECE_PAINT_SELECTED]); PieceMenu->addAction(mActions[LC_PIECE_ARRAY]); PieceMenu->addAction(mActions[LC_PIECE_MINIFIG_WIZARD]); + PieceMenu->addAction(mActions[LC_PIECE_TRAIN_TRACK_WIZARD]); PieceMenu->addAction(mActions[LC_PIECE_RESET_PIVOT_POINT]); PieceMenu->addAction(mActions[LC_PIECE_REMOVE_KEY_FRAMES]); PieceMenu->addSeparator(); @@ -2981,6 +2982,11 @@ void lcMainWindow::HandleCommand(lcCommandId CommandId) ActiveModel->ShowMinifigDialog(); break; + case LC_PIECE_TRAIN_TRACK_WIZARD: + if (ActiveModel) + ActiveModel->ShowTrainTrackSystemDialog(); + break; + case LC_PIECE_ARRAY: if (ActiveModel) ActiveModel->ShowArrayDialog(); diff --git a/common/lc_model.cpp b/common/lc_model.cpp index f65f247e..824747e7 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -15,9 +15,11 @@ #include "pieceinf.h" #include "lc_view.h" #include "minifig.h" +#include "traintracksystem.h" #include "lc_arraydialog.h" #include "lc_qselectdialog.h" #include "lc_minifigdialog.h" +#include "lc_traintracksystemdialog.h" #include "lc_groupdialog.h" #include "lc_qeditgroupsdialog.h" #include "lc_qpropertiesdialog.h" @@ -4716,6 +4718,44 @@ void lcModel::SetMinifig(const lcMinifig& Minifig) SetSelectionAndFocus(Pieces, nullptr, 0, false); } +void lcModel::ShowTrainTrackSystemDialog() +{ + lcTrainTrackSystemDialog Dialog(gMainWindow); + + if (Dialog.exec() != QDialog::Accepted) + return; + + gMainWindow->GetActiveView()->MakeCurrent(); + + lcGroup* Group = AddGroup(tr("TrainTrackSystem #"), nullptr); + + std::vector trackSystemPieces = Dialog.mTrainTrackSystem->GetPieces(); + for (lcPiece* Piece : trackSystemPieces) + { + Piece->SetGroup(Group); + AddPiece(Piece); + Piece->UpdatePosition(mCurrentStep); + } + + gMainWindow->UpdateTimeline(false, false); + SaveCheckpoint(tr("Train track system")); +} + +void lcModel::SetTrainTrackSystem(const std::vector& Pieces) +{ + DeleteModel(); + + std::vector mPieces; + mPieces.reserve(Pieces.size()); + + for (lcPiece* Piece : Pieces) + { + AddPiece(Piece); + Piece->UpdatePosition(1); + mPieces.emplace_back(Piece); + } +} + void lcModel::SetPreviewPieceInfo(PieceInfo* Info, int ColorIndex) { DeleteModel(); diff --git a/common/lc_model.h b/common/lc_model.h index fed286d5..277ecf94 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -250,6 +250,7 @@ public: } void SetMinifig(const lcMinifig& Minifig); + void SetTrainTrackSystem(const std::vector& Pieces); void SetPreviewPieceInfo(PieceInfo* Info, int ColorIndex); void Cut(); @@ -373,6 +374,7 @@ public: void ShowSelectByNameDialog(); void ShowArrayDialog(); void ShowMinifigDialog(); + void ShowTrainTrackSystemDialog(); void UpdateInterface(); protected: diff --git a/common/lc_partselectionwidget.cpp b/common/lc_partselectionwidget.cpp index ae8599c4..1a33106b 100644 --- a/common/lc_partselectionwidget.cpp +++ b/common/lc_partselectionwidget.cpp @@ -147,6 +147,23 @@ void lcPartSelectionListModel::SetCategory(int CategoryIndex) SetFilter(mFilter); } +void lcPartSelectionListModel::SetParts(std::vector partsList) +{ + beginResetModel(); + + ReleaseThumbnails(); + mParts.clear(); + + mParts.resize(partsList.size()); + for (unsigned long PartIdx = 0; PartIdx < partsList.size(); PartIdx++) { + mParts[PartIdx].Info = partsList[PartIdx]; + } + + endResetModel(); + + SetFilter(mFilter); +} + void lcPartSelectionListModel::SetModelsCategory() { beginResetModel(); @@ -514,6 +531,14 @@ void lcPartSelectionListView::SetCategory(lcPartCategoryType Type, int Index) setCurrentIndex(mListModel->index(0, 0)); } +void lcPartSelectionListView::SetParts(std::vector partsList) +{ + mListModel->SetParts(partsList); + + if(mListModel->rowCount()>0) + setCurrentIndex(mListModel->index(0, 0)); +} + void lcPartSelectionListView::SetCurrentPart(PieceInfo* Info) { QModelIndex Index = mListModel->GetPieceInfoIndex(Info); diff --git a/common/lc_partselectionwidget.h b/common/lc_partselectionwidget.h index d66945fc..af8ce66e 100644 --- a/common/lc_partselectionwidget.h +++ b/common/lc_partselectionwidget.h @@ -117,6 +117,7 @@ public: void ToggleColorLocked(); void ToggleListMode(); void SetCategory(int CategoryIndex); + void SetParts(std::vector partsList); void SetModelsCategory(); void SetPaletteCategory(int SetIndex); void SetCurrentModelCategory(); @@ -155,6 +156,7 @@ public: void startDrag(Qt::DropActions SupportedActions) override; void SetCategory(lcPartCategoryType Type, int Index); + void SetParts(std::vector partsList); void SetCurrentPart(PieceInfo* Info); PieceInfo* GetCurrentPart() const diff --git a/common/lc_traintracksystemdialog.cpp b/common/lc_traintracksystemdialog.cpp new file mode 100644 index 00000000..da6dbb1c --- /dev/null +++ b/common/lc_traintracksystemdialog.cpp @@ -0,0 +1,224 @@ +#include "lc_traintracksystemdialog.h" +#include "ui_lc_traintracksystemdialog.h" +#include "lc_viewwidget.h" +#include "lc_mainwindow.h" +#include "pieceinf.h" +#include "lc_view.h" +#include "piece.h" +#include "camera.h" +#include "lc_partselectionwidget.h" + +lcTrainTrackSystemDialog::lcTrainTrackSystemDialog(QWidget* Parent) + : QDialog(Parent), ui(new Ui::lcTrainTrackSystemDialog) +{ + + gMainWindow->SetTool(lcTool::Pan); + + editor_state = LC_TTS_STATE_INSERT; + + ui->setupUi(this); + + QGridLayout* PreviewLayout = new QGridLayout(ui->trainTrackSystemFrame); + PreviewLayout->setContentsMargins(0, 0, 0, 0); + + mTrainTrackSystem = new TrainTrackSystem(); + SetInitialTrainTrackSystem(); + mView = new lcView(lcViewType::View, mTrainTrackSystem->GetModel()); + + lcViewWidget* ViewWidget = new lcViewWidget(nullptr, mView); + ViewWidget->setMinimumWidth(1600); + + connect(ViewWidget, &lcViewWidget::mousePressOnPiece, this, &lcTrainTrackSystemDialog::mousePressOnPiece); + connect(ViewWidget, &lcViewWidget::mouseRelease, this, &lcTrainTrackSystemDialog::mouseRelease); + + PreviewLayout->addWidget(ViewWidget); + + mView->MakeCurrent(); + + QGridLayout* PartSelector = new QGridLayout(ui->partSelector); + PartSelector->setContentsMargins(0, 0, 0, 0); + + mPartsWidget = new lcPartSelectionListView(nullptr, nullptr); + PartSelector->addWidget(mPartsWidget); + + mPartsWidget->SetParts(mTrainTrackSystem->getTrackTypes()); + + mView->GetCamera()->SetViewpoint(lcVector3(0.0f, 0.0f, 90.0f)); + mView->ZoomExtents(); +} + + +lcTrainTrackSystemDialog::~lcTrainTrackSystemDialog() +{ + delete mTrainTrackSystem; + delete ui; +} + + +void lcTrainTrackSystemDialog::mousePressOnPiece(lcPiece* pieceClickedOn) { + + if(pieceClickedOn != nullptr) { + + if(mTrainTrackSystem->findTrackTypeByString(pieceClickedOn->mPieceInfo->mFileName) == -1) { + + PieceInfo* piecePartlistInf = mPartsWidget->GetCurrentPart(); + + insertTrackType = mTrainTrackSystem->findTrackTypeByString(piecePartlistInf->mFileName); + + if(selectedFromTrackSection == nullptr) { + + std::vector trackSections = mTrainTrackSystem->GetTrackSections(); + int found_con_no = 0; + + for(TrainTrackSection* trackSection : trackSections) { + found_con_no = trackSection->FindConnectionNumber(pieceClickedOn->GetRotationCenter()); + if(found_con_no != -1) { + selectedFromTrackSection = trackSection; + selectedFromConnectionNo = found_con_no; + break; + } + } + } + if(selectedFromTrackSection != nullptr) { + + selectedToConnectionNo = 0; + newSectionInserted = true; + mTrainTrackSystem->addTrackSection(selectedFromTrackSection, selectedFromConnectionNo, insertTrackType, selectedToConnectionNo); + mTrainTrackSystem->SetModel(); + mView->Redraw(); + } + } + else { + + if(mTrainTrackSystem->deleteTrackSection(pieceClickedOn) == true) { + mTrainTrackSystem->SetModel(); + mView->Redraw(); + } + } + } +} + +void lcTrainTrackSystemDialog::mouseRelease() { + selectedFromTrackSection = nullptr; + newSectionInserted = false; +} + +void lcTrainTrackSystemDialog::keyPressEvent(QKeyEvent *event) { + + if(selectedFromTrackSection == nullptr) { + + lcModel* activeModel = mView->GetActiveModel(); + const std::vector>& Pieces = activeModel->GetPieces(); + for (const std::unique_ptr& Piece : Pieces) { + if (Piece->IsFocused()) { + + std::vector trackSections = mTrainTrackSystem->GetTrackSections(); + int found_con_no = 0; + + for(TrainTrackSection* trackSection : trackSections) { + found_con_no = trackSection->FindConnectionNumber(Piece->GetRotationCenter()); + if(found_con_no != -1) { + selectedFromTrackSection = trackSection; + selectedFromConnectionNo = found_con_no; + break; + } + } + break; + } + } + } + + if(selectedFromTrackSection != nullptr) { + bool updateSection = true; + switch(event->key()) { + case Qt::Key_S: { + insertTrackType = LC_TTS_STRAIGHT; + selectedToConnectionNo = 0; + break; + } + case Qt::Key_C: { + insertTrackType = LC_TTS_CURVED; + selectedToConnectionNo = 0; + break; + } + case Qt::Key_X: { + insertTrackType = LC_TTS_CROSS; + selectedToConnectionNo = 0; + break; + } + case Qt::Key_L: { + insertTrackType = LC_TTS_LEFT_BRANCH; + selectedToConnectionNo = 0; + break; + } + case Qt::Key_R: { + insertTrackType = LC_TTS_RIGHT_BRANCH; + selectedToConnectionNo = 0; + break; + } + case Qt::Key_Right: { + if(newSectionInserted == true) { + std::vector trackSections = mTrainTrackSystem->GetTrackSections(); + TrainTrackSection* newTrackSection = trackSections[trackSections.size() - 1]; + + selectedToConnectionNo++; + if(selectedToConnectionNo >= newTrackSection->GetNoOfConnections()) + selectedToConnectionNo = 0; + } + break; + } + case Qt::Key_Insert: { + selectedFromTrackSection = nullptr; + selectedFromConnectionNo = -1; + newSectionInserted = false; + insertTrackType = LC_TTS_STRAIGHT; + selectedToConnectionNo = 0; + updateSection = false; + break; + } + default: { + updateSection = false; + } + } + + if(updateSection == true) { + + if(newSectionInserted == true) { + std::vector* trackSections = mTrainTrackSystem->GetTrackSectionsPtr(); + trackSections->erase(trackSections->begin() + trackSections->size() - 1); + } + mTrainTrackSystem->addTrackSection(selectedFromTrackSection, selectedFromConnectionNo, insertTrackType, selectedToConnectionNo); + mTrainTrackSystem->SetModel(); + mView->Redraw(); + newSectionInserted = true; + } + } +} + +void lcTrainTrackSystemDialog::SetInitialTrainTrackSystem() +{ + int colorIndex = 8; + int mCurrentStep = 1; + mTrainTrackSystem->setColorIndex(colorIndex); + mTrainTrackSystem->setCurrentStep(mCurrentStep); + mTrainTrackSystem->addFirstTrackSection(lcMatrix44Identity(),LC_TTS_STRAIGHT); //Idx: 0 +} + + + + + + + + + + + + + + + + + + + diff --git a/common/lc_traintracksystemdialog.h b/common/lc_traintracksystemdialog.h new file mode 100644 index 00000000..902c5075 --- /dev/null +++ b/common/lc_traintracksystemdialog.h @@ -0,0 +1,62 @@ +#pragma once + +#include "traintracksystem.h" +#include "lc_partselectionwidget.h" + +class lcQColorPicker; + +enum LC_TTS_EDITOR_STATES { + LC_TTS_STATE_INSERT, + LC_TTS_STATE_ROTATE, + LC_TTS_STATE_NUMITEMS +}; + +namespace Ui +{ +class lcTrainTrackSystemDialog; +} + +class lcTrainTrackSystemDialog : public QDialog +{ + Q_OBJECT + +public: + explicit lcTrainTrackSystemDialog(QWidget* Parent); + ~lcTrainTrackSystemDialog(); + + //MinifigWizard* mMinifigWizard; + TrainTrackSystem* mTrainTrackSystem; + +public slots: + void mousePressOnPiece(lcPiece* piece); + void mouseRelease(); + +protected: + + Ui::lcTrainTrackSystemDialog* ui; + + //void mousePressEvent(QMouseEvent* Event) override; + + //bool eventFilter(QObject* Object, QEvent* Event) override;' + void keyPressEvent(QKeyEvent *event) override; + + + enum LC_TTS_EDITOR_STATES editor_state; + + lcView* mView; + + +private: + + lcPartSelectionListView* mPartsWidget; + TrainTrackSection* selectedFromTrackSection = nullptr; + int selectedFromConnectionNo = -1; + bool newSectionInserted = false; + enum LC_TTS_TYPES insertTrackType; + int selectedToConnectionNo = 0; + + enum LC_TTS_TYPES selectedTrackTypeId; + + void SetInitialTrainTrackSystem(); + +}; diff --git a/common/lc_traintracksystemdialog.ui b/common/lc_traintracksystemdialog.ui new file mode 100644 index 00000000..6d0b4980 --- /dev/null +++ b/common/lc_traintracksystemdialog.ui @@ -0,0 +1,86 @@ + + + lcTrainTrackSystemDialog + + + + 0 + 0 + 2000 + 1000 + + + + Train track system Wizard + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + 1 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + lcTrainTrackSystemDialog + accept() + + + buttonBox + rejected() + lcTrainTrackSystemDialog + reject() + + + diff --git a/common/lc_viewwidget.cpp b/common/lc_viewwidget.cpp index e4c2d563..c835d766 100644 --- a/common/lc_viewwidget.cpp +++ b/common/lc_viewwidget.cpp @@ -11,6 +11,8 @@ #include "lc_mesh.h" #include "lc_profile.h" #include "lc_previewwidget.h" +#include "pieceinf.h" +#include "object.h" lcViewWidget::lcViewWidget(QWidget* Parent, lcView* View) : QOpenGLWidget(Parent), mView(View) @@ -128,10 +130,24 @@ void lcViewWidget::mousePressEvent(QMouseEvent* MouseEvent) switch (MouseEvent->button()) { - case Qt::LeftButton: - mView->OnLeftButtonDown(); - break; + case Qt::LeftButton: { + + //Emit piece, if the button is pressed on a piece + lcObjectSection ObjectSection = mView->FindObjectUnderPointer(false, false); + lcObject* Object = ObjectSection.Object; + if (Object) + { + if (Object->IsPiece()) + { + lcPiece* Piece = (lcPiece*)Object; + emit mousePressOnPiece(Piece); + } + } + + mView->OnLeftButtonDown(); + break; + } case Qt::MiddleButton: mView->OnMiddleButtonDown(); break; @@ -155,7 +171,9 @@ void lcViewWidget::mousePressEvent(QMouseEvent* MouseEvent) void lcViewWidget::mouseReleaseEvent(QMouseEvent* MouseEvent) { - float DeviceScale = GetDeviceScale(); + emit mouseRelease(); + + float DeviceScale = GetDeviceScale(); mView->SetMousePosition(MouseEvent->x() * DeviceScale, mView->GetHeight() - MouseEvent->y() * DeviceScale - 1); mView->SetMouseModifiers(MouseEvent->modifiers()); diff --git a/common/lc_viewwidget.h b/common/lc_viewwidget.h index b8e849bc..a9ff7037 100644 --- a/common/lc_viewwidget.h +++ b/common/lc_viewwidget.h @@ -13,6 +13,10 @@ public: QSize sizeHint() const override; +signals: + void mousePressOnPiece(lcPiece* piece); + void mouseRelease(); + protected: float GetDeviceScale() const { diff --git a/common/traintracksystem.cpp b/common/traintracksystem.cpp new file mode 100644 index 00000000..838ba3f2 --- /dev/null +++ b/common/traintracksystem.cpp @@ -0,0 +1,365 @@ +#include "piece.h" +#include "traintracksystem.h" +#include "lc_model.h" +#include "lc_application.h" +#include "lc_library.h" +#include + +TrainTrackConnectionPoint::TrainTrackConnectionPoint(float angle, float x, float y) { + this->angle = angle; + xy_coordinate.x = x; + xy_coordinate.y = y; +} + + + +void TrainTrackType::Load(lcPiecesLibrary* Library, char const* filename) { + pieceInfo = Library->FindPiece(filename, nullptr, false, false); +} + +void TrainTrackType::AddConnection(TrainTrackConnectionPoint *connectionPoint) { + connectionPoints.push_back(connectionPoint); +} + +TrainTrackConnectionPoint* TrainTrackType::GetConnection(int index) { + return connectionPoints[index]; +} + +std::vector& TrainTrackType::GetConnections() { + return connectionPoints; +} + +int TrainTrackType::GetNoOfConnections() { + return connectionPoints.size(); +} + + + +TrainTrackSection::TrainTrackSection(TrainTrackType *trackType, enum LC_TTS_TYPES trackTypeId, lcMatrix44 location, int mCurrentStep, int mColorIndex) { + this->trackType = trackType; + this->trackTypeId = trackTypeId; + this->location = location; + this->mCurrentStep = mCurrentStep; + this->mColorIndex = mColorIndex; +} + + +lcMatrix44 TrainTrackSection::GetConnectionLocation(int connectionNo) { + + lcMatrix44 mat44; + lcMatrix44 matOffset; + + TrainTrackConnectionPoint* connection = trackType->GetConnections()[connectionNo]; + + mat44 = lcMatrix44Identity(); + mat44 = lcMatrix44RotationZ(LC_DTOR * connection->angle); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(connection->xy_coordinate.x, connection->xy_coordinate.y,0)); + + matOffset = lcMul(mat44, matOffset); + + return lcMul(matOffset,location); +} + +int TrainTrackSection::GetNoOfConnections() { + return trackType->GetNoOfConnections(); +} + +int TrainTrackSection::FindConnectionNumber(lcVector3 v3searchLocation) { + float precisionErrorNumber = 0.001; + + lcMatrix44 matOffset; + + for(int con_no = 0; con_no < trackType->GetNoOfConnections(); con_no++) { + + lcMatrix44 matSelection = GetConnectionLocation(con_no); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(-10, 0, 8)); + + lcVector3 v3Selection = lcMul(matOffset,matSelection).GetTranslation(); + + if(abs(v3Selection.x - v3searchLocation.x) < precisionErrorNumber && + abs(v3Selection.y - v3searchLocation.y) < precisionErrorNumber && + abs(v3Selection.z - v3searchLocation.z) < precisionErrorNumber) + { + return con_no; + } + } + return -1; +} + + + +const char* TrainTrackSystem::mTrackTypeFilenames[LC_TTS_NUMITEMS] = +{ + "74746.dat", // LC_TTS_STRAIGHT, + "74747.dat", // LC_TTS_CURVED, + "32087.dat", // LC_TTS_CROSS, + "2861c04.dat", // LC_TTS_LEFT_BRANCH, + "2859c04.dat" // LC_TTS_RIGHT_BRANCH +}; + + +TrainTrackSystem::TrainTrackSystem() + : mModel(new lcModel(QString(), nullptr, false)) +{ + lcPiecesLibrary* Library = lcGetPiecesLibrary(); + + float xHalfBendOff = sin(LC_DTOR * 11.25) * 800; + float yHalfBendOff = ((cos(LC_DTOR * 11.25) * 800) - 800); + + float x_left_branch = 320 + 320 + 0 + (-(sin(LC_DTOR * 22.5)*800)); + float y_left_branch = 0 + 0 + 320 + ((cos(LC_DTOR * 22.5)*800)-800); + + float x_right_branch = 320 + 320 + 0 + (-(sin(LC_DTOR * 22.5)*800)); + float y_right_branch = 0 + 0 - 320 - ((cos(LC_DTOR * 22.5)*800)-800); + + TrainTrackType *trackType; + + trainTrackTypes.reserve(LC_TTS_NUMITEMS); + + // straight + trackType = new TrainTrackType(); + trackType->Load(Library,mTrackTypeFilenames[LC_TTS_STRAIGHT]); + trackType->AddConnection(new TrainTrackConnectionPoint(0,160,0)); + trackType->AddConnection(new TrainTrackConnectionPoint(180,-160,0)); + trainTrackTypes[LC_TTS_STRAIGHT] = trackType; + + // curved + trackType = new TrainTrackType(); + trackType->Load(Library,mTrackTypeFilenames[LC_TTS_CURVED]); + trackType->AddConnection(new TrainTrackConnectionPoint(-11.25,xHalfBendOff,yHalfBendOff)); + trackType->AddConnection(new TrainTrackConnectionPoint(-168.75,-xHalfBendOff,yHalfBendOff)); + trainTrackTypes[LC_TTS_CURVED] = trackType; + + // Crossing + trackType = new TrainTrackType(); + trackType->Load(Library,mTrackTypeFilenames[LC_TTS_CROSS]); + trackType->AddConnection(new TrainTrackConnectionPoint(0,160,0)); + trackType->AddConnection(new TrainTrackConnectionPoint(90,0,160)); + trackType->AddConnection(new TrainTrackConnectionPoint(180,-160,0)); + trackType->AddConnection(new TrainTrackConnectionPoint(-90,0,-160)); + trainTrackTypes[LC_TTS_CROSS] = trackType; + + // Left branch + trackType = new TrainTrackType(); + trackType->Load(Library,mTrackTypeFilenames[LC_TTS_LEFT_BRANCH]); + trackType->AddConnection(new TrainTrackConnectionPoint(0,320,0)); + trackType->AddConnection(new TrainTrackConnectionPoint(22.50,x_left_branch,y_left_branch)); + trackType->AddConnection(new TrainTrackConnectionPoint(180,-320,0)); + trainTrackTypes[LC_TTS_LEFT_BRANCH] = trackType; + + // Right branch + trackType = new TrainTrackType(); + trackType->Load(Library,mTrackTypeFilenames[LC_TTS_RIGHT_BRANCH]); + trackType->AddConnection(new TrainTrackConnectionPoint(0,320,0)); + trackType->AddConnection(new TrainTrackConnectionPoint(180,-320,0)); + trackType->AddConnection(new TrainTrackConnectionPoint(-22.50,x_right_branch,y_right_branch)); + trainTrackTypes[LC_TTS_RIGHT_BRANCH] = trackType; + + // Create map for lookup track type by name + for(int i = 0; i < LC_TTS_NUMITEMS; i++) trackTypesByName.insert({mTrackTypeFilenames[i], static_cast(i)}); +} + + +TrainTrackSystem::~TrainTrackSystem() {} + +void TrainTrackSystem::setColorIndex(int mColorIndex) { + this->mColorIndex = mColorIndex; +} + +void TrainTrackSystem::setCurrentStep(int mCurrentStep) { + this->mCurrentStep = mCurrentStep; +} + +void TrainTrackSystem::addFirstTrackSection(lcMatrix44 position, enum LC_TTS_TYPES trackTypeId) { + TrainTrackType* trainTrackType = trainTrackTypes[trackTypeId]; + trackSections.push_back(new TrainTrackSection(trainTrackType, trackTypeId,position, mCurrentStep, mColorIndex)); +} + +void TrainTrackSystem::addTrackSection(int fromTrackSectionIdx, int fromTrackSectionConnectionIdx, enum LC_TTS_TYPES toTrackType, int toTrackTypeConnectionIdx) +{ + TrainTrackSection* fromTrackSection = trackSections[fromTrackSectionIdx]; + TrainTrackType* fromTrack = trainTrackTypes[fromTrackSection->trackTypeId]; + TrainTrackConnectionPoint * fromConnectIdx = fromTrack->GetConnection(fromTrackSectionConnectionIdx); + TrainTrackType* toTrack = trainTrackTypes[toTrackType]; + TrainTrackConnectionPoint * toConnectIdx = toTrack->GetConnection(toTrackTypeConnectionIdx); + + lcMatrix44 currentLocation = fromTrackSection->location; + lcMatrix44 mat44; + lcMatrix44 matOffset; + + // calculate position on exiting connection point + mat44 = lcMatrix44Identity(); + mat44 = lcMatrix44RotationZ(LC_DTOR * fromConnectIdx->angle); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(fromConnectIdx->xy_coordinate.x, fromConnectIdx->xy_coordinate.y,0)); + + matOffset = lcMul(mat44, matOffset); + + currentLocation = lcMul(matOffset,currentLocation); + + // calculate position on entering new track section + mat44 = lcMatrix44Identity(); + mat44 = lcMatrix44RotationZ(LC_DTOR * (180 - toConnectIdx->angle)); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(-toConnectIdx->xy_coordinate.x, -toConnectIdx->xy_coordinate.y,0)); + + matOffset = lcMul(matOffset,mat44); + + currentLocation = lcMul(matOffset,currentLocation); + + trackSections.push_back(new TrainTrackSection(toTrack, toTrackType,currentLocation, mCurrentStep, mColorIndex)); +} + + +void TrainTrackSystem::addTrackSection(TrainTrackSection* fromTrackSection, int fromTrackSectionConnectionIdx, enum LC_TTS_TYPES toTrackType, int toTrackTypeConnectionIdx) +{ + TrainTrackType* fromTrack = trainTrackTypes[fromTrackSection->trackTypeId]; + TrainTrackConnectionPoint * fromConnectIdx = fromTrack->GetConnection(fromTrackSectionConnectionIdx); + TrainTrackType* toTrack = trainTrackTypes[toTrackType]; + TrainTrackConnectionPoint * toConnectIdx = toTrack->GetConnection(toTrackTypeConnectionIdx); + + lcMatrix44 currentLocation = fromTrackSection->location; + lcMatrix44 mat44; + lcMatrix44 matOffset; + + // calculate position on exiting connection point + mat44 = lcMatrix44Identity(); + mat44 = lcMatrix44RotationZ(LC_DTOR * fromConnectIdx->angle); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(fromConnectIdx->xy_coordinate.x, fromConnectIdx->xy_coordinate.y,0)); + + matOffset = lcMul(mat44, matOffset); + + currentLocation = lcMul(matOffset,currentLocation); + + // calculate position on entering new track section + mat44 = lcMatrix44Identity(); + mat44 = lcMatrix44RotationZ(LC_DTOR * (180 - toConnectIdx->angle)); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(-toConnectIdx->xy_coordinate.x, -toConnectIdx->xy_coordinate.y,0)); + + matOffset = lcMul(matOffset,mat44); + + currentLocation = lcMul(matOffset,currentLocation); + + trackSections.push_back(new TrainTrackSection(toTrack, toTrackType,currentLocation, mCurrentStep, mColorIndex)); +} + +bool TrainTrackSystem::deleteTrackSection(lcPiece* piece) +{ + float precisionErrorNumber = 0.001; + lcVector3 vec3PieceDel = piece->GetRotationCenter(); + + for(unsigned long i = 0; i < trackSections.size(); i++) { + + lcVector3 vec3PieceCur = trackSections[i]->location.GetTranslation(); + + if(abs(vec3PieceDel.x - vec3PieceCur.x) < precisionErrorNumber && + abs(vec3PieceDel.y - vec3PieceCur.y) < precisionErrorNumber && + abs(vec3PieceDel.z - vec3PieceCur.z) < precisionErrorNumber) + { + trackSections.erase(trackSections.begin() + i); + return true; + } + } + return false; +} + +std::vector TrainTrackSystem::getTrackTypes() +{ + std::vector trackTypes; + for(int i = 0; i < LC_TTS_NUMITEMS; i++) { + trackTypes.push_back(trainTrackTypes[i]->pieceInfo); + } + return trackTypes; +} + +std::vector TrainTrackSystem::GetTrackSections() +{ + return trackSections; +} + +std::vector* TrainTrackSystem::GetTrackSectionsPtr() +{ + return &trackSections; +} + +std::vector TrainTrackSystem::GetPieces() +{ + std::vector pieces; + PieceInfo* pieceInfo; + + lcPiecesLibrary* Library = lcGetPiecesLibrary(); + PieceInfo* pieceInfoSel = Library->FindPiece("3023.dat", nullptr, false, false); + + TrainTrackSection* trackSection; + lcPiece* piece; + + for(unsigned long i = 0; i < trackSections.size(); i++) + { + trackSection = trackSections[i]; + pieceInfo = trainTrackTypes[trackSection->trackTypeId]->pieceInfo; + piece = new lcPiece(pieceInfo); + piece->Initialize(trackSection->location, trackSection->mCurrentStep); + piece->SetColorIndex(trackSection->mColorIndex); + pieces.push_back(piece); + + // Add 1 x 2 plate on each connecton point, for detect selection + lcMatrix44 mat44; + lcMatrix44 matOffset; + + for(int con_no = 0; con_no < trackSection->GetNoOfConnections(); con_no++) + { + mat44 = trackSection->GetConnectionLocation(con_no); + + matOffset = lcMatrix44Identity(); + matOffset.SetTranslation(lcVector3(-10, 0, 8)); + + mat44 = lcMul(matOffset,mat44); + + matOffset = lcMatrix44Identity(); + matOffset = lcMatrix44RotationZ(LC_DTOR * 90); + + mat44 = lcMul(matOffset,mat44); + + piece = new lcPiece(pieceInfoSel); + piece->Initialize(mat44, trackSection->mCurrentStep); + piece->SetColorIndex(trackSection->mColorIndex); + //pieces.Add(piece); + pieces.push_back(piece); + } + } + return pieces; +} + +lcModel* TrainTrackSystem::GetModel() +{ + std::vector trackSystem = this->GetPieces(); + mModel->SetTrainTrackSystem(trackSystem); + return mModel.get(); +} + +void TrainTrackSystem::SetModel() +{ + std::vector trackSystem = this->GetPieces(); + mModel->SetTrainTrackSystem(trackSystem); +} + + +LC_TTS_TYPES TrainTrackSystem::findTrackTypeByString(const char *tracktypeName) +{ + std::string str_search = tracktypeName; + std::map::iterator search = trackTypesByName.find(str_search); + if (search != trackTypesByName.end()) { + return search->second; + } + return static_cast(-1); +} diff --git a/common/traintracksystem.h b/common/traintracksystem.h new file mode 100644 index 00000000..92a0336d --- /dev/null +++ b/common/traintracksystem.h @@ -0,0 +1,105 @@ +#pragma once + +#include "lc_library.h" +#include +#include +#include +#include + + +enum LC_TTS_TYPES { + LC_TTS_STRAIGHT, + LC_TTS_CURVED, + LC_TTS_CROSS, + LC_TTS_LEFT_BRANCH, + LC_TTS_RIGHT_BRANCH, + LC_TTS_NUMITEMS +}; + +class TrainTrackConnectionPoint { + public: + TrainTrackConnectionPoint(float angle, float x, float y); + float angle; + lcVector2 xy_coordinate; +}; + + +class TrainTrackType { + public: + + void Load(lcPiecesLibrary* Library, char const* filename); + void AddConnection(TrainTrackConnectionPoint *connectionPoint); + TrainTrackConnectionPoint *GetConnection(int index); + + //lcArray& GetConnections(); + std::vector& GetConnections(); + PieceInfo* pieceInfo; + int GetNoOfConnections(); + private: + char const* filename; + //lcArray connectionPoints; + std::vector connectionPoints; + +}; + +class TrainTrackSection { + public: + TrainTrackSection(TrainTrackType *trackType, enum LC_TTS_TYPES trackTypeId, lcMatrix44 location, int mCurrentStep, int mColorIndex); + lcMatrix44 GetConnectionLocation(int connectionNo); + int GetNoOfConnections(); + int FindConnectionNumber(lcVector3 searchLocation); + TrainTrackType *trackType; + enum LC_TTS_TYPES trackTypeId; + lcMatrix44 location; + int mCurrentStep; + int mColorIndex; +}; + + +class TrainTrackSystem +{ + public: + TrainTrackSystem(); + ~TrainTrackSystem(); + void setColorIndex(int colorIndex); + void setCurrentStep(int mCurrentStep); + + void addFirstTrackSection(lcMatrix44 position, enum LC_TTS_TYPES trackTypeId); + void addTrackSection(int fromTrackSectionIdx, int fromTrackSectionConnectionIdx, enum LC_TTS_TYPES toTrackType, int toTrackTypeConnectionIdx); + void addTrackSection(TrainTrackSection* fromTrackSection, int fromTrackSectionConnectionIdx, enum LC_TTS_TYPES toTrackType, int toTrackTypeConnectionIdx); + bool deleteTrackSection(lcPiece* piece); + + //lcArray getTrackTypes(); + std::vector getTrackTypes(); + + //lcArray GetTrackSections(); + std::vector GetTrackSections(); + //lcArray* GetTrackSectionsPtr(); + std::vector* GetTrackSectionsPtr(); + + //lcArray GetPieces(); + std::vector GetPieces(); + + lcModel* GetModel(); + void SetModel(); + LC_TTS_TYPES findTrackTypeByString(const char *tracktypeName); + private: + + //lcArray trainTrackTypes; + std::vector trainTrackTypes; + + static const char* mTrackTypeFilenames[LC_TTS_NUMITEMS]; + //lcArray trackSections; + std::vector trackSections; + + int mColorIndex; + int mCurrentStep; + + std::unique_ptr mModel; + + std::map trackTypesByName; + +}; + + + diff --git a/leocad.pro b/leocad.pro index 6aac24a6..8363048d 100644 --- a/leocad.pro +++ b/leocad.pro @@ -170,6 +170,7 @@ SOURCES += \ common/image.cpp \ common/light.cpp \ common/minifig.cpp \ + common/traintracksystem.cpp \ common/object.cpp \ common/piece.cpp \ common/pieceinf.cpp \ @@ -203,6 +204,7 @@ SOURCES += \ common/lc_mesh.cpp \ common/lc_meshloader.cpp \ common/lc_minifigdialog.cpp \ + common/lc_traintracksystemdialog.cpp \ common/lc_model.cpp \ common/lc_modellistdialog.cpp \ common/lc_objectproperty.cpp \ @@ -242,6 +244,7 @@ HEADERS += \ common/image.h \ common/light.h \ common/minifig.h \ + common/traintracksystem.h \ common/object.h \ common/piece.h \ common/pieceinf.h \ @@ -277,6 +280,7 @@ HEADERS += \ common/lc_mesh.h \ common/lc_meshloader.h \ common/lc_minifigdialog.h \ + common/lc_traintracksystemdialog.h \ common/lc_model.h \ common/lc_modellistdialog.h \ common/lc_objectproperty.h \ @@ -323,6 +327,7 @@ FORMS += \ common/lc_categorydialog.ui \ common/lc_groupdialog.ui \ common/lc_minifigdialog.ui \ + common/lc_traintracksystemdialog.ui \ common/lc_modellistdialog.ui \ common/lc_pagesetupdialog.ui \ common/lc_partpalettedialog.ui