Added Intersector interface. I'm beginning to think that groups were a bad idea...

Tue, 07 May 2013 19:48:51 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Tue, 07 May 2013 19:48:51 +0300
changeset 175
b094d5e9d6e0
parent 174
963697b36118
child 176
84132e178d46

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
Binary file icons/ytruder.png has changed
--- 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 () {

mercurial