diff options
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; @@ -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> @@ -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 Binary files differindex 2f555c4..23a67c7 100644 --- a/tests/regression/cgalpngtest/arc-expected.png +++ b/tests/regression/cgalpngtest/arc-expected.png diff --git a/tests/regression/cgalpngtest/circle-expected.png b/tests/regression/cgalpngtest/circle-expected.png Binary files differindex aacf12d..89a7fd0 100644 --- a/tests/regression/cgalpngtest/circle-expected.png +++ b/tests/regression/cgalpngtest/circle-expected.png diff --git a/tests/regression/cgalpngtest/circle-tests-expected.png b/tests/regression/cgalpngtest/circle-tests-expected.png Binary files differindex 0736af5..d640042 100644 --- a/tests/regression/cgalpngtest/circle-tests-expected.png +++ b/tests/regression/cgalpngtest/circle-tests-expected.png diff --git a/tests/regression/cgalpngtest/cylinder-tests-expected.png b/tests/regression/cgalpngtest/cylinder-tests-expected.png Binary files differindex 843d70f..5d63548 100644 --- a/tests/regression/cgalpngtest/cylinder-tests-expected.png +++ b/tests/regression/cgalpngtest/cylinder-tests-expected.png diff --git a/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png b/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png Binary files differindex ee60a72..1488c85 100644 --- a/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png +++ b/tests/regression/cgalpngtest/rotate_extrude-tests-expected.png diff --git a/tests/regression/cgalpngtest/sphere-tests-expected.png b/tests/regression/cgalpngtest/sphere-tests-expected.png Binary files differindex f2a11f3..781d8a9 100644 --- a/tests/regression/cgalpngtest/sphere-tests-expected.png +++ b/tests/regression/cgalpngtest/sphere-tests-expected.png 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 Binary files differindex a930c0e..7361853 100644 --- a/tests/regression/opencsgtest/arc-expected.png +++ b/tests/regression/opencsgtest/arc-expected.png diff --git a/tests/regression/opencsgtest/circle-expected.png b/tests/regression/opencsgtest/circle-expected.png Binary files differindex 7bc63b1..14fce98 100644 --- a/tests/regression/opencsgtest/circle-expected.png +++ b/tests/regression/opencsgtest/circle-expected.png diff --git a/tests/regression/opencsgtest/circle-tests-expected.png b/tests/regression/opencsgtest/circle-tests-expected.png Binary files differindex 2e5b314..06f7d9c 100644 --- a/tests/regression/opencsgtest/circle-tests-expected.png +++ b/tests/regression/opencsgtest/circle-tests-expected.png diff --git a/tests/regression/opencsgtest/cylinder-tests-expected.png b/tests/regression/opencsgtest/cylinder-tests-expected.png Binary files differindex 4c7ab79..d0c607c 100644 --- a/tests/regression/opencsgtest/cylinder-tests-expected.png +++ b/tests/regression/opencsgtest/cylinder-tests-expected.png diff --git a/tests/regression/opencsgtest/rotate_extrude-tests-expected.png b/tests/regression/opencsgtest/rotate_extrude-tests-expected.png Binary files differindex 96452e1..861f6ab 100644 --- a/tests/regression/opencsgtest/rotate_extrude-tests-expected.png +++ b/tests/regression/opencsgtest/rotate_extrude-tests-expected.png diff --git a/tests/regression/opencsgtest/sphere-tests-expected.png b/tests/regression/opencsgtest/sphere-tests-expected.png Binary files differindex d11e3bf..d1b4845 100644 --- a/tests/regression/opencsgtest/sphere-tests-expected.png +++ b/tests/regression/opencsgtest/sphere-tests-expected.png diff --git a/tests/regression/throwntogethertest/arc-expected.png b/tests/regression/throwntogethertest/arc-expected.png Binary files differindex 8783806..7361853 100644 --- a/tests/regression/throwntogethertest/arc-expected.png +++ b/tests/regression/throwntogethertest/arc-expected.png diff --git a/tests/regression/throwntogethertest/circle-expected.png b/tests/regression/throwntogethertest/circle-expected.png Binary files differindex c001955..14fce98 100644 --- a/tests/regression/throwntogethertest/circle-expected.png +++ b/tests/regression/throwntogethertest/circle-expected.png diff --git a/tests/regression/throwntogethertest/circle-tests-expected.png b/tests/regression/throwntogethertest/circle-tests-expected.png Binary files differindex 2e5b314..06f7d9c 100644 --- a/tests/regression/throwntogethertest/circle-tests-expected.png +++ b/tests/regression/throwntogethertest/circle-tests-expected.png diff --git a/tests/regression/throwntogethertest/cylinder-tests-expected.png b/tests/regression/throwntogethertest/cylinder-tests-expected.png Binary files differindex 4c7ab79..d0c607c 100644 --- a/tests/regression/throwntogethertest/cylinder-tests-expected.png +++ b/tests/regression/throwntogethertest/cylinder-tests-expected.png diff --git a/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png b/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png Binary files differindex 94b0d9c..8956be2 100644 --- a/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png +++ b/tests/regression/throwntogethertest/rotate_extrude-tests-expected.png diff --git a/tests/regression/throwntogethertest/sphere-tests-expected.png b/tests/regression/throwntogethertest/sphere-tests-expected.png Binary files differindex d11e3bf..d1b4845 100644 --- a/tests/regression/throwntogethertest/sphere-tests-expected.png +++ b/tests/regression/throwntogethertest/sphere-tests-expected.png 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)) |