]> Shamusworld >> Repos - architektonas/blobdiff - src/applicationwindow.cpp
Added new triangulation tool, ability to snap to endpoints/intersections.
[architektonas] / src / applicationwindow.cpp
index 83dbd54bd1b86f20bc82964473e6641f5900f725..ad3bc8d9ec0b4c209087f7d58d39e8c79c427fc2 100644 (file)
 
 #include "about.h"
 #include "blockwidget.h"
+#include "dimension.h"
 #include "drawingview.h"
 #include "drawarcaction.h"
 #include "drawcircleaction.h"
 #include "drawdimensionaction.h"
 #include "drawlineaction.h"
+#include "drawsplineaction.h"
 #include "fileio.h"
 #include "generaltab.h"
+#include "geometry.h"
 #include "layerwidget.h"
+#include "line.h"
 #include "mirroraction.h"
 #include "painter.h"
+#include "rotateaction.h"
 #include "settingsdialog.h"
+#include "triangulateaction.h"
+#include "trimaction.h"
 
 
 // Class variables
@@ -82,7 +89,7 @@ ApplicationWindow::ApplicationWindow():
        dock2->setObjectName("Blocks");
 
        //      Create status bar
-       zoomIndicator = new QLabel("Grid: 12.0\" Zoom: 12.5%");
+       zoomIndicator = new QLabel("Grid: 12.0\" BU: Inch");
        statusBar()->addPermanentWidget(zoomIndicator);
        statusBar()->showMessage(tr("Ready"));
 
@@ -117,6 +124,11 @@ void ApplicationWindow::FileOpen(void)
 {
        QString filename = QFileDialog::getOpenFileName(this, tr("Open Drawing"),
                "", tr("Architektonas files (*.drawing)"));
+
+       // User cancelled open
+       if (filename.isEmpty())
+               return;
+
        FILE * file = fopen(filename.toAscii().data(), "r");
 
        if (file == 0)
@@ -177,7 +189,8 @@ void ApplicationWindow::FileSave(void)
                msg.setIcon(QMessageBox::Critical);
                msg.exec();
                // In this case, we should unlink the created file, since it's not right...
-               unlink(documentName.toAscii().data());
+//             unlink(documentName.toAscii().data());
+               QFile::remove(documentName);
                return;
        }
 
@@ -257,6 +270,20 @@ void ApplicationWindow::MirrorTool(void)
 }
 
 
+void ApplicationWindow::TrimTool(void)
+{
+       ClearUIToolStatesExcept(trimAct);
+       SetInternalToolStates();
+}
+
+
+void ApplicationWindow::TriangulateTool(void)
+{
+       ClearUIToolStatesExcept(triangulateAct);
+       SetInternalToolStates();
+}
+
+
 void ApplicationWindow::AddLineTool(void)
 {
        ClearUIToolStatesExcept(addLineAct);
@@ -285,6 +312,13 @@ void ApplicationWindow::AddPolygonTool(void)
 }
 
 
+void ApplicationWindow::AddSplineTool(void)
+{
+       ClearUIToolStatesExcept(addSplineAct);
+       SetInternalToolStates();
+}
+
+
 void ApplicationWindow::ZoomInTool(void)
 {
        double zoomFactor = 2.0;
@@ -311,18 +345,14 @@ when zooming in, new origin will be (xCenter - origin.x) / 2, (yCenter - origin.
        Painter::origin = newOrigin;
 
 //printf("Zoom in... level going from %02f to ", Painter::zoom);
-       // This just zooms leaving origin intact... should zoom in at the current center! [DONE]
-       // This should actually be calculated by drawing->gridPixels / grid size.
+       // This just zooms leaving origin intact... should zoom in at the current
+       // center! [DONE]
        Painter::zoom *= zoomFactor;
-//     drawing->gridSpacing = drawing->gridPixels / Painter::zoom;
        Object::gridSpacing = drawing->gridPixels / Painter::zoom;
-//     zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
-//     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
-       zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
        drawing->UpdateGridBackground();
        drawing->update();
 
-//     baseUnitInput->setText(QString("%1").arg(drawing->gridSpacing));
+       zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
        baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
 }
 
@@ -354,17 +384,14 @@ x 2 = (-426, -301)
 //printf("newOrigin=%.2f,%.2f;\n", newOrigin.x, newOrigin.y);
        Painter::origin = newOrigin;
 //printf("Zoom out...\n");
-       // This just zooms leaving origin intact... should zoom out at the current center! [DONE]
+       // This just zooms leaving origin intact... should zoom out at the current
+       // center! [DONE]
        Painter::zoom /= zoomFactor;
-//     drawing->gridSpacing = drawing->gridPixels / Painter::zoom;
        Object::gridSpacing = drawing->gridPixels / Painter::zoom;
-//     zoomIndicator->setText(QString("Grid: %2\" Zoom: %1%").arg(Painter::zoom * 100.0 * SCREEN_ZOOM).arg(drawing->gridSpacing));
-//     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(drawing->gridSpacing));
-       zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
        drawing->UpdateGridBackground();
        drawing->update();
 
-//     baseUnitInput->setText(QString("%1").arg(drawing->gridSpacing));
+       zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Object::gridSpacing));
        baseUnitInput->setText(QString("%1").arg(Object::gridSpacing));
 }
 
@@ -386,6 +413,9 @@ void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
        if (exception != addPolygonAct)
                addPolygonAct->setChecked(false);
 
+       if (exception != addSplineAct)
+               addSplineAct->setChecked(false);
+
        if (exception != deleteAct)
                deleteAct->setChecked(false);
 
@@ -394,6 +424,12 @@ void ApplicationWindow::ClearUIToolStatesExcept(QAction * exception)
 
        if (exception != mirrorAct)
                mirrorAct->setChecked(false);
+
+       if (exception != trimAct)
+               trimAct->setChecked(false);
+
+       if (exception != triangulateAct)
+               triangulateAct->setChecked(false);
 }
 
 
@@ -401,7 +437,6 @@ void ApplicationWindow::SetInternalToolStates(void)
 {
        Object::SetDeleteActive(deleteAct->isChecked());
        Object::SetDimensionActive(addDimensionAct->isChecked());
-       drawing->SetRotateToolActive(rotateAct->isChecked());
 
        // We can be sure that if we've come here, then either an active tool is
        // being deactivated, or a new tool is being created. In either case, the
@@ -413,23 +448,20 @@ void ApplicationWindow::SetInternalToolStates(void)
                Object::ignoreClicks = false;
        }
 
-#if 0
-       drawing->SetAddLineToolActive(addLineAct->isChecked());
-       drawing->SetAddCircleToolActive(addCircleAct->isChecked());
-       drawing->SetAddArcToolActive(addArcAct->isChecked());
-       drawing->SetAddDimensionToolActive(addDimensionAct->isChecked());
-#else
        drawing->SetToolActive(addLineAct->isChecked() ? new DrawLineAction() : NULL);
        drawing->SetToolActive(addCircleAct->isChecked() ? new DrawCircleAction() : NULL);
        drawing->SetToolActive(addArcAct->isChecked() ? new DrawArcAction() : NULL);
        drawing->SetToolActive(addDimensionAct->isChecked() ? new DrawDimensionAction() : NULL);
+       drawing->SetToolActive(addSplineAct->isChecked() ? new DrawSplineAction() : NULL);
        drawing->SetToolActive(mirrorAct->isChecked() ? new MirrorAction() : NULL);
-#endif
+       drawing->SetToolActive(rotateAct->isChecked() ? new RotateAction() : NULL);
+       drawing->SetToolActive(trimAct->isChecked() ? new TrimAction() : NULL);
+       drawing->SetToolActive(triangulateAct->isChecked() ? new TriangulateAction() : NULL);
 
        if (drawing->toolAction)
                Object::ignoreClicks = true;
 
-       update();
+       drawing->update();
 }
 
 
@@ -512,6 +544,78 @@ else
 }
 
 
+void ApplicationWindow::HandleConnection(void)
+{
+//double tt = Geometry::ParameterOfLineAndPoint(Vector(0, 0), Vector(10, 0), Vector(8, 2));
+//printf("Parameter of point @ (8,2) of line (0,0), (10,0): %lf\n", tt);
+       int itemsSelected = drawing->document.ItemsSelected();
+
+       // If nothing selected, do nothing
+       if (itemsSelected == 0)
+       {
+               statusBar()->showMessage(tr("No objects selected to connect."));
+               return;
+       }
+
+       // If one thing selected, do nothing
+       if (itemsSelected == 1)
+       {
+               statusBar()->showMessage(tr("Nothing to connect object to."));
+               return;
+       }
+
+       // This is O(n^2 / 2) :-P
+       for(int i=0; i<itemsSelected; i++)
+       {
+               Object * obj1 = drawing->document.SelectedItem(i);
+
+               for(int j=i+1; j<itemsSelected; j++)
+               {
+                       Object * obj2 = drawing->document.SelectedItem(j);
+                       double t, u, v, w;
+
+//                     if ((obj1->type != OTLine) || (obj2->type != OTLine))
+//                             continue;
+
+                       if ((obj1->type == OTLine) && (obj2->type == OTLine))
+                       {
+//printf("Testing objects for intersection (%X, %X)...\n", obj1, obj2);
+                               int intersects = Geometry::Intersects((Line *)obj1, (Line *)obj2, &t, &u);
+//printf("  (%s) --> t=%lf, u=%lf\n", (intersects ? "true" : "FALSE"), t, u);
+
+                               if (intersects)
+                               {
+       //printf("Connecting objects (%X, %X)...\n", obj1, obj2);
+                                       obj1->Connect(obj2, u);
+                                       obj2->Connect(obj1, t);
+                               }
+                       }
+                       else if (((obj1->type == OTLine) && (obj2->type == OTDimension))
+                               || ((obj2->type == OTLine) && (obj1->type == OTDimension)))
+                       {
+printf("Testing Line<->Dimension intersection...\n");
+                               Line * line = (Line *)(obj1->type == OTLine ? obj1 : obj2);
+                               Dimension * dim = (Dimension *)(obj1->type == OTDimension ? obj1 : obj2);
+
+                               int intersects = Geometry::Intersects(line, dim, &t, &u);
+printf("   -> intersects = %i, t=%lf, u=%lf\n", intersects, t, u);
+
+                               if (intersects)
+                               {
+                                       obj1->Connect(obj2, u);
+                                       obj2->Connect(obj1, t);
+                               }
+                       }
+               }
+       }
+}
+
+
+void ApplicationWindow::HandleDisconnection(void)
+{
+}
+
+
 void ApplicationWindow::HandleGridSizeInPixels(int size)
 {
        drawing->SetGridSize(size);
@@ -591,6 +695,9 @@ void ApplicationWindow::CreateActions(void)
        addPolygonAct = CreateAction(tr("Add &Polygon"), tr("Add Polygon"), tr("Add polygons to the drawing."), QIcon(":/res/add-polygon-tool.png"), QKeySequence("A,P"), true);
        connect(addPolygonAct, SIGNAL(triggered()), this, SLOT(AddPolygonTool()));
 
+       addSplineAct = CreateAction(tr("Add &Spline"), tr("Add Spline"), tr("Add a NURB spline to the drawing."), QIcon(":/res/add-spline-tool.png"), QKeySequence("A,S"), true);
+       connect(addSplineAct, SIGNAL(triggered()), this, SLOT(AddSplineTool()));
+
        aboutAct = CreateAction(tr("About &Architektonas"), tr("About Architektonas"), tr("Gives information about this program."), QIcon(":/res/generic-tool.png"), QKeySequence());
        connect(aboutAct, SIGNAL(triggered()), this, SLOT(HelpAbout()));
 
@@ -624,12 +731,20 @@ void ApplicationWindow::CreateActions(void)
        connect(groupAct, SIGNAL(triggered()), this, SLOT(HandleGrouping()));
 
        connectAct = CreateAction(tr("&Connect"), tr("Connect"), tr("Connect objects at point."), QIcon(":/res/connect-tool.png"), QKeySequence("c,c"));
+       connect(connectAct, SIGNAL(triggered()), this, SLOT(HandleConnection()));
 
        disconnectAct = CreateAction(tr("&Disconnect"), tr("Disconnect"), tr("Disconnect objects joined at point."), QIcon(":/res/disconnect-tool.png"), QKeySequence("d,d"));
+       connect(disconnectAct, SIGNAL(triggered()), this, SLOT(HandleDisconnection()));
 
        mirrorAct = CreateAction(tr("&Mirror"), tr("Mirror"), tr("Mirror selected objects around a line."), QIcon(":/res/mirror-tool.png"), QKeySequence("m,i"), true);
        connect(mirrorAct, SIGNAL(triggered()), this, SLOT(MirrorTool()));
 
+       trimAct = CreateAction(tr("&Trim"), tr("Trim"), tr("Trim extraneous lines from selected objects."), QIcon(":/res/trim-tool.png"), QKeySequence("t,r"), true);
+       connect(trimAct, SIGNAL(triggered()), this, SLOT(TrimTool()));
+
+       triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
+       connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
+
 
 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
@@ -700,6 +815,8 @@ void ApplicationWindow::CreateMenus(void)
        menu->addAction(fixLengthAct);
        menu->addAction(rotateAct);
        menu->addAction(mirrorAct);
+       menu->addAction(trimAct);
+       menu->addAction(triangulateAct);
        menu->addAction(connectAct);
        menu->addAction(disconnectAct);
        menu->addSeparator();
@@ -709,6 +826,7 @@ void ApplicationWindow::CreateMenus(void)
        menu->addAction(addCircleAct);
        menu->addAction(addArcAct);
        menu->addAction(addPolygonAct);
+       menu->addAction(addSplineAct);
        menu->addAction(addDimensionAct);
        menu->addSeparator();
        menu->addAction(settingsAct);
@@ -748,6 +866,8 @@ void ApplicationWindow::CreateToolbars(void)
        toolbar->addAction(fixLengthAct);
        toolbar->addAction(rotateAct);
        toolbar->addAction(mirrorAct);
+       toolbar->addAction(trimAct);
+       toolbar->addAction(triangulateAct);
        toolbar->addAction(deleteAct);
        toolbar->addAction(connectAct);
        toolbar->addAction(disconnectAct);
@@ -756,6 +876,7 @@ void ApplicationWindow::CreateToolbars(void)
        toolbar->addAction(addCircleAct);
        toolbar->addAction(addArcAct);
        toolbar->addAction(addPolygonAct);
+       toolbar->addAction(addSplineAct);
        toolbar->addAction(addDimensionAct);
 
        spinbox->setRange(4, 256);