Added dialog for rotation points

Thu, 16 May 2013 22:59:10 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Thu, 16 May 2013 22:59:10 +0300
changeset 211
8d35e631bef3
parent 210
58a3cbb49374
child 212
79c5205b807c

Added dialog for rotation points

src/aboutDialog.cpp file | annotate | diff | comparison | revisions
src/colors.cpp file | annotate | diff | comparison | revisions
src/common.h file | annotate | diff | comparison | revisions
src/configDialog.cpp file | annotate | diff | comparison | revisions
src/dialogs.cpp file | annotate | diff | comparison | revisions
src/dialogs.h file | annotate | diff | comparison | revisions
src/extprogs.cpp file | annotate | diff | comparison | revisions
src/file.cpp file | annotate | diff | comparison | revisions
src/gldraw.cpp file | annotate | diff | comparison | revisions
src/gui.cpp file | annotate | diff | comparison | revisions
src/gui_editactions.cpp file | annotate | diff | comparison | revisions
src/historyDialog.cpp file | annotate | diff | comparison | revisions
src/ldtypes.cpp file | annotate | diff | comparison | revisions
src/ldtypes.h file | annotate | diff | comparison | revisions
src/misc.cpp file | annotate | diff | comparison | revisions
src/misc.h file | annotate | diff | comparison | revisions
src/types.cpp file | annotate | diff | comparison | revisions
--- a/src/aboutDialog.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/aboutDialog.cpp	Thu May 16 22:59:10 2013 +0300
@@ -27,8 +27,6 @@
 #include "aboutDialog.h"
 
 AboutDialog::AboutDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) {
-	QWidget* mainTab, *licenseTab;
-	
 	// Application icon - in full 64 x 64 glory.
 	QLabel* icon = new QLabel;
 	icon->setPixmap (getIcon ("ldforge"));
--- a/src/colors.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/colors.cpp	Thu May 16 22:59:10 2013 +0300
@@ -56,17 +56,6 @@
 }
 
 // =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-static bool parseLDConfigTag (StringParser& pars, char const* tag, str& val) {
-	short pos;
-	if (!pars.findToken (pos, tag, 1))
-		return false;
-	
-	return pars.getToken (val, pos + 1);
-}
-
-// =============================================================================
 uchar luma (QColor& col) {
 	return (0.2126f * col.red ()) +
 		(0.7152f * col.green ()) +
@@ -74,7 +63,18 @@
 }
 
 // =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Helper function for parseLDConfig
+static bool parseLDConfigTag (StringParser& pars, char const* tag, str& val) {
+	short pos;
+	
+	// Try find the token and get its position
+	if (!pars.findToken (pos, tag, 1))
+		return false;
+	
+	// Get the token after it and store it into val
+	return pars.getToken (val, pos + 1);
+}
+
 // =============================================================================
 void parseLDConfig () {
 	FILE* fp = openLDrawFile ("LDConfig.ldr", false);
@@ -82,13 +82,13 @@
 	if (!fp)
 		return;
 	
-	// Even though LDConfig.ldr is technically an LDraw file, parsing it as one
-	// would be overkill by any standard.
+	// Read in the lines
 	char buf[1024];
 	while (fgets (buf, sizeof buf, fp)) {
 		if (strlen (buf) == 0 || buf[0] != '0')
 			continue; // empty or illogical
 		
+		// Use StringParser to parse the LDConfig.ldr file.
 		str line = str (buf).strip ({'\n', '\r'});
 		StringParser pars (line, ' ');
 		
@@ -102,21 +102,20 @@
 		// Replace underscores in the name with spaces for readability
 		name.replace ("_", " ");
 		
-		// get the CODE tag
+		// Get the CODE tag
 		if (!parseLDConfigTag (pars, "CODE", valuestr))
 			continue;
 		
-		// Ensure that the code is within range. must be within 0 - 512
+		if (!isNumber (valuestr))
+			continue; // not a number
+		
+		// Ensure that the code is within [0 - 511]
 		code = atoi (valuestr);
 		if (code < 0 || code >= 512)
 			continue;
 		
-		// VALUE tag
-		if (!parseLDConfigTag (pars, "VALUE", facename))
-			continue;
-		
-		// EDGE tag
-		if (!parseLDConfigTag (pars, "EDGE", edgename))
+		// VALUE and EDGE tags
+		if (!parseLDConfigTag (pars, "VALUE", facename) || !parseLDConfigTag (pars, "EDGE", edgename))
 			continue;
 		
 		// Ensure that our colors are correct
--- a/src/common.h	Thu May 16 02:26:50 2013 +0300
+++ b/src/common.h	Thu May 16 22:59:10 2013 +0300
@@ -92,22 +92,11 @@
 class OpenFile;
 class QApplication;
 
-// =============================================================================
+// -----------------------------------------------------------------------------
 // Plural expression
-#define PLURAL(n) ((n != 1) ? "s" : "")
-
-// -----------------------------------------------------------------------------
-// Shortcut for formatting
-#define PERFORM_FORMAT(in, out) \
-	va_list v; \
-	va_start (v, in); \
-	char* out = vdynformat (in, v, 256); \
-	va_end (v);
-
-// -----------------------------------------------------------------------------
-// Shortcuts for stuffing vertices into printf-formatting.
-#define FMT_VERTEX "(%.3f, %.3f, %.3f)"
-#define FVERTEX(V) V.x, V.y, V.z
+template<class T> static inline const char* plural (T n) {
+	return (n != 1) ? "s" : "";
+}
 
 // -----------------------------------------------------------------------------
 // Templated clamp
@@ -131,15 +120,23 @@
 }
 
 // Quick QString to const char* conversion
-static inline const char* qchars (QString qstr) {
+static inline const char* qchars (const QString& qstr) {
 	return qstr.toStdString ().c_str ();
 }
 
 static const double pi = 3.14159265358979323846f;
 
-#ifdef IN_IDE_PARSER // KDevelop workaround
+#ifdef IN_IDE_PARSER // KDevelop workarounds:
 // Current function name
 static const char* __func__ = "";
+
+#ifndef va_start
+#define va_start(va, arg)
+#endif // va_start
+
+#ifndef va_end
+#define va_end(va)
+#endif // va_end
 #endif // IN_IDE_PARSER
 
 // -----------------------------------------------------------------------------
--- a/src/configDialog.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/configDialog.cpp	Thu May 16 22:59:10 2013 +0300
@@ -120,11 +120,10 @@
 		"colored in the object list. A red polygon will have its description "
 		"written in red text.");
 	
-	cb_colorBFC = new QCheckBox ("Red/green BFC view");
+	cb_colorBFC = new QCheckBox ("Red/green BFC view (incomplete)");
 	cb_colorBFC->setChecked (gl_colorbfc);
-	cb_colorBFC->setWhatsThis ("Polygons' front sides become green and back "
-		"sides red. Not implemented yet.");
-	
+	cb_colorBFC->setWhatsThis ("Polygons' front sides become green and back sides red.");
+
 	cb_blackEdges = new QCheckBox ("Black edges");
 	cb_blackEdges->setWhatsThis ("Makes all edgelines appear black. If this is "
 		"not set, edge lines take their color as defined in LDConfig.ldr");
@@ -267,8 +266,8 @@
 // =============================================================================
 void ConfigDialog::initGridTab () {
 	QWidget* tab = new QWidget;
-	QGridLayout* layout = new QGridLayout;
-	QVBoxLayout* l2 = new QVBoxLayout;
+	QGridLayout* gridlayout = new QGridLayout;
+	QVBoxLayout* mainlayout = new QVBoxLayout;
 	
 	QLabel* xlabel = new QLabel ("X"),
 		*ylabel = new QLabel ("Y"),
@@ -278,7 +277,7 @@
 	short i = 1;
 	for (QLabel* label : std::initializer_list<QLabel*> ({xlabel, ylabel, zlabel, anglabel})) {
 		label->setAlignment (Qt::AlignCenter);
-		layout->addWidget (label, 0, i++);
+		gridlayout->addWidget (label, 0, i++);
 	}
 	
 	for (int i = 0; i < g_NumGrids; ++i) {
@@ -292,20 +291,20 @@
 		QHBoxLayout* labellayout = new QHBoxLayout;
 		labellayout->addWidget (lb_gridIcons[i]);
 		labellayout->addWidget (lb_gridLabels[i]);
-		layout->addLayout (labellayout, i + 1, 0);
+		gridlayout->addLayout (labellayout, i + 1, 0);
 		
 		// Add the widgets
 		for (int j = 0; j < 4; ++j) {
 			dsb_gridData[i][j] = new QDoubleSpinBox;
 			dsb_gridData[i][j]->setValue (g_GridInfo[i].confs[j]->value);
-			layout->addWidget (dsb_gridData[i][j], i + 1, j + 1);
+			gridlayout->addWidget (dsb_gridData[i][j], i + 1, j + 1);
 		}
 	}
 	
-	l2->addLayout (layout);
-	l2->addStretch (1);
+	mainlayout->addLayout (gridlayout);
+	mainlayout->addStretch (1);
 	
-	tab->setLayout (l2);
+	tab->setLayout (mainlayout);
 	tabs->addTab (tab, "Grids");
 }
 
@@ -360,7 +359,7 @@
 	
 	pathsBox->setLayout (pathsLayout);
 	layout->addWidget (pathsBox);
-	layout->addSpacing (10);
+	layout->addStretch (1);
 	
 	tab->setLayout (layout);
 	tabs->addTab (tab, "Ext. Programs");
--- a/src/dialogs.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/dialogs.cpp	Thu May 16 22:59:10 2013 +0300
@@ -24,6 +24,7 @@
 #include <QLabel>
 #include <QPushButton>
 #include <QBoxLayout>
+#include <QGridLayout>
 
 #include "dialogs.h"
 #include "widgets.h"
@@ -419,4 +420,51 @@
 		
 		g_win->fullRefresh ();
 	}
+}
+
+RotationPointDialog::RotationPointDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) {
+	rb_rotpoint = new RadioBox ("Rotation Point", { "Object center", "Custom" }, 0, Qt::Vertical, this);
+	connect (rb_rotpoint, SIGNAL (valueChanged (int)), this, SLOT (radioBoxChanged ()));
+	
+	gb_customPos = new QGroupBox ("Custom point", this);
+	dsb_customX = new QDoubleSpinBox;
+	dsb_customY = new QDoubleSpinBox;
+	dsb_customZ = new QDoubleSpinBox;
+	
+	QGridLayout* customLayout = new QGridLayout (gb_customPos);
+	customLayout->setColumnStretch (1, 1);
+	customLayout->addWidget (new QLabel ("X"),	0, 0);
+	customLayout->addWidget (dsb_customX,			0, 1);
+	customLayout->addWidget (new QLabel ("Y"),	1, 0);
+	customLayout->addWidget (dsb_customY,			1, 1);
+	customLayout->addWidget (new QLabel ("Z"),	2, 0);
+	customLayout->addWidget (dsb_customZ,			2, 1);
+	
+	QVBoxLayout* layout = new QVBoxLayout (this);
+	layout->addWidget (rb_rotpoint);
+	layout->addWidget (gb_customPos);
+	layout->addWidget (makeButtonBox (*this));
+}
+
+bool RotationPointDialog::custom () const {
+	return rb_rotpoint->value () == 1;
+}
+
+vertex RotationPointDialog::customPos () const {
+	return vertex (dsb_customX->value (), dsb_customY->value (), dsb_customZ->value ());
+}
+
+void RotationPointDialog::setCustom (bool custom) {
+	rb_rotpoint->setValue (custom == true ? 1 : 0);
+	gb_customPos->setEnabled (custom);
+}
+
+void RotationPointDialog::setCustomPos (const vertex& pos) {
+	dsb_customX->setValue (pos[X]);
+	dsb_customY->setValue (pos[Y]);
+	dsb_customZ->setValue (pos[Z]);
+}
+
+void RotationPointDialog::radioBoxChanged () {
+	setCustom (rb_rotpoint->value ());
 }
\ No newline at end of file
--- a/src/dialogs.h	Thu May 16 02:26:50 2013 +0300
+++ b/src/dialogs.h	Thu May 16 22:59:10 2013 +0300
@@ -4,6 +4,7 @@
 #include <QDialog>
 #include "common.h"
 
+class QGroupBox;
 class QDialogButtonBox;
 class QDoubleSpinBox;
 class QPushButton;
@@ -74,6 +75,7 @@
 	QLineEdit* le_contents;
 };
 
+// =============================================================================
 class LDrawPathDialog : public QDialog {
 	Q_OBJECT
 	
@@ -99,6 +101,7 @@
 	void slot_exit ();
 };
 
+// =============================================================================
 class NewPartDialog : public QDialog {
 public:
 	enum { CCAL, NonCA, NoLicense };
@@ -112,4 +115,25 @@
 	RadioBox* rb_license, *rb_BFC;
 };
 
+// =============================================================================
+class RotationPointDialog : public QDialog {
+	Q_OBJECT
+	
+public:
+	explicit RotationPointDialog (QWidget* parent = null, Qt::WindowFlags f = 0);
+	
+	vertex customPos () const;
+	bool custom () const;
+	void setCustom (bool custom);
+	void setCustomPos (const vertex& pos);
+	
+private:
+	QDoubleSpinBox* dsb_customX, *dsb_customY, *dsb_customZ;
+	RadioBox* rb_rotpoint;
+	QGroupBox* gb_customPos;
+	
+private slots:
+	void radioBoxChanged ();
+};
+
 #endif // DIALOGS_H
\ No newline at end of file
--- a/src/extprogs.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/extprogs.cpp	Thu May 16 22:59:10 2013 +0300
@@ -137,11 +137,11 @@
 	
 	writeObjects (objects, fp);
 	
-#ifndef RELEASE
+#if 0
 	ushort idx = rand ();
 	printf ("%s -> debug_%u\n", fname.chars (), idx);
 	QFile::copy (fname.chars (), fmt ("debug_%u", idx));
-#endif // RELEASE
+#endif // 0
 	
 	fclose (fp);
 }
--- a/src/file.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/file.cpp	Thu May 16 22:59:10 2013 +0300
@@ -227,7 +227,7 @@
 	g_loadedFiles.push_back (load);
 	
 	logf ("File %s parsed successfully (%lu warning%s).\n",
-		path.chars(), numWarnings, PLURAL (numWarnings));
+		path.chars(), numWarnings, plural (numWarnings));
 	
 	return load;
 }
--- a/src/gldraw.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/gldraw.cpp	Thu May 16 22:59:10 2013 +0300
@@ -157,7 +157,10 @@
 	m_panX = m_panY = m_rotZ = 0.0f;
 	
 	// Set the default zoom based on the bounding box
-	m_zoom = g_BBox.size () * 6;
+	if (g_BBox.empty () == false)
+		m_zoom = g_BBox.size () * 6;
+	else
+		m_zoom = 30.0f;
 }
 
 // =============================================================================
--- a/src/gui.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/gui.cpp	Thu May 16 22:59:10 2013 +0300
@@ -249,6 +249,7 @@
 	addMenuAction ("rotateYNeg");			// Rotate -Y
 	addMenuAction ("rotateZPos");			// Rotate +Z
 	addMenuAction ("rotateZNeg");			// Rotate -Z
+	addMenuAction ("rotpoint");			// Set Rotation Point
 	
 	initMenu ("E&xternal Programs");
 	addMenuAction ("ytruder");
@@ -361,6 +362,7 @@
 	addToolBarAction ("rotateYNeg");
 	addToolBarAction ("rotateZPos");
 	addToolBarAction ("rotateZNeg");
+	addToolBarAction ("rotpoint");
 	
 	// ==========================================
 	initSingleToolBar ("Grids");
@@ -723,15 +725,11 @@
 	}
 	
 	// Update the GL renderer
-	for (LDObject* obj : m_sel) {
-		printf ("recompile %lu\n", obj->getIndex (g_curfile));
+	for (LDObject* obj : m_sel)
 		m_renderer->compileObject (obj);
-	}
 	
-	for (LDObject* obj : priorSelection) {
+	for (LDObject* obj : priorSelection)
 		printf ("recompile %lu\n", obj->getIndex (g_curfile));
-		m_renderer->compileObject (obj);
-	}
 	
 	m_renderer->update ();
 }
@@ -1065,7 +1063,7 @@
 		
 		QIcon ico = makeColorIcon (col, 16);
 		box->addItem (ico, fmt ("[%d] %s (%lu object%s)",
-			pair.first, col->name.chars (), pair.second, PLURAL (pair.second)));
+			pair.first, col->name.chars (), pair.second, plural (pair.second)));
 		box->setItemData (row, pair.first);
 		
 		++row;
--- a/src/gui_editactions.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/gui_editactions.cpp	Thu May 16 22:59:10 2013 +0300
@@ -27,7 +27,6 @@
 #include "colorSelectDialog.h"
 #include "historyDialog.h"
 #include "misc.h"
-#include "bbox.h"
 #include "widgets.h"
 #include "extprogs.h"
 #include "gldraw.h"
@@ -541,53 +540,40 @@
 // =============================================================================
 static void doRotate (const short l, const short m, const short n) {
 	std::vector<LDObject*> sel = g_win->sel ();
-	bbox box;
 	vertex origin;
 	std::vector<vertex*> queue;
 	const double angle = (pi * currentGrid ().confs[Grid::Angle]->value) / 360;
 	
 	// ref: http://en.wikipedia.org/wiki/Transformation_matrix#Rotation_2
+	const double cosangle = cos (angle),
+		sinangle = sin (angle);
+	
 	matrix transform ({
-		(l * l * (1 - cos (angle))) + cos (angle),
-		(m * l * (1 - cos (angle))) - (n * sin (angle)),
-		(n * l * (1 - cos (angle))) + (m * sin (angle)),
+		(l * l * (1 - cosangle)) + cosangle,
+		(m * l * (1 - cosangle)) - (n * sinangle),
+		(n * l * (1 - cosangle)) + (m * sinangle),
 		
-		(l * m * (1 - cos (angle))) + (n * sin (angle)),
-		(m * m * (1 - cos (angle))) + cos (angle),
-		(n * m * (1 - cos (angle))) - (l * sin (angle)),
+		(l * m * (1 - cosangle)) + (n * sinangle),
+		(m * m * (1 - cosangle)) + cosangle,
+		(n * m * (1 - cosangle)) - (l * sinangle),
 		
-		(l * n * (1 - cos (angle))) - (m * sin (angle)),
-		(m * n * (1 - cos (angle))) + (l * sin (angle)),
-		(n * n * (1 - cos (angle))) + cos (angle)
+		(l * n * (1 - cosangle)) - (m * sinangle),
+		(m * n * (1 - cosangle)) + (l * sinangle),
+		(n * n * (1 - cosangle)) + cosangle
 	});
 	
-	// Calculate center vertex
-	for (LDObject* obj : sel) {
-		if (obj->getType () == LDObject::Subfile)
-			box << static_cast<LDSubfile*> (obj)->pos;
-		else if (obj->getType () == LDObject::Radial)
-			box << static_cast<LDRadial*> (obj)->pos;
-		else
-			box << obj;
-	}
-	
-	origin = box.center ();
+	origin = rotPoint (sel);
 	
 	// Apply the above matrix to everything
 	for (LDObject* obj : sel) {
 		if (obj->vertices ())
 			for (short i = 0; i < obj->vertices (); ++i)
 				queue.push_back (&obj->coords[i]);
-		else if (obj->getType () == LDObject::Subfile) {
-			LDSubfile* ref = static_cast<LDSubfile*> (obj);
+		else if (obj->hasMatrix ()) {
+			LDMatrixObject* mobj = static_cast<LDSubfile*> (obj);
 			
-			queue.push_back (&ref->pos);
-			ref->transform = ref->transform * transform;
-		} else if (obj->getType () == LDObject::Radial) {
-			LDRadial* rad = static_cast<LDRadial*> (obj);
-			
-			queue.push_back (&rad->pos);
-			rad->transform = rad->transform * transform;
+			queue.push_back (&mobj->pos);
+			mobj->transform = mobj->transform * transform;
 		} else if (obj->getType () == LDObject::Vertex)
 			queue.push_back (&static_cast<LDVertex*> (obj)->pos);
 		
@@ -627,6 +613,11 @@
 	doRotate (0, 0, -1);
 }
 
+// =========================================================================================================================================
+MAKE_ACTION (rotpoint, "Set Rotation Point", "rotpoint", "Configure the rotation point.", (0)) {
+	configRotationPoint ();
+}
+
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
--- a/src/historyDialog.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/historyDialog.cpp	Thu May 16 22:59:10 2013 +0300
@@ -128,8 +128,8 @@
 		case HISTORY_QuadSplit:
 			{
 				QuadSplitHistory* subentry = static_cast<QuadSplitHistory*> (entry);
-				ulong ulCount = subentry->paQuads.size ();
-				text.format ("Split %lu quad%s to triangles", ulCount, PLURAL (ulCount));
+				ulong count = subentry->paQuads.size ();
+				text.format ("Split %lu quad%s to triangles", count, plural (count));
 				
 				entryIcon = getIcon ("quad-split");
 			}
--- a/src/ldtypes.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/ldtypes.cpp	Thu May 16 22:59:10 2013 +0300
@@ -385,7 +385,7 @@
 		if (!firstDetails)
 			text += ", ";
 		
-		str noun = fmt ("%s%s", g_saObjTypeNames[objType], PLURAL (objCount));
+		str noun = fmt ("%s%s", g_saObjTypeNames[objType], plural (objCount));
 		
 		// Plural of "vertex" is "vertices". Stupid English.
 		if (objType == LDObject::Vertex && objCount != 1)
--- a/src/ldtypes.h	Thu May 16 02:26:50 2013 +0300
+++ b/src/ldtypes.h	Thu May 16 22:59:10 2013 +0300
@@ -24,7 +24,7 @@
 
 class HistoryEntry;
 
-#define IMPLEMENT_LDTYPE(T, NUMVERTS) \
+#define LDOBJ(T) \
 	LD##T () {} \
 	virtual ~LD##T () {} \
 	virtual LDObject::Type getType () const { \
@@ -35,9 +35,9 @@
 		return new LD##T (*this); \
 	} \
 	virtual void move (vertex vVector); \
-	virtual short vertices () const { return NUMVERTS; } \
 	virtual HistoryEntry* invert ();
 
+#define LDOBJ_VERTICES(V) virtual short vertices () const { return V; }
 #define LDOBJ_SETCOLORED(V) virtual bool isColored () const { return V; }
 #define LDOBJ_COLORED LDOBJ_SETCOLORED (true)
 #define LDOBJ_UNCOLORED LDOBJ_SETCOLORED (false)
@@ -46,10 +46,29 @@
 #define LDOBJ_SCHEMANTIC LDOBJ_CUSTOM_SCHEMANTIC { return true; }
 #define LDOBJ_NON_SCHEMANTIC LDOBJ_CUSTOM_SCHEMANTIC { return false; }
 
+#define LDOBJ_SETMATRIX(V) virtual bool hasMatrix () const { return V; }
+#define LDOBJ_HAS_MATRIX LDOBJ_SETMATRIX (true)
+#define LDOBJ_NO_MATRIX LDOBJ_SETMATRIX (false)
+
 class QListWidgetItem;
 class LDSubfile;
 
 // =============================================================================
+// LDMatrixObject
+// 
+// Common code for objects with matrices
+// =============================================================================
+class LDMatrixObject {
+public:
+	LDMatrixObject () {}
+	LDMatrixObject (const matrix& transform, const vertex& pos) :
+		transform (transform), pos (pos) {}
+	
+	matrix transform;
+	vertex pos;
+};
+
+// =============================================================================
 // LDObject
 // 
 // Base class object for all LD* types. Each LDObject represents a single line
@@ -142,6 +161,7 @@
 	QListWidgetItem* qObjListEntry;
 	
 	bool					hidden			() const { return m_hidden; }
+	virtual bool			hasMatrix		() const { return false; }
 	virtual HistoryEntry*	invert			();
 	LDObject*				next			() const;
 	LDObject*				prev			() const;
@@ -164,9 +184,11 @@
 // =============================================================================
 class LDGibberish : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Gibberish, 0)
+	LDOBJ (Gibberish)
+	LDOBJ_VERTICES (0)
 	LDOBJ_UNCOLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 	
 	LDGibberish (str _zContent, str _zReason);
 	
@@ -184,9 +206,11 @@
 // =============================================================================
 class LDEmpty : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Empty, 0)
+	LDOBJ (Empty)
+	LDOBJ_VERTICES (0)
 	LDOBJ_UNCOLORED
 	LDOBJ_NON_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 };
 
 // =============================================================================
@@ -197,9 +221,11 @@
 // =============================================================================
 class LDComment : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Comment, 0)
+	LDOBJ (Comment)
+	LDOBJ_VERTICES (0)
 	LDOBJ_UNCOLORED
 	LDOBJ_NON_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 	
 	LDComment (str text) : text (text) {}
 	
@@ -214,19 +240,13 @@
 // =============================================================================
 class LDBFC : public LDComment {
 public:
-	enum Type {
-		CertifyCCW,
-		CCW,
-		CertifyCW,
-		CW,
-		NoCertify,	// Winding becomes disabled (0 BFC NOCERTIFY)
-		InvertNext,	// Winding is inverted for next object (0 BFC INVERTNEXT)
-		NumStatements
-	};
+	enum Type { CertifyCCW, CCW, CertifyCW, CW, NoCertify, InvertNext, NumStatements };
 	
-	IMPLEMENT_LDTYPE (BFC, 0)
+	LDOBJ (BFC)
+	LDOBJ_VERTICES (0)
 	LDOBJ_UNCOLORED
 	LDOBJ_CUSTOM_SCHEMANTIC { return (type == InvertNext); }
+	LDOBJ_NO_MATRIX
 	
 	LDBFC (const LDBFC::Type type) : type (type) {}
 	
@@ -241,14 +261,14 @@
 //
 // Represents a single code-1 subfile reference.
 // =============================================================================
-class LDSubfile : public LDObject {
+class LDSubfile : public LDObject, public LDMatrixObject {
 public:
-	IMPLEMENT_LDTYPE (Subfile, 0)
+	LDOBJ (Subfile)
+	LDOBJ_VERTICES (0)
 	LDOBJ_COLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_HAS_MATRIX
 	
-	vertex pos; // Position of the subpart (TODO: should get rid of this)
-	matrix transform; // Transformation matrix for the subpart
 	str fileName; // Filename of the subpart (TODO: rid this too - use fileInfo->fileName instead)
 	OpenFile* fileInfo; // Pointer to opened file for this subfile. null if unopened.
 	
@@ -266,9 +286,11 @@
 // =============================================================================
 class LDLine : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Line, 2)
+	LDOBJ (Line)
+	LDOBJ_VERTICES (2)
 	LDOBJ_COLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 	
 	LDLine (vertex v1, vertex v2);
 };
@@ -281,9 +303,11 @@
 // =============================================================================
 class LDCondLine : public LDLine {
 public:
-	IMPLEMENT_LDTYPE (CondLine, 4)
+	LDOBJ (CondLine)
+	LDOBJ_VERTICES (4)
 	LDOBJ_COLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 };
 
 // =============================================================================
@@ -295,9 +319,11 @@
 // =============================================================================
 class LDTriangle : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Triangle, 3)
+	LDOBJ (Triangle)
+	LDOBJ_VERTICES (3)
 	LDOBJ_COLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 	
 	LDTriangle (vertex _v0, vertex _v1, vertex _v2) {
 		coords[0] = _v0;
@@ -314,9 +340,11 @@
 // =============================================================================
 class LDQuad : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Quad, 4)
+	LDOBJ (Quad)
+	LDOBJ_VERTICES (4)
 	LDOBJ_COLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 	
 	// Split this quad into two triangles (note: heap-allocated)
 	vector<LDTriangle*> splitToTriangles ();
@@ -332,9 +360,11 @@
 // =============================================================================
 class LDVertex : public LDObject {
 public:
-	IMPLEMENT_LDTYPE (Vertex, 0) // TODO: move pos to vaCoords[0]
+	LDOBJ (Vertex)
+	LDOBJ_VERTICES (0) // TODO: move pos to vaCoords[0]
 	LDOBJ_COLORED
 	LDOBJ_NON_SCHEMANTIC
+	LDOBJ_NO_MATRIX
 	
 	vertex pos;
 };
@@ -348,7 +378,7 @@
 // allow part authors to add radial primitives to parts without much hassle about
 // non-existant primitive parts.
 // =============================================================================
-class LDRadial : public LDObject {
+class LDRadial : public LDObject, public LDMatrixObject {
 public:
 	enum Type {
 		Circle,
@@ -360,17 +390,17 @@
 		NumTypes
 	};
 	
-	IMPLEMENT_LDTYPE (Radial, 0)
+	LDOBJ (Radial)
+	LDOBJ_VERTICES (0)
 	LDOBJ_COLORED
 	LDOBJ_SCHEMANTIC
+	LDOBJ_HAS_MATRIX
 	
 	LDRadial::Type radType;
-	vertex pos;
-	matrix transform;
 	short divs, segs, ringNum;
 	
 	LDRadial (LDRadial::Type radType, vertex pos, matrix transform, short divs, short segs, short ringNum) :
-		radType (radType), pos (pos), transform (transform), divs (divs), segs (segs), ringNum (ringNum) {}
+		LDMatrixObject (transform, pos), radType (radType), divs (divs), segs (segs), ringNum (ringNum) {}
 	
 	// Returns a set of objects that provide the equivalent of this radial.
 	// Note: objects are heap-allocated.
--- a/src/misc.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/misc.cpp	Thu May 16 22:59:10 2013 +0300
@@ -22,6 +22,8 @@
 #include "common.h"
 #include "misc.h"
 #include "gui.h"
+#include "bbox.h"
+#include "dialogs.h"
 
 // Prime number table.
 const ushort g_primes[NUM_PRIMES] = {
@@ -98,6 +100,10 @@
 cfg (float, grid_fine_y,			0.1f);
 cfg (float, grid_fine_z,			0.1f);
 cfg (float, grid_fine_angle,		7.5f);
+cfg (int, edit_rotpoint, 0);
+cfg (float, edit_rotpoint_x, 0.0f); // TODO: make a vertexconfig object and use it here
+cfg (float, edit_rotpoint_y, 0.0f);
+cfg (float, edit_rotpoint_z, 0.0f);
 
 const gridinfo g_GridInfo[3] = {
 	{ "Coarse",	{ &grid_coarse_x,	&grid_coarse_y,	&grid_coarse_z,	&grid_coarse_angle	}, &ACTION (gridCoarse) },
@@ -204,6 +210,42 @@
 }
 
 // =============================================================================
+vertex rotPoint (const vector<LDObject*>& objs) {
+	if (edit_rotpoint == 1)
+		return vertex (edit_rotpoint_x, edit_rotpoint_y, edit_rotpoint_z);
+	
+	bbox box;
+	
+	// Calculate center vertex
+	for (LDObject* obj : objs) {
+		if (obj->getType () == LDObject::Subfile)
+			box << static_cast<LDSubfile*> (obj)->pos;
+		else if (obj->getType () == LDObject::Radial)
+			box << static_cast<LDRadial*> (obj)->pos;
+		else
+			box << obj;
+	}
+	
+	return box.center ();
+}
+
+void configRotationPoint () {
+	RotationPointDialog dlg;
+	dlg.setCustom (edit_rotpoint);
+	dlg.setCustomPos (vertex (edit_rotpoint_x, edit_rotpoint_y, edit_rotpoint_z));
+	
+	if (!dlg.exec ())
+		return;
+	
+	edit_rotpoint = dlg.custom ();
+	
+	vertex pos = dlg.customPos ();
+	edit_rotpoint_x = pos[X];
+	edit_rotpoint_y = pos[Y];
+	edit_rotpoint_z = pos[Z];
+}
+
+// =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 StringParser::StringParser (str inText, char sep) {
--- a/src/misc.h	Thu May 16 02:26:50 2013 +0300
+++ b/src/misc.h	Thu May 16 22:59:10 2013 +0300
@@ -54,6 +54,11 @@
 	return g_GridInfo[grid];
 }
 
+// =============================================================================
+vertex rotPoint (const vector<LDObject*>& objs);
+void configRotationPoint ();
+
+// =============================================================================
 namespace Grid {
 	enum Type {
 		Coarse,
--- a/src/types.cpp	Thu May 16 02:26:50 2013 +0300
+++ b/src/types.cpp	Thu May 16 22:59:10 2013 +0300
@@ -130,12 +130,12 @@
 matrix matrix::mult (matrix other) {
 	matrix val;
 	val.zero ();
-
+	
 	for (short i = 0; i < 3; ++i)
 	for (short j = 0; j < 3; ++j)
 	for (short k = 0; k < 3; ++k)
 		val[(i * 3) + j] += m_vals[(i * 3) + k] * other[(k * 3) + j];
-
+	
 	return val;
 }
 

mercurial