Tue, 07 May 2013 19:48:51 +0300
Added Intersector interface. I'm beginning to think that groups were a bad idea...
extprogs.cpp | file | annotate | diff | comparison | revisions | |
extprogs.h | file | annotate | diff | comparison | revisions | |
gui.cpp | file | annotate | diff | comparison | revisions | |
gui.h | file | annotate | diff | comparison | revisions | |
gui_actions.cpp | file | annotate | diff | comparison | revisions | |
icons/ytruder.png | file | annotate | diff | comparison | revisions | |
zz_configDialog.cpp | file | annotate | diff | comparison | revisions |
--- a/extprogs.cpp Tue May 07 17:51:10 2013 +0300 +++ b/extprogs.cpp Tue May 07 19:48:51 2013 +0300 @@ -23,6 +23,7 @@ #include <qdialogbuttonbox.h> #include <qspinbox.h> #include <qcheckbox.h> +#include <qcombobox.h> #include "common.h" #include "config.h" #include "misc.h" @@ -105,7 +106,7 @@ } // ============================================================================= -void writeSelection (str fname) { +void writeObjects (std::vector<LDObject*>& objects, str fname) { // Write the input file FILE* fp = fopen (fname, "w"); if (!fp) { @@ -113,7 +114,7 @@ return; } - for (LDObject* obj : g_win->sel ()) { + for (LDObject* obj : objects) { str line = fmt ("%s\r\n", obj->getContents ().chars ()); fwrite (line.chars(), 1, ~line, fp); } @@ -122,6 +123,24 @@ } // ============================================================================= +void writeSelection (str fname) { + writeObjects (g_win->sel (), fname); +} + +// ============================================================================= +void writeGroup (const LDObject::Group group, str fname) { + std::vector<LDObject*> objects; + for (LDObject*& obj : g_curfile->m_objs) { + if (obj->group() != group) + continue; + + objects.push_back (obj); + } + + writeObjects (objects, fname); +} + +// ============================================================================= void runUtilityProcess (extprog prog, str path, QString argvstr) { QTemporaryFile input, output; str inputname, outputname; @@ -160,8 +179,8 @@ } } -// ============================================================================= -static void insertOutput (str fname, bool replace) { +// ======================================================================================================================================== +static void insertOutput (str fname, bool replace, vector<LDObject::Group> groupsToReplace) { #ifndef RELEASE QFile::copy (fname, "./output.dat"); #endif @@ -182,6 +201,9 @@ if (replace) *cmb << g_win->deleteSelection (); + for (const LDObject::Group group : groupsToReplace) + *cmb << g_win->deleteGroup (group); + // Insert the new objects g_win->sel ().clear (); for (LDObject* obj : objs) { @@ -208,10 +230,10 @@ g_win->refresh (); } -QDialogButtonBox* makeButtonBox (QDialog* dlg) { +QDialogButtonBox* makeButtonBox (QDialog& dlg) { QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QWidget::connect (bbx_buttons, SIGNAL (accepted ()), dlg, SLOT (accept ())); - QWidget::connect (bbx_buttons, SIGNAL (rejected ()), dlg, SLOT (reject ())); + QWidget::connect (bbx_buttons, SIGNAL (accepted ()), &dlg, SLOT (accept ())); + QWidget::connect (bbx_buttons, SIGNAL (rejected ()), &dlg, SLOT (reject ())); return bbx_buttons; } @@ -223,12 +245,12 @@ if (!checkProgPath (prog_ytruder, Ytruder)) return; - QDialog* dlg = new QDialog (g_win); + QDialog dlg; - RadioBox* rb_mode = new RadioBox ("Extrusion mode", {"Distance", "Symmetry", "Projection", "Radial"}, 0, Qt::Horizontal, dlg); - RadioBox* rb_axis = new RadioBox ("Axis", {"X", "Y", "Z"}, 0, Qt::Horizontal, dlg); - LabeledWidget<QDoubleSpinBox>* dsb_depth = new LabeledWidget<QDoubleSpinBox> ("Plane depth", dlg), - *dsb_condAngle = new LabeledWidget<QDoubleSpinBox> ("Conditional line threshold", dlg); + RadioBox* rb_mode = new RadioBox ("Extrusion mode", {"Distance", "Symmetry", "Projection", "Radial"}, 0, Qt::Horizontal); + RadioBox* rb_axis = new RadioBox ("Axis", {"X", "Y", "Z"}, 0, Qt::Horizontal); + LabeledWidget<QDoubleSpinBox>* dsb_depth = new LabeledWidget<QDoubleSpinBox> ("Plane depth"), + *dsb_condAngle = new LabeledWidget<QDoubleSpinBox> ("Conditional line threshold"); rb_axis->setValue (Y); dsb_depth->w ()->setMinimum (-10000.0); @@ -236,16 +258,16 @@ dsb_depth->w ()->setDecimals (3); dsb_condAngle->w ()->setValue (30.0f); - QVBoxLayout* layout = new QVBoxLayout (dlg); + QVBoxLayout* layout = new QVBoxLayout (&dlg); layout->addWidget (rb_mode); layout->addWidget (rb_axis); layout->addWidget (dsb_depth); layout->addWidget (dsb_condAngle); layout->addWidget (makeButtonBox (dlg)); - dlg->setWindowIcon (getIcon ("extrude")); + dlg.setWindowIcon (getIcon ("extrude")); - if (!dlg->exec ()) + if (!dlg.exec ()) return; // Read the user's choices @@ -269,10 +291,10 @@ writeSelection (inDATName); runUtilityProcess (Ytruder, prog_ytruder, argv); - insertOutput (outDATName, false); + insertOutput (outDATName, false, {}); } -// ============================================================================= +// ======================================================================================================================================== // Rectifier interface MAKE_ACTION (rectifier, "Rectifier", "rectifier", "Optimizes quads into rect primitives.", (0)) { setlocale (LC_ALL, "C"); @@ -280,12 +302,12 @@ if (!checkProgPath (prog_rectifier, Rectifier)) return; - QDialog* dlg = new QDialog (g_win); + QDialog dlg; QCheckBox* cb_condense = new QCheckBox ("Condense triangles to quads"), *cb_subst = new QCheckBox ("Substitute rect primitives"), *cb_condlineCheck = new QCheckBox ("Don't replace quads with adj. condlines"), *cb_colorize = new QCheckBox ("Colorize resulting objects"); - LabeledWidget<QDoubleSpinBox>* dsb_coplthres = new LabeledWidget<QDoubleSpinBox> ("Coplanarity threshold", dlg); + LabeledWidget<QDoubleSpinBox>* dsb_coplthres = new LabeledWidget<QDoubleSpinBox> ("Coplanarity threshold"); dsb_coplthres->w ()->setMinimum (0.0f); dsb_coplthres->w ()->setMaximum (360.0f); @@ -294,7 +316,7 @@ cb_condense->setChecked (true); cb_subst->setChecked (true); - QVBoxLayout* layout = new QVBoxLayout (dlg); + QVBoxLayout* layout = new QVBoxLayout (&dlg); layout->addWidget (cb_condense); layout->addWidget (cb_subst); layout->addWidget (cb_condlineCheck); @@ -302,7 +324,7 @@ layout->addWidget (dsb_coplthres); layout->addWidget (makeButtonBox (dlg)); - if (!dlg->exec ()) + if (!dlg.exec ()) return; const bool condense = cb_condense->isChecked (), @@ -328,5 +350,106 @@ writeSelection (inDATName); runUtilityProcess (Rectifier, prog_rectifier, argv); - insertOutput (outDATName, true); + insertOutput (outDATName, true, {}); +} + +// ======================================================================================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ======================================================================================================================================= +// Intersector interface +MAKE_ACTION (intersector, "Intersector", "intersector", "Perform clipping between two input groups.", (0)) { + setlocale (LC_ALL, "C"); + + if (!checkProgPath (prog_intersector, Intersector)) + return; + + QDialog dlg; + + LabeledWidget<QComboBox>* cmb_ingroup = new LabeledWidget<QComboBox> ("Input group", new QComboBox), + *cmb_cutgroup = new LabeledWidget<QComboBox> ("Cutter group", new QComboBox); + QCheckBox* cb_colorize = new QCheckBox ("Colorize output"), + *cb_nocondense = new QCheckBox ("No condensing"), + *cb_repeatInverse = new QCheckBox ("Repeat inverse"), + *cb_edges = new QCheckBox ("Add edges"); + LabeledWidget<QDoubleSpinBox>* dsb_prescale = new LabeledWidget<QDoubleSpinBox> ("Prescaling factor"); + + cb_repeatInverse->setWhatsThis ("If this is set, " APPNAME " runs Intersector a second time with inverse files to cut the " + " cutter group with the input group. Both groups are cut by the intersection."); + cb_edges->setWhatsThis ("Makes " APPNAME " try run Isecalc to create edgelines for the intersection."); + + makeGroupSelector (cmb_ingroup->w ()); + makeGroupSelector (cmb_cutgroup->w ()); + dsb_prescale->w ()->setMinimum (0.0f); + dsb_prescale->w ()->setMaximum (10000.0f); + dsb_prescale->w ()->setSingleStep (0.01f); + dsb_prescale->w ()->setValue (1.0f); + + QVBoxLayout* layout = new QVBoxLayout (&dlg); + layout->addWidget (cmb_ingroup); + layout->addWidget (cmb_cutgroup); + + QHBoxLayout* cblayout = new QHBoxLayout; + cblayout->addWidget (cb_colorize); + cblayout->addWidget (cb_nocondense); + + QHBoxLayout* cb2layout = new QHBoxLayout; + cb2layout->addWidget (cb_repeatInverse); + cb2layout->addWidget (cb_edges); + + layout->addLayout (cblayout); + layout->addLayout (cb2layout); + layout->addWidget (dsb_prescale); + layout->addWidget (makeButtonBox (dlg)); + +exec: + if (!dlg.exec ()) + return; + + const LDObject::Group inGroup = (LDObject::Group) cmb_ingroup->w ()->currentIndex (), + cutGroup = (LDObject::Group) cmb_cutgroup->w ()->currentIndex (); + const bool repeatInverse = cb_repeatInverse->isChecked (); + + if (inGroup == cutGroup) { + critical ("Cannot use the same group for both input and cutter!"); + goto exec; + } + + // Five temporary files! + // indat = input group file + // cutdat = cutter group file + // outdat = primary output + // outdat2 = inverse output + // edgesdat = edges output (isecalc) + QTemporaryFile indat, cutdat, outdat, outdat2, edgesdat; + str inDATName, cutDATName, outDATName, outDAT2Name, edgesDATName; + + if (!mkTempFile (indat, inDATName) || !mkTempFile (cutdat, cutDATName) || + !mkTempFile (outdat, outDATName) || !mkTempFile (outdat2, outDAT2Name) || + !mkTempFile (edgesdat, edgesDATName)) + { + return; + } + + str parms = fmt ("%s %s -s %f", + (cb_colorize->isChecked ()) ? "-c" : "", + (cb_nocondense->isChecked ()) ? "-t" : "", + dsb_prescale->w ()->value ()); + + str argv_normal = fmt ("%s %s %s %s", parms.chars (), inDATName.chars (), cutDATName.chars (), outDATName.chars ()); + str argv_inverse = fmt ("%s %s %s %s", parms.chars (), cutDATName.chars (), inDATName.chars (), outDAT2Name.chars ()); + + writeGroup (inGroup, inDATName); + writeGroup (cutGroup, cutDATName); + runUtilityProcess (Intersector, prog_intersector, argv_normal); + insertOutput (outDATName, false, {inGroup}); + + if (repeatInverse) { + runUtilityProcess (Intersector, prog_intersector, argv_inverse); + insertOutput (outDAT2Name, false, {cutGroup}); + } + + if (cb_edges->isChecked ()) { + runUtilityProcess (Isecalc, prog_isecalc, fmt ("%s %s %s", inDATName.chars (), cutDATName.chars (), edgesDATName.chars ())); + insertOutput (edgesDATName, false, {}); + } } \ No newline at end of file
--- a/extprogs.h Tue May 07 17:51:10 2013 +0300 +++ b/extprogs.h Tue May 07 19:48:51 2013 +0300 @@ -22,7 +22,7 @@ #include <qobject.h> enum extprog { - IseCalc, + Isecalc, Intersector, Coverer, Ytruder,
--- a/gui.cpp Tue May 07 17:51:10 2013 +0300 +++ b/gui.cpp Tue May 07 19:48:51 2013 +0300 @@ -24,6 +24,7 @@ #include <qsplitter.h> #include <qlistwidget.h> #include <qtoolbutton.h> +#include <qcombobox.h> #include <qcoreapplication.h> #include "common.h" #include "gldraw.h" @@ -54,6 +55,8 @@ QColor (0, 255, 160), // emerald }; +QIcon g_groupSelectorIcons[6]; + const ushort g_numGroups = 2; // ============================================================================= @@ -96,6 +99,16 @@ setMinimumSize (320, 200); resize (800, 600); + // Init group bg icons + for (uchar i = 0; i < LDObject::NumGroups; ++i) { + QImage img (16, 16, QImage::Format_ARGB32); + QPainter paint (&img); + paint.fillRect (0, 0, 16, 16, Qt::black); + paint.fillRect (1, 1, 14, 14, g_GroupBackgrounds[i]); + + g_groupSelectorIcons[i] = QIcon (QPixmap::fromImage (img)); + } + connect (QCoreApplication::instance (), SIGNAL (aboutToQuit ()), this, SLOT (slot_lastSecondCleanup ())); } @@ -258,13 +271,7 @@ initMenu ("E&xternal Programs"); addMenuAction ("ytruder"); addMenuAction ("rectifier"); - -#ifndef RELEASE - // Debug menu - initMenu ("&Debug"); - addMenuAction ("addTestQuad"); // Add Test Quad - addMenuAction ("addTestRadial"); // Add Test Radial -#endif // RELEASE + addMenuAction ("intersector"); // Help menu initMenu ("&Help"); @@ -409,6 +416,7 @@ initSingleToolBar ("External Programs"); addToolBarAction ("ytruder"); addToolBarAction ("rectifier"); + addToolBarAction ("intersector"); initSingleToolBar ("Groups"); @@ -947,12 +955,12 @@ contextMenu->exec (pos); } -// ============================================================================= -DelHistory* ForgeWindow::deleteSelection () { +// ======================================================================================================================================== +DelHistory* ForgeWindow::deleteObjVector (const std::vector<LDObject*> objs) { vector<ulong> indices; - vector<LDObject*> cache, sel = g_win->sel (); + vector<LDObject*> cache; - for (LDObject* obj : sel) { + for (LDObject* obj : objs) { indices.push_back (obj->getIndex (g_curfile)); cache.push_back (obj->clone ()); @@ -966,7 +974,25 @@ return null; } -// ============================================================================= +// ======================================================================================================================================== +DelHistory* ForgeWindow::deleteSelection () { + return deleteObjVector (sel ()); +} + +// ======================================================================================================================================== +DelHistory* ForgeWindow::deleteGroup (const LDObject::Group group) { + vector<LDObject*> objs; + for (LDObject* obj : g_curfile->m_objs) { + if (obj->group () != group) + continue; + + objs.push_back (obj); + } + + return deleteObjVector (objs); +} + +// ======================================================================================================================================== void ObjectList::contextMenuEvent (QContextMenuEvent* ev) { g_win->spawnContextMenu (ev->globalPos ()); } @@ -1016,4 +1042,25 @@ fprintf (stderr, "%s: couldn't find action named `%s'!\n", __func__, name.chars ()); assert (false); return null; +} + +// ============================================================================= +void makeGroupSelector (QComboBox* box) { + ulong counts[6]; + uchar selGroup = 0; + memset (&counts[0], 0, sizeof counts); + + for (LDObject* obj : g_curfile->m_objs) + if (obj->group () != LDObject::NoGroup) + counts[obj->group ()]++; + + box->clear (); + for (uchar i = 0; i < LDObject::NumGroups; ++i) { + box->addItem (g_groupSelectorIcons[i], fmt ("%c (%lu objects)", QChar ('A' + i), counts[i])); + + if (counts[i] > 0 && selGroup == 0) + selGroup = i; + } + + box->setCurrentIndex (selGroup); } \ No newline at end of file
--- a/gui.h Tue May 07 17:51:10 2013 +0300 +++ b/gui.h Tue May 07 19:48:51 2013 +0300 @@ -32,6 +32,7 @@ #include "gldraw.h" #include "config.h" +class QComboBox; class ForgeWindow; class color; class QSplitter; @@ -137,7 +138,9 @@ LDObject::Type uniformSelectedType (); void scrollToSelection (); void spawnContextMenu (const QPoint pos); + DelHistory* deleteObjVector (const std::vector<LDObject*> objs); DelHistory* deleteSelection (); + DelHistory* deleteGroup (const LDObject::Group group); GLRenderer* R () { return m_renderer; } std::vector<LDObject*>& sel () { return m_sel; } void setQuickColorMeta (std::vector<quickColorMetaEntry>& quickColorMeta) { @@ -194,14 +197,20 @@ // ============================================================================= template<class R> class LabeledWidget : public QWidget { public: - LabeledWidget (const char* labelstr, QWidget* parent) : QWidget (parent) { + explicit LabeledWidget (const char* labelstr, QWidget* parent = null) : QWidget (parent) { m_widget = new R (this); - m_label = new QLabel (labelstr, this); - - m_layout = new QHBoxLayout; - m_layout->addWidget (m_label); - m_layout->addWidget (m_widget); - setLayout (m_layout); + commonInit (labelstr); + } + + explicit LabeledWidget (const char* labelstr, R* widget, QWidget* parent = null) : + QWidget (parent), m_widget (widget) + { + commonInit (labelstr); + } + + explicit LabeledWidget (QWidget* parent = 0, Qt::WindowFlags f = 0) { + m_widget = new R (this); + commonInit (""); } R* widget () const { return m_widget; } @@ -213,6 +222,16 @@ operator R* () { return m_widget; } private: + Q_DISABLE_COPY (LabeledWidget<R>) + + void commonInit (const char* labelstr) { + m_label = new QLabel (labelstr, this); + m_layout = new QHBoxLayout; + m_layout->addWidget (m_label); + m_layout->addWidget (m_widget); + setLayout (m_layout); + } + R* m_widget; QLabel* m_label; QHBoxLayout* m_layout; @@ -226,6 +245,7 @@ bool confirm (str msg); void critical (str msg); QAction* findAction (str name); +void makeGroupSelector (QComboBox* box); // ----------------------------------------------------------------------------- // Pointer to the instance of ForgeWindow.
--- a/gui_actions.cpp Tue May 07 17:51:10 2013 +0300 +++ b/gui_actions.cpp Tue May 07 19:48:51 2013 +0300 @@ -454,39 +454,4 @@ obj->setHidden (!obj->hidden ()); g_win->refresh (); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -// Debug things -#ifndef RELEASE -MAKE_ACTION (addTestQuad, "Add Test Quad", "add-quad", "Adds a test quad.", (0)) { - LDQuad* pQuad = new LDQuad; - pQuad->dColor = rand () % 24; - pQuad->vaCoords[0] = { 1.0f, 0.0f, 1.0f}; - pQuad->vaCoords[1] = {-1.0f, 0.0f, 1.0f}; - pQuad->vaCoords[2] = {-1.0f, 0.0f, -1.0f}; - pQuad->vaCoords[3] = { 1.0f, 0.0f, -1.0f}; - - g_curfile->insertObj (g_win->getInsertionPoint (), pQuad); - History::addEntry (new AddHistory ({(ulong)pQuad->getIndex (g_curfile)}, {pQuad->clone ()})); - g_win->refresh (); -} - -MAKE_ACTION (addTestRadial, "Add Test Radial", "add-radial", "Adds a test radial.", (0)) { - LDRadial* pRad = new LDRadial; - pRad->eRadialType = LDRadial::Cone; - pRad->mMatrix = g_identity; - pRad->vPosition = vertex (0, 0, 0); - pRad->dColor = rand () % 24; - pRad->dDivisions = 16; - pRad->dRingNum = 2; - pRad->dSegments = 16; - - g_curfile->insertObj (g_win->getInsertionPoint (), pRad); - History::addEntry (new AddHistory ({(ulong)pRad->getIndex (g_curfile)}, {pRad->clone ()})); - g_win->refresh (); -} - -#endif // RELEASE \ No newline at end of file +} \ No newline at end of file
--- a/zz_configDialog.cpp Tue May 07 17:51:10 2013 +0300 +++ b/zz_configDialog.cpp Tue May 07 19:48:51 2013 +0300 @@ -339,6 +339,8 @@ // ============================================================================= extern_cfg (str, prog_ytruder); extern_cfg (str, prog_rectifier); +extern_cfg (str, prog_intersector); +extern_cfg (str, prog_isecalc); static const struct extProgInfo { const char* const name, *iconname; strconfig* const path; @@ -347,6 +349,8 @@ } g_extProgInfo[] = { { "Ytruder", "ytruder", &prog_ytruder, null, null }, { "Rectifier", "rectifier", &prog_rectifier, null, null }, + { "Intersector", "intersector", &prog_intersector, null, null }, + { "Isecalc", "isecalc", &prog_isecalc, null, null }, }; void ConfigDialog::initExtProgTab () {