summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_NOTES9
-rw-r--r--doc/TODO.txt2
-rw-r--r--doc/release-checklist.txt19
-rw-r--r--examples/example017.scad2
m---------libraries/MCAD0
-rw-r--r--mingw-cross-env.pri3
-rw-r--r--openscad.pro1
-rwxr-xr-xscripts/builder.sh10
-rwxr-xr-xscripts/check-dependencies.sh12
-rwxr-xr-xscripts/git-archive-all.py571
-rw-r--r--scripts/installer.nsi1
-rwxr-xr-xscripts/macosx-build-dependencies.sh20
-rwxr-xr-xscripts/publish-macosx.sh7
-rw-r--r--scripts/setenv-mingw-xbuild.sh1
-rw-r--r--scripts/setenv-unibuild.sh4
-rwxr-xr-xscripts/uni-build-dependencies.sh23
-rwxr-xr-xscripts/uni-get-dependencies.sh12
-rw-r--r--setenv_mjau.sh2
-rw-r--r--src/AboutDialog.html16
-rw-r--r--src/CGALEvaluator.cc13
-rw-r--r--src/CGAL_Nef_polyhedron.h2
-rw-r--r--src/MainWindow.ui5
-rw-r--r--src/ModuleCache.cc26
-rw-r--r--src/ModuleCache.h1
-rw-r--r--src/OffscreenContextWGL.cc33
-rw-r--r--src/PolySetCGALEvaluator.cc1
-rw-r--r--src/cgal.h10
-rw-r--r--src/cgalutils.cc3
-rw-r--r--src/cgalutils.h2
-rw-r--r--src/csgterm.cc1
-rw-r--r--src/highlighter.cc16
-rw-r--r--src/linearextrude.cc6
-rw-r--r--src/localscope.cc8
-rw-r--r--src/mainwin.cc38
-rw-r--r--src/modcontext.cc74
-rw-r--r--src/modcontext.h3
-rw-r--r--src/module.cc15
-rw-r--r--src/module.h7
-rw-r--r--src/openscad.cc1
-rw-r--r--src/parser.y8
-rw-r--r--src/parsersettings.cc6
-rw-r--r--src/primitives.cc5
-rw-r--r--src/rotateextrude.cc1
-rw-r--r--src/svg.cc40
-rwxr-xr-xtestdata/modulecache-tests/cascade.sh2
-rwxr-xr-xtestdata/modulecache-tests/cascade2.sh2
-rw-r--r--testdata/scad/dxf/arc.scad1
-rw-r--r--testdata/scad/dxf/circle.scad1
-rw-r--r--testdata/scad/features/circle-tests.scad1
-rw-r--r--testdata/scad/features/cylinder-tests.scad4
-rw-r--r--testdata/scad/features/linear_extrude-tests.scad3
-rw-r--r--testdata/scad/features/rotate_extrude-tests.scad4
-rw-r--r--testdata/scad/features/sphere-tests.scad1
-rw-r--r--testdata/scad/misc/value-reassignment-tests.scad9
-rw-r--r--testdata/scad/misc/value-reassignment-tests2.scad16
-rw-r--r--testdata/scad/misc/variable-scope-tests.scad13
-rw-r--r--tests/.gitignore3
-rw-r--r--tests/CMakeLists.txt4
-rw-r--r--tests/regression/cgalpngtest/arc-expected.pngbin6782 -> 6641 bytes
-rw-r--r--tests/regression/cgalpngtest/circle-expected.pngbin6979 -> 6282 bytes
-rw-r--r--tests/regression/cgalpngtest/circle-tests-expected.pngbin8435 -> 7373 bytes
-rw-r--r--tests/regression/cgalpngtest/cylinder-tests-expected.pngbin11017 -> 11431 bytes
-rw-r--r--tests/regression/cgalpngtest/rotate_extrude-tests-expected.pngbin20273 -> 17684 bytes
-rw-r--r--tests/regression/cgalpngtest/sphere-tests-expected.pngbin16818 -> 16561 bytes
-rw-r--r--tests/regression/dumptest/circle-tests-expected.txt3
-rw-r--r--tests/regression/dumptest/cylinder-tests-expected.txt3
-rw-r--r--tests/regression/dumptest/linear_extrude-tests-expected.txt5
-rw-r--r--tests/regression/dumptest/rotate_extrude-tests-expected.txt7
-rw-r--r--tests/regression/dumptest/sphere-tests-expected.txt3
-rw-r--r--tests/regression/echotest/value-reassignment-tests-expected.txt3
-rw-r--r--tests/regression/echotest/value-reassignment-tests2-expected.txt1
-rw-r--r--tests/regression/echotest/variable-scope-tests-expected.txt2
-rw-r--r--tests/regression/opencsgtest/arc-expected.pngbin7166 -> 6711 bytes
-rw-r--r--tests/regression/opencsgtest/circle-expected.pngbin7115 -> 6464 bytes
-rw-r--r--tests/regression/opencsgtest/circle-tests-expected.pngbin8880 -> 8418 bytes
-rw-r--r--tests/regression/opencsgtest/cylinder-tests-expected.pngbin11612 -> 12080 bytes
-rw-r--r--tests/regression/opencsgtest/rotate_extrude-tests-expected.pngbin21093 -> 18320 bytes
-rw-r--r--tests/regression/opencsgtest/sphere-tests-expected.pngbin18173 -> 17564 bytes
-rw-r--r--tests/regression/throwntogethertest/arc-expected.pngbin2758 -> 6711 bytes
-rw-r--r--tests/regression/throwntogethertest/circle-expected.pngbin2837 -> 6464 bytes
-rw-r--r--tests/regression/throwntogethertest/circle-tests-expected.pngbin8880 -> 8418 bytes
-rw-r--r--tests/regression/throwntogethertest/cylinder-tests-expected.pngbin11612 -> 12080 bytes
-rw-r--r--tests/regression/throwntogethertest/rotate_extrude-tests-expected.pngbin6429 -> 8198 bytes
-rw-r--r--tests/regression/throwntogethertest/sphere-tests-expected.pngbin18173 -> 17564 bytes
-rwxr-xr-xtests/virtualfb.sh6
85 files changed, 837 insertions, 300 deletions
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 870b498..455515c 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,4 +1,4 @@
-OpenSCAD 2013.05
+OpenSCAD 2013.06
================
Language Features:
@@ -8,7 +8,6 @@ o Recursive use of modules is now supported (including cascading child() operati
https://github.com/openscad/openscad/blob/master/examples/example024.scad
o Parameter list values can now depend on earlier values, e.g. for (i=[0:2], j=[0:i]) ..
o value assignments in parameters can now depend on already declared parameters
-o value reassignment is now less strict
o Added resize() module:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#resize
@@ -17,7 +16,7 @@ o Added basic syntax highlighting in the editor
o There is now a built-in library path in user-space:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Libraries#Library_Locations
o Commandline output to PNG, with various camera and rendering settings.
- Run openscad -h to see usage info.
+ Run openscad -h to see usage info or see the OpenSCAD wiki user manual.
o Attempting to open dxf, off or stl files in the GUI will now create an import statement.
o The preview operator (%) will now preserve any manually set color
o The highlight operator (#) will now color the object in transparent red
@@ -47,6 +46,10 @@ o Regression test auto-starts & stops Xvfb / Xvnc if on headless unix machine
o The backend is finally independent of Qt
o Windows: We now have a 64-bit version
+Known Bugs:
+o Linux: command-line png rendering on Gallium is flaky.
+ Workaround: use CGAL --render or hardware rendering.
+
OpenSCAD 2013.01
================
diff --git a/doc/TODO.txt b/doc/TODO.txt
index d05df2c..e56dbd7 100644
--- a/doc/TODO.txt
+++ b/doc/TODO.txt
@@ -227,7 +227,7 @@ DOCUMENTATION
-------------
o Auto-generate API documentation instead of, in addition to or combined with, the wikibooks docs.
o Write checklists for typical extension work (add new module, add new function)
- -> make sure new test files are added
+ -> syntax highlighter, test files, examples, documentation (external editor modes)
o Clarify include/use better in the wikibook docs (e.g. that use'd modules have to be self-contained)
TESTING
diff --git a/doc/release-checklist.txt b/doc/release-checklist.txt
index a1cc6ff..d239278 100644
--- a/doc/release-checklist.txt
+++ b/doc/release-checklist.txt
@@ -44,19 +44,24 @@ o git push --tags
o Upload Source package
$ ./scripts/googlecode_upload.py -s 'Source Code' -p openscad -l Featured,Type-Source openscad-$VERSION.src.tar.gz
+ $ scp openscad-$VERSION.src.tar.gz openscad@files.openscad.org:www
o Remove VERSION environment variable
$ unset VERSION
+o Write release email/blog entry
o Update web page
-o Write email to mailing list
+ - news.html
+ - inc/src_release_links.js
o Update external resources:
- http://en.wikipedia.org/wiki/OpenSCAD
+o Write to mailing list
+o Tweet
o Notify package managers
- Ubuntu: https://launchpad.net/~chrysn
- Fedora: Miro HronĨok <miro@hroncok.cz> or <mhroncok@redhat.com>
- - MacPorts:
-
+ - OpenSUSE: Pavol Rusnak <prusnak@opensuse.org>
+ - MacPorts: Frank Schima <macports2000@gmail.com>
Build and Upload Release Binaries
---------------------------------
@@ -79,10 +84,6 @@ Linux:
$ ./scripts/googlecode_upload.py -s 'Linux Binaries' -p openscad openscad-$VERSION.x86-ARCH.tar.gz -l Featured,OpSys-Linux,Type-Archive openscad-$VERSION.x86-ARCH.tar.gz
o Update web page with download links
-Windows mingw cross-build: FIXME 32 vs. 64 bit
+Windows mingw cross-build:
- $ ./scripts/publish-mingw-x.sh -> mingw32/Openscad-$VERSION.zip
- -> mingw32/Openscad-$VERSION-Installer.exe
- $ ./scripts/googlecode_upload.py -s 'Windows Binaries' -p openscad OpenSCAD-$VERSION.zip -l Featured,OpSys-Windows,Type-Archive OpenSCAD-$VERSION.zip
- $ ./scripts/googlecode_upload.py -s 'Windows Installer' -p openscad OpenSCAD-$VERSION-Installer.exe -l Featured,OpSys-Windows,Type-Installer OpenSCAD-$VERSION-Installer.exe
- o Update web page with download links
+FIXME: Adapt scripts/builder.sh to build release binaries
diff --git a/examples/example017.scad b/examples/example017.scad
index 9013d4e..4279546 100644
--- a/examples/example017.scad
+++ b/examples/example017.scad
@@ -1,6 +1,6 @@
// To render the DXF file from the command line:
-// openscad -x example017.dxf -D'mode="parts"' example017.scad
+// openscad -o example017.dxf -D'mode="parts"' example017.scad
// mode = "parts";
// mode = "exploded";
diff --git a/libraries/MCAD b/libraries/MCAD
-Subproject 1cc850b44914e1863adfaea2d6f9c848bbc514e
+Subproject 9a958fd11b0a6b5f8becd37c4f8a42f585abfcd
diff --git a/mingw-cross-env.pri b/mingw-cross-env.pri
index e696b56..07a0fc1 100644
--- a/mingw-cross-env.pri
+++ b/mingw-cross-env.pri
@@ -13,6 +13,9 @@ CONFIG(mingw-cross-env) {
LIBS += mingw-cross-env/lib/libgmp.a
LIBS += mingw-cross-env/lib/libCGAL.a
QMAKE_CXXFLAGS += -fpermissive
+ WINSTACKSIZE = 8388608 # 8MB # github issue 116
+ QMAKE_CXXFLAGS += -Wl,--stack,$$WINSTACKSIZE
+ LIBS += -Wl,--stack,$$WINSTACKSIZE
QMAKE_DEL_FILE = rm -f
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-local-typedefs #eigen3
}
diff --git a/openscad.pro b/openscad.pro
index c007330..fd9f494 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -107,6 +107,7 @@ netbsd* {
QMAKE_LFLAGS += -L/usr/X11R7/lib
QMAKE_LFLAGS += -Wl,-R/usr/X11R7/lib
QMAKE_LFLAGS += -Wl,-R/usr/pkg/lib
+ !clang: { QMAKE_CXXFLAGS += -std=c++0x }
!isEmpty(OPENSCAD_LIBDIR) {
QMAKE_CFLAGS = -I$$OPENSCAD_LIBDIR/include $$QMAKE_CFLAGS
QMAKE_CXXFLAGS = -I$$OPENSCAD_LIBDIR/include $$QMAKE_CXXFLAGS
diff --git a/scripts/builder.sh b/scripts/builder.sh
index 71023da..b00919f 100755
--- a/scripts/builder.sh
+++ b/scripts/builder.sh
@@ -11,6 +11,9 @@
# todo - make linux work
#
# todo - detect failure and stop
+#
+# todo - generalize to build release binaries as well
+#
init_variables()
{
@@ -94,8 +97,11 @@ upload_win_generic()
if [ $DRYRUN ]; then
echo dry run, not uploading to googlecode
echo cmd - python ./scripts/googlecode_upload.py -s '"'$summary'"' $opts
+ echo dry run, not uploading to files.openscad.org
+ echo scp -v $filename openscad@files.openscad.org:www/
else
python ./scripts/googlecode_upload.py -s "$summary" $opts
+ scp -v $filename openscad@files.openscad.org:www/
fi
}
@@ -173,6 +179,7 @@ update_win_www_download_links()
cd inc
echo `pwd`
BASEURL='https://openscad.googlecode.com/files/'
+ # BASEURL='http://files.openscad.org'
DATECODE=`date +"%Y.%m.%d"`
rm win_snapshot_links.js
@@ -200,6 +207,9 @@ update_win_www_download_links()
fi
}
+# FIXME: We might be running this locally and not need an ssh agent.
+# Before checking $SSH_AUTH_SOCK, try 'ssh -T git@github.com' to verify that we
+# can access github over ssh
check_ssh_agent()
{
if [ $DRYRUN ]; then echo 'skipping ssh, dry run'; return; fi
diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh
index 4d5505e..5fddb13 100755
--- a/scripts/check-dependencies.sh
+++ b/scripts/check-dependencies.sh
@@ -87,11 +87,16 @@ mpfr_sysver()
gmp_sysver()
{
# on some systems you have VERSION in gmp-$arch.h not gmp.h. use gmp*.h
- if [ ! -e $1/include ]; then return; fi
- gmppaths=`ls $1/include | grep ^gmp`
+ if [ -e $1/include/multiarch-x86_64-linux ]; then
+ subdir=include/multiarch-x86_64-linux
+ else
+ subdir=include
+ fi
+ if [ ! -e $1/$subdir ]; then return; fi
+ gmppaths=`ls $1/$subdir | grep ^gmp`
if [ ! "$gmppaths" ]; then return; fi
for gmpfile in $gmppaths; do
- gmppath=$1/include/$gmpfile
+ gmppath=$1/$subdir/$gmpfile
if [ "`grep __GNU_MP_VERSION $gmppath`" ]; then
gmpmaj=`grep "define *__GNU_MP_VERSION *[0-9]*" $gmppath | awk '{print $3}'`
gmpmin=`grep "define *__GNU_MP_VERSION_MINOR *[0-9]*" $gmppath | awk '{print $3}'`
@@ -518,6 +523,7 @@ main()
deps="qt4 cgal gmp mpfr boost opencsg glew eigen gcc bison flex make"
#deps="$deps curl git" # not technically necessary for build
#deps="$deps python cmake imagemagick" # only needed for tests
+ #deps="cgal"
pretty_print title
for depname in $deps; do
debug "processing $dep"
diff --git a/scripts/git-archive-all.py b/scripts/git-archive-all.py
index ccfb08a..0088e1a 100755
--- a/scripts/git-archive-all.py
+++ b/scripts/git-archive-all.py
@@ -1,171 +1,464 @@
#! /usr/bin/env python
+# coding=utf-8
+
+from __future__ import print_function
+from __future__ import unicode_literals
+
+__version__ = "1.7"
import sys
-from os import path, chdir
-from subprocess import Popen, PIPE
-from sys import argv, stdout
-from fnmatch import fnmatch
+from os import path, extsep
+from subprocess import Popen, PIPE, CalledProcessError
class GitArchiver(object):
"""
GitArchiver
-
+
Scan a git repository and export all tracked files, and submodules.
Checks for .gitattributes files in each directory and uses 'export-ignore'
pattern entries for ignore files in the archive.
-
- Automatically detects output format extension: zip, tar, bz2, or gz
+
+ Automatically detects output format extension: zip, tar, bz2, or gz.
"""
-
- def __init__(self, prefix='', verbose=False, exclude=True, extra=[]):
- self.prefix = prefix
- self.verbose = verbose
- self.exclude = exclude
- self.extra = extra
-
- self._excludes = []
+ def __init__(self, prefix='', verbose=False, exclude=True, force_sub=False, extra=None, main_repo_abspath=None):
+ """
+ @type prefix: string
+ @param prefix: Prefix used to prepend all paths in the resulting archive.
+
+ @type verbose: bool
+ @param verbose: Determines verbosity of the output (stdout).
+
+ @type exclude: bool
+ @param exclude: Determines whether archiver should follow rules specified in .gitattributes files.
+ Defaults to True.
+
+ @type force_sub: bool
+ @param force_sub: Determines whether submodules are initialized and updated before archiving.
+ Defaults to False
- def create(self, output_file):
+ @type extra: list
+ @param extra: List of extra paths to include in the resulting archive.
+
+ @type main_repo_abspath: string
+ @param main_repo_abspath: Absolute path to the main repository (or one of subdirectories).
+ If None, current cwd is used.
+ If given path is path to a subdirectory (but not a submodule directory!)
+ it will be replaced with abspath to toplevel directory of the repository.
"""
- create(str output_file) -> None
-
- Creates the archive, written to the given output_file
- Filetype may be one of: gz, zip, bz2, tar
+ if extra is None:
+ extra = []
+
+ if main_repo_abspath is None:
+ main_repo_abspath = path.abspath('')
+ elif not path.isabs(main_repo_abspath):
+ raise ValueError("You MUST pass absolute path to the main git repository.")
+
+ # Raises an exception if there is no repo under main_repo_abspath.
+ try:
+ self.run_shell("[ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1", main_repo_abspath)
+ except Exception as e:
+ raise ValueError("Not a git repository (or any of the parent directories).".format(path=main_repo_abspath))
+
+ # Detect toplevel directory of the repo.
+ main_repo_abspath = path.abspath(self.read_git_shell('git rev-parse --show-toplevel', main_repo_abspath).rstrip())
+
+ self.prefix = prefix
+ self.verbose = verbose
+ self.exclude = exclude
+ self.extra = extra
+ self.force_sub = force_sub
+ self.main_repo_abspath = main_repo_abspath
+
+ def create(self, output_path, dry_run=False, output_format=None):
"""
- #
- # determine the format
- #
- _, _, format = output_file.rpartition(".")
+ Creates the archive, written to the given output_file_path
+
+ Type of the archive is determined either by extension of output_file_path or by the format argument.
+ Supported formats are: gz, zip, bz2, tar, tgz
+
+ @type output_path: string
+ @param output_path: Output file path.
- if format.lower() == 'zip':
+ @type dry_run: bool
+ @param dry_run: Determines whether create should do nothing but print what it would archive.
+
+ @type output_format: string
+ @param output_format: Determines format of the output archive.
+ If None, format is determined from extension of output_file_path.
+ """
+ if output_format is None:
+ file_name, file_ext = path.splitext(output_path)
+ output_format = file_ext[len(extsep):].lower()
+
+ if output_format == 'zip':
from zipfile import ZipFile, ZIP_DEFLATED
- output_archive = ZipFile(path.abspath(output_file), 'w')
- add = lambda name, arcname: output_archive.write(name, self.prefix + arcname, ZIP_DEFLATED)
-
- elif format.lower() in ['tar', 'bz2', 'gz']:
+
+ if not dry_run:
+ archive = ZipFile(path.abspath(output_path), 'w')
+ add = lambda file_path, file_name: archive.write(file_path, path.join(self.prefix, file_name), ZIP_DEFLATED)
+ elif output_format in ['tar', 'bz2', 'gz', 'tgz']:
import tarfile
- t_mode = ('w:%s' % format) if format != 'tar' else 'w'
-
- output_archive = tarfile.open(path.abspath(output_file), t_mode)
- add = lambda name, arcname: output_archive.add(name, self.prefix + arcname)
+
+ if output_format == 'tar':
+ t_mode = 'w'
+ elif output_format == 'tgz':
+ t_mode = 'w:gz'
+ else:
+ t_mode = 'w:{f}'.format(f=output_format)
+
+ if not dry_run:
+ archive = tarfile.open(path.abspath(output_path), t_mode)
+ add = lambda file_path, file_name: archive.add(file_path, path.join(self.prefix, file_name))
+ else:
+ raise RuntimeError("Unknown format: {f}".format(f=output_format))
+
+ for file_path in self.extra:
+ if not dry_run:
+ if self.verbose:
+ print("Compressing {f} => {a}...".format(f=file_path,
+ a=path.join(self.prefix, file_path)))
+ add(file_path, file_path)
+ else:
+ print("{f} => {a}".format(f=file_path,
+ a=path.join(self.prefix, file_path)))
+
+ for file_path in self.list_files():
+ if not dry_run:
+ if self.verbose:
+ print("Compressing {f} => {a}...".format(f=path.join(self.main_repo_abspath, file_path),
+ a=path.join(self.prefix, file_path)))
+ add(path.join(self.main_repo_abspath, file_path), file_path)
+ else:
+ print("{f} => {a}".format(f=path.join(self.main_repo_abspath, file_path),
+ a=path.join(self.prefix, file_path)))
+
+ if not dry_run:
+ archive.close()
+
+ def get_path_components(self, repo_abspath, abspath):
+ """
+ Splits given abspath into components until repo_abspath is reached.
+
+ E.g. if repo_abspath is '/Documents/Hobby/ParaView/' and abspath is
+ '/Documents/Hobby/ParaView/Catalyst/Editions/Base/', function will return:
+ ['.', 'Catalyst', 'Editions', 'Base']
+
+ First element is always '.' (concrete symbol depends on OS).
+
+ @type repo_abspath: string
+ @param repo_abspath: Absolute path to the git repository.
+
+ @type abspath: string
+ @param abspath: Absolute path to within repo_abspath.
+
+ @rtype: list
+ @return: List of path components.
+ """
+ components = []
+
+ while not path.samefile(abspath, repo_abspath):
+ abspath, tail = path.split(abspath)
+
+ if len(tail):
+ components.insert(0, tail)
+
+ components.insert(0, path.relpath(repo_abspath, repo_abspath))
+ return components
+
+ def get_exclude_patterns(self, repo_abspath, repo_file_paths):
+ """
+ Returns exclude patterns for a given repo. It looks for .gitattributes files in repo_file_paths.
+
+ Resulting dictionary will contain exclude patterns per path (relative to the repo_abspath).
+ E.g. {('.', 'Catalyst', 'Editions', 'Base'), ['Foo*', '*Bar']}
+
+ @type repo_abspath: string
+ @param repo_abspath: Absolute path to the git repository.
+
+ @type repo_file_paths: list
+ @param repo_file_paths: List of paths relative to the repo_abspath that are under git control.
+
+ @rtype: dict
+ @return: Dictionary representing exclude patterns.
+ Keys are tuples of strings. Values are lists of strings.
+ Returns None if self.exclude is not set.
+ """
+ if not self.exclude:
+ return None
+
+ def read_attributes(attributes_abspath):
+ patterns = []
+ if path.isfile(attributes_abspath):
+ attributes = open(attributes_abspath, 'r').readlines()
+ patterns = []
+ for line in attributes:
+ tokens = line.strip().split()
+ if "export-ignore" in tokens[1:]:
+ patterns.append(tokens[0])
+ return patterns
+
+ exclude_patterns = {(): []}
+
+ # There may be no gitattributes.
+ try:
+ global_attributes_abspath = self.read_shell("git config --get core.attributesfile", repo_abspath).rstrip()
+ exclude_patterns[()] = read_attributes(global_attributes_abspath)
+ except:
+ # And valid to not have them.
+ pass
+
+ for attributes_abspath in [path.join(repo_abspath, f) for f in repo_file_paths if f.endswith(".gitattributes")]:
+ # Each .gitattributes affects only files within its directory.
+ key = tuple(self.get_path_components(repo_abspath, path.dirname(attributes_abspath)))
+ exclude_patterns[key] = read_attributes(attributes_abspath)
+
+ local_attributes_abspath = path.join(repo_abspath, ".git", "info", "attributes")
+ key = tuple(self.get_path_components(repo_abspath, repo_abspath))
+
+ if key in exclude_patterns:
+ exclude_patterns[key].extend(read_attributes(local_attributes_abspath))
else:
- raise RuntimeError("Unknown format: '%s'" % format)
-
- #
- # compress
- #
-
- # extra files first (we may change folder later)
- for name in self.extra:
- if self.verbose:
- toPath = '=> %s%s' % (self.prefix, name) if self.prefix else ""
- print 'Compressing %s %s ...' % (name, toPath)
- add(name, name)
-
- self._excludes = []
-
- for name, arcname in self.listFiles(path.abspath('')):
- if self.verbose:
- toPath = '=> %s%s' % (self.prefix, arcname) if self.prefix else ""
- print 'Compressing %s %s ...' % (arcname, toPath)
- add(name, arcname)
-
- output_archive.close()
-
-
- def listFiles(self, git_repositary_path, baselevel=''):
- """
- listFiles(str git_repository_path, str baselevel='') -> iterator
-
- An iterator method that yields a tuple(filepath, fullpath)
+ exclude_patterns[key] = read_attributes(local_attributes_abspath)
+
+ return exclude_patterns
+
+ def is_file_excluded(self, repo_abspath, repo_file_path, exclude_patterns):
+ """
+ Checks whether file at a given path is excluded.
+
+ @type repo_abspath: string
+ @param repo_abspath: Absolute path to the git repository.
+
+ @type repo_file_path: string
+ @param repo_file_path: Path to a file within repo_abspath.
+
+ @type exclude_patterns: dict
+ @param exclude_patterns: Exclude patterns with format specified for get_exclude_patterns.
+
+ @rtype: bool
+ @return: True if file should be excluded. Otherwise False.
+ """
+ if exclude_patterns is None or not len(exclude_patterns):
+ return False
+
+ from fnmatch import fnmatch
+
+ file_name = path.basename(repo_file_path)
+ components = self.get_path_components(repo_abspath, path.join(repo_abspath, path.dirname(repo_file_path)))
+
+ is_excluded = False
+ # We should check all patterns specified in intermediate directories to the given file.
+ # At the end we should also check for the global patterns (key '()' or empty tuple).
+ while not is_excluded:
+ key = tuple(components)
+ if key in exclude_patterns:
+ patterns = exclude_patterns[key]
+ for p in patterns:
+ if fnmatch(file_name, p) or fnmatch(repo_file_path, p):
+ if self.verbose:
+ print("Exclude pattern matched {pattern}: {path}".format(pattern=p, path=repo_file_path))
+ is_excluded = True
+
+ if not len(components):
+ break
+
+ components.pop()
+
+ return is_excluded
+
+ def list_files(self, repo_path=''):
+ """
+ An iterator method that yields a file path relative to main_repo_abspath
for each file that should be included in the archive.
Skips those that match the exclusion patterns found in
any discovered .gitattributes files along the way.
-
- Recurses into submodules as well.
- """
- for filepath in self.runShell('git ls-files --cached --full-name --no-empty-directory'):
- fullpath = path.join(baselevel, filepath)
- filename = path.basename(filepath)
-
- if self.exclude and filename == '.gitattributes':
- self._excludes = []
- fh = open(filepath, 'r')
- for line in fh:
- if not line: break
- tokens = line.strip().split()
- if 'export-ignore' in tokens[1:]:
- self._excludes.append(tokens[0])
- fh.close()
-
- if not filename.startswith('.git') and not path.isdir(filepath):
-
- # check the patterns first
- ignore = False
- for pattern in self._excludes:
- if fnmatch(fullpath, pattern) or fnmatch(filename, pattern):
- if self.verbose: print 'Exclude pattern matched (%s): %s' % (pattern, fullpath)
- ignore = True
- break
- if ignore:
- continue
-
- # baselevel is needed to tell the arhiver where it have to extract file
- yield filepath, fullpath
-
- # get paths for every submodule
- for submodule in self.runShell("git submodule --quiet foreach 'pwd'"):
- chdir(submodule)
- # in order to get output path we need to exclude repository path from the submodule path
- submodule = submodule[len(git_repositary_path)+1:]
- # recursion allows us to process repositories with more than one level of submodules
- for git_file in self.listFiles(git_repositary_path, submodule):
- yield git_file
-
-
-
+
+ Recurs into submodules as well.
+
+ @type repo_path: string
+ @param repo_path: Path to the git submodule repository within the main git repository.
+
+ @rtype: iterator
+ @return: Iterator to traverse files under git control relative to main_repo_abspath.
+ """
+ repo_abspath = path.join(self.main_repo_abspath, repo_path)
+ repo_file_paths = self.read_git_shell("git ls-files --cached --full-name --no-empty-directory", repo_abspath).splitlines()
+ exclude_patterns = self.get_exclude_patterns(repo_abspath, repo_file_paths)
+
+ for repo_file_path in repo_file_paths:
+ # Git puts path in quotes if file path has unicode characters.
+ repo_file_path = repo_file_path.strip('"') # file path relative to current repo
+ file_name = path.basename(repo_file_path)
+
+ # Only list symlinks and files that don't start with git.
+ if file_name.startswith(".git") or (not path.islink(repo_file_path) and path.isdir(repo_file_path)):
+ continue
+
+ main_repo_file_path = path.join(repo_path, repo_file_path) # file path relative to the main repo
+
+ if self.is_file_excluded(repo_abspath, repo_file_path, exclude_patterns):
+ continue
+
+ # Yield both repo_file_path and main_repo_file_path to preserve structure of the repo.
+ yield main_repo_file_path
+
+ if self.force_sub:
+ self.run_shell("git submodule init", repo_abspath)
+ self.run_shell("git submodule update", repo_abspath)
+
+ # List files of every submodule.
+ for submodule_path in self.read_shell("git submodule --quiet foreach 'pwd'", repo_abspath).splitlines():
+ # In order to get output path we need to exclude repository path from submodule_path.
+ submodule_path = path.relpath(submodule_path, self.main_repo_abspath)
+ for file_path in self.list_files(submodule_path):
+ yield file_path
+
@staticmethod
- def runShell(cmd):
- return Popen(cmd, shell=True, stdout=PIPE).stdout.read().splitlines()
-
-
-
-if __name__ == "__main__":
+ def run_shell(cmd, cwd=None):
+ """
+ Runs shell command.
+
+ @type cmd: string
+ @param cmd: Command to be executed.
+
+ @type cwd: string
+ @param cwd: Working directory.
+
+ @rtype: int
+ @return: Return code of the command.
+
+ @raise CalledProcessError: Raises exception if return code of the command is non-zero.
+ """
+ p = Popen(cmd, shell=True, cwd=cwd)
+ p.wait()
+
+ if p.returncode:
+ raise CalledProcessError(returncode=p.returncode, cmd=cmd)
+
+ return p.returncode
+
+ @staticmethod
+ def read_shell(cmd, cwd=None, encoding='utf-8'):
+ """
+ Runs shell command and reads output.
+
+ @type cmd: string
+ @param cmd: Command to be executed.
+
+ @type cwd: string
+ @param cwd: Working directory.
+
+ @type encoding: string
+ @param encoding: Encoding used to decode bytes returned by Popen into string.
+
+ @rtype: string
+ @return: Output of the command.
+
+ @raise CalledProcessError: Raises exception if return code of the command is non-zero.
+ """
+ p = Popen(cmd, shell=True, stdout=PIPE, cwd=cwd)
+ output, _ = p.communicate()
+ output = output.decode(encoding)
+
+ if p.returncode:
+ raise CalledProcessError(returncode=p.returncode, cmd=cmd, output=output)
+
+ return output
+
+ @staticmethod
+ def read_git_shell(cmd, cwd=None):
+ """
+ Runs git shell command, reads output and decodes it into unicode string
+
+ @type cmd: string
+ @param cmd: Command to be executed.
+
+ @type cwd: string
+ @param cwd: Working directory.
+
+ @rtype: string
+ @return: Output of the command.
+
+ @raise CalledProcessError: Raises exception if return code of the command is non-zero.
+ """
+ p = Popen(cmd, shell=True, stdout=PIPE, cwd=cwd)
+ output, _ = p.communicate()
+ output = output.decode('unicode_escape').encode('raw_unicode_escape').decode('utf-8')
+
+ if p.returncode:
+ raise CalledProcessError(returncode=p.returncode, cmd=cmd, output=output)
+
+ return output
+
+
+if __name__ == '__main__':
from optparse import OptionParser
- parser = OptionParser(usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] OUTPUT_FILE", version="%prog 1.0")
-
- parser.add_option('--prefix', type='string', dest='prefix',
- default='', help="prepend PREFIX to each filename in the archive")
-
- parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='enable verbose mode')
-
- parser.add_option('--no-exclude', action='store_false', dest='exclude',
- default=True, help="Dont read .gitattributes files for patterns containing export-ignore attrib")
-
- parser.add_option('--extra', action='append', dest='extra', default=[],
+ parser = OptionParser(usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] [--force-submodules] [--dry-run] OUTPUT_FILE",
+ version="%prog {version}".format(version=__version__))
+
+ parser.add_option('--prefix',
+ type='string',
+ dest='prefix',
+ default='',
+ help="Prepend PREFIX to each filename in the archive. OUTPUT_FILE name is used by default to avoid tarbomb.")
+
+ parser.add_option('-v', '--verbose',
+ action='store_true',
+ dest='verbose',
+ help='Enable verbose mode.')
+
+ parser.add_option('--no-exclude',
+ action='store_false',
+ dest='exclude',
+ default=True,
+ help="Don't read .gitattributes files for patterns containing export-ignore attrib.")
+
+ parser.add_option('--force-submodules',
+ action='store_true',
+ dest='force_sub',
+ help="Force a git submodule init && git submodule update at each level before iterating submodules.")
+
+ parser.add_option('--extra',
+ action='append',
+ dest='extra',
+ default=[],
help="Any additional files to include in the archive.")
+ parser.add_option('--dry-run',
+ action='store_true',
+ dest='dry_run',
+ help="Don't actually archive anything, just show what would be done.")
options, args = parser.parse_args()
-
+
if len(args) != 1:
- parser.error('You must specify exactly one output file')
-
- outFile = args[0]
-
- if path.isdir(outFile):
- parser.error('You cannot use directory as output')
-
- archiver = GitArchiver(options.prefix,
- options.verbose,
- options.exclude,
- options.extra)
-
+ parser.error("You must specify exactly one output file")
+
+ output_file_path = args[0]
+
+ if path.isdir(output_file_path):
+ parser.error("You cannot use directory as output")
+
+ # avoid tarbomb
+ if options.prefix:
+ options.prefix = path.join(options.prefix, '')
+ else:
+ import re
+
+ output_name = path.basename(output_file_path)
+ output_name = re.sub('(\.zip|\.tar|\.tgz|\.gz|\.bz2|\.tar\.gz|\.tar\.bz2)$', '', output_name) or "Archive"
+ options.prefix = path.join(output_name, '')
+
try:
- archiver.create(outFile)
- except Exception, e:
- parser.exit(2, "%s\n" % e)
-
+ archiver = GitArchiver(options.prefix,
+ options.verbose,
+ options.exclude,
+ options.force_sub,
+ options.extra)
+ archiver.create(output_file_path, options.dry_run)
+ except Exception as e:
+ parser.exit(2, "{exception}\n".format(exception=e))
+
sys.exit(0)
diff --git a/scripts/installer.nsi b/scripts/installer.nsi
index 9d7d891..fea6563 100644
--- a/scripts/installer.nsi
+++ b/scripts/installer.nsi
@@ -17,6 +17,7 @@ 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"
+WriteRegStr HKCR ".scad" "PerceivedType" "text"
SectionEnd
Section "Uninstall"
${unregisterExtension} ".scad" "OpenSCAD_File"
diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh
index 088d8b4..9cc0662 100755
--- a/scripts/macosx-build-dependencies.sh
+++ b/scripts/macosx-build-dependencies.sh
@@ -8,6 +8,7 @@
#
# Usage: macosx-build-dependencies.sh [-6lcd]
# -6 Build only 64-bit binaries
+# -c Force use of LLVM compiler
# -l Force use of LLVM compiler
# -c Force use of clang compiler
# -d Build for deployment (if not specified, e.g. Sparkle won't be built)
@@ -17,6 +18,7 @@
#
# FIXME:
# o Verbose option
+# o Force rebuild vs. only rebuild changes
#
BASEDIR=$PWD/../libraries
@@ -238,8 +240,9 @@ build_cgal()
cd $BASEDIR/src
rm -rf CGAL-$version
if [ ! -f CGAL-$version.tar.gz ]; then
- # 4.1
- curl -O https://gforge.inria.fr/frs/download.php/31641/CGAL-$version.tar.gz
+ # 4.2
+ curl -O https://gforge.inria.fr/frs/download.php/32359/CGAL-$version.tar.gz
+ # 4.1 curl -O https://gforge.inria.fr/frs/download.php/31641/CGAL-$version.tar.gz
# 4.1-beta1 curl -O https://gforge.inria.fr/frs/download.php/31348/CGAL-$version.tar.gz
# 4.0.2 curl -O https://gforge.inria.fr/frs/download.php/31175/CGAL-$version.tar.gz
# 4.0 curl -O https://gforge.inria.fr/frs/download.php/30387/CGAL-$version.tar.gz
@@ -306,7 +309,9 @@ build_eigen()
EIGENDIR="none"
if [ $version = "2.0.17" ]; then EIGENDIR=eigen-eigen-b23437e61a07; fi
- if [ $version = "3.1.2" ]; then EIGENDIR=eigen-eigen-5097c01bcdc4; fi
+ if [ $version = "3.1.2" ]; then EIGENDIR=eigen-eigen-5097c01bcdc4;
+ elif [ $version = "3.1.3" ]; then EIGENDIR=eigen-eigen-2249f9c22fe8; fi
+
if [ $EIGENDIR = "none" ]; then
echo Unknown eigen version. Please edit script.
exit 1
@@ -389,7 +394,7 @@ elif $OPTION_GCC; then
elif $OPTION_CLANG; then
USING_CLANG=true
elif (( $OSX_VERSION >= 7 )); then
- USING_GCC=true
+ USING_CLANG=true
fi
if $USING_LLVM; then
@@ -435,12 +440,13 @@ fi
echo "Using basedir:" $BASEDIR
mkdir -p $SRCDIR $DEPLOYDIR
build_qt 4.8.4
-build_eigen 3.1.2
-build_gmp 5.1.1
+# NB! For eigen, also update the path in the function
+build_eigen 3.1.3
+build_gmp 5.1.2
build_mpfr 3.1.2
build_boost 1.53.0
# NB! For CGAL, also update the actual download URL in the function
-build_cgal 4.1
+build_cgal 4.2
build_glew 1.9.0
build_opencsg 1.3.2
if $OPTION_DEPLOY; then
diff --git a/scripts/publish-macosx.sh b/scripts/publish-macosx.sh
index ed72163..3617570 100755
--- a/scripts/publish-macosx.sh
+++ b/scripts/publish-macosx.sh
@@ -67,7 +67,7 @@ if [[ $? != 0 ]]; then
exit 1
fi
-SIGNATURE=$(openssl dgst -sha1 -binary < OpenSCAD-$VERSION.dmg | openssl dgst -dss1 -sign dsa_priv.pem | openssl enc -base64)
+SIGNATURE=$(openssl dgst -sha1 -binary < OpenSCAD-$VERSION.dmg | openssl dgst -dss1 -sign $HOME/.ssh/openscad-appcast.pem | openssl enc -base64)
if [[ $VERSION == $VERSIONDATE ]]; then
APPCASTFILE=appcast-snapshots.xml
@@ -90,5 +90,10 @@ if [[ $? != 0 ]]; then
exit 1
fi
+scp OpenSCAD-$VERSION.dmg openscad@files.openscad.org:www
+if [[ $? != 0 ]]; then
+ exit 1
+fi
+
# Update snapshot filename on web page
update_www_download_links version=$VERSION packagefile=OpenSCAD-$VERSION.dmg filesize=$FILESIZE
diff --git a/scripts/setenv-mingw-xbuild.sh b/scripts/setenv-mingw-xbuild.sh
index d3a014c..a88b752 100644
--- a/scripts/setenv-mingw-xbuild.sh
+++ b/scripts/setenv-mingw-xbuild.sh
@@ -6,6 +6,7 @@
#
# source ./scripts/setenv-mingw-xbuild.sh # 32 bit build
# source ./scripts/setenv-mingw-xbuild.sh 64 # 64 bit build
+# source ./scripts/setenv-mingw-xbuild.sh clean # Clean up exported variables
#
# Prerequisites:
#
diff --git a/scripts/setenv-unibuild.sh b/scripts/setenv-unibuild.sh
index 980fa7b..cb0b0a0 100644
--- a/scripts/setenv-unibuild.sh
+++ b/scripts/setenv-unibuild.sh
@@ -54,7 +54,9 @@ setenv_netbsd()
QMAKESPEC=netbsd-g++
QTDIR=/usr/pkg/qt4
PATH=/usr/pkg/qt4/bin:$PATH
- LD_LIBRARY_PATH=/usr/pkg/qt4/lib:/usr/X11R7/lib:$LD_LIBRARY_PATH
+ LD_LIBRARY_PATH=/usr/pkg/qt4/lib:$LD_LIBRARY_PATH
+ LD_LIBRARY_PATH=/usr/X11R7/lib:$LD_LIBRARY_PATH
+ LD_LIBRARY_PATH=/usr/pkg/lib:$LD_LIBRARY_PATH
export QMAKESPEC
export QTDIR
diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh
index 60dbb74..6596c8a 100755
--- a/scripts/uni-build-dependencies.sh
+++ b/scripts/uni-build-dependencies.sh
@@ -290,11 +290,26 @@ build_cgal()
ver3_7="curl --insecure -O https://gforge.inria.fr/frs/download.php/27641/CGAL-3.7.tar.gz"
vernull="echo already downloaded..skipping"
download_cmd=ver`echo $version | sed s/"\."/"_"/`
- if [ -e CGAL-$version.tar.gz ]; then download_cmd=vernull; fi
- if [ -e CGAL-$version.tar.bz2 ]; then download_cmd=vernull; fi
+
+ if [ -e CGAL-$version.tar.gz ]; then
+ download_cmd=vernull;
+ fi
+ if [ -e CGAL-$version.tar.bz2 ]; then
+ download_cmd=vernull;
+ fi
+
`eval echo "$"$download_cmd`
- if [ -e CGAL-$version.tar.gz ]; then tar xf CGAL-$version.tar.gz; fi
- if [ -e CGAL-$version.tar.bz2 ]; then tar xf CGAL-$version.tar.bz2; fi
+
+ zipper=gzip
+ suffix=gz
+ if [ -e CGAL-$version.tar.bz2 ]; then
+ zipper=bzip2
+ suffix=bz2
+ fi
+
+ $zipper -f -d CGAL-$version.tar.$suffix;
+ tar xf CGAL-$version.tar
+
cd CGAL-$version
# older cmakes have buggy FindBoost that can result in
diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh
index e2fdaa7..31337c8 100755
--- a/scripts/uni-get-dependencies.sh
+++ b/scripts/uni-get-dependencies.sh
@@ -7,8 +7,9 @@
get_fedora_deps()
{
sudo yum install qt-devel bison flex eigen2-devel python-paramiko \
- boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc pkgconfig \
- git libXmu-devel curl imagemagick
+ boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
+ opencsg-devel git libXmu-devel curl imagemagick ImageMagick make \
+ xorg-x11-server-Xvfb
}
get_qomo_deps()
@@ -34,7 +35,8 @@ get_freebsd_deps()
get_netbsd_deps()
{
sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \
- qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl imagemagick
+ qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl \
+ imagemagick ImageMagick
}
get_opensuse_deps()
@@ -48,7 +50,7 @@ get_mageia_deps()
sudo urpmi ctags
sudo urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \
libmpfr-devel libboost-devel eigen3-devel libglew-devel bison flex \
- cmake imagemagick python curl git
+ cmake imagemagick python curl git x11-server-xvfb
}
get_debian_deps()
@@ -74,6 +76,8 @@ if [ -e /etc/issue ]; then
get_debian_deps
elif [ "`grep -i debian /etc/issue`" ]; then
get_debian_deps
+ elif [ "`grep -i mint /etc/issue`" ]; then
+ get_debian_deps
elif [ "`grep -i suse /etc/issue`" ]; then
get_opensuse_deps
elif [ "`grep -i fedora /etc/issue`" ]; then
diff --git a/setenv_mjau.sh b/setenv_mjau.sh
index 7976c60..51eec8e 100644
--- a/setenv_mjau.sh
+++ b/setenv_mjau.sh
@@ -1,7 +1,7 @@
export OPENSCAD_LIBRARIES=$PWD/../libraries/install
export DYLD_LIBRARY_PATH=$OPENSCAD_LIBRARIES/lib
export DYLD_FRAMEWORK_PATH=$OPENSCAD_LIBRARIES/lib
-export QMAKESPEC=macx-g++
+#export QMAKESPEC=macx-g++
#export OPENCSGDIR=$PWD/../OpenCSG-1.3.0
#export CGALDIR=$PWD/../install/CGAL-3.6
diff --git a/src/AboutDialog.html b/src/AboutDialog.html
index 005f61f..b5a5d7c 100644
--- a/src/AboutDialog.html
+++ b/src/AboutDialog.html
@@ -7,7 +7,8 @@
make to do your testing. -->
<head>
- <meta name="qrichtext" content="1" />
+ <meta charset="UTF-8"/>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
@@ -74,18 +75,23 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
<b>OpenSCAD Github Project members (public)</b>
</p>
-<lu>
+<ul>
<li><a href="https://github.com/kintel">Marius Kintel </a>
<li><a href="http://clifford.at">Clifford Wolf</a>
<li><a href="http://www.github.com/GilesBathgate">Giles Bathgate</a>
<li><a href="https://github.com/brad">Brad Pitcher</a>
<li><a href="https://github.com/donbright">Don Bright</a>
-</lu>
+</ul>
<p>
-<b><a href="http://www.debian.org">Debian</a> maintainer:</b>
- <a href="http://christian.amsuess.com/">chrysn</a>
+<b>Package Maintainers</b>
</p>
+<ul>
+<li><a href="http://www.debian.org">Debian</a> maintainer:</b>
+ <a href="http://christian.amsuess.com/">chrysn</a></lu>
+<li><a href="http://fedoraproject.org/">Fedora</a> maintainer:</b>
+ <a href="http://hroncok.cz/">Miro HronĨok</a></lu>
+</ul>
<p>
<b>Patches</b>
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc
index 686bde1..8e1b5eb 100644
--- a/src/CGALEvaluator.cc
+++ b/src/CGALEvaluator.cc
@@ -202,30 +202,31 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
if ( N.dim == 2 ) {
CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 );
CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
- CGAL_Point_3 min3(min2.x(),min2.y(),0), max3(max2.x(),max2.y(),0);
+ CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0),
+ max3(CGAL::to_double(max2.x()), CGAL::to_double(max2.y()), 0);
bb = CGAL_Iso_cuboid_3( min3, max3 );
}
else {
bb = bounding_box( *N.p3 );
}
- std::vector<NT> scale, bbox_size;
- for (int i=0;i<3;i++) scale.push_back( NT(1) );
+ std::vector<NT3> scale, bbox_size;
+ for (int i=0;i<3;i++) scale.push_back( NT3(1) );
bbox_size.push_back( bb.xmax()-bb.xmin() );
bbox_size.push_back( bb.ymax()-bb.ymin() );
bbox_size.push_back( bb.zmax()-bb.zmin() );
for (int i=0;i<3;i++) {
if (node.newsize[i]) {
- if (bbox_size[i]==NT(0)) {
+ if (bbox_size[i]==NT3(0)) {
PRINT("WARNING: Cannot resize in direction normal to flat object");
return N;
}
else {
- scale[i] = NT(node.newsize[i]) / bbox_size[i];
+ scale[i] = NT3(node.newsize[i]) / bbox_size[i];
}
}
}
- NT autoscale = std::max( scale[0], std::max( scale[1], scale[2] ));
+ NT3 autoscale = std::max( scale[0], std::max( scale[1], scale[2] ));
for (int i=0;i<3;i++) {
if (node.autosize[i]) scale[i] = autoscale;
}
diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h
index cfab993..7f59861 100644
--- a/src/CGAL_Nef_polyhedron.h
+++ b/src/CGAL_Nef_polyhedron.h
@@ -1,7 +1,7 @@
#ifndef CGAL_NEF_POLYHEDRON_H_
#define CGAL_NEF_POLYHEDRON_H_
-#include "cgalfwd.h"
+#include "cgal.h"
#include "memory.h"
#include <string>
#include "linalg.h"
diff --git a/src/MainWindow.ui b/src/MainWindow.ui
index e9bd96e..68bc064 100644
--- a/src/MainWindow.ui
+++ b/src/MainWindow.ui
@@ -177,14 +177,17 @@
<addaction name="designActionReloadAndCompile"/>
<addaction name="designActionCompile"/>
<addaction name="designActionCompileAndRender"/>
+ <addaction name="separator"/>
<addaction name="designActionDisplayAST"/>
<addaction name="designActionDisplayCSGTree"/>
<addaction name="designActionDisplayCSGProducts"/>
+ <addaction name="separator"/>
<addaction name="designActionExportSTL"/>
<addaction name="designActionExportOFF"/>
<addaction name="designActionExportDXF"/>
<addaction name="designActionExportCSG"/>
<addaction name="designActionExportImage"/>
+ <addaction name="separator"/>
<addaction name="designActionFlushCaches"/>
</widget>
<widget class="QMenu" name="menu_View">
@@ -622,7 +625,7 @@
</action>
<action name="helpActionManual">
<property name="text">
- <string>OpenSCAD Manual</string>
+ <string>Documentation</string>
</property>
</action>
<action name="fileActionClearRecent">
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc
index 5ebd549..de9af01 100644
--- a/src/ModuleCache.cc
+++ b/src/ModuleCache.cc
@@ -30,25 +30,29 @@ ModuleCache *ModuleCache::inst = NULL;
*/
FileModule *ModuleCache::evaluate(const std::string &filename)
{
+ FileModule *lib_mod = (this->entries.find(filename) != this->entries.end()) ?
+ &(*this->entries[filename].module) : NULL;
+
+ // Don't try to recursively evaluate - if the file changes
+ // during evaluation, that would be really bad.
+ if (lib_mod && lib_mod->isHandlingDependencies()) return lib_mod;
+
bool shouldCompile = true;
- FileModule *lib_mod = NULL;
// Create cache ID
struct stat st;
memset(&st, 0, sizeof(struct stat));
bool valid = (stat(filename.c_str(), &st) == 0);
- // If file isn't there, just return and let the cache retain the old module
+ // If file isn't there, just return and let the cache retain the old module
if (!valid) return NULL;
-
+
std::string cache_id = str(boost::format("%x.%x") % st.st_mtime % st.st_size);
// Lookup in cache
- if (this->entries.find(filename) != this->entries.end()) {
- lib_mod = &(*this->entries[filename].module);
+ if (lib_mod) {
if (this->entries[filename].cache_id == cache_id) {
shouldCompile = false;
-
if (lib_mod->includesChanged()) {
lib_mod = NULL;
shouldCompile = true;
@@ -104,7 +108,9 @@ FileModule *ModuleCache::evaluate(const std::string &filename)
print_messages_pop();
}
- if (lib_mod) lib_mod->handleDependencies();
+ if (lib_mod) {
+ lib_mod->handleDependencies();
+ }
return lib_mod;
}
@@ -114,3 +120,9 @@ void ModuleCache::clear()
this->entries.clear();
}
+FileModule *ModuleCache::lookup(const std::string &filename)
+{
+ return (this->entries.find(filename) != this->entries.end()) ?
+ &(*this->entries[filename].module) : NULL;
+}
+
diff --git a/src/ModuleCache.h b/src/ModuleCache.h
index b8ded38..7795ab7 100644
--- a/src/ModuleCache.h
+++ b/src/ModuleCache.h
@@ -9,6 +9,7 @@ class ModuleCache
public:
static ModuleCache *instance() { if (!inst) inst = new ModuleCache; return inst; }
class FileModule *evaluate(const std::string &filename);
+ class FileModule *lookup(const std::string &filename);
size_t size() { return this->entries.size(); }
void clear();
diff --git a/src/OffscreenContextWGL.cc b/src/OffscreenContextWGL.cc
index 0ccd68d..6e657fe 100644
--- a/src/OffscreenContextWGL.cc
+++ b/src/OffscreenContextWGL.cc
@@ -108,15 +108,33 @@ bool create_wgl_dummy_context(OffscreenContext &ctx)
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.hInstance = inst;
- wc.lpszClassName = (LPCWSTR)"OpenSCAD";
- RegisterClass( &wc );
+ wc.lpszClassName = L"OpenSCAD";
+ ATOM class_atom = RegisterClassW( &wc );
- HWND window = CreateWindow( (LPCWSTR)"OpenSCAD", (LPCWSTR)"OpenSCAD",
- WS_CAPTION | WS_POPUPWINDOW, //| WS_VISIBLE,
- 0, 0, ctx.width, ctx.height, NULL, NULL, inst, NULL );
+ if ( class_atom == 0 ) {
+ cerr << "MS GDI - RegisterClass failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
+ return false;
+ }
+
+ LPCTSTR lpClassName = L"OpenSCAD";
+ LPCTSTR lpWindowName = L"OpenSCAD";
+ DWORD dwStyle = WS_CAPTION | WS_POPUPWINDOW; // | WS_VISIBLE
+ int x = 0;
+ int y = 0;
+ int nWidth = ctx.width;
+ int nHeight = ctx.height;
+ HWND hWndParent = NULL;
+ HMENU hMenu = NULL;
+ HINSTANCE hInstance = inst;
+ LPVOID lpParam = NULL;
+
+ HWND window = CreateWindowW( lpClassName, lpWindowName, dwStyle, x, y,
+ nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam );
if ( window==NULL ) {
cerr << "MS GDI - CreateWindow failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
return false;
}
@@ -127,6 +145,7 @@ bool create_wgl_dummy_context(OffscreenContext &ctx)
HDC dev_context = GetDC( window );
if ( dev_context == NULL ) {
cerr << "MS GDI - GetDC failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
return false;
}
@@ -145,18 +164,21 @@ bool create_wgl_dummy_context(OffscreenContext &ctx)
chosenformat = ChoosePixelFormat( dev_context, &pixformat );
if (chosenformat==0) {
cerr << "MS GDI - ChoosePixelFormat failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
return false;
}
bool spfok = SetPixelFormat( dev_context, chosenformat, &pixformat );
if (!spfok) {
cerr << "MS GDI - SetPixelFormat failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
return false;
}
HGLRC gl_render_context = wglCreateContext( dev_context );
if ( gl_render_context == NULL ) {
cerr << "MS WGL - wglCreateContext failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
ReleaseDC( ctx.window, ctx.dev_context );
return false;
}
@@ -164,6 +186,7 @@ bool create_wgl_dummy_context(OffscreenContext &ctx)
bool mcok = wglMakeCurrent( dev_context, gl_render_context );
if (!mcok) {
cerr << "MS WGL - wglMakeCurrent failed\n";
+ cerr << "last-error code: " << GetLastError() << "\n";
return false;
}
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index f0c274f..bc9206f 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -324,6 +324,7 @@ PolySet *PolySetCGALEvaluator::extrudeDxfData(const LinearExtrudeNode &node, Dxf
{
PolySet *ps = new PolySet();
ps->convexity = node.convexity;
+ if (node.height <= 0) return ps;
double h1, h2;
diff --git a/src/cgal.h b/src/cgal.h
index a7300c6..45228be 100644
--- a/src/cgal.h
+++ b/src/cgal.h
@@ -39,8 +39,8 @@ using boost::uintmax_t;
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
-typedef CGAL::Gmpq NT;
-typedef CGAL::Extended_cartesian<NT> CGAL_Kernel2;
+typedef CGAL::Gmpq NT2;
+typedef CGAL::Extended_cartesian<NT2> CGAL_Kernel2;
typedef CGAL::Nef_polyhedron_2<CGAL_Kernel2> CGAL_Nef_polyhedron2;
typedef CGAL_Kernel2::Aff_transformation_2 CGAL_Aff_transformation2;
@@ -48,7 +48,9 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_ExactKernel2;
typedef CGAL::Polygon_2<CGAL_ExactKernel2> CGAL_Poly2;
typedef CGAL::Polygon_with_holes_2<CGAL_ExactKernel2> CGAL_Poly2h;
-typedef CGAL::Cartesian<NT> CGAL_Kernel3;
+ //typedef CGAL::Cartesian<NT> CGAL_Kernel3;
+typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_Kernel3;
+typedef CGAL::Exact_predicates_exact_constructions_kernel::FT NT3;
typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3> CGAL_Nef_polyhedron3;
typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation;
@@ -63,7 +65,7 @@ typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
// CGAL_Nef_polyhedron2::Explorer::Point which is different than
// CGAL_Kernel2::Point. Hence the suffix 'e'
typedef CGAL_Nef_polyhedron2::Explorer::Point CGAL_Point_2e;
-typedef CGAL::Iso_rectangle_2< CGAL::Simple_cartesian<NT> > CGAL_Iso_rectangle_2e;
+typedef CGAL::Iso_rectangle_2<CGAL::Simple_cartesian<NT2> > CGAL_Iso_rectangle_2e;
#ifdef PREV_NDEBUG
diff --git a/src/cgalutils.cc b/src/cgalutils.cc
index 8b4c476..bb46f1c 100644
--- a/src/cgalutils.cc
+++ b/src/cgalutils.cc
@@ -193,7 +193,8 @@ void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
CGAL_For_all( c1, cend ) {
CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
- CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
+ CGAL_Nef_polyhedron2::Explorer::Point point2d(CGAL::to_double(point3d.x()),
+ CGAL::to_double(point3d.y()));
contour.push_back( point2d );
}
if (contour.size()==0) continue;
diff --git a/src/cgalutils.h b/src/cgalutils.h
index 6ea7711..d25fd4c 100644
--- a/src/cgalutils.h
+++ b/src/cgalutils.h
@@ -1,7 +1,7 @@
#ifndef CGALUTILS_H_
#define CGALUTILS_H_
-#include <cgalfwd.h>
+#include <cgal.h>
class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p);
CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps);
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
diff --git a/src/csgterm.cc b/src/csgterm.cc
index 7852715..a0379e7 100644
--- a/src/csgterm.cc
+++ b/src/csgterm.cc
@@ -188,6 +188,7 @@ void CSGChain::import(shared_ptr<CSGTerm> term, CSGTerm::type_e type, CSGTerm::F
if (term->type == CSGTerm::TYPE_PRIMITIVE) {
this->objects.push_back(CSGChainObject(term->polyset, term->m, term->color, type, term->label, newflag));
} else {
+ assert(term->left && term->right);
import(term->left, type, newflag);
import(term->right, term->type, newflag);
}
diff --git a/src/highlighter.cc b/src/highlighter.cc
index bf80bb4..4b4aa30 100644
--- a/src/highlighter.cc
+++ b/src/highlighter.cc
@@ -132,11 +132,14 @@ Highlighter::Highlighter(QTextDocument *parent)
tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";";
typeformats["operator"].setForeground(Qt::blue);
- tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign";
+ tokentypes["math"] << "abs" << "sign" << "acos" << "asin" << "atan" << "atan2" << "sin" << "cos" << "floor" << "round" << "ceil" << "ln" << "log" << "lookup" << "min" << "max" << "pow" << "sqrt" << "exp" << "rands";
+ typeformats["math"].setForeground(Qt::green);
+
+ tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign" << "echo"<< "search" << "str";
typeformats["keyword"].setForeground(QColor("Green"));
typeformats["keyword"].setToolTip("Keyword");
- tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull" << "resize";
+ tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull" << "resize" << "mirror" << "minkowski";
typeformats["transform"].setForeground(QColor("Indigo"));
tokentypes["csgop"] << "union" << "intersection" << "difference" << "render";
@@ -148,7 +151,7 @@ Highlighter::Highlighter(QTextDocument *parent)
tokentypes["prim2d"] << "square" << "polygon" << "circle";
typeformats["prim2d"].setForeground(QColor("MidnightBlue"));
- tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross";
+ tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross" << "surface";
typeformats["import"].setForeground(Qt::darkYellow);
tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fs" << "$t" << "$vpt" << "$vpr";
@@ -285,6 +288,7 @@ void Highlighter::highlightBlock(const QString &text)
// Quoting and Comments.
state_e state = (state_e) previousBlockState();
+ int quote_esc_state = 0;
for (int n = 0; n < text.size(); ++n){
if (state == NORMAL){
if (text[n] == '"'){
@@ -301,7 +305,11 @@ void Highlighter::highlightBlock(const QString &text)
}
} else if (state == QUOTE){
setFormat(n,1,quoteFormat);
- if (text[n] == '"' && n-1 >=0 && text[n-1] != '\\')
+ if (quote_esc_state > 0)
+ quote_esc_state = 0;
+ else if (text[n] == '\\')
+ quote_esc_state = 1;
+ else if (text[n] == '"')
state = NORMAL;
} else if (state == COMMENT){
setFormat(n,1,commentFormat);
diff --git a/src/linearextrude.cc b/src/linearextrude.cc
index 9a7365b..c5d4529 100644
--- a/src/linearextrude.cc
+++ b/src/linearextrude.cc
@@ -88,7 +88,8 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
}
node->layername = layer.isUndefined() ? "" : layer.toString();
- node->height = height.toDouble();
+ node->height = 100;
+ height.getDouble(node->height);
node->convexity = (int)convexity.toDouble();
origin.getVec2(node->origin_x, node->origin_y);
node->scale_x = node->scale_y = 1;
@@ -99,8 +100,7 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
if (center.type() == Value::BOOL)
node->center = center.toBool();
- if (node->height <= 0)
- node->height = 100;
+ if (node->height <= 0) node->height = 0;
if (node->convexity <= 0)
node->convexity = 1;
diff --git a/src/localscope.cc b/src/localscope.cc
index eecff91..dd40563 100644
--- a/src/localscope.cc
+++ b/src/localscope.cc
@@ -55,9 +55,11 @@ std::vector<AbstractNode*> LocalScope::instantiateChildren(const Context *evalct
// c->functions_p = &this->functions;
// c->modules_p = &this->modules;
- BOOST_FOREACH (const Assignment &ass, this->assignments) {
- c->set_variable(ass.first, ass.second->evaluate(c));
- }
+ // Uncommenting the following would allow assignments in local scopes,
+ // but would cause duplicate evaluation of module scopes
+ // BOOST_FOREACH (const Assignment &ass, this->assignments) {
+ // c->set_variable(ass.first, ass.second->evaluate(c));
+ // }
}
std::vector<AbstractNode*> childnodes;
diff --git a/src/mainwin.cc b/src/mainwin.cc
index 597a094..3d50d6f 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -122,7 +122,7 @@ static char helptitle[] =
#endif
"\nhttp://www.openscad.org\n\n";
static char copyrighttext[] =
- "Copyright (C) 2009-2013 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n"
+ "Copyright (C) 2009-2013 The OpenSCAD Developers\n"
"\n"
"This program is free software; you can redistribute it and/or modify "
"it under the terms of the GNU General Public License as published by "
@@ -470,7 +470,6 @@ void MainWindow::report_func(const class AbstractNode*, void *vp, int mark)
MainWindow *thisp = static_cast<MainWindow*>(vp);
int v = (int)((mark*1000.0) / progress_report_count);
int permille = v < 1000 ? v : 999;
- printf("Progress: %d\n", permille);
if (permille > thisp->progresswidget->value()) {
QMetaObject::invokeMethod(thisp->progresswidget, "setValue", Qt::QueuedConnection,
Q_ARG(int, permille));
@@ -511,7 +510,7 @@ MainWindow::openFile(const QString &new_filename)
}
#endif
setFileName(actual_filename);
-
+
fileChangedOnDisk(); // force cached autoReloadId to update
refreshDocument();
updateRecentFiles();
@@ -744,7 +743,11 @@ void MainWindow::instantiateRoot()
if (this->procevents) QApplication::processEvents();
AbstractNode::resetIndexCounter();
- this->root_inst = ModuleInstantiation("group");
+
+ // split these two lines - gcc 4.7 bug
+ ModuleInstantiation mi = ModuleInstantiation( "group" );
+ this->root_inst = mi;
+
this->absolute_root_node = this->root_module->instantiate(&top_ctx, &this->root_inst, NULL);
if (this->absolute_root_node) {
@@ -778,8 +781,7 @@ void MainWindow::compileCSG(bool procevents)
{
assert(this->root_node);
PRINT("Compiling design (CSG Products generation)...");
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
// Main CSG evaluation
QTime t;
@@ -797,16 +799,16 @@ void MainWindow::compileCSG(bool procevents)
PolySetEvaluator psevaluator(this->tree);
#endif
CSGTermEvaluator csgrenderer(this->tree, &psevaluator);
+ if (procevents) QApplication::processEvents();
this->root_raw_term = csgrenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
if (!root_raw_term) {
PRINT("ERROR: CSG generation failed! (no top level object found)");
- if (procevents)
- QApplication::processEvents();
}
PolySetCache::instance()->print();
#ifdef ENABLE_CGAL
CGALCache::instance()->print();
#endif
+ if (procevents) QApplication::processEvents();
}
catch (const ProgressCancelException &e) {
PRINT("CSG generation cancelled.");
@@ -818,8 +820,7 @@ void MainWindow::compileCSG(bool procevents)
if (root_raw_term) {
PRINT("Compiling design (CSG Products normalization)...");
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
size_t normalizelimit = 2 * Preferences::inst()->getValue("advanced/openCSGLimit").toUInt();
CSGTermNormalizer normalizer(normalizelimit);
@@ -831,15 +832,13 @@ void MainWindow::compileCSG(bool procevents)
else {
this->root_chain = NULL;
PRINT("WARNING: CSG normalization resulted in an empty tree");
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
}
if (highlight_terms.size() > 0)
{
PRINTB("Compiling highlights (%d CSG Trees)...", highlight_terms.size());
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
highlights_chain = new CSGChain();
for (unsigned int i = 0; i < highlight_terms.size(); i++) {
@@ -851,8 +850,7 @@ void MainWindow::compileCSG(bool procevents)
if (background_terms.size() > 0)
{
PRINTB("Compiling background (%d CSG Trees)...", background_terms.size());
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
background_chain = new CSGChain();
for (unsigned int i = 0; i < background_terms.size(); i++) {
@@ -881,8 +879,7 @@ void MainWindow::compileCSG(bool procevents)
PRINT("CSG generation finished.");
int s = t.elapsed() / 1000;
PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60));
- if (procevents)
- QApplication::processEvents();
+ if (procevents) QApplication::processEvents();
}
}
@@ -1175,8 +1172,7 @@ void MainWindow::autoReloadSet(bool on)
QSettings settings;
settings.setValue("design/autoReload",designActionAutoReload->isChecked());
if (on) {
- autoReloadId = "";
- autoReloadTimer->start();
+ autoReloadTimer->start(200);
} else {
autoReloadTimer->stop();
}
@@ -1829,7 +1825,7 @@ MainWindow::helpHomepage()
void
MainWindow::helpManual()
{
- QDesktopServices::openUrl(QUrl("http://en.wikibooks.org/wiki/OpenSCAD_User_Manual"));
+ QDesktopServices::openUrl(QUrl("http://www.openscad.org/documentation.html"));
}
#define STRINGIFY(x) #x
diff --git a/src/modcontext.cc b/src/modcontext.cc
index 3b957fd..5b48009 100644
--- a/src/modcontext.cc
+++ b/src/modcontext.cc
@@ -4,6 +4,7 @@
#include "function.h"
#include "printutils.h"
#include "builtin.h"
+#include "ModuleCache.h"
#include <boost/foreach.hpp>
@@ -16,6 +17,51 @@ ModuleContext::~ModuleContext()
{
}
+// Experimental code. See issue #399
+#if 0
+void ModuleContext::evaluateAssignments(const AssignmentList &assignments)
+{
+ // First, assign all simple variables
+ std::list<std::string> undefined_vars;
+ BOOST_FOREACH(const Assignment &ass, assignments) {
+ Value tmpval = ass.second->evaluate(this);
+ if (tmpval.isUndefined()) undefined_vars.push_back(ass.first);
+ else this->set_variable(ass.first, tmpval);
+ }
+
+ // Variables which couldn't be evaluated in the first pass is attempted again,
+ // to allow for initialization out of order
+
+ boost::unordered_map<std::string, Expression *> tmpass;
+ BOOST_FOREACH (const Assignment &ass, assignments) {
+ tmpass[ass.first] = ass.second;
+ }
+
+ bool changed = true;
+ while (changed) {
+ changed = false;
+ std::list<std::string>::iterator iter = undefined_vars.begin();
+ while (iter != undefined_vars.end()) {
+ std::list<std::string>::iterator curr = iter++;
+ boost::unordered_map<std::string, Expression *>::iterator found = tmpass.find(*curr);
+ if (found != tmpass.end()) {
+ const Expression *expr = found->second;
+ Value tmpval = expr->evaluate(this);
+ // FIXME: it's not enough to check for undefined;
+ // we need to check for any undefined variable in the subexpression
+ // For now, ignore this and revisit the validity and order of variable
+ // assignments later
+ if (!tmpval.isUndefined()) {
+ changed = true;
+ this->set_variable(*curr, tmpval);
+ undefined_vars.erase(curr);
+ }
+ }
+ }
+ }
+}
+#endif
+
void ModuleContext::initializeModule(const class Module &module)
{
this->setVariables(module.definition_arguments, evalctx);
@@ -25,6 +71,8 @@ void ModuleContext::initializeModule(const class Module &module)
BOOST_FOREACH(const Assignment &ass, module.scope.assignments) {
this->set_variable(ass.first, ass.second->evaluate(this));
}
+// Experimental code. See issue #399
+// evaluateAssignments(module.scope.assignments);
}
/*!
@@ -125,17 +173,18 @@ Value FileContext::evaluate_function(const std::string &name, const EvalContext
if (foundf) return foundf->evaluate(this, evalctx);
BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
- // m.second is NULL if the library wasn't be compiled (error or file-not-found)
- if (m.second &&
- m.second->scope.functions.find(name) != m.second->scope.functions.end()) {
- FileContext ctx(*m.second, this->parent);
- ctx.initializeModule(*m.second);
+ // usedmod is NULL if the library wasn't be compiled (error or file-not-found)
+ FileModule *usedmod = ModuleCache::instance()->lookup(m);
+ if (usedmod &&
+ usedmod->scope.functions.find(name) != usedmod->scope.functions.end()) {
+ FileContext ctx(*usedmod, this->parent);
+ ctx.initializeModule(*usedmod);
// FIXME: Set document path
#if 0 && DEBUG
PRINTB("New lib Context for %s func:", name);
ctx.dump(NULL, NULL);
#endif
- return m.second->scope.functions[name]->evaluate(&ctx, evalctx);
+ return usedmod->scope.functions[name]->evaluate(&ctx, evalctx);
}
}
@@ -148,17 +197,18 @@ AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, c
if (foundm) return foundm->instantiate(this, &inst, evalctx);
BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
- // m.second is NULL if the library wasn't be compiled (error or file-not-found)
- if (m.second &&
- m.second->scope.modules.find(inst.name()) != m.second->scope.modules.end()) {
- FileContext ctx(*m.second, this->parent);
- ctx.initializeModule(*m.second);
+ FileModule *usedmod = ModuleCache::instance()->lookup(m);
+ // usedmod is NULL if the library wasn't be compiled (error or file-not-found)
+ if (usedmod &&
+ usedmod->scope.modules.find(inst.name()) != usedmod->scope.modules.end()) {
+ FileContext ctx(*usedmod, this->parent);
+ ctx.initializeModule(*usedmod);
// FIXME: Set document path
#if 0 && DEBUG
PRINT("New file Context:");
ctx.dump(NULL, &inst);
#endif
- return m.second->scope.modules[inst.name()]->instantiate(&ctx, &inst, evalctx);
+ return usedmod->scope.modules[inst.name()]->instantiate(&ctx, &inst, evalctx);
}
}
diff --git a/src/modcontext.h b/src/modcontext.h
index 0b3e48c..3a05a0c 100644
--- a/src/modcontext.h
+++ b/src/modcontext.h
@@ -36,6 +36,9 @@ public:
#ifdef DEBUG
virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#endif
+private:
+// Experimental code. See issue #399
+// void evaluateAssignments(const AssignmentList &assignments);
};
class FileContext : public ModuleContext
diff --git a/src/module.cc b/src/module.cc
index 046d0c4..9c0272d 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -264,34 +264,33 @@ bool FileModule::handleDependencies()
// as it will have a relative path.
// Iterating manually since we want to modify the container while iterating
+<<<<<<< HEAD
+=======
std::vector<std::pair<std::string, FileModule*> > modified_modules;
+>>>>>>> origin/issue181
FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
FileModule::ModuleContainer::iterator curr = iter++;
- FileModule *oldmodule = curr->second;
bool wasmissing = false;
// Get an absolute filename for the module
- std::string filename = curr->first;
+ std::string filename = *curr;
if (!boosty::is_absolute(filename)) {
wasmissing = true;
fs::path fullpath = find_valid_path(this->path, filename);
if (!fullpath.empty()) filename = boosty::stringy(fullpath);
}
+ FileModule *oldmodule = ModuleCache::instance()->lookup(filename);
FileModule *newmodule = ModuleCache::instance()->evaluate(filename);
// Detect appearance but not removal of files
if (newmodule && oldmodule != newmodule) {
changed = true;
#ifdef DEBUG
- PRINTB_NOCACHE(" %s: %p", filename % newmodule);
+ PRINTB_NOCACHE(" %s: %p -> %p", filename % oldmodule % newmodule);
#endif
}
- if (newmodule) {
- modified_modules.push_back(std::make_pair(filename, newmodule));
- this->usedlibs.erase(curr);
- }
- else {
+ if (!newmodule) {
// Only print warning if we're not part of an automatic reload
if (!oldmodule && !wasmissing) {
PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename);
diff --git a/src/module.h b/src/module.h
index 682e65b..b5c58af 100644
--- a/src/module.h
+++ b/src/module.h
@@ -5,6 +5,7 @@
#include <vector>
#include <list>
#include <boost/unordered_map.hpp>
+#include <boost/unordered_set.hpp>
#include <time.h>
#include <sys/stat.h>
@@ -92,12 +93,11 @@ public:
bool includesChanged() const;
bool handleDependencies();
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
-
bool hasIncludes() const { return !this->includes.empty(); }
bool usesLibraries() const { return !this->usedlibs.empty(); }
+ bool isHandlingDependencies() const { return this->is_handling_dependencies; }
-
- typedef boost::unordered_map<std::string, class FileModule*> ModuleContainer;
+ typedef boost::unordered_set<std::string> ModuleContainer;
ModuleContainer usedlibs;
private:
struct IncludeFile {
@@ -110,7 +110,6 @@ private:
typedef boost::unordered_map<std::string, struct IncludeFile> IncludeContainer;
IncludeContainer includes;
-
bool is_handling_dependencies;
std::string path;
};
diff --git a/src/openscad.cc b/src/openscad.cc
index 7c54762..bcde5e2 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -330,7 +330,6 @@ int main(int argc, char **argv)
// Top context - this context only holds builtins
ModuleContext top_ctx;
top_ctx.registerBuiltin();
- PRINT("Root Context:");
#if 0 && DEBUG
top_ctx.dump(NULL, NULL);
#endif
diff --git a/src/parser.y b/src/parser.y
index 2b07f14..5b3d019 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -127,7 +127,7 @@
input:
/* empty */ |
-TOK_USE { rootmodule->usedlibs[$1] = NULL; } input |
+TOK_USE { rootmodule->usedlibs.insert($1); } input |
statement input ;
inner_input:
@@ -136,15 +136,17 @@ statement inner_input ;
assignment:
TOK_ID '=' expr ';' {
+ bool found = false;
for (AssignmentList::iterator iter = scope_stack.top()->assignments.begin();
iter != scope_stack.top()->assignments.end();
iter++) {
if (iter->first == $1) {
- scope_stack.top()->assignments.erase(iter);
+ iter->second = $3;
+ found = true;
break;
}
}
- scope_stack.top()->assignments.push_back(Assignment($1, $3));
+ if (!found) scope_stack.top()->assignments.push_back(Assignment($1, $3));
} ;
statement:
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index 04c20ed..5ad30e1 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -30,8 +30,8 @@ fs::path search_libs(const fs::path &localpath)
}
// files must be 'ordinary' - they must exist and be non-directories
-// FIXME: Don't print anything from this function as it's called repeatedly
-// for the automatic reload function (FileModule::include_modified())
+// FIXME: We cannot print any output here since these function is called periodically
+// from "Automatic reload and compile"
static bool check_valid(const fs::path &p, const std::vector<std::string> *openfilenames)
{
if (p.empty()) {
@@ -55,7 +55,7 @@ static bool check_valid(const fs::path &p, const std::vector<std::string> *openf
if (openfilenames) {
BOOST_FOREACH(const std::string &s, *openfilenames) {
if (s == fullname) {
- //PRINTB("WARNING: circular include file %s", fullname);
+// PRINTB("WARNING: circular include file %s", fullname);
return false;
}
}
diff --git a/src/primitives.cc b/src/primitives.cc
index 9b755ef..89c1573 100644
--- a/src/primitives.cc
+++ b/src/primitives.cc
@@ -242,9 +242,8 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta
*/
int get_fragments_from_r(double r, double fn, double fs, double fa)
{
- if (r < GRID_FINE) return 0;
- if (fn > 0.0)
- return (int)fn;
+ if (r < GRID_FINE) return 3;
+ if (fn > 0.0) return (int)(fn >= 3 ? fn : 3);
return (int)ceil(fmax(fmin(360.0 / fa, r*2*M_PI / fs), 5));
}
diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc
index e073a69..a79b92e 100644
--- a/src/rotateextrude.cc
+++ b/src/rotateextrude.cc
@@ -33,7 +33,6 @@
#include "polyset.h"
#include "visitor.h"
#include "PolySetEvaluator.h"
-#include "openscad.h" // get_fragments_from_r()
#include <sstream>
#include <boost/assign/std/vector.hpp>
diff --git a/src/svg.cc b/src/svg.cc
index c1231a5..a21e844 100644
--- a/src/svg.cc
+++ b/src/svg.cc
@@ -70,29 +70,29 @@ std::string svg_axes()
return out.str();
}
-CGAL_Point_2e project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox )
+CGAL_Nef_polyhedron2::Explorer::Point project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox )
{
- NT screenw(svg_px_width);
- NT screenh(svg_px_height);
- NT screenxc = screenw / 2;
- NT screenyc = screenh / 2;
- NT bboxx = ( bbox.xmax() - bbox.xmin() );
- NT bboxy = ( bbox.ymax() - bbox.ymin() );
- NT bboxz = ( bbox.zmax() - bbox.zmin() );
- NT largest_dim = CGAL::max( CGAL::max( bboxx, bboxy ), bboxz );
- NT bboxxc = bboxx / 2 + bbox.xmin();
- NT bboxyc = bboxy / 2 + bbox.ymin();
- NT bboxzc = bboxz / 2 + bbox.zmin();
- NT xinbox = ( p.x() - bboxxc ) / largest_dim;
- NT yinbox = ( p.y() - bboxyc ) / largest_dim;
- NT zinbox = ( p.z() - bboxzc ) / largest_dim;
+ CGAL_Kernel3::FT screenw(svg_px_width);
+ CGAL_Kernel3::FT screenh(svg_px_height);
+ CGAL_Kernel3::FT screenxc = screenw / 2;
+ CGAL_Kernel3::FT screenyc = screenh / 2;
+ CGAL_Kernel3::FT bboxx = ( bbox.xmax() - bbox.xmin() );
+ CGAL_Kernel3::FT bboxy = ( bbox.ymax() - bbox.ymin() );
+ CGAL_Kernel3::FT bboxz = ( bbox.zmax() - bbox.zmin() );
+ CGAL_Kernel3::FT largest_dim = CGAL::max( CGAL::max( bboxx, bboxy ), bboxz );
+ CGAL_Kernel3::FT bboxxc = bboxx / 2 + bbox.xmin();
+ CGAL_Kernel3::FT bboxyc = bboxy / 2 + bbox.ymin();
+ CGAL_Kernel3::FT bboxzc = bboxz / 2 + bbox.zmin();
+ CGAL_Kernel3::FT xinbox = ( p.x() - bboxxc ) / largest_dim;
+ CGAL_Kernel3::FT yinbox = ( p.y() - bboxyc ) / largest_dim;
+ CGAL_Kernel3::FT zinbox = ( p.z() - bboxzc ) / largest_dim;
// do simple fake paralell projection
- NT tx = screenxc + xinbox * screenw / 1.618 + yinbox * screenh / 3.2;
- NT ty = screenyc - zinbox * screenh / 1.618 - yinbox * screenh / 3.2;
- return CGAL_Point_2e( tx, ty );
+ CGAL_Kernel3::FT tx = screenxc + xinbox * screenw / 1.618 + yinbox * screenh / 3.2;
+ CGAL_Kernel3::FT ty = screenyc - zinbox * screenh / 1.618 - yinbox * screenh / 3.2;
+ return CGAL_Point_2e(CGAL::to_double(tx), CGAL::to_double(ty));
}
-CGAL_Point_2e project_svg_2to2( CGAL_Point_2e p, CGAL_Iso_rectangle_2e bbox )
+CGAL_Point_2e project_svg_2to2(const CGAL_Point_2e &p, const CGAL_Iso_rectangle_2e &bbox)
{
double screenw = svg_px_width;
double screenh = svg_px_height;
@@ -122,7 +122,7 @@ std::string dump_cgal_nef_polyhedron2_face_svg(
std::stringstream out;
CGAL_For_all(c1, c2) {
if ( explorer.is_standard( explorer.target(c1) ) ) {
- CGAL_Point_2e source = explorer.point( explorer.source( c1 ) );
+CGAL_Nef_polyhedron2::Explorer::Point source = explorer.point( explorer.source( c1 ) );
CGAL_Point_2e target = explorer.point( explorer.target( c1 ) );
out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
std::string he_mark = boost::lexical_cast<std::string>(c1->mark());
diff --git a/testdata/modulecache-tests/cascade.sh b/testdata/modulecache-tests/cascade.sh
index 5dd0ef7..3193d06 100755
--- a/testdata/modulecache-tests/cascade.sh
+++ b/testdata/modulecache-tests/cascade.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-rm cascade*.scad
+rm -f cascade*.scad
echo "include <cascade-A.scad> include <cascade-B.scad> use <cascade-C.scad> use <cascade-D.scad> A(); translate([11,0,0]) B(); translate([22,0,0]) C(); translate([33,0,0]) D();" > cascadetest.scad
sleep 0.05
echo "module A() { sphere(5); }" > cascade-A.scad
diff --git a/testdata/modulecache-tests/cascade2.sh b/testdata/modulecache-tests/cascade2.sh
index 50f98e0..4969e6f 100755
--- a/testdata/modulecache-tests/cascade2.sh
+++ b/testdata/modulecache-tests/cascade2.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-rm cascade-*.scad
+rm -f cascade-*.scad
echo "include <cascade-A.scad> include <cascade-B.scad> use <cascade-C.scad> use <cascade-D.scad> A(); translate([11,0,0]) B(); translate([22,0,0]) C(); translate([33,0,0]) D();" > cascadetest.scad
sleep 0.1
echo "module A() { sphere(6); }" > cascade-A.scad
diff --git a/testdata/scad/dxf/arc.scad b/testdata/scad/dxf/arc.scad
index fff70a3..f53b7bd 100644
--- a/testdata/scad/dxf/arc.scad
+++ b/testdata/scad/dxf/arc.scad
@@ -1 +1,2 @@
import("../../dxf/arc.dxf");
+translate([110,0]) import("../../dxf/arc.dxf", $fn=0.1);
diff --git a/testdata/scad/dxf/circle.scad b/testdata/scad/dxf/circle.scad
index 8b5d132..edb9f77 100644
--- a/testdata/scad/dxf/circle.scad
+++ b/testdata/scad/dxf/circle.scad
@@ -1 +1,2 @@
import("../../dxf/circle.dxf");
+translate([210,0,0]) import("../../dxf/circle.dxf", $fn=0.1);
diff --git a/testdata/scad/features/circle-tests.scad b/testdata/scad/features/circle-tests.scad
index 6b54d55..90cd9f6 100644
--- a/testdata/scad/features/circle-tests.scad
+++ b/testdata/scad/features/circle-tests.scad
@@ -8,3 +8,4 @@ translate([6,-3,0]) circle(1, $fn=12);
translate([0,-6,0]) circle(1, $fa=20, $fs=0.3);
translate([3,-6,0]) circle(1, $fa=30, $fs=0.3);
translate([6,-6,0]) circle(1, $fa=40, $fs=0.3);
+translate([3,-9,0]) circle(1, $fn=0.1);
diff --git a/testdata/scad/features/cylinder-tests.scad b/testdata/scad/features/cylinder-tests.scad
index 71f43a6..75b06f2 100644
--- a/testdata/scad/features/cylinder-tests.scad
+++ b/testdata/scad/features/cylinder-tests.scad
@@ -16,5 +16,5 @@ translate([22,11,0]) cylinder(h=15, r=5, r2=5);
// tend to "abuse" this for captured nut slots
translate([-10,0,0]) cylinder(h=2, r=3, $fn=6);
-
-// FIXME: We could test $fs, $fa, $fn as well
+// Test that we clamp number of sections to a minimum of 3
+translate([-10, -10, 0]) cylinder(r=3.5356, h=7.0711, $fn=0.1, center=true);
diff --git a/testdata/scad/features/linear_extrude-tests.scad b/testdata/scad/features/linear_extrude-tests.scad
index 528eea2..680bf53 100644
--- a/testdata/scad/features/linear_extrude-tests.scad
+++ b/testdata/scad/features/linear_extrude-tests.scad
@@ -22,3 +22,6 @@ translate([-15,20,0]) linear_extrude(height=20, scale=[4,5,6]) square(10);
translate([-10,5,0]) linear_extrude(height=15, scale=-2) square(10, center=true);
// scale given as undefined
translate([-15,-15,0]) linear_extrude(height=10, scale=var_undef) square(10);
+
+// height is negative
+translate([0,-25,0]) linear_extrude(-1) square(10, center=true);
diff --git a/testdata/scad/features/rotate_extrude-tests.scad b/testdata/scad/features/rotate_extrude-tests.scad
index 347bc78..010b7d2 100644
--- a/testdata/scad/features/rotate_extrude-tests.scad
+++ b/testdata/scad/features/rotate_extrude-tests.scad
@@ -28,3 +28,7 @@ translate([50,50,0]) {
translate([-50,0,0]) cube([100,100,100], center=true);
}
}
+
+// Minimal $fn
+translate([0,-60,0]) rotate_extrude($fn=1) translate([20,0,0]) circle(r=10,$fn=1);
+
diff --git a/testdata/scad/features/sphere-tests.scad b/testdata/scad/features/sphere-tests.scad
index e666c1b..cc80738 100644
--- a/testdata/scad/features/sphere-tests.scad
+++ b/testdata/scad/features/sphere-tests.scad
@@ -8,3 +8,4 @@ translate([11,11,0]) sphere(5, $fn=15);
translate([22,-11, 0]) sphere(5, $fa=20, $fs=0.3);
translate([22, 0, 0]) sphere(5, $fa=30, $fs=0.3);
translate([22, 11, 0]) sphere(5, $fa=40, $fs=0.3);
+translate([11, 22, 0]) sphere(5, $fn=0.1);
diff --git a/testdata/scad/misc/value-reassignment-tests.scad b/testdata/scad/misc/value-reassignment-tests.scad
index 475f78f..26afa03 100644
--- a/testdata/scad/misc/value-reassignment-tests.scad
+++ b/testdata/scad/misc/value-reassignment-tests.scad
@@ -1,4 +1,9 @@
+// Test reassignment which depends on a previously assigned variable,
+// as this could be messed up if order of assignment evaluation
+// changes
+
myval = 2;
i = 2;
-myval = i * 2;
-echo(myval);
+myval = i * 2; // This is not (yet) allowed as it will be evaluates in place of the first assignment
+echo(myval, i); // Should output undef, 2
+
diff --git a/testdata/scad/misc/value-reassignment-tests2.scad b/testdata/scad/misc/value-reassignment-tests2.scad
new file mode 100644
index 0000000..29a2fb7
--- /dev/null
+++ b/testdata/scad/misc/value-reassignment-tests2.scad
@@ -0,0 +1,16 @@
+// Test reassignment where another variable has used the previous
+// value before the reassignment. This could get messed up if order of
+// assignment evaluation changes
+
+myval = 2;
+i = myval;
+myval = 3;
+echo(myval, i); // Should output 3, 3
+
+// NB! This feels wrong, but it's a simulation of what happens
+// when overriding a variable on the cmd-line: openscad -Dmyval=3 myfile.scad
+// Since the intention is to override a top-level variable, the evaluation of the
+// new expression must be done in the same place as the old.
+// This is currently solved by appending the text given to the -D parameter to the end
+// of the main file.
+
diff --git a/testdata/scad/misc/variable-scope-tests.scad b/testdata/scad/misc/variable-scope-tests.scad
index 8426fbb..104d1a4 100644
--- a/testdata/scad/misc/variable-scope-tests.scad
+++ b/testdata/scad/misc/variable-scope-tests.scad
@@ -49,5 +49,16 @@ echo("undeclared variable can still be passed and used");
module undeclared_var() {
echo(d);
}
-
undeclared_var(d=6);
+
+echo("attempt to assign from a not-yet-defined variable which also exists globally");
+
+globalval = 1;
+// Test that b = a turns into b = 1, heeding the order of the assignments
+// See issue #399 for more discussion
+module global_lookup() {
+ b = globalval; // Should be assigned 1 since the local one isn't yet defined
+ globalval = 5; // Overrides the value for the local scope only
+ echo(globalval,b); // Should output 5, 1
+}
+global_lookup();
diff --git a/tests/.gitignore b/tests/.gitignore
index 2f5abd7..5033bd2 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -21,5 +21,8 @@ out.png
/throwntogethertest
/cgalstlsanitytest
/cgalcachetest
+/modulecachetest
+/moduledumptest
+/test_pretty_print
/sysinfo.txt
/CTestCustom.cmake \ No newline at end of file
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2781124..7509ed1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -333,6 +333,9 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
include_directories( /usr/pkg/include /usr/X11R7/include )
set(FLEX_EXECUTABLE /usr/pkg/bin/flex)
+ if(NOT ${CMAKE_CXX_COMPILER} MATCHES ".*clang.*")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+ endif()
endif()
find_package(FLEX REQUIRED)
@@ -776,6 +779,7 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/variable-scope-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/lookup-tests.scad)
diff --git a/tests/regression/cgalpngtest/arc-expected.png b/tests/regression/cgalpngtest/arc-expected.png
index 2f555c4..23a67c7 100644
--- a/tests/regression/cgalpngtest/arc-expected.png
+++ b/tests/regression/cgalpngtest/arc-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/circle-expected.png b/tests/regression/cgalpngtest/circle-expected.png
index aacf12d..89a7fd0 100644
--- a/tests/regression/cgalpngtest/circle-expected.png
+++ b/tests/regression/cgalpngtest/circle-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/circle-tests-expected.png b/tests/regression/cgalpngtest/circle-tests-expected.png
index 0736af5..d640042 100644
--- a/tests/regression/cgalpngtest/circle-tests-expected.png
+++ b/tests/regression/cgalpngtest/circle-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/cylinder-tests-expected.png b/tests/regression/cgalpngtest/cylinder-tests-expected.png
index 843d70f..5d63548 100644
--- a/tests/regression/cgalpngtest/cylinder-tests-expected.png
+++ b/tests/regression/cgalpngtest/cylinder-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png b/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png
index ee60a72..1488c85 100644
--- a/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png
+++ b/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/sphere-tests-expected.png b/tests/regression/cgalpngtest/sphere-tests-expected.png
index f2a11f3..781d8a9 100644
--- a/tests/regression/cgalpngtest/sphere-tests-expected.png
+++ b/tests/regression/cgalpngtest/sphere-tests-expected.png
Binary files differ
diff --git a/tests/regression/dumptest/circle-tests-expected.txt b/tests/regression/dumptest/circle-tests-expected.txt
index 910b375..28359d8 100644
--- a/tests/regression/dumptest/circle-tests-expected.txt
+++ b/tests/regression/dumptest/circle-tests-expected.txt
@@ -26,4 +26,7 @@
multmatrix([[1, 0, 0, 6], [0, 1, 0, -6], [0, 0, 1, 0], [0, 0, 0, 1]]) {
circle($fn = 0, $fa = 40, $fs = 0.3, r = 1);
}
+ multmatrix([[1, 0, 0, 3], [0, 1, 0, -9], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ circle($fn = 0.1, $fa = 12, $fs = 2, r = 1);
+ }
diff --git a/tests/regression/dumptest/cylinder-tests-expected.txt b/tests/regression/dumptest/cylinder-tests-expected.txt
index b1e8b6e..c47ffe1 100644
--- a/tests/regression/dumptest/cylinder-tests-expected.txt
+++ b/tests/regression/dumptest/cylinder-tests-expected.txt
@@ -32,4 +32,7 @@
multmatrix([[1, 0, 0, -10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
cylinder($fn = 6, $fa = 12, $fs = 2, h = 2, r1 = 3, r2 = 3, center = false);
}
+ multmatrix([[1, 0, 0, -10], [0, 1, 0, -10], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ cylinder($fn = 0.1, $fa = 12, $fs = 2, h = 7.0711, r1 = 3.5356, r2 = 3.5356, center = true);
+ }
diff --git a/tests/regression/dumptest/linear_extrude-tests-expected.txt b/tests/regression/dumptest/linear_extrude-tests-expected.txt
index c867388..face5e2 100644
--- a/tests/regression/dumptest/linear_extrude-tests-expected.txt
+++ b/tests/regression/dumptest/linear_extrude-tests-expected.txt
@@ -54,4 +54,9 @@
square(size = [10, 10], center = false);
}
}
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, -25], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ linear_extrude(height = 0, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
+ square(size = [10, 10], center = true);
+ }
+ }
diff --git a/tests/regression/dumptest/rotate_extrude-tests-expected.txt b/tests/regression/dumptest/rotate_extrude-tests-expected.txt
index 42faff2..023d78d 100644
--- a/tests/regression/dumptest/rotate_extrude-tests-expected.txt
+++ b/tests/regression/dumptest/rotate_extrude-tests-expected.txt
@@ -42,4 +42,11 @@
}
}
}
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, -60], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ rotate_extrude(convexity = 1, $fn = 1, $fa = 12, $fs = 2) {
+ multmatrix([[1, 0, 0, 20], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ circle($fn = 1, $fa = 12, $fs = 2, r = 10);
+ }
+ }
+ }
diff --git a/tests/regression/dumptest/sphere-tests-expected.txt b/tests/regression/dumptest/sphere-tests-expected.txt
index 84f8c23..461e946 100644
--- a/tests/regression/dumptest/sphere-tests-expected.txt
+++ b/tests/regression/dumptest/sphere-tests-expected.txt
@@ -26,4 +26,7 @@
multmatrix([[1, 0, 0, 22], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) {
sphere($fn = 0, $fa = 40, $fs = 0.3, r = 5);
}
+ multmatrix([[1, 0, 0, 11], [0, 1, 0, 22], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ sphere($fn = 0.1, $fa = 12, $fs = 2, r = 5);
+ }
diff --git a/tests/regression/echotest/value-reassignment-tests-expected.txt b/tests/regression/echotest/value-reassignment-tests-expected.txt
index 05a6741..344f7ab 100644
--- a/tests/regression/echotest/value-reassignment-tests-expected.txt
+++ b/tests/regression/echotest/value-reassignment-tests-expected.txt
@@ -1 +1,2 @@
-ECHO: 4
+WARNING: Ignoring unknown variable 'i'.
+ECHO: undef, 2
diff --git a/tests/regression/echotest/value-reassignment-tests2-expected.txt b/tests/regression/echotest/value-reassignment-tests2-expected.txt
new file mode 100644
index 0000000..efb1be7
--- /dev/null
+++ b/tests/regression/echotest/value-reassignment-tests2-expected.txt
@@ -0,0 +1 @@
+ECHO: 3, 3
diff --git a/tests/regression/echotest/variable-scope-tests-expected.txt b/tests/regression/echotest/variable-scope-tests-expected.txt
index 92db05d..5994778 100644
--- a/tests/regression/echotest/variable-scope-tests-expected.txt
+++ b/tests/regression/echotest/variable-scope-tests-expected.txt
@@ -14,3 +14,5 @@ ECHO: undef
ECHO: 5
ECHO: "undeclared variable can still be passed and used"
ECHO: 6
+ECHO: "attempt to assign from a not-yet-defined variable which also exists globally"
+ECHO: 5, 1
diff --git a/tests/regression/opencsgtest/arc-expected.png b/tests/regression/opencsgtest/arc-expected.png
index a930c0e..7361853 100644
--- a/tests/regression/opencsgtest/arc-expected.png
+++ b/tests/regression/opencsgtest/arc-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/circle-expected.png b/tests/regression/opencsgtest/circle-expected.png
index 7bc63b1..14fce98 100644
--- a/tests/regression/opencsgtest/circle-expected.png
+++ b/tests/regression/opencsgtest/circle-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/circle-tests-expected.png b/tests/regression/opencsgtest/circle-tests-expected.png
index 2e5b314..06f7d9c 100644
--- a/tests/regression/opencsgtest/circle-tests-expected.png
+++ b/tests/regression/opencsgtest/circle-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/cylinder-tests-expected.png b/tests/regression/opencsgtest/cylinder-tests-expected.png
index 4c7ab79..d0c607c 100644
--- a/tests/regression/opencsgtest/cylinder-tests-expected.png
+++ b/tests/regression/opencsgtest/cylinder-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/rotate_extrude-tests-expected.png b/tests/regression/opencsgtest/rotate_extrude-tests-expected.png
index 96452e1..861f6ab 100644
--- a/tests/regression/opencsgtest/rotate_extrude-tests-expected.png
+++ b/tests/regression/opencsgtest/rotate_extrude-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/sphere-tests-expected.png b/tests/regression/opencsgtest/sphere-tests-expected.png
index d11e3bf..d1b4845 100644
--- a/tests/regression/opencsgtest/sphere-tests-expected.png
+++ b/tests/regression/opencsgtest/sphere-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/arc-expected.png b/tests/regression/throwntogethertest/arc-expected.png
index 8783806..7361853 100644
--- a/tests/regression/throwntogethertest/arc-expected.png
+++ b/tests/regression/throwntogethertest/arc-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/circle-expected.png b/tests/regression/throwntogethertest/circle-expected.png
index c001955..14fce98 100644
--- a/tests/regression/throwntogethertest/circle-expected.png
+++ b/tests/regression/throwntogethertest/circle-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/circle-tests-expected.png b/tests/regression/throwntogethertest/circle-tests-expected.png
index 2e5b314..06f7d9c 100644
--- a/tests/regression/throwntogethertest/circle-tests-expected.png
+++ b/tests/regression/throwntogethertest/circle-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/cylinder-tests-expected.png b/tests/regression/throwntogethertest/cylinder-tests-expected.png
index 4c7ab79..d0c607c 100644
--- a/tests/regression/throwntogethertest/cylinder-tests-expected.png
+++ b/tests/regression/throwntogethertest/cylinder-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png b/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png
index 94b0d9c..8956be2 100644
--- a/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png
+++ b/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/sphere-tests-expected.png b/tests/regression/throwntogethertest/sphere-tests-expected.png
index d11e3bf..d1b4845 100644
--- a/tests/regression/throwntogethertest/sphere-tests-expected.png
+++ b/tests/regression/throwntogethertest/sphere-tests-expected.png
Binary files differ
diff --git a/tests/virtualfb.sh b/tests/virtualfb.sh
index 186b389..c5c9668 100755
--- a/tests/virtualfb.sh
+++ b/tests/virtualfb.sh
@@ -24,7 +24,11 @@ start()
fi
VFB_DISPLAY=`echo | awk 'BEGIN{srand();} {printf ":%.0f", rand()*1000+100};'`
- $VFB_BINARY $VFB_DISPLAY -screen 0 800x600x24 &> ./virtualfb.log &
+ if [ $debug ]; then
+ echo debug VFB_DISPLAY $VFB_DISPLAY
+ echo debug VFB_BINARY $VFB_BINARY
+ fi
+ $VFB_BINARY $VFB_DISPLAY -screen 0 800x600x24 > ./virtualfb1.log 2> ./virtualfb2.log &
# on some systems $! gives us VFB_BINARY's PID, on others we have to subtract 1
VFB_PID_MINUS0=$!
VFB_PID_MINUS1=$(($VFB_PID_MINUS0 - 1))
contact: Jan Huwald // Impressum