Finally got the ringfinder working! Working on integrating it to ring drawing...

Wed, 16 Oct 2013 15:32:38 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Wed, 16 Oct 2013 15:32:38 +0300
changeset 500
cad8cdc42a64
parent 499
ebd30d9eb667
child 501
8f314f3f5054

Finally got the ringfinder working! Working on integrating it to ring drawing...

src/file.cpp file | annotate | diff | comparison | revisions
src/file.h file | annotate | diff | comparison | revisions
src/gldraw.cpp file | annotate | diff | comparison | revisions
src/gui.cpp file | annotate | diff | comparison | revisions
src/ldtypes.cpp file | annotate | diff | comparison | revisions
src/misc.cpp file | annotate | diff | comparison | revisions
src/misc.h file | annotate | diff | comparison | revisions
src/primitives.cpp file | annotate | diff | comparison | revisions
src/primitives.h file | annotate | diff | comparison | revisions
src/types.h file | annotate | diff | comparison | revisions
--- a/src/file.cpp	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/file.cpp	Wed Oct 16 15:32:38 2013 +0300
@@ -619,7 +619,7 @@
 
 	// File is open, now save the model to it. Note that LDraw requires files to
 	// have DOS line endings, so we terminate the lines with \r\n.
-for (LDObject * obj : objects())
+	for (LDObject* obj : objects())
 		f.write (obj->raw() + "\r\n");
 
 	// File is saved, now clean up.
@@ -1015,9 +1015,12 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 str LDFile::getShortName()
-{	if (name().length() > 0)
+{	if (!name().isEmpty())
 		return basename (name());
 
+	if (!defaultName().isEmpty())
+		return defaultName();
+
 	return tr ("<anonymous>");
 }
 
--- a/src/file.h	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/file.h	Wed Oct 16 15:32:38 2013 +0300
@@ -47,6 +47,9 @@
 //
 // A file is implicit when they are opened automatically for caching purposes
 // and are hidden from the user. User-opened files are explicit (not implicit).
+//
+// The default name is a placeholder, initially suggested name for a file. The
+// primitive generator uses this to give initial names to primitives.
 // =============================================================================
 class LDFile : public QObject
 {	Q_OBJECT
@@ -54,6 +57,7 @@
 		READ_PROPERTY (History, history, setHistory)
 		READ_PROPERTY (List<LDObject*>, vertices, setVertices)
 		PROPERTY (str, name, setName)
+		PROPERTY (str, defaultName, setDefaultName)
 		PROPERTY (bool, implicit, setImplicit)
 		PROPERTY (List<LDObject*>, cache, setCache)
 		PROPERTY (long, savePos, setSavePos)
--- a/src/gldraw.cpp	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/gldraw.cpp	Wed Oct 16 15:32:38 2013 +0300
@@ -36,6 +36,7 @@
 #include "dialogs.h"
 #include "addObjectDialog.h"
 #include "messagelog.h"
+#include "primitives.h"
 #include "moc_gldraw.cpp"
 
 static const LDFixedCameraInfo g_FixedCameras[6] =
@@ -655,6 +656,11 @@
 				if (points.size() >= 33)
 					points.insert (33, points[17]);
 
+				// Draw the circle/ring
+				paint.setPen (linepen);
+				paint.setBrush ((m_drawedVerts.size() >= 2) ? polybrush : Qt::NoBrush);
+				paint.drawPolygon (QPolygon (points));
+
 				{ // Draw the current radius in the middle of the circle.
 					QPoint origin = coordconv3_2 (m_drawedVerts[0]);
 					str label = str::number (dist0);
@@ -666,11 +672,6 @@
 						paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y() + metrics.height(), label);
 					}
 				}
-
-				// Draw the circle/ring
-				paint.setPen (linepen);
-				paint.setBrush ((m_drawedVerts.size() >= 2) ? polybrush : Qt::NoBrush);
-				paint.drawPolygon (QPolygon (points));
 			}
 		}
 	}
@@ -894,10 +895,12 @@
 // -----------------------------------------------------------------------------
 void GLRenderer::addDrawnVertex (vertex pos)
 {	// If we picked an already-existing vertex, stop drawing
-for (vertex & vert : m_drawedVerts)
-	{	if (vert == pos)
-		{	endDraw (true);
-			return;
+	if (editMode() != CircleMode)
+	{	for (vertex& vert : m_drawedVerts)
+		{	if (vert == pos)
+			{	endDraw (true);
+				return;
+			}
 		}
 	}
 
@@ -1326,12 +1329,11 @@
 
 	// Clean the selection and create the object
 	List<vertex>& verts = m_drawedVerts;
-	LDObject* obj = null;
+	List<LDObject*> objs;
 
 	switch (editMode())
 	{	case Draw:
-
-			if (m_rectdraw)
+		{	if (m_rectdraw)
 			{	LDQuad* quad = new LDQuad;
 
 				// Copy the vertices from m_rectverts
@@ -1341,26 +1343,28 @@
 					quad->setVertex (i, m_rectverts[i]);
 
 				quad->setColor (maincolor);
-				obj = quad;
+				objs << quad;
 			}
 			else
 			{	switch (verts.size())
 				{	case 1:
-						// 1 vertex - add a vertex object
-						obj = new LDVertex;
-						static_cast<LDVertex*> (obj)->pos = verts[0];
+					{	// 1 vertex - add a vertex object
+						LDVertex* obj = new LDVertex;
+						obj->pos = verts[0];
 						obj->setColor (maincolor);
-						break;
+						objs << obj;
+					} break;
 
 					case 2:
-						// 2 verts - make a line
-						obj = new LDLine (verts[0], verts[1]);
+					{	// 2 verts - make a line
+						LDLine* obj = new LDLine (verts[0], verts[1]);
 						obj->setColor (edgecolor);
-						break;
+						objs << obj;
+					} break;
 
 					case 3:
 					case 4:
-						obj = (verts.size() == 3) ?
+					{	LDObject* obj = (verts.size() == 3) ?
 							  static_cast<LDObject*> (new LDTriangle) :
 							  static_cast<LDObject*> (new LDQuad);
 
@@ -1369,43 +1373,106 @@
 						for (int i = 0; i < obj->vertices(); ++i)
 							obj->setVertex (i, verts[i]);
 
-						break;
+						objs << obj;
+					} break;
 				}
 			}
-
-			break;
+		} break;
 
 		case CircleMode:
-		{	const double dist = circleDrawDist (0);
+		{	const int segs = lores, divs = lores; // TODO: make customizable
+			double dist0 = circleDrawDist (0),
+				dist1 = circleDrawDist (1);
+			enum {Circle, Ring, Disc, CustomRing} type = Ring;
+			int num = 0;
+			double scale;
 
-			matrix transform = g_circleDrawTransforms[camera() % 3];
+			if (dist1 < dist0)
+				std::swap<double> (dist0, dist1);
 
-			for (int i = 0; i < 9; ++i)
-			{	if (transform[i] == 2)
-					transform[i] = dist;
-				elif (transform[i] == 1 && camera() >= 3)
-					transform[i] = -1;
+			if (dist0 == dist1)
+			{	scale = dist0;
+				type = Circle;
+			} elif (dist0 == 0 || dist1 == 0)
+			{	scale = (dist0 != 0) ? dist0 : dist1;
+				type = Disc;
+			} else
+			{	/*	scale = |r1 - r0|
+					number = r0 / scale */
+				scale = abs (dist1 - dist0);
+				assert (scale != 0);
+
+				if (!isInteger (dist0) || !isInteger (scale) || (((int) dist0) % ((int) scale)) != 0)
+					type = CustomRing; // Non-integer ring number - make a custom ring
+				else
+					num = ((int) dist0) / ((int) scale);
 			}
 
-			LDSubfile* ref = new LDSubfile;
-			ref->setFileInfo (findLoadedFile ("4-4edge.dat"));
-			ref->setTransform (transform);
-			ref->setPosition (m_drawedVerts[0]);
-			ref->setColor (maincolor);
-			obj = ref;
-		}
-		break;
+			if (type == CustomRing)
+			{	// Last resort: draw the ring with quads
+				List<QLineF> c0, c1;
+
+				makeCircle (segs, divs, dist0, c0);
+				makeCircle (segs, divs, dist1, c1);
+
+				for (int i = 0; i < 16; ++i)
+				{
+				}
+			}
+			else
+			{	matrix transform = g_circleDrawTransforms[camera() % 3];
+				LDFile* refFile = null;
+
+				for (int i = 0; i < 9; ++i)
+				{	if (transform[i] == 2)
+						transform[i] = scale;
+					elif (transform[i] == 1 && camera() >= 3)
+						transform[i] = -1;
+				}
+
+				switch (type)
+				{	case Circle:
+					{	refFile = getFile ("4-4edge.dat");
+					} break;
+
+					case Disc:
+					{	refFile = getFile ("4-4disc.dat");
+					} break;
+
+					case Ring:
+					{	if ((refFile = getFile (radialFileName (::Ring, lores, lores, num))) == null)
+						{	refFile = generatePrimitive (::Ring, lores, lores, num);
+							refFile->setImplicit (false);
+						}
+					} break;
+				}
+
+				if (refFile)
+				{	LDSubfile* ref = new LDSubfile;
+					ref->setFileInfo (refFile);
+					ref->setTransform (transform);
+					ref->setPosition (m_drawedVerts[0]);
+					ref->setColor (maincolor);
+					objs << ref;
+				}
+			}
+		} break;
 
 		case Select:
-			assert (false);
+		{	assert (false);
 			return;
+		} break;
 	}
 
-	if (obj)
+	if (objs.size() > 0)
 	{	g_win->beginAction (null);
-		file()->addObject (obj);
-		compileObject (obj);
-		g_win->fullRefresh();
+
+		for (LDObject* obj : objs)
+		{	file()->addObject (obj);
+			compileObject (obj);
+		}
+
+		g_win->refresh();
 		g_win->endAction();
 	}
 
--- a/src/gui.cpp	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/gui.cpp	Wed Oct 16 15:32:38 2013 +0300
@@ -696,7 +696,7 @@
 
 	if (saveAs || path.isEmpty())
 	{	path = QFileDialog::getSaveFileName (g_win, tr ("Save As"),
-			LDFile::current()->name(), tr ("LDraw files (*.dat *.ldr)"));
+			(f->name().isEmpty()) ? f->name() : f->defaultName(), tr ("LDraw files (*.dat *.ldr)"));
 
 		if (path.isEmpty())
 		{	// User didn't give a file name, abort.
@@ -755,13 +755,13 @@
 
 bool confirm (str title, str msg)
 {	return QMessageBox::question (g_win, title, msg,
-								  (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes;
+		(QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes;
 }
 
 // =============================================================================
 void critical (str msg)
 {	QMessageBox::critical (g_win, ForgeWindow::tr ("Error"), msg,
-						   (QMessageBox::Close), QMessageBox::Close);
+		(QMessageBox::Close), QMessageBox::Close);
 }
 
 // =============================================================================
--- a/src/ldtypes.cpp	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/ldtypes.cpp	Wed Oct 16 15:32:38 2013 +0300
@@ -230,12 +230,11 @@
 void LDObject::swap (LDObject* other)
 {	int i = 0;
 
-for (LDObject * obj : file()->objects())
+	for (LDObject* obj : file()->objects())
 	{	if (obj == this)
 			file()->setObject (i, other);
-
 		elif (obj == other)
-		file()->setObject (i, this);
+			file()->setObject (i, this);
 
 		++i;
 	}
--- a/src/misc.cpp	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/misc.cpp	Wed Oct 16 15:32:38 2013 +0300
@@ -25,6 +25,8 @@
 #include "dialogs.h"
 #include "ui_rotpoint.h"
 
+RingFinder g_RingFinder;
+
 // Prime number table.
 const int g_primes[NUM_PRIMES] =
 {	2,    3,    5,    7,   11,   13,   17,   19,   23,   29,
@@ -181,7 +183,7 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-void simplify (short& numer, short& denom)
+void simplify (int& numer, int& denom)
 {	bool repeat;
 
 	do
@@ -274,7 +276,7 @@
 str join (initlist<StringFormatArg> vals, str delim)
 {	QStringList list;
 
-for (const StringFormatArg & arg : vals)
+	for (const StringFormatArg& arg : vals)
 		list << arg.value();
 
 	return list.join (delim);
@@ -301,3 +303,46 @@
 	delete[] buf;
 	return fval;
 }
+
+// =============================================================================
+// This is the main algorithm of the ring finder. It tries to use math to find
+// the one ring between r0 and r1. If it fails (the ring number is non-integral),
+// it finds an intermediate radius (ceil of the ring number times scale) and
+// splits the radius at this point, calling this function again to try find the
+// rings between r0 - r and r - r1.
+//
+// This does not always yield into usable results. If at some point r == r0 or
+// r == r1, there is no hope of finding the rings, at least with this algorithm,
+// as it would fall into an infinite recursion.
+// -----------------------------------------------------------------------------
+bool RingFinder::findRings (double r0, double r1)
+{	// Find the scale and number of a ring between r1 and r0.
+	double scale = r1 - r0;
+	double num = r0 / scale;
+
+	// If the ring number is integral, we have found a fitting ring to r0 -> r1!
+	if (isInteger (num))
+	{	SolutionComponent cmp;
+		cmp.scale = scale;
+		cmp.num = (int) ceil (num);
+		m_solution << cmp;
+	}
+	else
+	{	// If not, find an intermediate <r> between the radii
+		double r = ceil (num) * scale;
+
+		// If r is the same as r0 or r1, we simply cannot find any rings between
+		// r0 and r1. Stop and return failure.
+		if (isZero (r0 - r) || isZero (r1 - r))
+			return false;
+
+		// Split this ring into r0 -> r and r -> r1. Recurse to possibly find
+		// the rings for these. If either recurse fails, the entire algorithm
+		// fails as well.
+		if (!findRings (r0, r) || !findRings (r, r1))
+			return false;
+	}
+
+	// The algorithm did not fail, thus we succeeded!
+	return true;
+}
\ No newline at end of file
--- a/src/misc.h	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/misc.h	Wed Oct 16 15:32:38 2013 +0300
@@ -40,7 +40,7 @@
 double atof (str val);
 
 // Simplifies the given fraction.
-void simplify (short& numer, short& denom);
+void simplify (int& numer, int& denom);
 
 str join (initlist<StringFormatArg> vals, str delim = " ");
 
@@ -51,7 +51,7 @@
 };
 
 extern_cfg (Int, grid);
-static const short g_NumGrids = 3;
+static const int g_NumGrids = 3;
 extern const gridinfo g_GridInfo[3];
 
 inline const gridinfo& currentGrid()
@@ -87,6 +87,37 @@
 }
 
 // =============================================================================
+// RingFinder
+//
+// Provides an algorithm for finding a solution of rings between radii r0 and r1.
+// =============================================================================
+class RingFinder
+{	public:
+	struct SolutionComponent
+	{	int num;
+		double scale;
+	};
+
+	typedef List<SolutionComponent> SolutionType;
+
+	RingFinder() {}
+	bool findRings (double r0, double r1);
+
+	inline const SolutionType& solution()
+	{	return m_solution;
+	}
+
+	inline bool operator() (double r0, double r1)
+	{	return findRings (r0, r1);
+	}
+
+private:
+	SolutionType m_solution;
+};
+
+extern RingFinder g_RingFinder;
+
+// =============================================================================
 template<class T> void dataswap (T& a, T& b)
 {	T c = a;
 	a = b;
@@ -120,4 +151,12 @@
 {	return (a >= 0) ? a : -a;
 }
 
+template<class T> inline bool isZero (T a)
+{	return abs<T> (a) < 0.0001;
+}
+
+template<class T> inline bool isInteger (T a)
+{	return isZero (a - (int) a);
+}
+
 #endif // MISC_H
--- a/src/primitives.cpp	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/primitives.cpp	Wed Oct 16 15:32:38 2013 +0300
@@ -61,7 +61,7 @@
 	}
 	else
 	{	// Read primitives from prims.cfg
-		for (str line : conf)
+	for (str line : conf)
 		{	int space = line.indexOf (" ");
 
 			if (space == -1)
@@ -108,7 +108,7 @@
 	recursiveGetFilenames (dir, fnames);
 	emit starting (fnames.size());
 
-	for (str fname : fnames)
+for (str fname : fnames)
 	{	File f (fname, File::Read);
 
 		Primitive info;
@@ -133,7 +133,7 @@
 	// Save to a config file
 	File conf (Config::filepath ("prims.cfg"), File::Write);
 
-	for (Primitive & info : m_prims)
+for (Primitive & info : m_prims)
 		fprint (conf, "%1 %2\n", info.name, info.title);
 
 	conf.close();
@@ -166,7 +166,7 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 static PrimitiveCategory* findCategory (str name)
-{	for (PrimitiveCategory& cat : g_PrimitiveCategories)
+{	for (PrimitiveCategory & cat : g_PrimitiveCategories)
 		if (cat.name() == name)
 			return &cat;
 
@@ -188,24 +188,24 @@
 		unmatched = & (g_PrimitiveCategories << cat);
 	}
 
-	for (Primitive& prim : g_primitives)
+for (Primitive & prim : g_primitives)
 	{	bool matched = false;
 		prim.cat = null;
 
 		// Go over the categories and their regexes, if and when there's a match,
 		// the primitive's category is set to the category the regex beloings to.
-		for (PrimitiveCategory & cat : g_PrimitiveCategories)
-		{	for (PrimitiveCategory::RegexEntry & entry : cat.regexes)
+	for (PrimitiveCategory & cat : g_PrimitiveCategories)
+	{	for (PrimitiveCategory::RegexEntry & entry : cat.regexes)
 			{	switch (entry.type)
 				{	case PrimitiveCategory::Filename:
-					// f-regex, check against filename
-					matched = entry.regex.exactMatch (prim.name);
-					break;
+						// f-regex, check against filename
+						matched = entry.regex.exactMatch (prim.name);
+						break;
 
 					case PrimitiveCategory::Title:
-					// t-regex, check against title
-					matched = entry.regex.exactMatch (prim.title);
-					break;
+						// t-regex, check against title
+						matched = entry.regex.exactMatch (prim.title);
+						break;
 				}
 
 				if (matched)
@@ -243,7 +243,7 @@
 	if (f)
 	{	PrimitiveCategory cat;
 
-		for (str line : f)
+	for (str line : f)
 		{	int colon;
 
 			if (line.length() == 0 || line[0] == '#')
@@ -263,8 +263,9 @@
 
 				if (cmd == "f")
 					type = PrimitiveCategory::Filename;
+
 				elif (cmd == "t")
-					type = PrimitiveCategory::Title;
+				type = PrimitiveCategory::Title;
 				else
 					continue;
 
@@ -293,7 +294,20 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 static double radialPoint (int i, int divs, double (*func) (double))
-{	return (*func) ((i * 2 * pi) / divs);
+{	return (*func) ( (i * 2 * pi) / divs);
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+void makeCircle (int segs, int divs, double radius, List<QLineF>& lines)
+{	for (int i = 0; i < segs; ++i)
+	{	double x0 = radius * radialPoint (i, divs, cos),
+				   x1 = radius * radialPoint (i + 1, divs, cos),
+				   z0 = radius * radialPoint (i, divs, sin),
+				   z1 = radius * radialPoint (i + 1, divs, sin);
+
+		lines << QLineF (QPointF (x0, z0), QPointF (x1, z1));
+	}
 }
 
 // =============================================================================
@@ -301,12 +315,15 @@
 List<LDObject*> makePrimitive (PrimitiveType type, int segs, int divs, int num)
 {	List<LDObject*> objs;
 	List<int> condLineSegs;
+	List<QLineF> circle;
+
+	makeCircle (segs, divs, 1, circle);
 
 	for (int i = 0; i < segs; ++i)
-	{	double x0 = radialPoint (i, divs, cos),
-			x1 = radialPoint (i + 1, divs, cos),
-			z0 = radialPoint (i, divs, sin),
-			z1 = radialPoint (i + 1, divs, sin);
+	{	double x0 = circle[i].x1(),
+				   x1 = circle[i].x2(),
+				   z0 = circle[i].y1(),
+				   z1 = circle[i].y2();
 
 		switch (type)
 		{	case Circle:
@@ -318,8 +335,7 @@
 				line->setVertex (1, v1);
 				line->setColor (edgecolor);
 				objs << line;
-			}
-			break;
+			} break;
 
 			case Cylinder:
 			case Ring:
@@ -374,8 +390,7 @@
 
 				if (type == Cylinder || type == Cone)
 					condLineSegs << i;
-			}
-			break;
+			} break;
 
 			case Disc:
 			case DiscNeg:
@@ -400,11 +415,7 @@
 				seg->setVertex (1, v1);
 				seg->setVertex (type == Disc ? 2 : 0, v2);
 				objs << seg;
-			}
-			break;
-
-			default:
-			break;
+			} break;
 		}
 	}
 
@@ -413,7 +424,7 @@
 	if (segs < divs && condLineSegs.size() != 0)
 		condLineSegs << segs;
 
-	for (int i : condLineSegs)
+for (int i : condLineSegs)
 	{	vertex v0 (radialPoint (i, divs, cos), 0.0f, radialPoint (i, divs, sin)),
 		  v1,
 		  v2 (radialPoint (i + 1, divs, cos), 0.0f, radialPoint (i + 1, divs, sin)),
@@ -421,6 +432,7 @@
 
 		if (type == Cylinder)
 			v1 = vertex (v0[X], 1.0f, v0[Z]);
+
 		elif (type == Cone)
 		{	v1 = vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1));
 			v0[X] *= num;
@@ -454,15 +466,14 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 str radialFileName (PrimitiveType type, int segs, int divs, int num)
-{	short numer = segs,
-			  denom = divs;
+{	int numer = segs,
+			denom = divs;
 
 	// Simplify the fractional part, but the denominator must be at least 4.
 	simplify (numer, denom);
 
 	if (denom < 4)
-	{	const short factor = 4 / denom;
-
+	{	const int factor = 4 / denom;
 		numer *= factor;
 		denom *= factor;
 	}
@@ -476,7 +487,7 @@
 	// Truncate the root if necessary (7-16rin4.dat for instance).
 	// However, always keep the root at least 2 characters.
 	int extra = (frac.length() + numstr.length() + root.length()) - 8;
-	root.chop (min<short> (max<short> (extra, 0), 2));
+	root.chop (clamp (extra, 0, 2));
 
 	// Stick them all together and return the result.
 	return prefix + frac + root + numstr + ".dat";
@@ -486,31 +497,31 @@
 // -----------------------------------------------------------------------------
 LDFile* generatePrimitive (PrimitiveType type, int segs, int divs, int num)
 {	// Make the description
-	str frac = ftoa (((float) segs) / divs);
+	str frac = ftoa ( ( (float) segs) / divs);
 	str name = radialFileName (type, segs, divs, num);
 	str descr;
-	
+
 	// Ensure that there's decimals, even if they're 0.
 	if (frac.indexOf (".") == -1)
 		frac += ".0";
-	
+
 	if (type == Ring || type == Cone)
 	{	str spacing =
-		(num < 10) ? "  " :
-		(num < 100) ? " "  : "";
-		
+			(num < 10) ? "  " :
+			(num < 100) ? " "  : "";
+
 		descr = fmt ("%1 %2%3 x %4", primitiveTypeName (type), spacing, num, frac);
 	}
 	else
 		descr = fmt ("%1 %2", primitiveTypeName (type), frac);
-	
+
 	// Prepend "Hi-Res" if 48/ primitive.
 	if (divs == hires)
 		descr.insert (0, "Hi-Res ");
-	
+
 	LDFile* f = new LDFile;
-	f->setName (QFileDialog::getSaveFileName (null, QObject::tr ("Save Primitive"), name));
-	
+	f->setDefaultName (name);
+
 	f->addObjects (
 	{	new LDComment (descr),
 		new LDComment (fmt ("Name: %1", name)),
@@ -521,7 +532,7 @@
 		new LDBFC (LDBFC::CertifyCCW),
 		new LDEmpty,
 	});
-	
+
 	f->addObjects (makePrimitive (type, segs, divs, num));
 	return f;
 }
@@ -531,6 +542,7 @@
 LDFile* getPrimitive (PrimitiveType type, int segs, int divs, int num)
 {	str name = radialFileName (type, segs, divs, num);
 	LDFile* f = getFile (name);
+
 	if (f != null)
 		return f;
 
@@ -540,10 +552,8 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 PrimitivePrompt::PrimitivePrompt (QWidget* parent, Qt::WindowFlags f) :
-QDialog (parent, f)
-{
-	
-	ui = new Ui_MakePrimUI;
+	QDialog (parent, f)
+{	ui = new Ui_MakePrimUI;
 	ui->setupUi (this);
 	connect (ui->cb_hires, SIGNAL (toggled (bool)), this, SLOT (hiResToggled (bool)));
 }
@@ -558,7 +568,7 @@
 // -----------------------------------------------------------------------------
 void PrimitivePrompt::hiResToggled (bool on)
 {	ui->sb_segs->setMaximum (on ? hires : lores);
-	
+
 	// If the current value is 16 and we switch to hi-res, default the
 	// spinbox to 48.
 	if (on && ui->sb_segs->value() == lores)
@@ -569,22 +579,22 @@
 // -----------------------------------------------------------------------------
 DEFINE_ACTION (MakePrimitive, 0)
 {	PrimitivePrompt* dlg = new PrimitivePrompt (g_win);
-	
+
 	if (!dlg->exec())
 		return;
-	
+
 	int segs = dlg->ui->sb_segs->value();
 	int divs = dlg->ui->cb_hires->isChecked() ? hires : lores;
 	int num = dlg->ui->sb_ringnum->value();
 	PrimitiveType type =
-	dlg->ui->rb_circle->isChecked()   ? Circle :
-	dlg->ui->rb_cylinder->isChecked() ? Cylinder :
-	dlg->ui->rb_disc->isChecked()     ? Disc :
-	dlg->ui->rb_ndisc->isChecked()    ? DiscNeg :
-	dlg->ui->rb_ring->isChecked()     ? Ring : Cone;
-	
+		dlg->ui->rb_circle->isChecked()   ? Circle :
+		dlg->ui->rb_cylinder->isChecked() ? Cylinder :
+		dlg->ui->rb_disc->isChecked()     ? Disc :
+		dlg->ui->rb_ndisc->isChecked()    ? DiscNeg :
+		dlg->ui->rb_ring->isChecked()     ? Ring : Cone;
+
 	LDFile* f = generatePrimitive (type, segs, divs, num);
-	
+
 	g_win->save (f, false);
 	delete f;
-}
\ No newline at end of file
+}
--- a/src/primitives.h	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/primitives.h	Wed Oct 16 15:32:38 2013 +0300
@@ -16,8 +16,8 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef PRIMITIVES_H
-#define PRIMITIVES_H
+#ifndef LDFORGE_PRIMITIVES_H
+#define LDFORGE_PRIMITIVES_H
 
 #include "common.h"
 #include "types.h"
@@ -104,10 +104,13 @@
 		void hiResToggled (bool on);
 };
 
+void makeCircle (int segs, int divs, double radius, List< QLineF >& lines);
 LDFile* generatePrimitive (PrimitiveType type, int segs, int divs, int num);
 
 // Gets a primitive by the given specs. If the primitive cannot be found, it will
 // be automatically generated.
 LDFile* getPrimitive (PrimitiveType type, int segs, int divs, int num);
 
-#endif // PRIMITIVES_H
+str radialFileName (PrimitiveType type, int segs, int divs, int num);
+
+#endif // LDFORGE_PRIMITIVES_H
--- a/src/types.h	Sun Oct 06 21:37:05 2013 +0300
+++ b/src/types.h	Wed Oct 16 15:32:38 2013 +0300
@@ -165,6 +165,46 @@
 };
 
 // =============================================================================
+// -----------------------------------------------------------------------------
+class Line
+{	public:
+		Line() {}
+		Line (const vertex& v0, const vertex v1) :
+			m_v0 (v0),
+			m_v1 (v1) {}
+
+		inline const vertex& getVertex (int i) const
+		{	assert (i == 0 || i == 1);
+			return (i == 0) ? m_v0 : m_v1;
+		}
+
+		inline void setVertex (int i, const vertex& a)
+		{	assert (i == 0 || i == 1);
+			(i == 0) ? m_v0 : m_v1 = a;
+		}
+
+		inline const vertex& v0() const
+		{	return m_v0;
+		}
+
+		inline const vertex& v1() const
+		{	return m_v1;
+		}
+
+		inline void setV0 (const vertex& a)
+		{	m_v0 = a;
+		}
+
+		inline void setV1 (const vertex& a)
+		{	m_v1 = a;
+		}
+
+	private:
+		vertex m_v0,
+		       m_v1;
+};
+
+// =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 // List

mercurial