diff options
| -rw-r--r-- | RELEASE_NOTES | 19 | ||||
| -rw-r--r-- | cgal.pri | 2 | ||||
| -rw-r--r-- | doc/TODO.txt | 4 | ||||
| -rw-r--r-- | doc/release-checklist.txt | 9 | ||||
| -rw-r--r-- | flex.pri | 2 | ||||
| -rw-r--r-- | scripts/installer.nsi | 30 | ||||
| -rwxr-xr-x | scripts/macosx-build-dependencies.sh | 4 | ||||
| -rwxr-xr-x | scripts/publish-macosx.sh | 2 | ||||
| -rwxr-xr-x | scripts/release-linux.sh | 2 | ||||
| -rw-r--r-- | src/MainWindow.h | 3 | ||||
| -rw-r--r-- | src/MainWindow.ui | 8 | ||||
| -rw-r--r-- | src/Preferences.cc | 16 | ||||
| -rw-r--r-- | src/Preferences.h | 1 | ||||
| -rw-r--r-- | src/Preferences.ui | 56 | ||||
| -rw-r--r-- | src/cgaladv_minkowski2.cc | 2 | ||||
| -rw-r--r-- | src/export.cc | 53 | ||||
| -rw-r--r-- | src/glview.cc | 52 | ||||
| -rw-r--r-- | src/mainwin.cc | 127 | ||||
| -rw-r--r-- | src/primitives.cc | 17 | ||||
| -rw-r--r-- | src/transform.cc | 20 | ||||
| -rw-r--r-- | testdata/scad/non-aff-matrix.scad | 6 | ||||
| -rw-r--r-- | testdata/scad/testcolornames.scad | 159 | 
22 files changed, 478 insertions, 116 deletions
| diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 81bf603..5364e0a 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,22 @@ +OpenSCAD 20xx.yy +================ + + +OpenSCAD 2011.06 +================ + +o Added "Export as Image" menu. + +Bugfixes: +o Cylinder tesselation broke existing models which are using cylinders +  for e.g. captured nut slots and are dependent on the orientation not +  changing. +o DXF output couldn't be imported into e.g. AutoCAD and Solidworks after updating +  to using the AutoCAD 2000 (AC1015) format. Reverted to the old entity-only output, +  causing LWPOLYLINES to not exported allowed anymore. + + +  OpenSCAD 2011.04  ================ @@ -14,7 +14,7 @@ cgal {    }    win32 { -    LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc90-mt-gd +    LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc90-mt-s    } else {      LIBS += -lgmp -lmpfr -lCGAL    } diff --git a/doc/TODO.txt b/doc/TODO.txt index 45660de..b9440c6 100644 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -8,6 +8,7 @@ o It's now possible to start a new rendering while one is already running (which    -> turn off most (or all) interaction while rendering    -> Lock all or only one MainWindow (MDI)?  o Look into the polygon winding and rotate_extrude() problem reported by Britton +o CGAL Aff_transformation_3 doesn't support non-affine transformations (non-aff-matrix.scad)  STL Import BUGS  --------------- @@ -152,7 +153,7 @@ o Language Frontend    - Rethink for vs. intersection_for vs. group. Should for loops      generate child lists instead, and make these passable to other      modules or accessible by child()? -  - constants: PI +  - constants: PI, OpenSCAD version  o DXF Import/Export    - Use dxflib from RibbonSoft for import/export? -> investigate    - Import @@ -221,6 +222,7 @@ o Write a simple test script that collects verified and current STL renderings  o Write simple driver scripts for comparing output of above command  o Collect "all" available OpenSCAD scripts from the internets and run the integration    tests on them all +o Write a regression test for the hexagonal cylinder orientation issue  INFRASTRUCTURE  -------------- diff --git a/doc/release-checklist.txt b/doc/release-checklist.txt index 45e84fb..a455ca9 100644 --- a/doc/release-checklist.txt +++ b/doc/release-checklist.txt @@ -15,16 +15,21 @@ o build source package    git archive --format=tar openscad-2011.01  --prefix=openscad-2011.01/ | gzip > openscad-2011.01.src.tar.gz  o build binaries +  tar xzf openscad-2011.01.src.tar.gz +  cd openscad-2011.01    Mac OS X -  - publish-macosx.sh -> OpenSCAD-2011.01.dmg +    For Qt-4.7.3: Remove /Developers/Applications/Qt/plugins/qmltooling +    ./scripts/publish-macosx.sh -> OpenSCAD-2011.01.dmg    Linux: FIXME 32 vs. 64 bit -  - release-linux.sh +    ./scripts/release-linux.sh    Windows: FIXME 32 vs. 64 bit  o FIXME: Run some tests  o Set back version: release-linux.sh, publish-macosx.sh, FIXME: Windows +o  git push --tags +  o Upload    - Github      Upload manually here: https://github.com/openscad/openscad/downloads @@ -3,7 +3,7 @@  flex.name = Flex ${QMAKE_FILE_IN}
  flex.input = FLEXSOURCES
  flex.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp
 -flex.commands = flex -P ${QMAKE_FILE_BASE} -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp ${QMAKE_FILE_IN}
 +flex.commands = flex -P ${QMAKE_FILE_BASE} -o${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp ${QMAKE_FILE_IN}
  flex.CONFIG += target_predeps
  flex.variable_out = GENERATED_SOURCES
  silent:flex.commands = @echo Lex ${QMAKE_FILE_IN} && $$flex.commands
 diff --git a/scripts/installer.nsi b/scripts/installer.nsi new file mode 100644 index 0000000..269a30c --- /dev/null +++ b/scripts/installer.nsi @@ -0,0 +1,30 @@ +!include "FileAssociation.nsh" +Name "OpenSCAD" +OutFile "openscad_setup.exe" +InstallDir $PROGRAMFILES\OpenSCAD +DirText "This will install OpenSCAD on your computer. Choose a directory" +Section "install" +SetOutPath $INSTDIR +File openscad.exe +File /r examples +File /r libraries +${registerExtension} "$INSTDIR\openscad.exe" ".scad" "OpenSCAD_File" +CreateShortCut $SMPROGRAMS\OpenSCAD.lnk $INSTDIR\openscad.exe +WriteUninstaller $INSTDIR\Uninstall.exe +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenSCAD" "DisplayName" "OpenSCAD (remove only)" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenSCAD" "UninstallString" "$INSTDIR\Uninstall.exe" +SectionEnd +Section "Uninstall" +${unregisterExtension} ".scad" "OpenSCAD_File" +Delete $INSTDIR\Uninstall.exe +Delete $INSTDIR\MyProg.exe +Delete $SMPROGRAMS\OpenSCAD.lnk +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenSCAD" +RMDir /r $INSTDIR\examples +RMDir /r $INSTDIR\libraries\mcad +Delete $INSTDIR\libraries\boxes.scad +Delete $INSTDIR\libraries\shapes.scad +RMDir $INSTDIR\libraries +Delete $INSTDIR\openscad.exe +RMDir $INSTDIR +SectionEnd diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index b03b2b2..e011582 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -17,8 +17,8 @@  # o Port to other platforms?  # -BASEDIR=/Users/kintel/code/metalab/checkout/OpenSCAD/libraries -OPENSCADDIR=/Users/kintel/code/metalab/checkout/OpenSCAD/openscad-release +BASEDIR=/Users/kintel/code/OpenSCAD/libraries +OPENSCADDIR=/Users/kintel/code/OpenSCAD/openscad  SRCDIR=$BASEDIR/src  DEPLOYDIR=$BASEDIR/install diff --git a/scripts/publish-macosx.sh b/scripts/publish-macosx.sh index 6586525..6415b52 100755 --- a/scripts/publish-macosx.sh +++ b/scripts/publish-macosx.sh @@ -1,7 +1,7 @@  #!/bin/sh  VERSION=`date "+%Y.%m.%d"` -#VERSION=2011.04 +#VERSION=2011.06  # This is the same location as DEPLOYDIR in macosx-build-dependencies.sh  export MACOSX_DEPLOY_DIR=$PWD/../libraries/install diff --git a/scripts/release-linux.sh b/scripts/release-linux.sh index e576faa..35d177f 100755 --- a/scripts/release-linux.sh +++ b/scripts/release-linux.sh @@ -2,7 +2,7 @@  # WARNING: This script might only work with the authors setup...  VERSION=`date "+%Y.%m.%d"` -#VERSION=2011.04 +#VERSION=2011.06  set -ex diff --git a/src/MainWindow.h b/src/MainWindow.h index c0a9844..43ab273 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -79,6 +79,8 @@ private:  	static void consoleOutput(const QString &msg, void *userdata) {  		static_cast<MainWindow*>(userdata)->console->append(msg);  	} +	void loadViewSettings(); +	void loadDesignSettings();  private slots:  	void actionNew(); @@ -109,6 +111,7 @@ private slots:  	void actionExportSTL();  	void actionExportOFF();  	void actionExportDXF(); +	void actionExportImage();  	void actionFlushCaches();  public: diff --git a/src/MainWindow.ui b/src/MainWindow.ui index f61d240..6548c8e 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -112,7 +112,7 @@       <x>0</x>       <y>0</y>       <width>681</width> -     <height>25</height> +     <height>22</height>      </rect>     </property>     <widget class="QMenu" name="menu_File"> @@ -178,6 +178,7 @@      <addaction name="designActionExportSTL"/>      <addaction name="designActionExportOFF"/>      <addaction name="designActionExportDXF"/> +    <addaction name="designActionExportImage"/>      <addaction name="designActionFlushCaches"/>     </widget>     <widget class="QMenu" name="menu_View"> @@ -651,6 +652,11 @@      <string>Automatic Reload and Compile</string>     </property>    </action> +  <action name="designActionExportImage"> +   <property name="text"> +    <string>Export as Image...</string> +   </property> +  </action>   </widget>   <customwidgets>    <customwidget> diff --git a/src/Preferences.cc b/src/Preferences.cc index 6419944..eb6af61 100644 --- a/src/Preferences.cc +++ b/src/Preferences.cc @@ -40,6 +40,7 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)  	this->defaultmap["3dview/colorscheme"] = this->colorSchemeChooser->currentItem()->text();  	this->defaultmap["editor/fontfamily"] = this->fontChooser->currentText();  	this->defaultmap["editor/fontsize"] = this->fontSize->currentText().toUInt(); +	this->defaultmap["editor/opengl20_warning_show"] = true;  	// Toolbar  	QActionGroup *group = new QActionGroup(this); @@ -97,7 +98,8 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)  					this, SLOT(fontFamilyChanged(const QString &)));  	connect(this->fontSize, SIGNAL(editTextChanged(const QString &)),  					this, SLOT(fontSizeChanged(const QString &))); - +	connect(this->OpenGL20WarningCheckbox, SIGNAL(clicked(bool)), +					this, SLOT(OpenGL20WarningChanged(bool)));  	updateGUI();  } @@ -148,6 +150,13 @@ void Preferences::fontSizeChanged(const QString &size)  	emit fontChanged(getValue("editor/fontfamily").toString(), intsize);  } +void +Preferences::OpenGL20WarningChanged(bool state) +{ +	QSettings settings; +	settings.setValue("editor/opengl20_warning_show",state); +} +  void Preferences::keyPressEvent(QKeyEvent *e)  {  #ifdef Q_WS_MAC @@ -185,6 +194,7 @@ QVariant Preferences::getValue(const QString &key) const  void Preferences::updateGUI()  { +	QSettings settings;  	QList<QListWidgetItem *> found =   		this->colorSchemeChooser->findItems(getValue("3dview/colorscheme").toString(),  																				Qt::MatchExactly); @@ -204,6 +214,9 @@ void Preferences::updateGUI()  	else {  		this->fontSize->setEditText(fontsize);  	} + +	bool opengl20_warning_show = getValue("editor/opengl20_warning_show").toBool(); +	this->OpenGL20WarningCheckbox->setChecked(opengl20_warning_show);  }  void Preferences::apply() const @@ -211,4 +224,3 @@ void Preferences::apply() const  	emit fontChanged(getValue("editor/fontfamily").toString(), getValue("editor/fontsize").toUInt());  	emit requestRedraw();  } - diff --git a/src/Preferences.h b/src/Preferences.h index 39599fd..79fa7ab 100644 --- a/src/Preferences.h +++ b/src/Preferences.h @@ -34,6 +34,7 @@ public slots:  	void colorSchemeChanged();  	void fontFamilyChanged(const QString &);  	void fontSizeChanged(const QString &); +	void OpenGL20WarningChanged(bool);  signals:  	void requestRedraw() const; diff --git a/src/Preferences.ui b/src/Preferences.ui index 13db9f3..2ab7646 100644 --- a/src/Preferences.ui +++ b/src/Preferences.ui @@ -179,71 +179,29 @@           <number>0</number>          </property>          <item> -         <spacer name="verticalSpacer_2"> -          <property name="orientation"> -           <enum>Qt::Vertical</enum> -          </property> -          <property name="sizeHint" stdset="0"> -           <size> -            <width>20</width> -            <height>120</height> -           </size> -          </property> -         </spacer> -        </item> -        <item> -         <layout class="QHBoxLayout" name="horizontalLayout_2"> +         <layout class="QVBoxLayout" name="verticalLayout_6">            <item> -           <spacer name="horizontalSpacer_2"> -            <property name="orientation"> -             <enum>Qt::Horizontal</enum> -            </property> -            <property name="sizeHint" stdset="0"> -             <size> -              <width>40</width> -              <height>20</height> -             </size> -            </property> -           </spacer> -          </item> -          <item> -           <widget class="QLabel" name="label_2"> -            <property name="enabled"> -             <bool>false</bool> -            </property> +           <widget class="QCheckBox" name="OpenGL20WarningCheckbox">              <property name="text"> -             <string>advanced</string> +             <string>Show OpenGL 2.0 warning && rendering info</string>              </property>             </widget>            </item>            <item> -           <spacer name="horizontalSpacer_3"> +           <spacer name="verticalSpacer_2">              <property name="orientation"> -             <enum>Qt::Horizontal</enum> +             <enum>Qt::Vertical</enum>              </property>              <property name="sizeHint" stdset="0">               <size> -              <width>40</width> -              <height>20</height> +              <width>20</width> +              <height>40</height>               </size>              </property>             </spacer>            </item>           </layout>          </item> -        <item> -         <spacer name="verticalSpacer_3"> -          <property name="orientation"> -           <enum>Qt::Vertical</enum> -          </property> -          <property name="sizeHint" stdset="0"> -           <size> -            <width>20</width> -            <height>120</height> -           </size> -          </property> -         </spacer> -        </item>         </layout>        </widget>       </widget> diff --git a/src/cgaladv_minkowski2.cc b/src/cgaladv_minkowski2.cc index 8d0bf62..b722708 100644 --- a/src/cgaladv_minkowski2.cc +++ b/src/cgaladv_minkowski2.cc @@ -85,7 +85,7 @@ CGAL_Poly2 nef2p2(CGAL_Nef_polyhedron2 p)  	typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;  	Explorer E = p.explorer(); -	for (fci_t fit = E.faces_begin(), fend = E.faces_end(); fit != fend; ++fit) +	for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit)  	{  		if (!E.mark(fit)) {  			continue; diff --git a/src/export.cc b/src/export.cc index 884e139..8e0ab16 100644 --- a/src/export.cc +++ b/src/export.cc @@ -167,20 +167,6 @@ void export_dxf(CGAL_Nef_polyhedron *root_N, QString filename, QProgressDialog *  	}  	setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output - -	// Some importers (e.g. QCAD) needs a HEADER section specifying AutoCAD 2000 as  -	// the file format for LWPOLYLINE entities to work -	fprintf(f, "  0\n" -					"SECTION\n" -					"  2\n" -					"HEADER\n" -					"  9\n" -					"$ACADVER\n" -					"  1\n" -					"AC1015\n" -					"  0\n" -					"ENDSEC\n"); -  	// Some importers (e.g. Inkscape) needs a BLOCKS section to be present  	fprintf(f, "  0\n"  					"SECTION\n" @@ -197,29 +183,26 @@ void export_dxf(CGAL_Nef_polyhedron *root_N, QString filename, QProgressDialog *  	DxfData dd(*root_N);  	for (int i=0; i<dd.paths.size(); i++)  	{ -		if (dd.paths[i].points.size() < 2) -			// not a valid polygon -			continue; -		// Use the LWPOLYLINE class - this makes it easier to handle complete -		// objects (as paths) in Inkscape. -		fprintf(f, "  0\n"); -		fprintf(f, "LWPOLYLINE\n"); -		// Some importers (e.g. Inkscape) need a layer to be specified -		fprintf(f, "  8\n"); -		fprintf(f, "0\n"); -		// number of vertices -		fprintf(f, "  90\n"); -		fprintf(f, "%d\n", dd.paths[i].points.size()); -		// polygon flag (closed, ...) -		fprintf(f, "  70\n"); -		fprintf(f, "%d\n", dd.paths[i].is_closed ? 1 : 0); -		// add all points -		for (int j=0; j<dd.paths[i].points.size(); j++) { -			DxfData::Point *p = dd.paths[i].points[j]; +		for (int j=1; j<dd.paths[i].points.size(); j++) { +			DxfData::Point *p1 = dd.paths[i].points[j-1]; +			DxfData::Point *p2 = dd.paths[i].points[j]; +			double x1 = p1->x; +			double y1 = p1->y; +			double x2 = p2->x; +			double y2 = p2->y; +			fprintf(f, "  0\n"); +			fprintf(f, "LINE\n"); +			// Some importers (e.g. Inkscape) needs a layer to be specified +			fprintf(f, "  8\n"); +			fprintf(f, "0\n");  			fprintf(f, " 10\n"); -			fprintf(f, "%f\n", p->x); +			fprintf(f, "%f\n", x1); +			fprintf(f, " 11\n"); +			fprintf(f, "%f\n", x2);  			fprintf(f, " 20\n"); -			fprintf(f, "%f\n", p->y); +			fprintf(f, "%f\n", y1); +			fprintf(f, " 21\n"); +			fprintf(f, "%f\n", y2);  		}  	} diff --git a/src/glview.cc b/src/glview.cc index d5285dc..31c9e58 100644 --- a/src/glview.cc +++ b/src/glview.cc @@ -29,9 +29,15 @@  #include <QApplication>  #include <QWheelEvent> +#include <QCheckBox> +#include <QDialogButtonBox>  #include <QMouseEvent>  #include <QMessageBox> +#include <QPushButton> +#include <QSettings>  #include <QTimer> +#include <QTextEdit> +#include <QVBoxLayout>  #include "mathc99.h"  #include <stdio.h> @@ -194,7 +200,10 @@ void GLView::initializeGL()  		}  	} else {  		opencsg_support = false; -		QTimer::singleShot(0, this, SLOT(display_opengl20_warning())); +		QSettings settings; +		if (settings.value("editor/opengl20_warning_show",true).toBool()) { +			QTimer::singleShot(0, this, SLOT(display_opengl20_warning())); +		}  	}  #endif /* ENABLE_OPENCSG */  } @@ -202,6 +211,9 @@ void GLView::initializeGL()  #ifdef ENABLE_OPENCSG  void GLView::display_opengl20_warning()  { +	// data +	QString title = QString("GLEW: GL_VERSION_2_0 is not supported!"); +  	QString rendererinfo;  	rendererinfo.sprintf("GLEW version %s\n"  											 "%s (%s)\n" @@ -210,11 +222,43 @@ void GLView::display_opengl20_warning()  											 glGetString(GL_RENDERER), glGetString(GL_VENDOR),  											 glGetString(GL_VERSION)); -	QMessageBox::warning(NULL, "GLEW: GL_VERSION_2_0 is not supported!", -			QString("Warning: No support for OpenGL 2.0 found! OpenCSG View has been disabled.\n\n" +	QString message = QString("Warning: No support for OpenGL 2.0 found! OpenCSG View has been disabled.\n\n"  			"It is highly recommended to use OpenSCAD on a system with OpenGL 2.0 "  			"support. Please check if OpenGL 2.0 drivers are available for your "	 -			"graphics hardware.\n\n%1").arg(rendererinfo)); +			"graphics hardware. Your renderer information is as follows:\n\n%1").arg(rendererinfo); + +	QString note = QString("Uncheck to hide this message in the future"); + +	// presentation +	QDialog *dialog = new QDialog(this); +	dialog->setSizeGripEnabled(true); +	dialog->setWindowTitle(title); +	dialog->resize(500,300); + +	QVBoxLayout *layout = new QVBoxLayout(dialog); +	dialog->setLayout(layout); + +	QTextEdit *textEdit = new QTextEdit(dialog); +	textEdit->setPlainText(message); +	layout->addWidget(textEdit); + +	QCheckBox *checkbox = new QCheckBox(note,dialog); +	checkbox->setCheckState(Qt::Checked); +	layout->addWidget(checkbox); + +	QDialogButtonBox *buttonbox = +		new QDialogButtonBox(	QDialogButtonBox::Ok, Qt::Horizontal,dialog); +	layout->addWidget(buttonbox); +	buttonbox->button(QDialogButtonBox::Ok)->setFocus(); +	buttonbox->button(QDialogButtonBox::Ok)->setDefault(true); + +	// action +	connect(buttonbox, SIGNAL(accepted()), dialog, SLOT(accept())); +	connect(checkbox, SIGNAL(clicked(bool)), +		Preferences::inst()->OpenGL20WarningCheckbox, SLOT(setChecked(bool))); +	connect(checkbox, SIGNAL(clicked(bool)), +		Preferences::inst(), SLOT(OpenGL20WarningChanged(bool))); +	dialog->exec();  }  #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index e217b1f..0492dac 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -118,6 +118,37 @@ static char copyrighttext[] =  	"the Free Software Foundation; either version 2 of the License, or"  	"(at your option) any later version."; +static void +settings_setValueList(const QString &key,const QList<int> &list) +{ +	QSettings settings; +	settings.beginWriteArray(key); +	for (int i=0;i<list.size(); ++i) { +		settings.setArrayIndex(i); +		settings.setValue("entry",list[i]); +	} +	settings.endArray(); +} + +QList<int> +settings_valueList(const QString &key, const QList<int> &defaultList = QList<int>()) +{ +	QSettings settings; +	QList<int> result; +	if (settings.contains(key+"/size")){ +		int length = settings.beginReadArray(key); +		for (int i = 0; i < length; ++i) { +			settings.setArrayIndex(i); +			result += settings.value("entry").toInt(); +		} +		settings.endArray(); +		return result; +	} else { +		return defaultList; +	} + +} +  MainWindow::MainWindow(const QString &filename)  {  	setupUi(this); @@ -259,6 +290,7 @@ MainWindow::MainWindow(const QString &filename)  	connect(this->designActionExportSTL, SIGNAL(triggered()), this, SLOT(actionExportSTL()));  	connect(this->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF()));  	connect(this->designActionExportDXF, SIGNAL(triggered()), this, SLOT(actionExportDXF())); +	connect(this->designActionExportImage, SIGNAL(triggered()), this, SLOT(actionExportImage()));  	connect(this->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches()));  	// View menu @@ -334,27 +366,69 @@ MainWindow::MainWindow(const QString &filename)  					this, SLOT(setFont(const QString&,uint)));  	Preferences::inst()->apply(); +	// make sure it looks nice.. +	QSettings settings; +	resize(settings.value("window/size", QSize(800, 600)).toSize()); +	move(settings.value("window/position", QPoint(0, 0)).toPoint()); +	QList<int> s1sizes = settings_valueList("window/splitter1sizes",QList<int>()<<400<<400); +	QList<int> s2sizes = settings_valueList("window/splitter2sizes",QList<int>()<<400<<200); +	splitter1->setSizes(s1sizes); +	splitter2->setSizes(s2sizes);  	// display this window and check for OpenGL 2.0 (OpenCSG) support  	viewModeThrownTogether();  	show(); -	// make sure it looks nice.. -	resize(800, 600); -	splitter1->setSizes(QList<int>() << 400 << 400); -	splitter2->setSizes(QList<int>() << 400 << 200); -  #ifdef ENABLE_OPENCSG  	viewModeOpenCSG();  #else  	viewModeThrownTogether();  #endif -	viewPerspective(); +	loadViewSettings(); +	loadDesignSettings();  	setAcceptDrops(true);  	clearCurrentOutput();  } +void +MainWindow::loadViewSettings(){ +	QSettings settings; +	if (settings.value("view/showEdges").toBool()) { +		viewActionShowEdges->setChecked(true); +		viewModeShowEdges(); +	} +	if (settings.value("view/showAxes").toBool()) { +		viewActionShowAxes->setChecked(true); +		viewModeShowAxes(); +	} +	if (settings.value("view/showCrosshairs").toBool()) { +		viewActionShowCrosshairs->setChecked(true); +		viewModeShowCrosshairs(); +	} +	if (settings.value("view/orthogonalProjection").toBool()) { +		viewOrthogonal(); +	} else { +		viewPerspective(); +	} +	if (settings.value("view/hideConsole").toBool()) { +		viewActionHide->setChecked(true); +		hideConsole(); +	} +	if (settings.value("view/hideEditor").toBool()) { +		editActionHide->setChecked(true); +		hideEditor(); +	} +} + +void +MainWindow::loadDesignSettings() +{ +	QSettings settings; +	if (settings.value("design/autoReload").toBool()) +		designActionAutoReload->setChecked(true); +} +  MainWindow::~MainWindow()  {  	if (root_module) @@ -951,10 +1025,13 @@ void MainWindow::actionReload()  void MainWindow::hideEditor()  { +	QSettings settings;  	if (editActionHide->isChecked()) {  		editor->hide(); +		settings.setValue("view/hideEditor",true);  	} else {  		editor->show(); +		settings.setValue("view/hideEditor",false);  	}  } @@ -995,6 +1072,8 @@ void MainWindow::checkAutoReload()  void MainWindow::autoReloadSet(bool on)  { +	QSettings settings; +	settings.setValue("design/autoReload",designActionAutoReload->isChecked());  	if (on) {  		autoReloadInfo = QString();  		autoReloadTimer->start(200); @@ -1342,6 +1421,24 @@ void MainWindow::actionExportDXF()  #endif /* ENABLE_CGAL */  } +void MainWindow::actionExportImage() +{ +	QImage img = screen->grabFrameBuffer(); +	setCurrentOutput(); + +	QString img_filename = QFileDialog::getSaveFileName(this, +			"Export Image", "", "PNG Files (*.png)"); +	if (img_filename.isEmpty()) { +		PRINTF("No filename specified. Image export aborted."); +		clearCurrentOutput(); +		return; +	} + +	img.save(img_filename, "PNG"); + +	clearCurrentOutput(); +} +  void MainWindow::actionFlushCaches()  {  	PolySet::ps_cache.clear(); @@ -1637,17 +1734,23 @@ void MainWindow::viewModeThrownTogether()  void MainWindow::viewModeShowEdges()  { +	QSettings settings; +	settings.setValue("view/showEdges",viewActionShowEdges->isChecked());  	screen->updateGL();  }  void MainWindow::viewModeShowAxes()  { +	QSettings settings; +	settings.setValue("view/showAxes",viewActionShowAxes->isChecked());  	screen->setShowAxes(viewActionShowAxes->isChecked());  	screen->updateGL();  }  void MainWindow::viewModeShowCrosshairs()  { +	QSettings settings; +	settings.setValue("view/showCrosshairs",viewActionShowCrosshairs->isChecked());  	screen->setShowCrosshairs(viewActionShowCrosshairs->isChecked());  	screen->updateGL();  } @@ -1751,6 +1854,8 @@ void MainWindow::viewCenter()  void MainWindow::viewPerspective()  { +	QSettings settings; +	settings.setValue("view/orthogonalProjection",false);  	viewActionPerspective->setChecked(true);  	viewActionOrthogonal->setChecked(false);  	screen->setOrthoMode(false); @@ -1759,6 +1864,8 @@ void MainWindow::viewPerspective()  void MainWindow::viewOrthogonal()  { +	QSettings settings; +	settings.setValue("view/orthogonalProjection",true);  	viewActionPerspective->setChecked(false);  	viewActionOrthogonal->setChecked(true);  	screen->setOrthoMode(true); @@ -1767,10 +1874,13 @@ void MainWindow::viewOrthogonal()  void MainWindow::hideConsole()  { +	QSettings settings;  	if (viewActionHide->isChecked()) {  		console->hide(); +		settings.setValue("view/hideConsole",true);  	} else {  		console->show(); +		settings.setValue("view/hideConsole",false);  	}  } @@ -1837,6 +1947,11 @@ MainWindow::maybeSave()  void MainWindow::closeEvent(QCloseEvent *event)  {  	if (maybeSave()) { +		QSettings settings; +		settings.setValue("window/size", size()); +		settings.setValue("window/position", pos()); +		settings_setValueList("window/splitter1sizes",splitter1->sizes()); +		settings_setValueList("window/splitter2sizes",splitter2->sizes());  		event->accept();  	} else {  		event->ignore(); diff --git a/src/primitives.cc b/src/primitives.cc index 0f82c1b..5180c16 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -34,6 +34,8 @@  #include "printutils.h"  #include <assert.h> +#define F_MINIMUM 0.01 +  enum primitive_type_e {  	CUBE,  	SPHERE, @@ -57,7 +59,6 @@ class PrimitiveNode : public AbstractPolyNode  public:  	bool center;  	double x, y, z, h, r1, r2; -	static const double F_MINIMUM = 0.01;  	double fn, fs, fa;  	primitive_type_e type;  	int convexity; @@ -106,13 +107,13 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti  	node->fs = c.lookup_variable("$fs").num;  	node->fa = c.lookup_variable("$fa").num; -	if (node->fs < PrimitiveNode::F_MINIMUM) { -		PRINTF("WARNING: $fs too small - clamping to %f", PrimitiveNode::F_MINIMUM); -		node->fs = PrimitiveNode::F_MINIMUM; +	if (node->fs < F_MINIMUM) { +		PRINTF("WARNING: $fs too small - clamping to %f", F_MINIMUM); +		node->fs = F_MINIMUM;  	} -	if (node->fa < PrimitiveNode::F_MINIMUM) { -		PRINTF("WARNING: $fa too small - clamping to %f", PrimitiveNode::F_MINIMUM); -		node->fa = PrimitiveNode::F_MINIMUM; +	if (node->fa < F_MINIMUM) { +		PRINTF("WARNING: $fa too small - clamping to %f", F_MINIMUM); +		node->fa = F_MINIMUM;  	} @@ -226,7 +227,7 @@ struct point2d {  static void generate_circle(point2d *circle, double r, int fragments)  {  	for (int i=0; i<fragments; i++) { -		double phi = (M_PI*2* (i + 0.5)) / fragments; +		double phi = (M_PI*2*i) / fragments;  		circle[i].x = r*cos(phi);  		circle[i].y = r*sin(phi);  	} diff --git a/src/transform.cc b/src/transform.cc index e841ef0..7b15a7e 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -91,7 +91,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti  		argnames = QVector<QString>() << "m";  	}  	if (type == COLOR) { -		argnames = QVector<QString>() << "c"; +		argnames = QVector<QString>() << "c" << "alpha";  	}  	Context c(ctx); @@ -227,6 +227,24 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti  		if (v.type == Value::VECTOR) {  			for (int i = 0; i < 4; i++)  				node->m[16+i] = i < v.vec.size() ? v.vec[i]->num : 1.0; +		} else if (v.type == Value::STRING) { +			QString colorname = v.text; +			QColor color; +			color.setNamedColor(colorname); +			if (color.isValid()) { +				node->m[16+0] = color.redF(); +				node->m[16+1] = color.greenF(); +				node->m[16+2] = color.blueF(); +			} else { +				PRINTF_NOCACHE("WARNING: Color name \"%s\" unknown. Please see",v.text.toUtf8().data()); +				PRINTF_NOCACHE("WARNING: http://en.wikipedia.org/wiki/Web_colors"); +			} +		} +		Value alpha = c.lookup_variable("alpha"); +		if (alpha.type == Value::NUMBER) { +			node->m[16+3] = alpha.num; +		} else { +			node->m[16+3] = 1.0;  		}  	} diff --git a/testdata/scad/non-aff-matrix.scad b/testdata/scad/non-aff-matrix.scad new file mode 100644 index 0000000..7dbced1 --- /dev/null +++ b/testdata/scad/non-aff-matrix.scad @@ -0,0 +1,6 @@ +multmatrix(m = [[1, 0,  0,      0], +                [0, 1,  0,      0], +                [0, 0,  1,      0], +                [0, 0,  -0.02, 1]])  + linear_extrude(height=20) circle(r=10); + diff --git a/testdata/scad/testcolornames.scad b/testdata/scad/testcolornames.scad new file mode 100644 index 0000000..b9ad334 --- /dev/null +++ b/testdata/scad/testcolornames.scad @@ -0,0 +1,159 @@ +/* color samples for SVG named colors, for OpenSCAD +Please see http://en.wikipedia.org/wiki/Web_colors +and http://www.w3.org/TR/SVG/types.html#ColorKeywords +for more information. */ + +$fn=5; +radius=0.8; +//translate([0,0]) color("Red colors") sphere(radius); +translate([1,0]) color("IndianRed") sphere(radius); +translate([2,0]) color("LightCoral") sphere(radius); +translate([3,0]) color("Salmon") sphere(radius); +translate([4,0]) color("DarkSalmon") sphere(radius); +translate([5,0]) color("LightSalmon") sphere(radius); +translate([6,0]) color("Red") sphere(radius); +translate([7,0]) color("Crimson") sphere(radius); +translate([8,0]) color("FireBrick") sphere(radius); +translate([9,0]) color("DarkRed") sphere(radius); +//translate([10,0]) color("Pink colors") sphere(radius); +translate([0,1]) color("Pink") sphere(radius); +translate([1,1]) color("LightPink") sphere(radius); +translate([2,1]) color("HotPink") sphere(radius); +translate([3,1]) color("DeepPink") sphere(radius); +translate([4,1]) color("MediumVioletRed") sphere(radius); +translate([5,1]) color("PaleVioletRed") sphere(radius); +//translate([6,1]) color("Orange colors") sphere(radius); +translate([7,1]) color("LightSalmon") sphere(radius); +translate([8,1]) color("Coral") sphere(radius); +translate([9,1]) color("Tomato") sphere(radius); +translate([10,1]) color("OrangeRed") sphere(radius); +translate([0,2]) color("DarkOrange") sphere(radius); +translate([1,2]) color("Orange") sphere(radius); +//translate([2,2]) color("Yellow colors") sphere(radius); +translate([3,2]) color("Gold") sphere(radius); +translate([4,2]) color("Yellow") sphere(radius); +translate([5,2]) color("LightYellow") sphere(radius); +translate([6,2]) color("LemonChiffon") sphere(radius); +translate([7,2]) color("LightGoldenrodYellow") sphere(radius); +translate([8,2]) color("PapayaWhip") sphere(radius); +translate([9,2]) color("Moccasin") sphere(radius); +translate([10,2]) color("PeachPuff") sphere(radius); +translate([0,3]) color("PaleGoldenrod") sphere(radius); +translate([1,3]) color("Khaki") sphere(radius); +translate([2,3]) color("DarkKhaki") sphere(radius); +//translate([3,3]) color("Purple colors") sphere(radius); +translate([4,3]) color("Lavender") sphere(radius); +translate([5,3]) color("Thistle") sphere(radius); +translate([6,3]) color("Plum") sphere(radius); +translate([7,3]) color("Violet") sphere(radius); +translate([8,3]) color("Orchid") sphere(radius); +translate([9,3]) color("Fuchsia") sphere(radius); +translate([10,3]) color("Magenta") sphere(radius); +translate([0,4]) color("MediumOrchid") sphere(radius); +translate([1,4]) color("MediumPurple") sphere(radius); +translate([2,4]) color("BlueViolet") sphere(radius); +translate([3,4]) color("DarkViolet") sphere(radius); +translate([4,4]) color("DarkOrchid") sphere(radius); +translate([5,4]) color("DarkMagenta") sphere(radius); +translate([6,4]) color("Purple") sphere(radius); +translate([7,4]) color("Indigo") sphere(radius); +translate([8,4]) color("DarkSlateBlue") sphere(radius); +translate([9,4]) color("SlateBlue") sphere(radius); +translate([10,4]) color("MediumSlateBlue") sphere(radius); +//translate([0,5]) color("Green colors") sphere(radius); +translate([1,5]) color("GreenYellow") sphere(radius); +translate([2,5]) color("Chartreuse") sphere(radius); +translate([3,5]) color("LawnGreen") sphere(radius); +translate([4,5]) color("Lime") sphere(radius); +translate([5,5]) color("LimeGreen") sphere(radius); +translate([6,5]) color("PaleGreen") sphere(radius); +translate([7,5]) color("LightGreen") sphere(radius); +translate([8,5]) color("MediumSpringGreen") sphere(radius); +translate([9,5]) color("SpringGreen") sphere(radius); +translate([10,5]) color("MediumSeaGreen") sphere(radius); +translate([0,6]) color("SeaGreen") sphere(radius); +translate([1,6]) color("ForestGreen") sphere(radius); +translate([2,6]) color("Green") sphere(radius); +translate([3,6]) color("DarkGreen") sphere(radius); +translate([4,6]) color("YellowGreen") sphere(radius); +translate([5,6]) color("OliveDrab") sphere(radius); +translate([6,6]) color("Olive") sphere(radius); +translate([7,6]) color("DarkOliveGreen") sphere(radius); +translate([8,6]) color("MediumAquamarine") sphere(radius); +translate([9,6]) color("DarkSeaGreen") sphere(radius); +translate([10,6]) color("LightSeaGreen") sphere(radius); +translate([0,7]) color("DarkCyan") sphere(radius); +translate([1,7]) color("Teal") sphere(radius); +//translate([2,7]) color("Blue/Cyan colors") sphere(radius); +translate([3,7]) color("Aqua") sphere(radius); +translate([4,7]) color("Cyan") sphere(radius); +translate([5,7]) color("LightCyan") sphere(radius); +translate([6,7]) color("PaleTurquoise") sphere(radius); +translate([7,7]) color("Aquamarine") sphere(radius); +translate([8,7]) color("Turquoise") sphere(radius); +translate([9,7]) color("MediumTurquoise") sphere(radius); +translate([10,7]) color("DarkTurquoise") sphere(radius); +translate([0,8]) color("CadetBlue") sphere(radius); +translate([1,8]) color("SteelBlue") sphere(radius); +translate([2,8]) color("LightSteelBlue") sphere(radius); +translate([3,8]) color("PowderBlue") sphere(radius); +translate([4,8]) color("LightBlue") sphere(radius); +translate([5,8]) color("SkyBlue") sphere(radius); +translate([6,8]) color("LightSkyBlue") sphere(radius); +translate([7,8]) color("DeepSkyBlue") sphere(radius); +translate([8,8]) color("DodgerBlue") sphere(radius); +translate([9,8]) color("CornflowerBlue") sphere(radius); +translate([10,8]) color("RoyalBlue") sphere(radius); +translate([0,9]) color("Blue") sphere(radius); +translate([1,9]) color("MediumBlue") sphere(radius); +translate([2,9]) color("DarkBlue") sphere(radius); +translate([3,9]) color("Navy") sphere(radius); +translate([4,9]) color("MidnightBlue") sphere(radius); +//translate([5,9]) color("Brown colors") sphere(radius); +translate([6,9]) color("Cornsilk") sphere(radius); +translate([7,9]) color("BlanchedAlmond") sphere(radius); +translate([8,9]) color("Bisque") sphere(radius); +translate([9,9]) color("NavajoWhite") sphere(radius); +translate([10,9]) color("Wheat") sphere(radius); +translate([0,10]) color("BurlyWood") sphere(radius); +translate([1,10]) color("Tan") sphere(radius); +translate([2,10]) color("RosyBrown") sphere(radius); +translate([3,10]) color("SandyBrown") sphere(radius); +translate([4,10]) color("Goldenrod") sphere(radius); +translate([5,10]) color("DarkGoldenrod") sphere(radius); +translate([6,10]) color("Peru") sphere(radius); +translate([7,10]) color("Chocolate") sphere(radius); +translate([8,10]) color("SaddleBrown") sphere(radius); +translate([9,10]) color("Sienna") sphere(radius); +translate([10,10]) color("Brown") sphere(radius); +translate([0,11]) color("Maroon") sphere(radius); +//translate([1,11]) color("White colors") sphere(radius); +translate([2,11]) color("White") sphere(radius); +translate([3,11]) color("Snow") sphere(radius); +translate([4,11]) color("Honeydew") sphere(radius); +translate([5,11]) color("MintCream") sphere(radius); +translate([6,11]) color("Azure") sphere(radius); +translate([7,11]) color("AliceBlue") sphere(radius); +translate([8,11]) color("GhostWhite") sphere(radius); +translate([9,11]) color("WhiteSmoke") sphere(radius); +translate([10,11]) color("Seashell") sphere(radius); +translate([0,12]) color("Beige") sphere(radius); +translate([1,12]) color("OldLace") sphere(radius); +translate([2,12]) color("FloralWhite") sphere(radius); +translate([3,12]) color("Ivory") sphere(radius); +translate([4,12]) color("AntiqueWhite") sphere(radius); +translate([5,12]) color("Linen") sphere(radius); +translate([6,12]) color("LavenderBlush") sphere(radius); +translate([7,12]) color("MistyRose") sphere(radius); +//translate([8,12]) color("Gray colors") sphere(radius); +translate([9,12]) color("Gainsboro") sphere(radius); +translate([10,12]) color("LightGrey") sphere(radius); +translate([0,13]) color("Silver") sphere(radius); +translate([1,13]) color("DarkGray") sphere(radius); +translate([2,13]) color("Gray") sphere(radius); +translate([3,13]) color("DimGray") sphere(radius); +translate([4,13]) color("LightSlateGray") sphere(radius); +translate([5,13]) color("SlateGray") sphere(radius); +translate([6,13]) color("DarkSlateGray") sphere(radius); +translate([7,13]) color("Black") sphere(radius); + | 
