mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into pymod
This commit is contained in:
commit
c9771f54eb
62
Changelog
62
Changelog
|
|
@ -1,8 +1,66 @@
|
|||
0.26 (2018-06-23):
|
||||
* Enhancement: Standalone Python modules provide
|
||||
0.26 (xxxx-xx-xx):
|
||||
* Enhancement: Standalone Python modules provided
|
||||
For details see:
|
||||
https://github.com/klayoutmatthias/klayout/wiki/klayout---Standalone-KLayout-Python-Module
|
||||
|
||||
0.25.5 (xxxx-xx-xx):
|
||||
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/162
|
||||
GDS2 LIBNAME was not maintained on "File/Save".
|
||||
|
||||
0.25.4 (2018-08-25):
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/121
|
||||
Issue with multiple reads of GDS2 layouts including PCells
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/134
|
||||
Error in cell.fill_region caused by big polygon with
|
||||
spikes
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/139
|
||||
Libraries have not been reassigned when loading a GDS file
|
||||
from command line (does not happen on File/Open)
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/141
|
||||
Issue with RBA::QHostAddress (ambiguous overload) on Qt5
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/142
|
||||
Issue with RBA::RecursiveShapeIterator#region=
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/144
|
||||
The Salt package descriptions are not shown with Motif
|
||||
style
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/148
|
||||
Wrong font is used
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/152
|
||||
Shapes#size reported a wrong shape count in viewer mode
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/153
|
||||
Application crash when editing guiding shape properties
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/155
|
||||
Program freezes after replacing nothing by something in
|
||||
Macro editor
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/157
|
||||
"Replace cell with ..." rejected cell names with a library
|
||||
prefix
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/158
|
||||
Repaint issue on cell context
|
||||
* Bugfix: https://github.com/klayoutmatthias/klayout/issues/159
|
||||
Tech specific macros and DRC scripts were not shown in tech
|
||||
manager
|
||||
* Bugfix: 8 bit indexed GIF images can be used for package icons now
|
||||
* Enhancement: Provide a way to specify the type of a macro
|
||||
This feature is mainly useful for command line arguments.
|
||||
If you run KLayout with "klayout -b -r myscript"
|
||||
it will not be able to determine the type of macro without
|
||||
a suffix.
|
||||
|
||||
You can now explicitly specify a certain type by
|
||||
giving the suffix implicitly like: "klayout -b -r myscript[rb]"
|
||||
This will read "myscript" but pretend it was "myscript.rb"
|
||||
and execute it as Ruby script.
|
||||
|
||||
This feature is handy if you need to run a file with a
|
||||
specific interpreter but cannot modify the file name.
|
||||
* Enhancement: Selection now shows PCell display names
|
||||
Before, the internal name was shown for instances
|
||||
* Enhancement: There is an option in the View menu to show or hide markers
|
||||
Markers may hide layout under them. With this feature you can
|
||||
quickly disable all markers and the layout becomes visible.
|
||||
|
||||
0.25.3 (2018-05-03):
|
||||
|
||||
* Enhancement: Compile option to use libcurl instead of QtNetwork
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
klayout (0.26-1) unstable; urgency=low
|
||||
klayout (0.25.4-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Sun, 24 Jun 2018 15:43:26 +0200
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Sat, 25 Aug 2018 23:15:23 +0200
|
||||
|
||||
klayout (0.25.3-1) unstable; urgency=low
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ Homebrew's installation of python3 (`brew install python3`) places a `Python.fra
|
|||
```
|
||||
# Build step
|
||||
./build4mac.py -p B36 -q Qt5Brew
|
||||
# build with log
|
||||
./build4mac.py -p B36 -q Qt5Brew 2>&1 | tee qt5.build.macos-HighSierra-release-version.log
|
||||
|
||||
|
||||
# Deploy step
|
||||
./build4mac.py -p B36 -q Qt5Brew -y # normal deploy
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
if [ "$1" != "" ]; then
|
||||
/Applications/klayout.app/Contents/MacOS/klayout $1 -r /Applications/klayout.app/Contents/MacOS/start-console.py
|
||||
else
|
||||
/Applications/klayout.app/Contents/MacOS/klayout -z -r /Applications/klayout.app/Contents/MacOS/start-console.py
|
||||
fi
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/Applications/klayout.app/Contents/MacOS/klayout -b -r
|
||||
import readline
|
||||
import code
|
||||
import sys
|
||||
import os
|
||||
pwd = os.getcwd()
|
||||
sys.path.append(pwd)
|
||||
|
||||
variables = globals().copy()
|
||||
variables.update(locals())
|
||||
shell = code.InteractiveConsole(variables)
|
||||
cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
|
||||
banner = "Python %s on %s\n%s\n(%s)" % (sys.version, sys.platform,
|
||||
cprt, "KLayout Python Console")
|
||||
exit_msg = 'now exiting %s...' % "KLayout Python Console"
|
||||
shell.interact(banner, exit_msg)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#! /usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#===============================================================================
|
||||
|
|
@ -125,7 +125,7 @@ def SetGlobals():
|
|||
ModulePython = "PythonYosemite"
|
||||
elif Platform == "ElCapitan":
|
||||
ModuleRuby = "RubyElCapitan"
|
||||
ModulePytyon = "PythonElCapitan"
|
||||
ModulePython = "PythonElCapitan"
|
||||
elif Platform == "Sierra":
|
||||
ModuleRuby = "RubySierra"
|
||||
ModulePython = "PythonSierra"
|
||||
|
|
@ -538,8 +538,8 @@ def DeployBinariesForBundle():
|
|||
if not DeploymentF and not DeploymentP:
|
||||
return 1
|
||||
if DeploymentF and NonOSStdLang:
|
||||
print( "WARNING!!! You chose <-y|--deploy> while using non-OS-standard script language.", file=sys.stderr )
|
||||
print( " Use <-Y|--DEPLOY> instead", file=sys.stderr )
|
||||
print( " WARNING!!! You chose <-y|--deploy> while using non-OS-standard script language.", file=sys.stderr )
|
||||
print( " Consider using <-Y|--DEPLOY> instead", file=sys.stderr )
|
||||
#return 1
|
||||
if not os.path.isfile(MacBuildLog):
|
||||
print( "!!! Build log file <%s> does not present !!!" % MacBuildLog, file=sys.stderr )
|
||||
|
|
@ -756,7 +756,6 @@ def DeployBinariesForBundle():
|
|||
os.chdir(ProjectDir)
|
||||
os.chdir(MacPkgDir)
|
||||
command = "%s %s %s" % ( deploytool, app_bundle, options )
|
||||
print(command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to deploy applications on OSX !!!"
|
||||
print( msg, file=sys.stderr )
|
||||
|
|
@ -764,43 +763,111 @@ def DeployBinariesForBundle():
|
|||
os.chdir(ProjectDir)
|
||||
return 1
|
||||
|
||||
deploymentPython = False
|
||||
if deploymentPython:
|
||||
# TODO Code incomplete! To be finished.
|
||||
from macbuild.build4mac_util import WalkFrameworkPaths, PerformChanges, DetectChanges
|
||||
|
||||
bundlePath = 'qt5.pkg.macos-HighSierra-release/klayout.app'
|
||||
bundleExecPathAbs = os.getcwd() + '/%s/Contents/MacOS/' % bundlePath
|
||||
|
||||
# rsync -a --safe-links /usr/local/opt/python/Frameworks/Python.framework/ qt5.pkg.macos-HighSierra-release/klayout.app/Contents/Frameworks/Python.framework
|
||||
# cp -RL /usr/local/opt/python/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages qt5.pkg.macos-HighSierra-release/klayout.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/
|
||||
# rm -rf qt5.pkg.macos-HighSierra-release/klayout.app/Contents/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/test
|
||||
deploymentPython = True
|
||||
if deploymentPython and NonOSStdLang:
|
||||
from build4mac_util import WalkFrameworkPaths, PerformChanges, DetectChanges
|
||||
|
||||
bundlePath = AbsMacPkgDir + '/klayout.app'
|
||||
# bundlePath = os.getcwd() + '/qt5.pkg.macos-HighSierra-release/klayout.app'
|
||||
bundleExecPathAbs = '%s/Contents/MacOS/' % bundlePath
|
||||
pythonOriginalFrameworkPath = '/usr/local/opt/python3/Frameworks/Python.framework'
|
||||
pythonFrameworkPath = '%s/Contents/Frameworks/Python.framework' % bundlePath
|
||||
|
||||
print(" [8.1] Deploying Python from %s ..." % pythonOriginalFrameworkPath)
|
||||
print(" [1] Copying Python Framework")
|
||||
shell_commands = list()
|
||||
shell_commands.append("rm -rf %s" % pythonFrameworkPath)
|
||||
shell_commands.append("rsync -a --safe-links %s/ %s" % (pythonOriginalFrameworkPath, pythonFrameworkPath))
|
||||
shell_commands.append("mkdir %s/Versions/3.7/lib/python3.7/site-packages/" % pythonFrameworkPath)
|
||||
shell_commands.append("cp -RL %s/Versions/3.7/lib/python3.7/site-packages/{pip*,pkg_resources,setuptools*,wheel*} " % pythonOriginalFrameworkPath +
|
||||
"%s/Versions/3.7/lib/python3.7/site-packages/" % pythonFrameworkPath)
|
||||
shell_commands.append("rm -rf %s/Versions/3.7/lib/python3.7/test" % pythonFrameworkPath)
|
||||
shell_commands.append("rm -rf %s/Versions/3.7/Resources" % pythonFrameworkPath)
|
||||
shell_commands.append("rm -rf %s/Versions/3.7/bin" % pythonFrameworkPath)
|
||||
|
||||
for command in shell_commands:
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "command failed: %s"
|
||||
print( msg % command, file=sys.stderr )
|
||||
exit(1)
|
||||
|
||||
shutil.copy2( sourceDir2 + "/start-console.py", targetDirM )
|
||||
shutil.copy2( sourceDir2 + "/klayout_console", targetDirM )
|
||||
os.chmod( targetDirM + "/klayout_console", 0o0755 )
|
||||
|
||||
print(" [2] Relinking dylib dependencies inside Python.framework")
|
||||
print(" [2.1] Patching Python Framework")
|
||||
depdict = WalkFrameworkPaths(pythonFrameworkPath)
|
||||
|
||||
pythonOriginalFrameworkPath = '/usr/local/opt/python/Frameworks/Python.framework'
|
||||
appPythonFrameworkPath = '@executable_path/../Frameworks/Python.framework/'
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
klayoutPath = bundleExecPathAbs
|
||||
depdict = WalkFrameworkPaths(klayoutPath, filter_regex=r'klayout$')
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
klayoutPath = bundleExecPathAbs + '../Frameworks'
|
||||
depdict = WalkFrameworkPaths(klayoutPath, filter_regex=r'libklayout')
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs)
|
||||
|
||||
print(" [2.2] Patching /usr/local/opt/ libs")
|
||||
usrLocalPath = '/usr/local/opt/'
|
||||
appUsrLocalPath = '@executable_path/../Frameworks/'
|
||||
depdict = WalkFrameworkPaths(pythonFrameworkPath)
|
||||
PerformChanges(depdict, [(usrLocalPath, appUsrLocalPath)], bundleExecPathAbs)
|
||||
replacePairs = [(usrLocalPath, appUsrLocalPath, True)]
|
||||
depdict = WalkFrameworkPaths(pythonFrameworkPath, search_path_filter=r'\t+/usr/local/(opt|Cellar)')
|
||||
PerformChanges(depdict, replacePairs, bundleExecPathAbs)
|
||||
|
||||
# usrLocalPath = '/usr/local/lib/'
|
||||
# appUsrLocalPath = '@executable_path/../Frameworks/'
|
||||
# depdict = WalkFrameworkPaths(pythonFrameworkPath)
|
||||
# PerformChanges(depdict, [(usrLocalPath, appUsrLocalPath)], bundleExecPathAbs)
|
||||
print(" [2.3] Patching openssl, gdbm, readline, sqlite, tcl-tk, xz")
|
||||
usrLocalPath = '/usr/local/opt'
|
||||
appUsrLocalPath = '@executable_path/../Frameworks/'
|
||||
replacePairs = [(usrLocalPath, appUsrLocalPath, True)]
|
||||
replacePairs.extend([(openssl_version, '@executable_path/../Frameworks/openssl', True)
|
||||
for openssl_version in glob.glob('/usr/local/Cellar/openssl/*')])
|
||||
depdict = WalkFrameworkPaths([pythonFrameworkPath + '/../openssl',
|
||||
pythonFrameworkPath + '/../gdbm',
|
||||
pythonFrameworkPath + '/../readline',
|
||||
pythonFrameworkPath + '/../sqlite',
|
||||
pythonFrameworkPath + '/../tcl-tk',
|
||||
pythonFrameworkPath + '/../xz'], search_path_filter=r'\t+/usr/local/(opt|Cellar)')
|
||||
|
||||
PerformChanges(depdict, replacePairs, bundleExecPathAbs)
|
||||
|
||||
print(" [3] Relinking dylib dependencies for klayout")
|
||||
klayoutPath = bundleExecPathAbs
|
||||
depdict = WalkFrameworkPaths(klayoutPath, filter_regex=r'klayout$')
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs)
|
||||
|
||||
libKlayoutPath = bundleExecPathAbs + '../Frameworks'
|
||||
depdict = WalkFrameworkPaths(libKlayoutPath, filter_regex=r'libklayout')
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath, False)], bundleExecPathAbs)
|
||||
|
||||
print(" [4] Patching site.py, pip/, and distutils/")
|
||||
site_module = "%s/Versions/3.7/lib/python3.7/site.py" % pythonFrameworkPath
|
||||
with open(site_module, 'r') as site:
|
||||
buf = site.readlines()
|
||||
with open(site_module, 'w') as site:
|
||||
import re
|
||||
for line in buf:
|
||||
# This will fool pip into thinking it's inside a virtual environment
|
||||
# and install new packates to the correct site-packages
|
||||
if re.match("^PREFIXES", line) is not None:
|
||||
line = line + "sys.real_prefix = sys.prefix\n"
|
||||
# do not allow installation in the user folder.
|
||||
if re.match("^ENABLE_USER_SITE", line) is not None:
|
||||
line = "ENABLE_USER_SITE = False\n"
|
||||
site.write(line)
|
||||
|
||||
pip_module = "%s/Versions/3.7/lib/python3.7/site-packages/pip/__init__.py" % pythonFrameworkPath
|
||||
with open(pip_module, 'r') as pip:
|
||||
buf = pip.readlines()
|
||||
with open(pip_module, 'w') as pip:
|
||||
import re
|
||||
for line in buf:
|
||||
# this will reject user's configuration of pip, forcing the isolated mode
|
||||
line = re.sub("return isolated$", "return isolated or True", line)
|
||||
pip.write(line)
|
||||
|
||||
distutilsconfig = "%s/Versions/3.7/lib/python3.7/distutils/distutils.cfg" % pythonFrameworkPath
|
||||
with open(distutilsconfig, 'r') as file:
|
||||
buf = file.readlines()
|
||||
with open(distutilsconfig, 'w') as file:
|
||||
import re
|
||||
for line in buf:
|
||||
# This will cause all packages to be installed to sys.prefix
|
||||
if re.match('prefix=', line) is not None:
|
||||
continue
|
||||
file.write(line)
|
||||
|
||||
else:
|
||||
print( " [8] Skipped deploying Qt's Frameworks ..." )
|
||||
|
|
@ -925,9 +992,7 @@ def main():
|
|||
#----------------------------------------------------------
|
||||
ret = RunMainBuildBash()
|
||||
if not DeploymentF and not DeploymentP:
|
||||
if ret == 0:
|
||||
sys.exit(0)
|
||||
else:
|
||||
if not ret == 0:
|
||||
sys.exit(1)
|
||||
else:
|
||||
#----------------------------------------------------------
|
||||
|
|
@ -944,6 +1009,7 @@ def main():
|
|||
# to make "KLayoutEditor.app" and "KLayoutViewer.app"
|
||||
#----------------------------------------------------------
|
||||
ret2 = DeployScriptBundles()
|
||||
|
||||
if not ret2 == 0:
|
||||
sys.exit(1)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -18,14 +18,6 @@ import string
|
|||
import subprocess
|
||||
import shutil
|
||||
|
||||
CAN_DEPLOY_PYTHON = False
|
||||
try:
|
||||
from pathlib import Path
|
||||
Path('~').expanduser()
|
||||
CAN_DEPLOY_PYTHON = True
|
||||
except (ImportError,AttributeError): # python2
|
||||
print("Warning: Cannot import pathlib, use python3 if you need python deployment.")
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
## To import global dictionaries of different modules
|
||||
#-------------------------------------------------------------------------------
|
||||
|
|
@ -181,176 +173,167 @@ def SetChangeLibIdentificationName( executable, relativedir ):
|
|||
# for-lib
|
||||
return 0
|
||||
|
||||
# TODO: undocumented
|
||||
if CAN_DEPLOY_PYTHON:
|
||||
def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'):
|
||||
NOTHINGTODO = [] # return empty list if nothing to do.
|
||||
dylibPath = str(Path(dylibPath))
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
|
||||
otoolOut = os.popen( otoolCm ).read()
|
||||
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
|
||||
keys = exedepdic.keys()
|
||||
deplibs = exedepdic[ list(keys)[0] ]
|
||||
def WalkLibDependencyTree( dylibPath, depth=0, filter_regex=r'\t+/usr/local/opt'):
|
||||
NOTHINGTODO = [] # return empty list if nothing to do.
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
otoolCm = 'otool -L %s | grep -E "%s"' % (dylibPath, filter_regex)
|
||||
otoolOut = os.popen( otoolCm ).read()
|
||||
exedepdic = DecomposeLibraryDependency( dylibPath + ":\n" + otoolOut )
|
||||
keys = exedepdic.keys()
|
||||
deplibs = exedepdic[ list(keys)[0] ]
|
||||
|
||||
if depth < 5:
|
||||
if len(deplibs) > 0:
|
||||
for idx, lib in enumerate(deplibs):
|
||||
lib = str(Path(lib))
|
||||
if lib != list(keys)[0]:
|
||||
deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
|
||||
else:
|
||||
return NOTHINGTODO
|
||||
if depth == 0:
|
||||
return deplibs
|
||||
return exedepdic
|
||||
if depth < 5:
|
||||
if len(deplibs) > 0:
|
||||
for idx, lib in enumerate(deplibs):
|
||||
lib = str(lib)
|
||||
if lib != list(keys)[0]:
|
||||
deplibs[idx] = WalkLibDependencyTree(lib, depth+1, filter_regex)
|
||||
if depth == 0:
|
||||
return deplibs
|
||||
return exedepdic
|
||||
else:
|
||||
raise RuntimeError("Exceeded maximum recursion depth.")
|
||||
|
||||
def WalkFrameworkPaths(frameworkPaths, filter_regex=r'\.(so|dylib)$', search_path_filter=r'\t+/usr/local/opt'):
|
||||
|
||||
if isinstance(frameworkPaths, str):
|
||||
frameworkPathsIter = [frameworkPaths]
|
||||
else:
|
||||
frameworkPathsIter = frameworkPaths
|
||||
|
||||
dependency_dict = dict()
|
||||
|
||||
for frameworkPath in frameworkPathsIter:
|
||||
# print("Calling:", 'find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex))
|
||||
find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
|
||||
framework_files = filter(lambda x: x != '',
|
||||
map(lambda x: x.strip(),
|
||||
find_grep_results))
|
||||
|
||||
dependency_dict[frameworkPath] = list()
|
||||
for idx, file in enumerate(framework_files):
|
||||
dict_file = {file: WalkLibDependencyTree(file, filter_regex=search_path_filter)}
|
||||
dependency_dict[frameworkPath].append(dict_file)
|
||||
return dependency_dict
|
||||
|
||||
def WalkDictTree(dependencyDict, visited_files):
|
||||
libNameChanges = list()
|
||||
for lib, dependencies in dependencyDict.items():
|
||||
if lib in visited_files:
|
||||
continue
|
||||
|
||||
dependency_list = list()
|
||||
if isinstance(dependencies, list):
|
||||
for deplib in dependencies:
|
||||
if isinstance(deplib, str):
|
||||
dependency_list.append(deplib)
|
||||
if deplib not in visited_files:
|
||||
visited_files.append(deplib)
|
||||
elif isinstance(deplib, dict):
|
||||
dependency_list.append(next(iter(deplib)))
|
||||
libNameChanges.extend(WalkDictTree(deplib, visited_files))
|
||||
else:
|
||||
#raise RuntimeError("Unexpected value: %s" % deplib)
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError("Exceeded maximum recursion depth.")
|
||||
raise RuntimeError("Unexpected value: %s" % dependencies)
|
||||
if len(dependency_list) > 0:
|
||||
libNameChanges.append((lib, dependency_list))
|
||||
else:
|
||||
libNameChanges.append((lib, ))
|
||||
visited_files.append(lib)
|
||||
return libNameChanges
|
||||
|
||||
def WalkFrameworkPaths(frameworkPaths, filter_regex=r'\.(so|dylib)$'):
|
||||
try:
|
||||
frameworkPathsIter = iter(frameworkPaths)
|
||||
except TypeError:
|
||||
frameworkPathsIter = [frameworkPaths]
|
||||
|
||||
dependency_dict = dict()
|
||||
def FindFramework(path, root_path):
|
||||
relPath = os.path.relpath(path, root_path)
|
||||
return os.path.join(root_path, relPath.split(os.sep)[0])
|
||||
def ResolveExecutablePath(path, executable_path):
|
||||
""" Transforms @executable_path into executable_path"""
|
||||
p = path.replace("@executable_path", "/%s/" % executable_path)
|
||||
return p
|
||||
|
||||
for frameworkPath in frameworkPaths:
|
||||
frameworkPath = str(Path(frameworkPath))
|
||||
find_grep_results = os.popen('find %s -type f | grep -E "%s"' % (frameworkPath, filter_regex)).read().split('\n')
|
||||
framework_files = filter(lambda x: x != '',
|
||||
map(lambda x: x.strip(),
|
||||
find_grep_results))
|
||||
def DetectChanges(frameworkDependencyDict):
|
||||
visited_files = list()
|
||||
libNameChanges = list()
|
||||
for framework, libraries in frameworkDependencyDict.items():
|
||||
for libraryDict in libraries:
|
||||
libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
|
||||
# Changes are stored in libNameChanges in the form of ('lib.dylib', ['dep1.dylib', ...])
|
||||
|
||||
dependency_dict[frameworkPath] = list()
|
||||
for idx, file in enumerate(framework_files):
|
||||
dict_file = {file: WalkLibDependencyTree(file)}
|
||||
dependency_dict[frameworkPath].append(dict_file)
|
||||
return dependency_dict
|
||||
return libNameChanges
|
||||
|
||||
def WalkDictTree(dependencyDict, visited_files):
|
||||
libNameChanges = list()
|
||||
for lib, dependencies in dependencyDict.items():
|
||||
if lib in visited_files:
|
||||
continue
|
||||
def PerformChanges(frameworkDependencyDict, replaceFromToPairs=None, executable_path="/tmp/klayout"):
|
||||
libNameChanges = DetectChanges(frameworkDependencyDict)
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
|
||||
dependency_list = list()
|
||||
if isinstance(dependencies, list):
|
||||
for deplib in dependencies:
|
||||
if isinstance(deplib, str):
|
||||
dependency_list.append(deplib)
|
||||
if deplib not in visited_files:
|
||||
visited_files.append(deplib)
|
||||
elif isinstance(deplib, dict):
|
||||
dependency_list.append(str(next(iter(deplib))))
|
||||
libNameChanges.extend(WalkDictTree(deplib, visited_files))
|
||||
if replaceFromToPairs is not None:
|
||||
for libNameChange in libNameChanges:
|
||||
libNameChangeIterator = iter(libNameChange)
|
||||
lib = next(libNameChangeIterator)
|
||||
try:
|
||||
dependencies = next(libNameChangeIterator)
|
||||
except StopIteration:
|
||||
dependencies = list()
|
||||
for replaceFrom, replaceTo, libdir in replaceFromToPairs:
|
||||
fileName = ResolveExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
|
||||
if fileName.startswith('/usr'):
|
||||
# print(f'skipping fileName: {fileName}')
|
||||
continue
|
||||
|
||||
if lib.find(replaceFrom) >= 0:
|
||||
if libdir:
|
||||
frameworkPath = FindFramework(lib, replaceFrom)
|
||||
else:
|
||||
#raise RuntimeError("Unexpected value: %s" % deplib)
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError("Unexpected value: %s" % dependencies)
|
||||
if len(dependency_list) > 0:
|
||||
libNameChanges.append((lib, dependency_list))
|
||||
else:
|
||||
libNameChanges.append((lib, ))
|
||||
visited_files.append(lib)
|
||||
return libNameChanges
|
||||
frameworkPath = lib
|
||||
destFrameworkPath = frameworkPath.replace(replaceFrom, replaceTo)
|
||||
destFrameworkPath = ResolveExecutablePath(destFrameworkPath, executable_path)
|
||||
|
||||
def FindFramework(path, root_path):
|
||||
path = Path(path)
|
||||
root_path = Path(root_path)
|
||||
relPath = path.relative_to(root_path)
|
||||
return str(root_path / relPath.parts[0])
|
||||
if not os.path.exists(fileName):
|
||||
print (lib.replace(replaceFrom, replaceTo), "DOES NOT EXIST")
|
||||
print ("COPY", frameworkPath, " -> ", destFrameworkPath)
|
||||
shutil.copytree(frameworkPath, destFrameworkPath)
|
||||
|
||||
def ReplaceExecutablePath(path, executable_path):
|
||||
executable_path = str(executable_path)
|
||||
p = Path(str(path).replace("@executable_path", "/%s/" % executable_path))
|
||||
return p
|
||||
nameId = lib.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
|
||||
if not os.access(fileName, os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
def FileExists(file_path, executable_path):
|
||||
p = ReplaceExecutablePath(file_path, executable_path)
|
||||
return p.exists()
|
||||
for dependency in dependencies:
|
||||
if dependency.find(replaceFrom) >= 0:
|
||||
print("\tIn:", fileName)
|
||||
print("\tRENAME", dependency, " -> ", dependency.replace(replaceFrom, replaceTo))
|
||||
|
||||
def DetectChanges(frameworkDependencyDict):
|
||||
visited_files = list()
|
||||
libNameChanges = list()
|
||||
for framework, libraries in frameworkDependencyDict.items():
|
||||
for libraryDict in libraries:
|
||||
libNameChanges.extend(WalkDictTree(libraryDict, visited_files))
|
||||
# Changes are stored in libNameChanges in the form of ('lib.dylib', ['dep1.dylib', ...])
|
||||
|
||||
return libNameChanges
|
||||
|
||||
def PerformChanges(frameworkDependencyDict, replaceFromToPairs=None, executable_path="/tmp/klayout", libdir=False):
|
||||
libNameChanges = DetectChanges(frameworkDependencyDict)
|
||||
cmdNameId = XcodeToolChain['nameID']
|
||||
cmdNameChg = XcodeToolChain['nameCH']
|
||||
|
||||
if replaceFromToPairs is not None:
|
||||
for libNameChange in libNameChanges:
|
||||
libNameChangeIterator = iter(libNameChange)
|
||||
lib = next(libNameChangeIterator)
|
||||
try:
|
||||
dependencies = next(libNameChangeIterator)
|
||||
except StopIteration:
|
||||
dependencies = list()
|
||||
for replaceFrom, replaceTo in replaceFromToPairs:
|
||||
replaceFrom = str(Path(replaceFrom))
|
||||
replaceTo = str(Path(replaceTo))
|
||||
|
||||
if lib.find(replaceFrom) >= 0:
|
||||
if libdir:
|
||||
frameworkPath = FindFramework(lib, replaceFrom)
|
||||
else:
|
||||
frameworkPath = lib
|
||||
destFrameworkPath = frameworkPath.replace(replaceFrom, replaceTo)
|
||||
destFrameworkPath = ReplaceExecutablePath(destFrameworkPath, executable_path)
|
||||
if not FileExists(lib.replace(replaceFrom, replaceTo), executable_path):
|
||||
print (lib.replace(replaceFrom, replaceTo), "DOES NOT EXIST")
|
||||
print ("COPY", frameworkPath, " -> ", destFrameworkPath)
|
||||
shutil.copytree(frameworkPath, destFrameworkPath)
|
||||
|
||||
fileName = ReplaceExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
|
||||
nameId = lib.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
|
||||
if not os.access(fileName, os.W_OK):
|
||||
# Try changing id first
|
||||
nameId = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName)
|
||||
if not os.access(str(fileName), os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
print("\t%s" % command)
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
fileName = ReplaceExecutablePath(lib.replace(replaceFrom, replaceTo), executable_path)
|
||||
for dependency in dependencies:
|
||||
if dependency.find(replaceFrom) >= 0:
|
||||
print("In:", fileName)
|
||||
print("\tRENAME", dependency, " -> ", dependency.replace(replaceFrom, replaceTo))
|
||||
# Rename dependencies
|
||||
nameOld = dependency
|
||||
nameNew = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, str(fileName) )
|
||||
if not os.access(str(fileName), os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
|
||||
# Try changing id first
|
||||
nameId = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s" % ( cmdNameId, nameId, fileName )
|
||||
if not os.access(fileName, os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
# Rename dependencies
|
||||
nameOld = dependency
|
||||
nameNew = dependency.replace(replaceFrom, replaceTo)
|
||||
command = "%s %s %s %s" % ( cmdNameChg, nameOld, nameNew, fileName )
|
||||
if not os.access(fileName, os.W_OK):
|
||||
command = "chmod u+w %s; %s; chmod u-w %s" % (fileName, command, fileName)
|
||||
|
||||
print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
# print("\t%s" % command)
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "!!! Failed to set the new identification name to <%s> !!!"
|
||||
print( msg % fileName, file=sys.stderr )
|
||||
return 1
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -89,10 +89,15 @@ cd ..
|
|||
mkdir -p makedeb-tmp/${sharedir}/doc/klayout
|
||||
mkdir -p makedeb-tmp/${sharedir}/applications
|
||||
mkdir -p makedeb-tmp/${sharedir}/pixmaps
|
||||
<<<<<<< HEAD
|
||||
mkdir -p makedeb-tmp/${libdir}/db_plugins
|
||||
mkdir -p makedeb-tmp/${libdir}/lay_plugins
|
||||
mkdir -p makedeb-tmp/${pylibdir}
|
||||
mkdir -p makedeb-tmp/${bindir}
|
||||
=======
|
||||
mkdir -p makedeb-tmp/${bindir}
|
||||
mkdir -p makedeb-tmp/${libdir}
|
||||
>>>>>>> master
|
||||
|
||||
cp etc/klayout.desktop makedeb-tmp/${sharedir}/applications
|
||||
cp etc/logo.png makedeb-tmp/${sharedir}/pixmaps
|
||||
|
|
@ -103,10 +108,13 @@ cp COPYRIGHT makedeb-tmp/${sharedir}/doc/klayout/copyright
|
|||
cp -pd $bininstdir/strm* makedeb-tmp/${bindir}
|
||||
cp -pd $bininstdir/klayout makedeb-tmp/${bindir}
|
||||
cp -pd $bininstdir/lib*so* makedeb-tmp/${libdir}
|
||||
<<<<<<< HEAD
|
||||
cp -pd $bininstdir/db_plugins/lib*so* makedeb-tmp/${libdir}/db_plugins
|
||||
cp -pd $bininstdir/lay_plugins/lib*so* makedeb-tmp/${libdir}/lay_plugins
|
||||
cp -pd $bininstdir/pymod/klayout/*so makedeb-tmp/${pylibdir}
|
||||
cp -pd $bininstdir/pymod/klayout/*py makedeb-tmp/${pylibdir}
|
||||
=======
|
||||
>>>>>>> master
|
||||
|
||||
cd makedeb-tmp
|
||||
|
||||
|
|
@ -131,9 +139,12 @@ echo "Modifying control file .."
|
|||
|
||||
strip ${bindir}/*
|
||||
strip ${libdir}/*.so*
|
||||
<<<<<<< HEAD
|
||||
strip ${pylibdir}/*.so
|
||||
strip ${libdir}/db_plugins/*.so*
|
||||
strip ${libdir}/lay_plugins/*.so*
|
||||
=======
|
||||
>>>>>>> master
|
||||
|
||||
size=`du -ck usr | grep total | sed "s/ *total//"`
|
||||
|
||||
|
|
|
|||
|
|
@ -864,10 +864,10 @@ no_imports "QAbstractXmlNodeModel" # base class is QSharedData which is not ava
|
|||
# QtNetwork
|
||||
|
||||
drop_method "QUrlInfo", /QUrlInfo::QUrlInfo\(.*permissions/ # too many arguments (13)
|
||||
drop_method "QHostAddress", /QHostAddress::QHostAddress\(\s*quint8\s*\*/ # requires char *, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::QHostAddress\(\s*(const\s*)?quint8\s*\*/ # requires char *, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::QHostAddress\(\s*const\s+QIPv6Address/ # requires QIPv6Address struct, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::QHostAddress\(\s*const\s+sockaddr/ # requires sockaddr struct, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::setAddress\(\s*quint8\s*\*/ # requires char *, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::setAddress\(\s*(const\s*)?quint8\s*\*/ # requires char *, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::setAddress\(\s*const\s+QIPv6Address/ # requires QIPv6Address struct, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::setAddress\(\s*const\s+sockaddr/ # requires sockaddr struct, a string version is available for IPv6
|
||||
drop_method "QHostAddress", /QHostAddress::toIPv6Address\(/ # requires QIPv6Address struct
|
||||
|
|
|
|||
|
|
@ -77,6 +77,14 @@ Requires: libqt4-x11 >= 4.8.7
|
|||
%define pylib %{python3_sitearch}
|
||||
%endif
|
||||
|
||||
%if "%{target_system}" == "opensuse15"
|
||||
# OpenSuSE Leap 15 requirements
|
||||
Requires: ruby >= 2.5
|
||||
Requires: python3 >= 3.6
|
||||
Requires: libqt4-x11 >= 4.8.7
|
||||
%define buildopt -j2
|
||||
%endif
|
||||
|
||||
%description
|
||||
Mask layout viewer and editor for the chip design engineer.
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ TEST(1)
|
|||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string path = tl::combine_path (".", "strmrun ") + fp;
|
||||
std::string path = tl::combine_path (tl::get_inst_path (), "strmrun ") + fp;
|
||||
tl::InputPipe pipe (path);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
|
|
|
|||
|
|
@ -22,6 +22,41 @@
|
|||
|
||||
|
||||
#include "dbEdge.h"
|
||||
#include "tlLongInt.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Computes the gcd of two numbers
|
||||
*/
|
||||
template <class C>
|
||||
inline C gcd (C a, C b)
|
||||
{
|
||||
while (b != 0) {
|
||||
a %= b;
|
||||
std::swap (a, b);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
typedef __int128 a2_type;
|
||||
#else
|
||||
// fallback to long_int in case the __int128 isn't defined
|
||||
typedef tl::long_int<4, uint32_t, uint64_t> a2_type;
|
||||
#endif
|
||||
|
||||
db::Coord div_exact (db::Coord a, db::coord_traits<db::Coord>::area_type b, db::coord_traits<db::Coord>::area_type d)
|
||||
{
|
||||
if (a < 0) {
|
||||
return -db::Coord ((a2_type (-a) * a2_type (b) + a2_type (d / 2)) / a2_type (d));
|
||||
} else {
|
||||
return db::Coord ((a2_type (a) * a2_type (b) + a2_type ((d - 1) / 2)) / a2_type (d));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,6 +38,25 @@
|
|||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief A helper function for dividing integers with exact rounding
|
||||
* This function computes (a*b/d) where rounding is exact in the sense of:
|
||||
* a*b/d == N+0.5 => div_exact(a*b/d) = N
|
||||
* b and d needs to be positive.
|
||||
* a can be positive or negative.
|
||||
* The implementation uses the gcd to reduce the ratios. This way we can
|
||||
* represent the numbers with the area type.
|
||||
*/
|
||||
db::Coord DB_PUBLIC div_exact (db::Coord a, db::coord_traits<db::Coord>::area_type b, db::coord_traits<db::Coord>::area_type d);
|
||||
|
||||
/**
|
||||
* @brief An overload of div_exact for double types
|
||||
*/
|
||||
inline db::DCoord div_exact (db::DCoord a, db::coord_traits<db::DCoord>::area_type b, db::coord_traits<db::DCoord>::area_type d)
|
||||
{
|
||||
return db::coord_traits<db::DCoord>::rounded (double (a) * double (b) / double (d));
|
||||
}
|
||||
|
||||
template <class C> class generic_repository;
|
||||
class ArrayRepository;
|
||||
|
||||
|
|
@ -794,10 +813,15 @@ public:
|
|||
|
||||
} else if (res) {
|
||||
|
||||
double f = fabs (double (vxa)) / (fabs (double (vxa)) + fabs (double (vxb)));
|
||||
if (vxa < 0) {
|
||||
vxa = -vxa;
|
||||
}
|
||||
if (vxb < 0) {
|
||||
vxb = -vxb;
|
||||
}
|
||||
|
||||
coord_type x = m_p1.x () + coord_traits::rounded (dx () * f);
|
||||
coord_type y = m_p1.y () + coord_traits::rounded (dy () * f);
|
||||
coord_type x = m_p1.x () + div_exact (dx (), vxa, vxa + vxb);
|
||||
coord_type y = m_p1.y () + div_exact (dy (), vxa, vxa + vxb);
|
||||
|
||||
return std::make_pair (true, db::point<C> (x, y));
|
||||
|
||||
|
|
@ -1073,10 +1097,15 @@ public:
|
|||
|
||||
if (res) {
|
||||
|
||||
double f = fabs (double (vxa)) / (fabs (double (vxa)) + fabs (double (vxb)));
|
||||
if (vxa < 0) {
|
||||
vxa = -vxa;
|
||||
}
|
||||
if (vxb < 0) {
|
||||
vxb = -vxb;
|
||||
}
|
||||
|
||||
coord_type x = e.p1 ().x () + coord_traits::rounded (e.dx () * f);
|
||||
coord_type y = e.p1 ().y () + coord_traits::rounded (e.dy () * f);
|
||||
coord_type x = e.p1 ().x () + div_exact (e.dx (), vxa, vxa + vxb);
|
||||
coord_type y = e.p1 ().y () + div_exact (e.dy (), vxa, vxa + vxb);
|
||||
|
||||
return std::make_pair (true, db::point<C> (x, y));
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,26 @@ private:
|
|||
db::Coord m_y;
|
||||
};
|
||||
|
||||
inline bool
|
||||
is_point_on_exact (const db::Edge &e, const db::Point &pt)
|
||||
{
|
||||
if (pt.x () < db::edge_xmin (e) || pt.x () > db::edge_xmax (e) ||
|
||||
pt.y () < db::edge_ymin (e) || pt.y () > db::edge_ymax (e)) {
|
||||
|
||||
return false;
|
||||
|
||||
} else if (e.dy () == 0 || e.dx () == 0) {
|
||||
|
||||
// shortcut for orthogonal edges
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return db::vprod_sign (pt - e.p1 (), e.p2 () - e.p1 ()) == 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_point_on_fuzzy (const db::Edge &e, const db::Point &pt)
|
||||
{
|
||||
|
|
@ -141,9 +161,12 @@ is_point_on_fuzzy (const db::Edge &e, const db::Point &pt)
|
|||
|
||||
} else {
|
||||
|
||||
bool with_equal = false;
|
||||
|
||||
db::Vector offset;
|
||||
if ((e.dx () < 0 && e.dy () > 0) || (e.dx () > 0 && e.dy () < 0)) {
|
||||
offset = db::Vector (1, 1);
|
||||
with_equal = true;
|
||||
} else {
|
||||
offset = db::Vector (-1, 1);
|
||||
}
|
||||
|
|
@ -152,30 +175,16 @@ is_point_on_fuzzy (const db::Edge &e, const db::Point &pt)
|
|||
|
||||
typedef db::coord_traits<db::Point::coord_type>::area_type area_type;
|
||||
area_type a1 = 2 * db::vprod (pp1, e.d ());
|
||||
if (a1 < 0) { a1 = -a1; }
|
||||
area_type a2 = db::vprod (offset, e.d ());
|
||||
|
||||
if ((a1 < 0) == (a2 < 0)) {
|
||||
with_equal = false;
|
||||
}
|
||||
|
||||
if (a1 < 0) { a1 = -a1; }
|
||||
if (a2 < 0) { a2 = -a2; }
|
||||
return a1 <= a2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_point_on_exact (const db::Edge &e, const db::Point &pt)
|
||||
{
|
||||
if (pt.x () < db::edge_xmin (e) || pt.x () > db::edge_xmax (e) ||
|
||||
pt.y () < db::edge_ymin (e) || pt.y () > db::edge_ymax (e)) {
|
||||
|
||||
return false;
|
||||
|
||||
} else if (e.dy () == 0 || e.dx () == 0) {
|
||||
|
||||
// shortcut for orthogonal edges
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return db::vprod_sign (pt - e.p1 (), e.p2 () - e.p1 ()) == 0;
|
||||
return a1 < a2 || (a1 == a2 && with_equal);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -804,7 +813,7 @@ MergeOp::edge (bool north, bool enter, property_type p)
|
|||
bool inside_after = (*wcv != 0);
|
||||
m_zeroes += (!inside_after) - (!inside_before);
|
||||
#ifdef DEBUG_MERGEOP
|
||||
printf ("north=%d, enter=%d, prop=%d -> %d\n", north, enter, p, m_zeroes);
|
||||
printf ("north=%d, enter=%d, prop=%d -> %d\n", north, enter, int (p), int (m_zeroes));
|
||||
#endif
|
||||
tl_assert (long (m_zeroes) >= 0);
|
||||
|
||||
|
|
@ -887,7 +896,7 @@ BooleanOp::edge_impl (bool north, bool enter, property_type p, const InsideFunc
|
|||
bool inside_after = ((p % 2) == 0 ? inside_a (*wcv) : inside_b (*wcv));
|
||||
m_zeroes += (!inside_after) - (!inside_before);
|
||||
#ifdef DEBUG_BOOLEAN
|
||||
printf ("north=%d, enter=%d, prop=%d -> %d\n", north, enter, p, m_zeroes);
|
||||
printf ("north=%d, enter=%d, prop=%d -> %d\n", north, enter, int (p), int (m_zeroes));
|
||||
#endif
|
||||
tl_assert (long (m_zeroes) >= 0);
|
||||
|
||||
|
|
@ -1345,32 +1354,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
#endif
|
||||
|
||||
// The new cutpoint must be inserted into other edges as well.
|
||||
// If the cutpoint is exactly on the edge and there is just one other edge
|
||||
// the cutpoint will be a weak attractor - that is an optional cutpoint.
|
||||
// In that case we can skip the cutpoint because no related edge will move.
|
||||
ip_weak.clear ();
|
||||
size_t n_off_edge = on_edge1 ? 0 : 1;
|
||||
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
||||
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
|
||||
ip_weak.push_back (&*cc);
|
||||
if (!is_point_on_exact (*cc, cp.second)) {
|
||||
++n_off_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
|
||||
if (n_off_edge > 1) {
|
||||
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
||||
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
||||
#endif
|
||||
} else {
|
||||
CutPoints *cpp = (*icc)->make_cutpoints (cutpoints);
|
||||
cpp->add_attractor (cp.second, (*icc)->data - 1);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("intersection point %s gives weak attractor in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1435,38 +1429,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
#endif
|
||||
|
||||
// The new cutpoint must be inserted into other edges as well.
|
||||
// If the cutpoint is exactly on the edge and there is just one other edge
|
||||
// the cutpoint will be a weak attractor - that is an optional cutpoint.
|
||||
// In that case we can skip the cutpoint because no related edge will move.
|
||||
ip_weak.clear ();
|
||||
size_t n_off_edge = 0;
|
||||
if (!on_edge1) {
|
||||
n_off_edge += 1;
|
||||
}
|
||||
if (!on_edge2) {
|
||||
n_off_edge += 1;
|
||||
}
|
||||
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
||||
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
|
||||
ip_weak.push_back (&*cc);
|
||||
if (!is_point_on_exact (*cc, cp.second)) {
|
||||
++n_off_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
|
||||
if (n_off_edge > 1) {
|
||||
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
||||
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
||||
#endif
|
||||
} else {
|
||||
CutPoints *cpp = (*icc)->make_cutpoints (cutpoints);
|
||||
cpp->add_attractor (cp.second, (*icc)->data - 1);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("intersection point %s gives weak attractor in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1829,7 +1802,7 @@ EdgeProcessor::process (db::EdgeSink &es, EdgeEvaluatorBase &op)
|
|||
size_t skip = c->data % skip_unit;
|
||||
size_t skip_res = c->data / skip_unit;
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("X %ld->%d,%d\n", long(c->data), skip, skip_res);
|
||||
printf ("X %ld->%d,%d\n", long (c->data), int (skip), int (skip_res));
|
||||
#endif
|
||||
|
||||
if (skip != 0 && (c + skip >= future || (c + skip)->data != 0)) {
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ PolygonGenerator::flush ()
|
|||
{
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
|
||||
printf ("%d:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
|
||||
printf ("%ld:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
|
@ -325,12 +325,12 @@ PolygonGenerator::begin_scanline (db::Coord y)
|
|||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("m_open=");
|
||||
for (open_map_type::const_iterator o = m_open.begin (); o != m_open.end (); ++o) {
|
||||
printf ("%d:%s ", o->contour, o->point.to_string().c_str());
|
||||
printf ("%ld:%s ", o->contour, o->point.to_string().c_str());
|
||||
}
|
||||
printf ("\n");
|
||||
printf ("contours:\n");
|
||||
for (size_t j = 0; j < mp_contours->size (); ++j) {
|
||||
printf ("c%d%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
|
||||
printf ("c%ld%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
|
||||
for (size_t i = 0; i < (*mp_contours)[j].size (); ++i) {
|
||||
printf ("%s ", ((*mp_contours)[j].begin () + i)->to_string().c_str ());
|
||||
}
|
||||
|
|
@ -364,7 +364,7 @@ PolygonGenerator::skip_n (size_t n)
|
|||
{
|
||||
join_contours (std::numeric_limits<db::Coord>::max ());
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("skip(%d)\n", n);
|
||||
printf ("skip(%ld)\n", n);
|
||||
#endif
|
||||
while (n-- > 0) {
|
||||
++m_open_pos;
|
||||
|
|
@ -375,9 +375,9 @@ void
|
|||
PolygonGenerator::put (const db::Edge &e)
|
||||
{
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("put(%s) y=%d m_open(%d)=", e.to_string().c_str(),m_y,std::distance (m_open.begin (), m_open_pos));
|
||||
printf ("put(%s) y=%d m_open(%ld)=", e.to_string().c_str(),m_y,std::distance (m_open.begin (), m_open_pos));
|
||||
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
|
||||
printf ("%d:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
|
||||
printf ("%ld:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
|
@ -438,7 +438,7 @@ PolygonGenerator::put (const db::Edge &e)
|
|||
cnew.push_back (e.p2 ());
|
||||
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("create %s %d\n", hole ? "hole" : "hull", poly_index);
|
||||
printf ("create %s %ld\n", hole ? "hole" : "hull", inew);
|
||||
#endif
|
||||
m_open.insert (m_open_pos, PGPoint (hole ? e.p1 () : e.p2 (), inew, true));
|
||||
m_open.insert (m_open_pos, PGPoint (hole ? e.p2 () : e.p1 (), inew, false));
|
||||
|
|
@ -449,7 +449,7 @@ PolygonGenerator::put (const db::Edge &e)
|
|||
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
|
||||
printf ("%d:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
|
||||
printf ("%ld:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
|
@ -552,14 +552,14 @@ PolygonGenerator::join_contours (db::Coord x)
|
|||
size_t i1 = m_open_pos->contour;
|
||||
size_t i2 = n->contour;
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("join %d and %d\n", i1, i2);
|
||||
printf ("join %ld and %ld\n", i1, i2);
|
||||
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
|
||||
printf ("%d:%s%c%c%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ', i == n ? '+' : ' ', i == nn ? '#' : ' ');
|
||||
printf ("%ld:%s%c%c%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ', i == n ? '+' : ' ', i == nn ? '#' : ' ');
|
||||
}
|
||||
printf ("\n");
|
||||
printf ("--> input contours:\n");
|
||||
for (size_t j = 0; j < mp_contours->size (); ++j) {
|
||||
printf ("--> c%d%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
|
||||
printf ("--> c%ld%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
|
||||
for (size_t i = 0; i < (*mp_contours)[j].size (); ++i) {
|
||||
printf ("%s ", ((*mp_contours)[j].begin () + i)->to_string().c_str ());
|
||||
}
|
||||
|
|
@ -705,7 +705,7 @@ PolygonGenerator::join_contours (db::Coord x)
|
|||
if (! c1.is_hole ()) {
|
||||
|
||||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("finish %d (hull)\n", i1);
|
||||
printf ("finish %ld (hull)\n", i1);
|
||||
#endif
|
||||
|
||||
produce_poly (c1);
|
||||
|
|
@ -775,7 +775,7 @@ PolygonGenerator::join_contours (db::Coord x)
|
|||
#ifdef DEBUG_POLYGON_GENERATOR
|
||||
printf ("--> output contours:\n");
|
||||
for (size_t j = 0; j < mp_contours->size (); ++j) {
|
||||
printf ("--> c%d%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
|
||||
printf ("--> c%ld%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
|
||||
for (size_t i = 0; i < (*mp_contours)[j].size (); ++i) {
|
||||
printf ("%s ", ((*mp_contours)[j].begin () + i)->to_string().c_str ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
) +
|
||||
gsi::method ("region=", (void (db::RecursiveShapeIterator::*)(const db::RecursiveShapeIterator::box_type &)) &db::RecursiveShapeIterator::set_region,
|
||||
"@brief Sets the rectangular region that is iterator is iterating over\n"
|
||||
"@args region\n"
|
||||
"@args box_region\n"
|
||||
"See \\region for a description of this attribute.\n"
|
||||
"Setting a simple region will reset the complex region to a rectangle and reset the iterator to "
|
||||
"the beginning of the sequence."
|
||||
|
|
@ -298,15 +298,19 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
) +
|
||||
gsi::method ("confine_region", (void (db::RecursiveShapeIterator::*)(const db::RecursiveShapeIterator::box_type &)) &db::RecursiveShapeIterator::confine_region,
|
||||
"@brief Confines the region that is iterator is iterating over\n"
|
||||
"@args region\n"
|
||||
"This method is similar to setting the region (see \\region=), but will add to any (complex or simple) region already set. "
|
||||
"@args box_region\n"
|
||||
"This method is similar to setting the region (see \\region=), but will confine any region (complex or simple) already set. "
|
||||
"Essentially it does a logical AND operation between the existing and given region. "
|
||||
"Hence this method can only reduce a region, not extend it.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25.\n"
|
||||
) +
|
||||
gsi::method ("region=", (void (db::RecursiveShapeIterator::*)(const db::RecursiveShapeIterator::region_type &)) &db::RecursiveShapeIterator::confine_region,
|
||||
gsi::method ("confine_region", (void (db::RecursiveShapeIterator::*)(const db::RecursiveShapeIterator::region_type &)) &db::RecursiveShapeIterator::confine_region,
|
||||
"@brief Confines the region that is iterator is iterating over\n"
|
||||
"@args region\n"
|
||||
"This method is similar to setting the complex region (see \\region=), but will add to any (complex or simple) region already set."
|
||||
"@args complex_region\n"
|
||||
"This method is similar to setting the region (see \\region=), but will confine any region (complex or simple) already set. "
|
||||
"Essentially it does a logical AND operation between the existing and given region. "
|
||||
"Hence this method can only reduce a region, not extend it.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25.\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -50,6 +50,21 @@ static void dump_mem_statistics (const db::Shapes *shapes, bool detailed)
|
|||
ms.print ();
|
||||
}
|
||||
|
||||
static size_t shapes_size (const db::Shapes *shapes)
|
||||
{
|
||||
// we may have shape arrays - expand their count to match the shape count with the shapes delivered
|
||||
size_t n = 0;
|
||||
for (db::Shapes::shape_iterator i = shapes->begin (db::ShapeIterator::All); ! i.at_end (); ++i) {
|
||||
if (i.in_array ()) {
|
||||
n += i.array ().array_size ();
|
||||
i.finish_array ();
|
||||
} else {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class Sh>
|
||||
static db::Shape insert (db::Shapes *s, const Sh &p)
|
||||
{
|
||||
|
|
@ -1088,7 +1103,7 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"@brief Clears the shape container\n"
|
||||
"This method has been introduced in version 0.16. It can only be used in editable mode."
|
||||
) +
|
||||
gsi::method ("size", (size_t (db::Shapes::*)() const) &db::Shapes::size,
|
||||
gsi::method_ext ("size", &shapes_size,
|
||||
"@brief Gets the number of shapes in this container\n"
|
||||
"This method was introduced in version 0.16\n"
|
||||
"@return The number of shapes in this container\n"
|
||||
|
|
|
|||
|
|
@ -514,3 +514,74 @@ TEST(14)
|
|||
EXPECT_EQ (e.coincident (db::Edge (db::Point (49, 0), db::Point (200, 0))), false);
|
||||
}
|
||||
|
||||
// exact rounding behaviour
|
||||
TEST(15)
|
||||
{
|
||||
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||
// div_exact(a, b, d) computes a*b/d with exact rounding behaviour
|
||||
EXPECT_EQ (db::div_exact (area_type (0), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5), area_type (0), area_type (176)), 0);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (3), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (4), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (7), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (8), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (12), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (13), area_type (22), area_type (176)), 2);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (3 * 11), area_type (2), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (4 * 11), area_type (2), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (7 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (8 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (12 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (13 * 11), area_type (2), area_type (176)), 2);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (-3), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-7), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-8), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-12), area_type (22), area_type (176)), -2);
|
||||
EXPECT_EQ (db::div_exact (area_type (-13), area_type (22), area_type (176)), -2);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (-3 * 11), area_type (2), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-7 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-8 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-12 * 11), area_type (2), area_type (176)), -2);
|
||||
EXPECT_EQ (db::div_exact (area_type (-13 * 11), area_type (2), area_type (176)), -2);
|
||||
|
||||
area_type f = 790014345;
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (4), area_type (22) * f, area_type (176) * f), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5), area_type (22) * f, area_type (176) * f), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (8), area_type (22) * f, area_type (176) * f), 1);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (-3), area_type (22) * f, area_type (176) * f), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4), area_type (22) * f, area_type (176) * f), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5), area_type (22) * f, area_type (176) * f), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-8), area_type (22) * f, area_type (176) * f), -1);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (4) * 100000000, area_type (22) * f, area_type (176) * f), 50000000);
|
||||
EXPECT_EQ (db::div_exact (area_type (5) * 100000000, area_type (22) * f, area_type (176) * f), 62500000);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4) * 100000000, area_type (22) * f, area_type (176) * f), -50000000);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5) * 100000000, area_type (22) * f, area_type (176) * f), -62500000);
|
||||
|
||||
EXPECT_EQ (db::div_exact (1000000004, area_type (22) * f, area_type (176) * f), 125000000);
|
||||
EXPECT_EQ (db::div_exact (1000000005, area_type (22) * f, area_type (176) * f), 125000001);
|
||||
EXPECT_EQ (db::div_exact (-1000000003, area_type (22) * f, area_type (176) * f), -125000000);
|
||||
EXPECT_EQ (db::div_exact (-1000000004, area_type (22) * f, area_type (176) * f), -125000001);
|
||||
EXPECT_EQ (db::div_exact (-1000000005, area_type (22) * f, area_type (176) * f), -125000001);
|
||||
|
||||
db::Edge e1 (db::Point (3, -3), db::Point (-8, -1));
|
||||
db::Edge e2 (db::Point (-4, -2), db::Point (13, -4));
|
||||
|
||||
std::pair<bool, db::Point> ip;
|
||||
ip = e1.intersect_point (e2);
|
||||
EXPECT_EQ (ip.second.to_string ().c_str (), "0,-3");
|
||||
ip = e2.intersect_point (e1);
|
||||
EXPECT_EQ (ip.second.to_string ().c_str (), "0,-3");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbPolygonGenerators.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbCommonReader.h"
|
||||
|
|
@ -1332,7 +1333,7 @@ TEST(23)
|
|||
|
||||
EXPECT_EQ (out.size (), size_t (1));
|
||||
std::sort (out.begin (), out.end ());
|
||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,1;1,0)");
|
||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,1;1,1)");
|
||||
}
|
||||
|
||||
TEST(24)
|
||||
|
|
@ -1390,15 +1391,29 @@ TEST(24)
|
|||
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
|
||||
}
|
||||
|
||||
std::vector<db::Polygon> out;
|
||||
{
|
||||
std::vector<db::Polygon> out;
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.simple_merge (in1, out, false, false);
|
||||
db::EdgeProcessor ep;
|
||||
ep.simple_merge (in1, out, false, false);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (2));
|
||||
std::sort (out.begin (), out.end ());
|
||||
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;3,0;3,-2;1,0;1,-9)");
|
||||
EXPECT_EQ (out[1].to_string (), "(-2,1;-2,3;0,1;0,10;1,10;1,1)");
|
||||
EXPECT_EQ (out.size (), size_t (1));
|
||||
std::sort (out.begin (), out.end ());
|
||||
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;-2,1;-2,3;0,1;0,10;1,10;1,1;0,0;3,0;3,-2;1,0;1,-9)");
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<db::Polygon> out;
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.simple_merge (in1, out, false, true);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (3));
|
||||
std::sort (out.begin (), out.end ());
|
||||
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;1,0;1,-9)");
|
||||
EXPECT_EQ (out[1].to_string (), "(3,-2;1,0;3,0)");
|
||||
EXPECT_EQ (out[2].to_string (), "(0,0;-2,1;-2,3;0,1;0,10;1,10;1,1)");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(25)
|
||||
|
|
@ -2247,7 +2262,7 @@ TEST(100)
|
|||
}
|
||||
|
||||
// #74 (GitHub)
|
||||
TEST(101)
|
||||
std::string run_test101 (tl::TestBase *_this, const db::Trans &t)
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
|
|
@ -2260,6 +2275,7 @@ TEST(101)
|
|||
};
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
p.transform (t);
|
||||
ep.insert (p, 0);
|
||||
}
|
||||
|
||||
|
|
@ -2272,6 +2288,7 @@ TEST(101)
|
|||
};
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
p.transform (t);
|
||||
ep.insert (p, 1);
|
||||
}
|
||||
|
||||
|
|
@ -2284,6 +2301,7 @@ TEST(101)
|
|||
};
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
p.transform (t);
|
||||
ep.insert (p, 1);
|
||||
}
|
||||
|
||||
|
|
@ -2295,7 +2313,16 @@ TEST(101)
|
|||
ep.process (pg, op);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (1));
|
||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,9;1,10;10,10;10,0)");
|
||||
|
||||
return out.empty () ? std::string () : out.front ().to_string ();
|
||||
}
|
||||
|
||||
TEST(101)
|
||||
{
|
||||
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r0)), "(0,0;0,9;1,10;10,10;10,0)");
|
||||
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r90)), "(-9,0;-10,1;-10,10;0,10;0,0)");
|
||||
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r180)), "(-10,-10;-10,0;0,0;0,-9;-1,-10)");
|
||||
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r270)), "(0,-10;0,0;9,0;10,-1;10,-10)");
|
||||
}
|
||||
|
||||
TEST(102)
|
||||
|
|
@ -2348,3 +2375,111 @@ TEST(102)
|
|||
EXPECT_EQ (out.size (), size_t (1));
|
||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,200;100,200;100,100;200,100;200,200;500,200;500,100;600,100;600,200;0,200;0,1000;1000,1000;1000,0)");
|
||||
}
|
||||
|
||||
// Bug 134
|
||||
TEST(134)
|
||||
{
|
||||
const char *pd = "(30,-7957;0,0;56,-4102;30,-7921)";
|
||||
|
||||
db::Coord dx = 0;
|
||||
db::Coord dy = -3999;
|
||||
unsigned int mode = 3;
|
||||
|
||||
db::Polygon p;
|
||||
tl::from_string (pd, p);
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
db::Polygon ps (p.sized (dx, dy, mode));
|
||||
ep.insert (ps);
|
||||
|
||||
db::SimpleMerge op (1 /*wc>0*/);
|
||||
std::vector<db::Polygon> out;
|
||||
db::PolygonContainer pc (out);
|
||||
db::PolygonGenerator pg (pc);
|
||||
ep.process (pg, op);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (0));
|
||||
}
|
||||
|
||||
void run_test135a (tl::TestBase *_this, const db::Trans &t)
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
db::Point pts[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (19, 19),
|
||||
db::Point (19, 18),
|
||||
db::Point (43, 32),
|
||||
db::Point (37, 27)
|
||||
};
|
||||
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
p.transform (t);
|
||||
p.size (-2, -2, 2);
|
||||
|
||||
ep.insert (p);
|
||||
|
||||
// this is just supposed to work and not fail with internal error "m_open.empty()"
|
||||
std::vector<db::Polygon> out;
|
||||
db::PolygonContainer pc (out);
|
||||
db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::SimpleMerge op (1 /*wc>0*/);
|
||||
ep.process (pg2, op);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (0));
|
||||
}
|
||||
|
||||
TEST(135a)
|
||||
{
|
||||
run_test135a (_this, db::Trans (db::Trans::r0));
|
||||
run_test135a (_this, db::Trans (db::Trans::r90));
|
||||
run_test135a (_this, db::Trans (db::Trans::r180));
|
||||
run_test135a (_this, db::Trans (db::Trans::r270));
|
||||
run_test135a (_this, db::Trans (db::Trans::m0));
|
||||
run_test135a (_this, db::Trans (db::Trans::m45));
|
||||
run_test135a (_this, db::Trans (db::Trans::m90));
|
||||
run_test135a (_this, db::Trans (db::Trans::m135));
|
||||
}
|
||||
|
||||
std::string run_test135b (tl::TestBase *_this, const db::Trans &t)
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
db::Point pts[] = {
|
||||
db::Point (215, 0),
|
||||
db::Point (145, 11),
|
||||
db::Point (37, 31),
|
||||
db::Point (36, 31),
|
||||
db::Point (0, 43)
|
||||
};
|
||||
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
p.transform (t);
|
||||
p.size (-2, -2, 2);
|
||||
|
||||
ep.insert (p);
|
||||
|
||||
// this is just supposed to work and not fail with internal error "m_open.empty()"
|
||||
std::vector<db::Polygon> out;
|
||||
db::PolygonContainer pc (out);
|
||||
db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::SimpleMerge op (1 /*wc>0*/);
|
||||
ep.process (pg2, op);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (1));
|
||||
return out.empty () ? std::string () : out.front ().to_string ();
|
||||
}
|
||||
|
||||
TEST(135b)
|
||||
{
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r0)), "(36,33;32,34;37,33)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r90)), "(-35,32;-26,77;-33,37;-33,36)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r180)), "(-33,-35;-78,-26;-37,-33;-36,-33)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r270)), "(25,-78;33,-37;33,-36;34,-33)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m0)), "(32,-35;36,-33;37,-33;77,-26)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m45)), "(34,32;33,36;33,37)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m90)), "(-78,25;-33,34;-36,33;-37,33)");
|
||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m135)), "(-26,-78;-35,-33;-33,-36;-33,-37)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1082,7 +1082,7 @@ TEST(31)
|
|||
|
||||
pout = minkowsky_sum (p, db::Edge (db::Point (10, 10), db::Point (210, -90)), true);
|
||||
|
||||
EXPECT_EQ (pout.to_string (), "(210,-190;143,-157;110,-165;-90,-65;10,110;85,73;110,85;310,-15;310,-140)");
|
||||
EXPECT_EQ (pout.to_string (), "(210,-190;143,-157;110,-165;-90,-65;10,110;85,72;110,85;310,-15;310,-140)");
|
||||
|
||||
std::vector <db::Point> c;
|
||||
c.push_back (db::Point (10, 10));
|
||||
|
|
|
|||
|
|
@ -26,10 +26,13 @@
|
|||
#include "dbTilingProcessor.h"
|
||||
#include "dbTextWriter.h"
|
||||
#include "gsiExpression.h"
|
||||
#include "gsiDecl.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
unsigned int get_rand()
|
||||
{
|
||||
|
|
@ -385,3 +388,63 @@ TEST(4)
|
|||
|
||||
}
|
||||
|
||||
class MyTilingOutputReceiver
|
||||
: public db::TileOutputReceiver
|
||||
{
|
||||
public:
|
||||
MyTilingOutputReceiver (double *sum, int *n)
|
||||
: mp_sum (sum), mp_n (n)
|
||||
{ }
|
||||
|
||||
MyTilingOutputReceiver ()
|
||||
: mp_sum (0), mp_n (0)
|
||||
{ }
|
||||
|
||||
void add (double x) const
|
||||
{
|
||||
static QMutex lock;
|
||||
QMutexLocker locker (&lock);
|
||||
*mp_sum += x;
|
||||
*mp_n += 1;
|
||||
}
|
||||
|
||||
private:
|
||||
double *mp_sum;
|
||||
int *mp_n;
|
||||
};
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
DB_PUBLIC gsi::Class<db::TileOutputReceiver> &dbdecl_TileOutputReceiverBase ();
|
||||
}
|
||||
|
||||
gsi::Class<MyTilingOutputReceiver> decl_MyTilingOutputReceiver (gsi::dbdecl_TileOutputReceiverBase (), "db", "MyTileOutputReceiver",
|
||||
gsi::method ("add", &MyTilingOutputReceiver::add)
|
||||
);
|
||||
|
||||
// Multithreaded, access to _rec()
|
||||
// This will mainly test the ability of gsi::Proxy to manage references
|
||||
// in a multithreaded case.
|
||||
TEST(5)
|
||||
{
|
||||
db::Layout ly1;
|
||||
ly1.dbu (0.001);
|
||||
unsigned int l11 = ly1.insert_layer (db::LayerProperties (1, 0));
|
||||
db::cell_index_type top1 = ly1.add_cell ("TOP");
|
||||
ly1.cell (top1).shapes (l11).insert (db::Box (0, 0, 50000, 50000));
|
||||
|
||||
double sum = 0.0;
|
||||
int num = 0;
|
||||
MyTilingOutputReceiver *rec = new MyTilingOutputReceiver (&sum, &num);
|
||||
|
||||
db::TilingProcessor tp;
|
||||
tp.set_threads (4);
|
||||
tp.tile_size (0.11, 0.17);
|
||||
tp.input ("i1", db::RecursiveShapeIterator (ly1, ly1.cell (top1), l11));
|
||||
tp.output ("o1", 0, rec, db::ICplxTrans ());
|
||||
tp.queue ("_rec(o1).add((i1 & _tile).area)");
|
||||
tp.execute ("test");
|
||||
|
||||
EXPECT_EQ (sum, 2500000000);
|
||||
EXPECT_EQ (num, 134225);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -896,7 +896,7 @@ CODE
|
|||
#
|
||||
# This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||
# while negative angles indicate a right turn. Since polygons are oriented clockwise, postive angles
|
||||
# while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
|
||||
# indicate concave corners while negative ones indicate convex corners.
|
||||
#
|
||||
# The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||
|
|
|
|||
|
|
@ -251,6 +251,8 @@ ShapePropertiesPage::do_apply (bool current_only)
|
|||
|
||||
for (std::vector<edt::Service::obj_iterator>::const_iterator p = m_selection_ptrs.begin (); p != m_selection_ptrs.end (); ++p) {
|
||||
|
||||
size_t index = p - m_selection_ptrs.begin ();
|
||||
|
||||
edt::Service::obj_iterator pos = *p;
|
||||
|
||||
// only update objects from the same layout - this is not practical limitation but saves a lot of effort for
|
||||
|
|
@ -259,6 +261,9 @@ ShapePropertiesPage::do_apply (bool current_only)
|
|||
continue;
|
||||
}
|
||||
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
db::Layout &layout = cv->layout ();
|
||||
|
||||
tl_assert (! pos->is_cell_inst ());
|
||||
|
||||
if (pos->shape ().is_array_member ()) {
|
||||
|
|
@ -271,10 +276,8 @@ ShapePropertiesPage::do_apply (bool current_only)
|
|||
std::map<db::Shape, db::Shape>::const_iterator s = shapes_seen.find (pos->shape ());
|
||||
if (s == shapes_seen.end ()) {
|
||||
|
||||
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
|
||||
|
||||
db::Shapes &shapes = cv->layout ().cell (pos->cell_index ()).shapes (pos->layer ());
|
||||
double dbu = cv->layout ().dbu ();
|
||||
db::Shapes &shapes = layout.cell (pos->cell_index ()).shapes (pos->layer ());
|
||||
double dbu = layout.dbu ();
|
||||
|
||||
if (!current_only || pos->shape () == current) {
|
||||
new_shape = applicator->do_apply (shapes, pos->shape (), dbu, relative_mode);
|
||||
|
|
@ -288,8 +291,6 @@ ShapePropertiesPage::do_apply (bool current_only)
|
|||
|
||||
if (new_shape != pos->shape ()) {
|
||||
|
||||
size_t index = p - m_selection_ptrs.begin ();
|
||||
|
||||
// change selection to new shape
|
||||
new_sel[index].set_shape (new_shape);
|
||||
|
||||
|
|
@ -298,21 +299,34 @@ ShapePropertiesPage::do_apply (bool current_only)
|
|||
|
||||
update_required = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// handle the case of guiding shape updates
|
||||
std::pair<bool, lay::ObjectInstPath> gs = mp_service->handle_guiding_shape_changes (new_sel[index]);
|
||||
if (gs.first) {
|
||||
|
||||
new_sel[index] = gs.second;
|
||||
|
||||
mp_service->select (*pos, lay::Editable::Reset);
|
||||
mp_service->select (new_sel [index], lay::Editable::Add);
|
||||
|
||||
update_required = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (update_required) {
|
||||
mp_service->view ()->cellview (cv_index)->layout ().cleanup ();
|
||||
recompute_selection_ptrs (new_sel);
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
mp_service->view ()->cellview (cv_index)->layout ().cleanup ();
|
||||
recompute_selection_ptrs (new_sel);
|
||||
throw;
|
||||
}
|
||||
|
||||
mp_service->handle_guiding_shape_changes ();
|
||||
|
||||
update ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1480,30 +1480,23 @@ Service::add_selection (const lay::ObjectInstPath &sel)
|
|||
selection_to_view ();
|
||||
}
|
||||
|
||||
bool
|
||||
Service::handle_guiding_shape_changes ()
|
||||
std::pair<bool, lay::ObjectInstPath>
|
||||
Service::handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const
|
||||
{
|
||||
// just allow one guiding shape to be selected
|
||||
if (m_selection.empty ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
objects::const_iterator s = m_selection.begin ();
|
||||
|
||||
unsigned int cv_index = s->cv_index ();
|
||||
unsigned int cv_index = obj.cv_index ();
|
||||
lay::CellView cv = view ()->cellview (cv_index);
|
||||
db::Layout *layout = &cv->layout ();
|
||||
|
||||
if (s->is_cell_inst () || s->layer () != layout->guiding_shape_layer ()) {
|
||||
return false;
|
||||
if (obj.is_cell_inst () || obj.layer () != layout->guiding_shape_layer ()) {
|
||||
return std::make_pair (false, lay::ObjectInstPath ());
|
||||
}
|
||||
|
||||
if (! s->shape ().has_prop_id ()) {
|
||||
return false;
|
||||
if (! obj.shape ().has_prop_id ()) {
|
||||
return std::make_pair (false, lay::ObjectInstPath ());
|
||||
}
|
||||
|
||||
if (! layout->is_pcell_instance (s->cell_index ()).first) {
|
||||
return false;
|
||||
if (! layout->is_pcell_instance (obj.cell_index ()).first) {
|
||||
return std::make_pair (false, lay::ObjectInstPath ());
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell = std::numeric_limits<db::cell_index_type>::max ();
|
||||
|
|
@ -1512,37 +1505,38 @@ Service::handle_guiding_shape_changes ()
|
|||
db::pcell_parameters_type parameters_for_pcell;
|
||||
|
||||
// determine parent cell and instance if required
|
||||
lay::ObjectInstPath::iterator e = s->end ();
|
||||
if (e == s->begin ()) {
|
||||
top_cell = s->cell_index ();
|
||||
lay::ObjectInstPath::iterator e = obj.end ();
|
||||
if (e == obj.begin ()) {
|
||||
top_cell = obj.cell_index ();
|
||||
} else {
|
||||
--e;
|
||||
db::cell_index_type pc = s->topcell ();
|
||||
if (e != s->begin ()) {
|
||||
db::cell_index_type pc = obj.topcell ();
|
||||
if (e != obj.begin ()) {
|
||||
--e;
|
||||
pc = e->inst_ptr.cell_index ();
|
||||
}
|
||||
parent_cell = pc;
|
||||
parent_inst = s->back ().inst_ptr;
|
||||
parent_inst = obj.back ().inst_ptr;
|
||||
}
|
||||
|
||||
db::property_names_id_type pn = layout->properties_repository ().prop_name_id ("name");
|
||||
|
||||
const db::PropertiesRepository::properties_set &input_props = layout->properties_repository ().properties (s->shape ().prop_id ());
|
||||
const db::PropertiesRepository::properties_set &input_props = layout->properties_repository ().properties (obj.shape ().prop_id ());
|
||||
db::PropertiesRepository::properties_set::const_iterator input_pv = input_props.find (pn);
|
||||
if (input_pv == input_props.end ()) {
|
||||
return false;
|
||||
return std::make_pair (false, lay::ObjectInstPath ());
|
||||
}
|
||||
|
||||
std::string shape_name = input_pv->second.to_string ();
|
||||
|
||||
// Hint: get_parameters_from_pcell_and_guiding_shapes invalidates the shapes because it resets the changed
|
||||
// guiding shapes. We must not access s->shape after that.
|
||||
if (! get_parameters_from_pcell_and_guiding_shapes (layout, s->cell_index (), parameters_for_pcell)) {
|
||||
return false;
|
||||
if (! get_parameters_from_pcell_and_guiding_shapes (layout, obj.cell_index (), parameters_for_pcell)) {
|
||||
return std::make_pair (false, lay::ObjectInstPath ());
|
||||
}
|
||||
|
||||
std::vector<lay::ObjectInstPath> new_sel;
|
||||
bool found = false;
|
||||
lay::ObjectInstPath new_obj = obj;
|
||||
|
||||
if (parent_cell != std::numeric_limits <db::cell_index_type>::max ()) {
|
||||
|
||||
|
|
@ -1550,21 +1544,20 @@ Service::handle_guiding_shape_changes ()
|
|||
|
||||
// try to identify the selected shape in the new shapes and select this one
|
||||
db::Shapes::shape_iterator sh = layout->cell (new_inst.cell_index ()).shapes (layout->guiding_shape_layer ()).begin (db::ShapeIterator::All);
|
||||
while (! sh.at_end ()) {
|
||||
while (! sh.at_end () && !found) {
|
||||
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (sh->prop_id ());
|
||||
db::PropertiesRepository::properties_set::const_iterator pv = props.find (pn);
|
||||
if (pv != props.end ()) {
|
||||
if (pv->second.to_string () == shape_name) {
|
||||
new_sel.push_back (*s);
|
||||
new_sel.back ().back ().inst_ptr = new_inst;
|
||||
new_sel.back ().back ().array_inst = new_inst.begin ();
|
||||
new_sel.back ().set_shape (*sh);
|
||||
break;
|
||||
new_obj.back ().inst_ptr = new_inst;
|
||||
new_obj.back ().array_inst = new_inst.begin ();
|
||||
new_obj.set_shape (*sh);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
++sh;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (top_cell != std::numeric_limits <db::cell_index_type>::max ()) {
|
||||
|
|
@ -1572,12 +1565,33 @@ Service::handle_guiding_shape_changes ()
|
|||
// Currently there is not way to create such a configuration ...
|
||||
}
|
||||
|
||||
// remove superfluous proxies
|
||||
layout->cleanup ();
|
||||
return std::make_pair (found, new_obj);
|
||||
}
|
||||
|
||||
set_selection (new_sel.begin (), new_sel.end ());
|
||||
bool
|
||||
Service::handle_guiding_shape_changes ()
|
||||
{
|
||||
// just allow one guiding shape to be selected
|
||||
if (m_selection.empty ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
std::pair<bool, lay::ObjectInstPath> gs = handle_guiding_shape_changes (*m_selection.begin ());
|
||||
if (gs.first) {
|
||||
|
||||
// remove superfluous proxies
|
||||
view ()->cellview (gs.second.cv_index ())->layout ().cleanup ();
|
||||
|
||||
// re-set the selection
|
||||
std::vector<lay::ObjectInstPath> new_sel;
|
||||
new_sel.push_back (gs.second);
|
||||
set_selection (new_sel.begin (), new_sel.end ());
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -342,9 +342,19 @@ public:
|
|||
* @brief Handle changes in the guiding shapes, i.e. create PCell variants
|
||||
*
|
||||
* @return true, if PCell's have been updated, indicating that our selection is no longer valid
|
||||
*
|
||||
* This version assumes there is only one guiding shape selected and will update the selection.
|
||||
* It will also call layout.cleanup() if required.
|
||||
*/
|
||||
bool handle_guiding_shape_changes ();
|
||||
|
||||
/**
|
||||
* @brief Handle changes in a specific guiding shape, i.e. create new PCell variants if required
|
||||
*
|
||||
* @return A pair of bool (indicating that the object path has changed) and the new guiding shape path
|
||||
*/
|
||||
std::pair<bool, lay::ObjectInstPath> handle_guiding_shape_changes (const lay::ObjectInstPath &obj) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Update m_markers to reflect the selection
|
||||
|
|
|
|||
|
|
@ -27,9 +27,13 @@
|
|||
|
||||
#include "tlLog.h"
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
QMutex Proxy::m_lock;
|
||||
|
||||
Proxy::Proxy (const gsi::ClassBase *_cls_decl)
|
||||
: m_cls_decl (_cls_decl),
|
||||
m_obj (0),
|
||||
|
|
@ -43,21 +47,34 @@ Proxy::Proxy (const gsi::ClassBase *_cls_decl)
|
|||
|
||||
Proxy::~Proxy ()
|
||||
{
|
||||
try {
|
||||
set (0, false, false, false);
|
||||
} catch (std::exception &ex) {
|
||||
tl::warn << "Caught exception in object destructor: " << ex.what ();
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << "Caught exception in object destructor: " << ex.msg ();
|
||||
} catch (...) {
|
||||
tl::warn << "Caught unspecified exception in object destructor";
|
||||
void *prev_obj = 0;
|
||||
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
try {
|
||||
prev_obj = set_internal (0, false, false, false);
|
||||
} catch (std::exception &ex) {
|
||||
tl::warn << "Caught exception in object destructor: " << ex.what ();
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << "Caught exception in object destructor: " << ex.msg ();
|
||||
} catch (...) {
|
||||
tl::warn << "Caught unspecified exception in object destructor";
|
||||
}
|
||||
m_destroyed = true;
|
||||
}
|
||||
|
||||
// destroy outside the locker because the destructor may raise status
|
||||
// changed events
|
||||
if (prev_obj) {
|
||||
m_cls_decl->destroy (prev_obj);
|
||||
}
|
||||
m_destroyed = true;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::destroy ()
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
|
||||
if (! m_cls_decl) {
|
||||
m_obj = 0;
|
||||
return;
|
||||
|
|
@ -82,7 +99,7 @@ Proxy::destroy ()
|
|||
if (m_owned || m_can_destroy) {
|
||||
o = m_obj;
|
||||
}
|
||||
detach ();
|
||||
detach_internal ();
|
||||
if (o) {
|
||||
m_cls_decl->destroy (o);
|
||||
}
|
||||
|
|
@ -91,28 +108,20 @@ Proxy::destroy ()
|
|||
void
|
||||
Proxy::detach ()
|
||||
{
|
||||
if (! m_destroyed && m_cls_decl && m_cls_decl->is_managed ()) {
|
||||
gsi::ObjectBase *gsi_object = m_cls_decl->gsi_object (m_obj, false);
|
||||
if (gsi_object) {
|
||||
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
|
||||
}
|
||||
}
|
||||
|
||||
m_obj = 0;
|
||||
m_destroyed = true;
|
||||
m_const_ref = false;
|
||||
m_owned = false;
|
||||
m_can_destroy = false;
|
||||
QMutexLocker locker (&m_lock);
|
||||
detach_internal ();
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::release ()
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
|
||||
// If the object is managed we first reset the ownership of all other clients
|
||||
// and then make us the owner
|
||||
const gsi::ClassBase *cls = m_cls_decl;
|
||||
if (cls && cls->is_managed ()) {
|
||||
void *o = obj ();
|
||||
void *o = obj_internal ();
|
||||
if (o) {
|
||||
cls->gsi_object (o)->keep ();
|
||||
}
|
||||
|
|
@ -125,9 +134,11 @@ Proxy::release ()
|
|||
void
|
||||
Proxy::keep ()
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
|
||||
const gsi::ClassBase *cls = m_cls_decl;
|
||||
if (cls) {
|
||||
void *o = obj ();
|
||||
void *o = obj_internal ();
|
||||
if (o) {
|
||||
if (cls->is_managed ()) {
|
||||
cls->gsi_object (o)->keep ();
|
||||
|
|
@ -142,12 +153,68 @@ Proxy::keep ()
|
|||
|
||||
void
|
||||
Proxy::set (void *obj, bool owned, bool const_ref, bool can_destroy)
|
||||
{
|
||||
void *prev_obj;
|
||||
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
prev_obj = set_internal (obj, owned, const_ref, can_destroy);
|
||||
}
|
||||
|
||||
// destroy outside the locker because the destructor may raise status
|
||||
// changed events
|
||||
if (prev_obj) {
|
||||
m_cls_decl->destroy (prev_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
Proxy::obj ()
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
return obj_internal ();
|
||||
}
|
||||
|
||||
void *
|
||||
Proxy::obj_internal ()
|
||||
{
|
||||
if (! m_obj) {
|
||||
if (m_destroyed) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Object has been destroyed already")));
|
||||
} else {
|
||||
// delayed creation of a detached C++ object ..
|
||||
tl_assert (set_internal (m_cls_decl->create (), true, false, true) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return m_obj;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::object_status_changed (gsi::ObjectBase::StatusEventType type)
|
||||
{
|
||||
if (type == gsi::ObjectBase::ObjectDestroyed) {
|
||||
QMutexLocker locker (&m_lock);
|
||||
m_destroyed = true; // NOTE: must be set before detach and indicates that the object was destroyed externally.
|
||||
detach_internal ();
|
||||
} else if (type == gsi::ObjectBase::ObjectKeep) {
|
||||
// NOTE: don't lock this as this will cause a deadlock from keep()
|
||||
m_owned = false;
|
||||
} else if (type == gsi::ObjectBase::ObjectRelease) {
|
||||
// NOTE: don't lock this as this will cause a deadlock from release()
|
||||
m_owned = true;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
Proxy::set_internal (void *obj, bool owned, bool const_ref, bool can_destroy)
|
||||
{
|
||||
bool prev_owned = m_owned;
|
||||
|
||||
m_owned = owned;
|
||||
m_can_destroy = can_destroy;
|
||||
m_const_ref = const_ref;
|
||||
void *prev_object = 0;
|
||||
|
||||
const gsi::ClassBase *cls = m_cls_decl;
|
||||
if (! cls) {
|
||||
|
|
@ -169,9 +236,8 @@ Proxy::set (void *obj, bool owned, bool const_ref, bool can_destroy)
|
|||
// Destroy the object if we are owner. We don't destroy the object if it was locked
|
||||
// (either because we are not owner or from C++ side using keep())
|
||||
if (prev_owned) {
|
||||
void *o = m_obj;
|
||||
prev_object = m_obj;
|
||||
m_obj = 0;
|
||||
cls->destroy (o);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -196,34 +262,25 @@ Proxy::set (void *obj, bool owned, bool const_ref, bool can_destroy)
|
|||
// now we have a valid object (or nil) - we can reset "destroyed" state. Note: this has to be done
|
||||
// here because before detach might be called on *this which resets m_destroyed.
|
||||
m_destroyed = false;
|
||||
}
|
||||
|
||||
void *
|
||||
Proxy::obj ()
|
||||
{
|
||||
if (! m_obj) {
|
||||
if (m_destroyed) {
|
||||
throw tl::Exception (tl::to_string (tr ("Object has been destroyed already")));
|
||||
} else {
|
||||
// delayed creation of a detached C++ object ..
|
||||
set(m_cls_decl->create (), true, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
return m_obj;
|
||||
return prev_object;
|
||||
}
|
||||
|
||||
void
|
||||
Proxy::object_status_changed (gsi::ObjectBase::StatusEventType type)
|
||||
Proxy::detach_internal()
|
||||
{
|
||||
if (type == gsi::ObjectBase::ObjectDestroyed) {
|
||||
m_destroyed = true; // NOTE: must be set before detach and indicates that the object was destroyed externally.
|
||||
detach ();
|
||||
} else if (type == gsi::ObjectBase::ObjectKeep) {
|
||||
m_owned = false;
|
||||
} else if (type == gsi::ObjectBase::ObjectRelease) {
|
||||
m_owned = true;
|
||||
if (! m_destroyed && m_cls_decl && m_cls_decl->is_managed ()) {
|
||||
gsi::ObjectBase *gsi_object = m_cls_decl->gsi_object (m_obj, false);
|
||||
if (gsi_object) {
|
||||
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
|
||||
}
|
||||
}
|
||||
|
||||
m_obj = 0;
|
||||
m_destroyed = true;
|
||||
m_const_ref = false;
|
||||
m_owned = false;
|
||||
m_can_destroy = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "gsiCommon.h"
|
||||
|
||||
#include <memory>
|
||||
#include <QMutex>
|
||||
|
||||
// For a comprehensive documentation see gsi.h
|
||||
|
||||
|
|
@ -191,6 +192,17 @@ private:
|
|||
*
|
||||
* Using a proxy object allows having a gsi::ObjectBase that does not derive
|
||||
* from tl::Object and can derive from any base class (specifically QObject).
|
||||
*
|
||||
* NOTE about MT safety: the model is:
|
||||
*
|
||||
* - the Proxy belongs to a thread
|
||||
* - the original object (the proxy target) belongs to a different thread
|
||||
* - there can be multiple Proxy objects for one target
|
||||
* - the target object itself and the methods by which the proxy acts on
|
||||
* the target object are thread safe
|
||||
*
|
||||
* This implies that all operations related to the manipulation of proxy
|
||||
* to target relation need to be guarded by a lock.
|
||||
*/
|
||||
class GSI_PUBLIC Proxy
|
||||
: public tl::Object
|
||||
|
|
@ -228,8 +240,12 @@ private:
|
|||
bool m_const_ref : 1;
|
||||
bool m_destroyed : 1;
|
||||
bool m_can_destroy : 1;
|
||||
static QMutex m_lock;
|
||||
|
||||
void *set_internal (void *obj, bool owned, bool const_ref, bool can_destroy);
|
||||
void object_status_changed (gsi::ObjectBase::StatusEventType type);
|
||||
void detach_internal ();
|
||||
void *obj_internal ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,25 +70,6 @@ static void _call_ctor_QHostAddress_1098 (const qt_gsi::GenericStaticMethod * /*
|
|||
}
|
||||
|
||||
|
||||
// Constructor QHostAddress::QHostAddress(const quint8 *ip6Addr)
|
||||
|
||||
|
||||
static void _init_ctor_QHostAddress_1934 (qt_gsi::GenericStaticMethod *decl)
|
||||
{
|
||||
static gsi::ArgSpecBase argspec_0 ("ip6Addr");
|
||||
decl->add_arg<const quint8 * > (argspec_0);
|
||||
decl->set_return_new<QHostAddress> ();
|
||||
}
|
||||
|
||||
static void _call_ctor_QHostAddress_1934 (const qt_gsi::GenericStaticMethod * /*decl*/, gsi::SerialArgs &args, gsi::SerialArgs &ret)
|
||||
{
|
||||
__SUPPRESS_UNUSED_WARNING(args);
|
||||
tl::Heap heap;
|
||||
const quint8 *arg1 = args.read<const quint8 * > (heap);
|
||||
ret.write<QHostAddress *> (new QHostAddress (arg1));
|
||||
}
|
||||
|
||||
|
||||
// Constructor QHostAddress::QHostAddress(const QString &address)
|
||||
|
||||
|
||||
|
|
@ -397,26 +378,6 @@ static void _call_f_setAddress_1098 (const qt_gsi::GenericMethod * /*decl*/, voi
|
|||
}
|
||||
|
||||
|
||||
// void QHostAddress::setAddress(const quint8 *ip6Addr)
|
||||
|
||||
|
||||
static void _init_f_setAddress_1934 (qt_gsi::GenericMethod *decl)
|
||||
{
|
||||
static gsi::ArgSpecBase argspec_0 ("ip6Addr");
|
||||
decl->add_arg<const quint8 * > (argspec_0);
|
||||
decl->set_return<void > ();
|
||||
}
|
||||
|
||||
static void _call_f_setAddress_1934 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)
|
||||
{
|
||||
__SUPPRESS_UNUSED_WARNING(args);
|
||||
tl::Heap heap;
|
||||
const quint8 *arg1 = args.read<const quint8 * > (heap);
|
||||
__SUPPRESS_UNUSED_WARNING(ret);
|
||||
((QHostAddress *)cls)->setAddress (arg1);
|
||||
}
|
||||
|
||||
|
||||
// bool QHostAddress::setAddress(const QString &address)
|
||||
|
||||
|
||||
|
|
@ -532,7 +493,6 @@ static gsi::Methods methods_QHostAddress () {
|
|||
gsi::Methods methods;
|
||||
methods += new qt_gsi::GenericStaticMethod ("new", "@brief Constructor QHostAddress::QHostAddress()\nThis method creates an object of class QHostAddress.", &_init_ctor_QHostAddress_0, &_call_ctor_QHostAddress_0);
|
||||
methods += new qt_gsi::GenericStaticMethod ("new_ip4", "@brief Constructor QHostAddress::QHostAddress(quint32 ip4Addr)\nThis method creates an object of class QHostAddress.", &_init_ctor_QHostAddress_1098, &_call_ctor_QHostAddress_1098);
|
||||
methods += new qt_gsi::GenericStaticMethod ("new", "@brief Constructor QHostAddress::QHostAddress(const quint8 *ip6Addr)\nThis method creates an object of class QHostAddress.", &_init_ctor_QHostAddress_1934, &_call_ctor_QHostAddress_1934);
|
||||
methods += new qt_gsi::GenericStaticMethod ("new", "@brief Constructor QHostAddress::QHostAddress(const QString &address)\nThis method creates an object of class QHostAddress.", &_init_ctor_QHostAddress_2025, &_call_ctor_QHostAddress_2025);
|
||||
methods += new qt_gsi::GenericStaticMethod ("new", "@brief Constructor QHostAddress::QHostAddress(const QHostAddress ©)\nThis method creates an object of class QHostAddress.", &_init_ctor_QHostAddress_2518, &_call_ctor_QHostAddress_2518);
|
||||
methods += new qt_gsi::GenericStaticMethod ("new_special", "@brief Constructor QHostAddress::QHostAddress(QHostAddress::SpecialAddress address)\nThis method creates an object of class QHostAddress.", &_init_ctor_QHostAddress_3172, &_call_ctor_QHostAddress_3172);
|
||||
|
|
@ -550,7 +510,6 @@ static gsi::Methods methods_QHostAddress () {
|
|||
methods += new qt_gsi::GenericMethod ("protocol", "@brief Method QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol()\n", true, &_init_f_protocol_c0, &_call_f_protocol_c0);
|
||||
methods += new qt_gsi::GenericMethod (":scopeId", "@brief Method QString QHostAddress::scopeId()\n", true, &_init_f_scopeId_c0, &_call_f_scopeId_c0);
|
||||
methods += new qt_gsi::GenericMethod ("setAddress", "@brief Method void QHostAddress::setAddress(quint32 ip4Addr)\n", false, &_init_f_setAddress_1098, &_call_f_setAddress_1098);
|
||||
methods += new qt_gsi::GenericMethod ("setAddress", "@brief Method void QHostAddress::setAddress(const quint8 *ip6Addr)\n", false, &_init_f_setAddress_1934, &_call_f_setAddress_1934);
|
||||
methods += new qt_gsi::GenericMethod ("setAddress", "@brief Method bool QHostAddress::setAddress(const QString &address)\n", false, &_init_f_setAddress_2025, &_call_f_setAddress_2025);
|
||||
methods += new qt_gsi::GenericMethod ("setScopeId|scopeId=", "@brief Method void QHostAddress::setScopeId(const QString &id)\n", false, &_init_f_setScopeId_2025, &_call_f_setScopeId_2025);
|
||||
methods += new qt_gsi::GenericMethod ("toIPv4Address", "@brief Method quint32 QHostAddress::toIPv4Address()\n", true, &_init_f_toIPv4Address_c0, &_call_f_toIPv4Address_c0);
|
||||
|
|
|
|||
|
|
@ -112,13 +112,11 @@ FontController::can_exit (lay::PluginRoot * /*root*/) const
|
|||
void
|
||||
FontController::sync_dirs ()
|
||||
{
|
||||
if (! m_file_watcher) {
|
||||
return;
|
||||
if (m_file_watcher) {
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
}
|
||||
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
|
||||
std::vector<std::string> paths = lay::ApplicationBase::instance ()->klayout_path ();
|
||||
|
||||
// add the salt grains as potential sources for library definitions
|
||||
|
|
@ -137,14 +135,18 @@ FontController::sync_dirs ()
|
|||
for (std::vector <std::string>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
QDir fp = QDir (tl::to_qstring (*p)).filePath (tl::to_qstring ("fonts"));
|
||||
if (fp.exists ()) {
|
||||
m_file_watcher->add_file (tl::to_string (fp.absolutePath ()));
|
||||
if (m_file_watcher) {
|
||||
m_file_watcher->add_file (tl::to_string (fp.absolutePath ()));
|
||||
}
|
||||
font_paths.push_back (tl::to_string (fp.absolutePath ()));
|
||||
}
|
||||
}
|
||||
|
||||
db::TextGenerator::set_font_paths (font_paths);
|
||||
|
||||
m_file_watcher->enable (true);
|
||||
if (m_file_watcher) {
|
||||
m_file_watcher->enable (true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -117,13 +117,11 @@ LibraryController::can_exit (lay::PluginRoot * /*root*/) const
|
|||
void
|
||||
LibraryController::sync_files ()
|
||||
{
|
||||
if (! m_file_watcher) {
|
||||
return;
|
||||
if (m_file_watcher) {
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
}
|
||||
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
|
||||
std::map<std::string, std::pair<std::string, QDateTime> > new_lib_files;
|
||||
|
||||
// build a list of paths vs. technology
|
||||
|
|
@ -158,7 +156,9 @@ LibraryController::sync_files ()
|
|||
QDir lp = QDir (tl::to_qstring (p->first)).filePath (tl::to_qstring ("libraries"));
|
||||
if (lp.exists ()) {
|
||||
|
||||
m_file_watcher->add_file (tl::to_string (lp.absolutePath ()));
|
||||
if (m_file_watcher) {
|
||||
m_file_watcher->add_file (tl::to_string (lp.absolutePath ()));
|
||||
}
|
||||
|
||||
QStringList name_filters;
|
||||
name_filters << QString::fromUtf8 ("*");
|
||||
|
|
@ -222,7 +222,9 @@ LibraryController::sync_files ()
|
|||
|
||||
}
|
||||
|
||||
m_file_watcher->enable (true);
|
||||
if (m_file_watcher) {
|
||||
m_file_watcher->enable (true);
|
||||
}
|
||||
|
||||
// remove libraries which are no longer present
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,10 @@ MacroController::finish ()
|
|||
|
||||
if (! m_no_implicit_macros) {
|
||||
for (std::vector <ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
||||
lym::MacroCollection::root ().add_folder (p->description, p->path, p->cat, p->readonly);
|
||||
lym::MacroCollection *mc = lym::MacroCollection::root ().add_folder (p->description, p->path, p->cat, p->readonly);
|
||||
if (mc) {
|
||||
mc->set_virtual_mode (p->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,8 @@ MacroEditorPage::replace_all (const QString &replace)
|
|||
int i = m_current_search.indexIn (b.text (), o);
|
||||
if (i < 0) {
|
||||
break;
|
||||
} else if (m_current_search.matchedLength () == 0) {
|
||||
break; // avoid an infinite loop
|
||||
}
|
||||
|
||||
QString r = interpolate_string (replace, m_current_search);
|
||||
|
|
|
|||
|
|
@ -842,6 +842,7 @@ MainWindow::init_menu ()
|
|||
MenuLayoutEntry ("show_grid", tl::to_string (QObject::tr ("Show Grid")), std::make_pair (cfg_grid_visible, "?")),
|
||||
MenuLayoutEntry ("default_grid:default_grids_group", tl::to_string (QObject::tr ("Grid")), empty_menu),
|
||||
MenuLayoutEntry::separator ("layout_group"),
|
||||
MenuLayoutEntry ("show_markers", tl::to_string (QObject::tr ("Show Markers")), std::make_pair (cfg_markers_visible, "?")),
|
||||
MenuLayoutEntry ("show_texts", tl::to_string (QObject::tr ("Show Texts")), std::make_pair (cfg_text_visible, "?")),
|
||||
MenuLayoutEntry ("show_cell_boxes", tl::to_string (QObject::tr ("Show Cell Frames")), std::make_pair (cfg_cell_box_visible, "?")),
|
||||
MenuLayoutEntry ("no_stipples", tl::to_string (QObject::tr ("Show Layers Without Fill")), std::make_pair (cfg_no_stipple, "?")),
|
||||
|
|
@ -1312,6 +1313,18 @@ MainWindow::about_to_exec ()
|
|||
}
|
||||
}
|
||||
|
||||
f = false;
|
||||
config_get (cfg_markers_visible, f);
|
||||
if (! f) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("Markers are not visible because they have been turned off.\nYou may not see markers when using the marker browser feature.\n\nTo turn markers on, check \"Show Markers\" in the \"View\" menu.")),
|
||||
"show-markers");
|
||||
if (td.exec_dialog ()) {
|
||||
// Don't bother the user with more dialogs.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
f = false;
|
||||
config_get (cfg_hide_empty_layers, f);
|
||||
if (f) {
|
||||
|
|
@ -3162,6 +3175,8 @@ MainWindow::do_save (bool as)
|
|||
options.set_dbu (cv->layout ().dbu ());
|
||||
options.set_format_from_filename (fn);
|
||||
|
||||
cv->update_save_options (options);
|
||||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
|
||||
if (as && ! mp_layout_save_as_options->get_options (current_view (), cv_index, fn, om, options)) {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ ConfirmationDialog::add_info (const std::string &name, bool update, const std::s
|
|||
item->setText (3, tl::to_qstring (url));
|
||||
|
||||
for (int column = 0; column < list->colorCount (); ++column) {
|
||||
item->setData (column, Qt::ForegroundRole, QVariant (QBrush (update ? Qt::blue : Qt::black)));
|
||||
item->setData (column, Qt::ForegroundRole, QVariant (QBrush (update ? QColor (Qt::blue) : QColor (Qt::black))));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,15 @@ SaltItemDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option,
|
|||
{
|
||||
QStyleOptionViewItemV4 optionV4 = option;
|
||||
initStyleOption (&optionV4, index);
|
||||
// let the text take all the available space (fixes #144)
|
||||
optionV4.showDecorationSelected = true;
|
||||
|
||||
bool is_enabled = (optionV4.state & QStyle::State_Enabled);
|
||||
if ((index.flags () & 0x10000) != 0) {
|
||||
// the item wants to be drawn "disabled"
|
||||
is_enabled = false;
|
||||
}
|
||||
|
||||
optionV4.state |= QStyle::State_Enabled;
|
||||
|
||||
QStyle *style = optionV4.widget ? optionV4.widget->style () : QApplication::style ();
|
||||
|
|
@ -121,6 +128,11 @@ SaltModel::flags (const QModelIndex &index) const
|
|||
f &= ~Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
if (g && (! is_enabled (g->name ()) || g->is_hidden ())) {
|
||||
// We use a custom flag to indicate "disabled" display without actually disabling the item
|
||||
f |= Qt::ItemFlags (0x10000);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
@ -134,15 +146,9 @@ SaltModel::data (const QModelIndex &index, int role) const
|
|||
return QVariant (tr ("<html><body><h4>There are no items to show in this list</h4><p>%1</p></body></html>").arg (m_empty_explanation));
|
||||
}
|
||||
|
||||
bool en = is_enabled (g->name ());
|
||||
bool hidden = g->is_hidden ();
|
||||
|
||||
std::string text = "<html><body>";
|
||||
if (! en || hidden) {
|
||||
text += "<font color=\"#c0c0c0\">";
|
||||
} else {
|
||||
text += "<font color=\"#303030\">";
|
||||
}
|
||||
if (hidden) {
|
||||
text += "<i>";
|
||||
}
|
||||
|
|
@ -179,7 +185,6 @@ SaltModel::data (const QModelIndex &index, int role) const
|
|||
text += tl::to_string (tr ("This package is an auxiliary package for use with other packages."));
|
||||
text += "</p></i>";
|
||||
}
|
||||
text += "</font>";
|
||||
text += "</body></html>";
|
||||
|
||||
return tl::to_qstring (text);
|
||||
|
|
|
|||
|
|
@ -164,6 +164,18 @@ Class<lay::DMarker> decl_Marker ("lay", "Marker",
|
|||
"@brief Returns a value indicating whether the marker has a specific frame color\n"
|
||||
"The set method has been added in version 0.20.\n"
|
||||
) +
|
||||
gsi::method ("dismissable=", &lay::DMarker::set_dismissable,
|
||||
"@brief Sets a value indicating whether the marker can be hidden\n"
|
||||
"@args flag\n"
|
||||
"Dismissable markers can be hidden setting \"View/Show Markers\" to \"off\". "
|
||||
"The default setting is \"false\" meaning the marker can't be hidden.\n"
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.25.4."
|
||||
) +
|
||||
gsi::method ("dismissable?", &lay::DMarker::get_dismissable,
|
||||
"@brief Gets a value indicating whether the marker can be hidden\n"
|
||||
"See \\dismissable= for a description of this predicate."
|
||||
) +
|
||||
gsi::method ("line_width=", &lay::DMarker::set_line_width,
|
||||
"@brief Sets the line width of the marker\n"
|
||||
"@args width\n"
|
||||
|
|
|
|||
|
|
@ -258,6 +258,31 @@ LayoutHandle::set_save_options (const db::SaveLayoutOptions &options, bool valid
|
|||
m_save_options_valid = valid;
|
||||
}
|
||||
|
||||
void
|
||||
LayoutHandle::update_save_options (db::SaveLayoutOptions &options)
|
||||
{
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
|
||||
const lay::StreamWriterPluginDeclaration *decl = dynamic_cast <const lay::StreamWriterPluginDeclaration *> (&*cls);
|
||||
if (! decl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::auto_ptr<db::FormatSpecificWriterOptions> specific_options;
|
||||
if (options.get_options (decl->format_name ())) {
|
||||
specific_options.reset (options.get_options (decl->format_name ())->clone ());
|
||||
} else {
|
||||
specific_options.reset (decl->create_specific_options ());
|
||||
}
|
||||
|
||||
if (specific_options.get ()) {
|
||||
decl->initialize_options_from_layout_handle (specific_options.get (), *this);
|
||||
options.set_options (specific_options.release ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayoutHandle::save_as (const std::string &fn, tl::OutputStream::OutputStreamMode om, const db::SaveLayoutOptions &options, bool update)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -234,6 +234,15 @@ public:
|
|||
return m_save_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the given save options with attributes from this cell view
|
||||
*
|
||||
* Some formats will initialize attributes from the cell view and the layout's
|
||||
* metadata (example: libname of GDS2). This method will update the options
|
||||
* if the layout provides attributes for initializing the latter.
|
||||
*/
|
||||
void update_save_options (db::SaveLayoutOptions &options);
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether the save options are valid
|
||||
*
|
||||
|
|
|
|||
|
|
@ -625,6 +625,18 @@ ReplaceCellOptionsDialog::~ReplaceCellOptionsDialog ()
|
|||
mp_ui = 0;
|
||||
}
|
||||
|
||||
static std::pair<bool, db::cell_index_type>
|
||||
find_cell_by_display_name (const db::Layout &layout, const std::string &cn)
|
||||
{
|
||||
for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
if (layout.display_name (c->cell_index ()) == cn) {
|
||||
return std::make_pair (true, c->cell_index ());
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair (false, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
ReplaceCellOptionsDialog::exec_dialog (const lay::CellView &cv, int &replace_mode, db::cell_index_type &cell_index)
|
||||
{
|
||||
|
|
@ -647,7 +659,7 @@ ReplaceCellOptionsDialog::exec_dialog (const lay::CellView &cv, int &replace_mod
|
|||
}
|
||||
|
||||
std::string cn = tl::to_string (mp_ui->cell_selection_cbx->lineEdit ()->text ());
|
||||
std::pair<bool, db::cell_index_type> cc = cv->layout ().cell_by_name (cn.c_str ());
|
||||
std::pair<bool, db::cell_index_type> cc = find_cell_by_display_name (cv->layout (), cn.c_str ());
|
||||
cell_index = cc.second;
|
||||
|
||||
return cc.first;
|
||||
|
|
@ -665,7 +677,7 @@ BEGIN_PROTECTED;
|
|||
lay::CellTreeModel *model = dynamic_cast<lay::CellTreeModel *> (mp_ui->cell_selection_cbx->model ());
|
||||
if (model) {
|
||||
std::string cn = tl::to_string (mp_ui->cell_selection_cbx->lineEdit ()->text ());
|
||||
std::pair<bool, db::cell_index_type> cc = model->layout ()->cell_by_name (cn.c_str ());
|
||||
std::pair<bool, db::cell_index_type> cc = find_cell_by_display_name (*model->layout (), cn.c_str ());
|
||||
if (! cc.first) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell name: ")) + cn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -555,6 +555,7 @@ DitherPatternInfo::operator< (const DitherPatternInfo &d) const
|
|||
return m_order_index < d.m_order_index;
|
||||
}
|
||||
|
||||
// TODO including a scaling algorithm in this formula, or give more resolution to the dither
|
||||
QBitmap
|
||||
DitherPatternInfo::get_bitmap (int width, int height) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -200,16 +200,29 @@ LCPDitherPalette::create_pixmap_for (LCPActiveLabel *b, int n)
|
|||
const unsigned int h = 24;
|
||||
const unsigned int w = 24;
|
||||
|
||||
QImage image (w, h, QImage::Format_RGB32);
|
||||
image.fill (color0.rgb ());
|
||||
#if QT_VERSION > 0x050000
|
||||
unsigned int dpr = devicePixelRatio ();
|
||||
#else
|
||||
unsigned int dpr = 1;
|
||||
#endif
|
||||
|
||||
QBitmap bitmap = pattern.pattern (n).get_bitmap (w, h);
|
||||
QImage image (w * dpr, h * dpr, QImage::Format_RGB32);
|
||||
image.fill (color0.rgb ());
|
||||
#if QT_VERSION > 0x050000
|
||||
image.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
|
||||
// TODO include a scaling algorithm in get_bitmap, because it looks small in highDPI screens
|
||||
QBitmap bitmap = pattern.pattern (n).get_bitmap (w * dpr, h * dpr);
|
||||
QPainter painter (&image);
|
||||
painter.setPen (QPen (color1));
|
||||
painter.setBackgroundMode (Qt::TransparentMode);
|
||||
painter.drawPixmap (0, 0, bitmap);
|
||||
painter.drawPixmap (0, 0, w, h, bitmap);
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage (image); // Qt 4.6.0 workaround
|
||||
#if QT_VERSION > 0x050000
|
||||
pixmap.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
b->setPixmap (pixmap);
|
||||
}
|
||||
|
||||
|
|
@ -629,16 +642,28 @@ LCPStylePalette::create_pixmap_for_line_style (LCPActiveLabel *b, int n)
|
|||
const unsigned int h = 14;
|
||||
const unsigned int w = 24;
|
||||
|
||||
QImage image (w, h, QImage::Format_RGB32);
|
||||
image.fill (color0.rgb ());
|
||||
#if QT_VERSION > 0x050000
|
||||
unsigned int dpr = devicePixelRatio ();
|
||||
#else
|
||||
unsigned int dpr = 1;
|
||||
#endif
|
||||
|
||||
QBitmap bitmap = styles.style (n).get_bitmap (w, h);
|
||||
QImage image (dpr * w, dpr * h, QImage::Format_RGB32);
|
||||
image.fill (color0.rgb ());
|
||||
#if QT_VERSION > 0x050000
|
||||
image.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
|
||||
QBitmap bitmap = styles.style (n).get_bitmap (dpr * w, dpr * h);
|
||||
QPainter painter (&image);
|
||||
painter.setPen (QPen (color1));
|
||||
painter.setBackgroundMode (Qt::TransparentMode);
|
||||
painter.drawPixmap (0, 0, bitmap);
|
||||
painter.drawPixmap (0, 0, w, h, bitmap);
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage (image); // Qt 4.6.0 workaround
|
||||
#if QT_VERSION > 0x050000
|
||||
pixmap.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
b->setPixmap (pixmap);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,8 +291,6 @@ LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutView *view, const char *
|
|||
{
|
||||
#if QT_VERSION > 0x050000
|
||||
m_dpr = devicePixelRatio ();
|
||||
#else
|
||||
m_dpr = 1;
|
||||
#endif
|
||||
|
||||
// The gamma value used for subsampling: something between 1.8 and 2.2.
|
||||
|
|
|
|||
|
|
@ -384,6 +384,7 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/)
|
|||
m_apply_text_trans = true;
|
||||
m_default_text_size = 0.1;
|
||||
m_text_font = 0;
|
||||
m_show_markers = true;
|
||||
m_no_stipples = false;
|
||||
m_stipple_offset = true;
|
||||
m_fit_new_cell = true;
|
||||
|
|
@ -1155,6 +1156,13 @@ LayoutView::configure (const std::string &name, const std::string &value)
|
|||
apply_text_trans (flag);
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_markers_visible) {
|
||||
|
||||
bool flag;
|
||||
tl::from_string (value, flag);
|
||||
mp_canvas->set_dismiss_view_objects (! flag);
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_no_stipple) {
|
||||
|
||||
bool flag;
|
||||
|
|
@ -4923,7 +4931,16 @@ LayoutView::no_stipples (bool f)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
LayoutView::show_markers (bool f)
|
||||
{
|
||||
if (m_show_markers != f) {
|
||||
m_show_markers = f;
|
||||
mp_canvas->update_image ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayoutView::text_color (QColor c)
|
||||
{
|
||||
if (m_text_color != c) {
|
||||
|
|
|
|||
|
|
@ -1062,6 +1062,19 @@ public:
|
|||
return m_default_text_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Show or hide markers
|
||||
*/
|
||||
void show_markers (bool f);
|
||||
|
||||
/**
|
||||
* @brief "show_markers" property getter
|
||||
*/
|
||||
bool show_markers () const
|
||||
{
|
||||
return m_show_markers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Don't show stipples
|
||||
*/
|
||||
|
|
@ -2671,6 +2684,7 @@ private:
|
|||
bool m_apply_text_trans;
|
||||
double m_default_text_size;
|
||||
unsigned int m_text_font;
|
||||
bool m_show_markers;
|
||||
bool m_no_stipples;
|
||||
bool m_stipple_offset;
|
||||
|
||||
|
|
|
|||
|
|
@ -819,9 +819,22 @@ LayoutViewConfigPage4::update ()
|
|||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION > 0x050000
|
||||
unsigned int dpr = 1; //devicePixelRatio ();
|
||||
#else
|
||||
unsigned int dpr = 1;
|
||||
#endif
|
||||
|
||||
QFontMetrics fm (font (), this);
|
||||
QRect rt (fm.boundingRect (QString::fromUtf8 ("AA")));
|
||||
QPixmap pxmp (rt.width () + 10, rt.height () + 10);
|
||||
|
||||
const unsigned int h = rt.height () + 10;
|
||||
const unsigned int w = rt.width () + 10;
|
||||
|
||||
QPixmap pxmp (w * dpr, h * dpr);
|
||||
#if QT_VERSION > 0x050000
|
||||
pxmp.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
|
||||
QPainter pxpainter (&pxmp);
|
||||
pxpainter.setPen (QPen (palette ().color (QPalette::Active, QPalette::Text)));
|
||||
|
|
@ -1159,29 +1172,29 @@ LayoutViewConfigPage6::update ()
|
|||
const unsigned int h = rt.height () + 10;
|
||||
const unsigned int w = rt.width () + 10;
|
||||
|
||||
unsigned int color0 = palette ().color (QPalette::Active, QPalette::Button).rgb();
|
||||
unsigned int color1 = palette ().color (QPalette::Active, QPalette::Dark).rgb();
|
||||
QColor color0 = palette ().color (QPalette::Active, QPalette::Button);
|
||||
QColor color1 = palette ().color (QPalette::Active, QPalette::Dark);
|
||||
|
||||
QImage image (w, h, QImage::Format_RGB32);
|
||||
if (s >= 0) {
|
||||
const uint32_t * const *dp = m_pattern.pattern ((unsigned int) s).pattern ();
|
||||
for (unsigned int l = 0; l < h; ++l, ++dp) {
|
||||
uint32_t m = **dp;
|
||||
if (l == 0 || l == h - 1) {
|
||||
m |= ((1 << w) - 1);
|
||||
} else {
|
||||
m |= ((1 << (w - 1)) | 1);
|
||||
}
|
||||
color_t *pt = (color_t *) image.scanLine (h - 1 - l);
|
||||
for (unsigned int b = 0; b < w; ++b) {
|
||||
*pt++ = (m & 1) ? color1 : color0;
|
||||
m >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if QT_VERSION > 0x050000
|
||||
unsigned int dpr = 1; //devicePixelRatio ();
|
||||
#else
|
||||
unsigned int dpr = 1;
|
||||
#endif
|
||||
|
||||
QImage image (w * dpr, h * dpr, QImage::Format_RGB32);
|
||||
#if QT_VERSION > 0x050000
|
||||
image.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
image.fill (color0.rgb ());
|
||||
|
||||
// copying code from layLayerToolbox.cc
|
||||
QBitmap bitmap = m_pattern.pattern ((unsigned int) s).get_bitmap (w * dpr, h * dpr);
|
||||
QPainter painter (&image);
|
||||
painter.setPen (QPen (color1));
|
||||
painter.setBackgroundMode (Qt::TransparentMode);
|
||||
painter.drawPixmap (0, 0, w, h, bitmap);
|
||||
|
||||
QPixmap pxmp = QPixmap::fromImage (image); // Qt 4.6.0 workaround
|
||||
|
||||
QPainter pxpainter (&pxmp);
|
||||
pxpainter.setPen (QPen (palette ().color (QPalette::Active, QPalette::Text)));
|
||||
QRect r (0, 0, pxmp.width () - 1, pxmp.height () - 1);
|
||||
|
|
@ -1189,6 +1202,10 @@ LayoutViewConfigPage6::update ()
|
|||
pxpainter.setFont (font ());
|
||||
pxpainter.drawText (r, Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextSingleLine, text);
|
||||
|
||||
#if QT_VERSION > 0x050000
|
||||
pxmp.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
|
||||
(mp_ui->*(cfg6_buttons [i]))->setIconSize (pxmp.size ());
|
||||
(mp_ui->*(cfg6_buttons [i]))->setIcon (QIcon (pxmp));
|
||||
|
||||
|
|
@ -1366,16 +1383,28 @@ LayoutViewConfigPage6a::update ()
|
|||
const unsigned int h = 26;
|
||||
const unsigned int w = 26;
|
||||
|
||||
QImage image (w, h, QImage::Format_RGB32);
|
||||
image.fill (color0.rgb ());
|
||||
#if QT_VERSION > 0x050000
|
||||
unsigned int dpr = 1; //devicePixelRatio ();
|
||||
#else
|
||||
unsigned int dpr = 1;
|
||||
#endif
|
||||
|
||||
QBitmap bitmap = m_style.style (s).get_bitmap (w, h);
|
||||
QImage image (w * dpr, h * dpr, QImage::Format_RGB32);
|
||||
image.fill (color0.rgb ());
|
||||
#if QT_VERSION > 0x050000
|
||||
image.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
|
||||
QBitmap bitmap = m_style.style (s).get_bitmap (w * dpr, h * dpr);
|
||||
QPainter painter (&image);
|
||||
painter.setPen (QPen (color1));
|
||||
painter.setBackgroundMode (Qt::TransparentMode);
|
||||
painter.drawPixmap (0, 0, bitmap);
|
||||
painter.drawPixmap (0, 0, w, h, bitmap);
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage (image); // Qt 4.6.0 workaround
|
||||
#if QT_VERSION > 0x050000
|
||||
pixmap.setDevicePixelRatio (dpr);
|
||||
#endif
|
||||
b->setIconSize (pixmap.size ());
|
||||
b->setIcon (QIcon (pixmap));
|
||||
|
||||
|
|
@ -1510,6 +1539,7 @@ public:
|
|||
options.push_back (std::pair<std::string, std::string> (cfg_stipple_offset, "true"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_line_style_palette, lay::LineStylePalette ().to_string ()));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_no_stipple, "false"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_markers_visible, "true"));
|
||||
}
|
||||
|
||||
virtual std::vector<std::pair <std::string, ConfigPage *> > config_pages (QWidget *parent) const
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ MarkerBase::set_line_style (int line_style)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MarkerBase::get_bitmaps (const Viewport & /*vp*/, ViewObjectCanvas &canvas, lay::CanvasPlane *&fill, lay::CanvasPlane *&contour, lay::CanvasPlane *&vertex, lay::CanvasPlane *&text)
|
||||
{
|
||||
double resolution = canvas.resolution ();
|
||||
|
|
|
|||
|
|
@ -665,13 +665,11 @@ need_draw_box (const db::Layout *layout, const db::Cell &cell,
|
|||
return int (cell.hierarchy_levels ()) + level >= to_level;
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level)
|
||||
void
|
||||
RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &redraw_regions, int level)
|
||||
{
|
||||
lay::Renderer &r = *mp_renderer;
|
||||
|
||||
// do not draw, if there is nothing to draw
|
||||
if (mp_layout->cells () <= ci || vp.empty ()) {
|
||||
if (mp_layout->cells () <= ci || redraw_regions.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -685,6 +683,17 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
return;
|
||||
}
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = redraw_regions.begin (); b != redraw_regions.end (); ++b) {
|
||||
draw_boxes (drawing_context, ci, trans, *b, level);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level)
|
||||
{
|
||||
lay::Renderer &r = *mp_renderer;
|
||||
const db::Cell &cell = mp_layout->cell (ci);
|
||||
|
||||
// For small bboxes, the cell outline can be reduced ..
|
||||
db::Box bbox = cell.bbox ();
|
||||
|
||||
|
|
@ -714,19 +723,19 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
} else {
|
||||
|
||||
db::box_convert <db::CellInst> bc (*mp_layout);
|
||||
|
||||
|
||||
// create a set of boxes to look into
|
||||
db::Coord aw = db::coord_traits<db::Coord>::rounded (m_abstract_mode_width / mp_layout->dbu ());
|
||||
std::vector<db::Box> vv;
|
||||
if (level == 1 && m_abstract_mode_width > 0 && bbox.width () > db::Box::distance_type (aw * 2) && bbox.height () > db::Box::distance_type (aw * 2)) {
|
||||
vv.reserve (4);
|
||||
vv.push_back (vp & db::Box (bbox.left (), bbox.bottom (), bbox.left () + aw, bbox.top ()));
|
||||
vv.push_back (vp & db::Box (bbox.right () - aw, bbox.bottom (), bbox.right (), bbox.top ()));
|
||||
vv.push_back (vp & db::Box (bbox.left () + aw, bbox.bottom (), bbox.right () - aw, bbox.bottom () + aw));
|
||||
vv.push_back (vp & db::Box (bbox.left () + aw, bbox.top () - aw, bbox.right () - aw, bbox.top ()));
|
||||
vv.push_back (redraw_box & db::Box (bbox.left (), bbox.bottom (), bbox.left () + aw, bbox.top ()));
|
||||
vv.push_back (redraw_box & db::Box (bbox.right () - aw, bbox.bottom (), bbox.right (), bbox.top ()));
|
||||
vv.push_back (redraw_box & db::Box (bbox.left () + aw, bbox.bottom (), bbox.right () - aw, bbox.bottom () + aw));
|
||||
vv.push_back (redraw_box & db::Box (bbox.left () + aw, bbox.top () - aw, bbox.right () - aw, bbox.top ()));
|
||||
} else {
|
||||
vv.reserve (1);
|
||||
vv.push_back (vp);
|
||||
vv.push_back (redraw_box);
|
||||
}
|
||||
|
||||
// dive down into the hierarchy ..
|
||||
|
|
@ -737,7 +746,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
bool anything = false;
|
||||
db::cell_index_type last_ci = std::numeric_limits<db::cell_index_type>::max ();
|
||||
|
||||
db::Cell::touching_iterator inst = cell.begin_touching (*v);
|
||||
db::Cell::touching_iterator inst = cell.begin_touching (*v);
|
||||
while (! inst.at_end ()) {
|
||||
|
||||
const db::CellInstArray &cell_inst = inst->cell_inst ();
|
||||
|
|
@ -746,7 +755,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
db::Box new_cell_box = mp_layout->cell (new_ci).bbox ();
|
||||
|
||||
if (last_ci != new_ci) {
|
||||
// Hint: don't use any_cell_box on partially visible cells because that will degrade performance
|
||||
// Hint: don't use any_cell_box on partially visible cells because that will degrade performance
|
||||
if (new_cell_box.inside (*v)) {
|
||||
last_ci = new_ci;
|
||||
anything = any_cell_box (new_ci, m_to_level - (level + 1));
|
||||
|
|
@ -758,7 +767,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
if (anything) {
|
||||
|
||||
db::Vector a, b;
|
||||
unsigned long amax, bmax;
|
||||
unsigned long amax, bmax;
|
||||
bool simplify = false;
|
||||
if (cell_inst.is_regular_array (a, b, amax, bmax)) {
|
||||
|
||||
|
|
@ -768,8 +777,8 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
} else {
|
||||
inst_box = trans * new_cell_box;
|
||||
}
|
||||
if (((a.x () == 0 && b.y () == 0) || (a.y () == 0 && b.x () == 0)) &&
|
||||
inst_box.width () < 1.5 && inst_box.height () < 1.5 &&
|
||||
if (((a.x () == 0 && b.y () == 0) || (a.y () == 0 && b.x () == 0)) &&
|
||||
inst_box.width () < 1.5 && inst_box.height () < 1.5 &&
|
||||
(amax <= 1 || trans.ctrans (a.length ()) < 1.5) &&
|
||||
(bmax <= 1 || trans.ctrans (b.length ()) < 1.5)) {
|
||||
simplify = true;
|
||||
|
|
@ -781,7 +790,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
|
||||
// The array can be simplified if there are levels below to draw
|
||||
if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1, m_to_level, m_hidden_cells, m_cv_index)) {
|
||||
|
||||
|
||||
db::box_convert <db::CellInst> bc (*mp_layout);
|
||||
|
||||
unsigned int plane_group = 2;
|
||||
|
|
@ -801,8 +810,8 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
// The array (or single instance) must be iterated instance
|
||||
// by instance
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
|
||||
|
||||
test_snapshot (0);
|
||||
|
||||
test_snapshot (0);
|
||||
db::ICplxTrans t (cell_inst.complex_trans (*p));
|
||||
db::Box new_vp = db::Box (t.inverted () * *v);
|
||||
draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1);
|
||||
|
|
@ -814,7 +823,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
}
|
||||
|
||||
++inst;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -828,7 +837,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level)
|
||||
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level)
|
||||
{
|
||||
if (! m_text_visible) {
|
||||
return;
|
||||
|
|
@ -838,7 +847,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
|
|||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, db::properties_id_type prop_id)
|
||||
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level, db::properties_id_type prop_id)
|
||||
{
|
||||
// do not draw, if there is nothing to draw
|
||||
if (mp_layout->cells () <= ci || vp.empty ()) {
|
||||
|
|
@ -855,6 +864,16 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
|
|||
return;
|
||||
}
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = vp.begin (); b != vp.end (); ++b) {
|
||||
draw_box_properties (drawing_context, ci, trans, *b, level, prop_id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, db::properties_id_type prop_id)
|
||||
{
|
||||
const db::Cell &cell = mp_layout->cell (ci);
|
||||
|
||||
// For small bboxes, the cell outline can be reduced ..
|
||||
db::Box bbox = cell.bbox ();
|
||||
|
||||
|
|
@ -1193,14 +1212,12 @@ RedrawThreadWorker::search_regions (const db::Box &cell_bbox, const db::Box &vp,
|
|||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level)
|
||||
RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level)
|
||||
{
|
||||
if (! m_text_visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
lay::Renderer &r = *mp_renderer;
|
||||
|
||||
unsigned int plane_group = 2;
|
||||
if (drawing_context) {
|
||||
plane_group = 0;
|
||||
|
|
@ -1214,8 +1231,6 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
|
|||
text = m_planes[2 + plane_group * (planes_per_layer / 3)];
|
||||
vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
|
||||
test_snapshot (0);
|
||||
|
||||
// do not draw, if there is nothing to draw
|
||||
if (mp_layout->cells () <= ci || vp.empty ()) {
|
||||
return;
|
||||
|
|
@ -1224,7 +1239,18 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
|
|||
return;
|
||||
}
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = vp.begin (); b != vp.end (); ++b) {
|
||||
draw_text_layer (drawing_context, ci, trans, *b, level, fill, frame, vertex, text);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, CanvasPlane *fill, CanvasPlane *frame, CanvasPlane *vertex, CanvasPlane *text)
|
||||
{
|
||||
test_snapshot (0);
|
||||
|
||||
const db::Cell &cell = mp_layout->cell (ci);
|
||||
lay::Renderer &r = *mp_renderer;
|
||||
|
||||
// For small bboxes, the cell outline can be reduced ..
|
||||
db::Box bbox = cell.bbox (m_layer);
|
||||
|
|
@ -1422,7 +1448,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
|
|||
|
||||
db::ICplxTrans t (cell_inst.complex_trans (*p));
|
||||
db::Box new_vp = db::Box (t.inverted () * *v);
|
||||
draw_text_layer (drawing_context, new_ci, trans * t, new_vp, level + 1);
|
||||
draw_text_layer (drawing_context, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1751,11 +1777,9 @@ private:
|
|||
};
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level,
|
||||
RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vp, int level,
|
||||
lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot)
|
||||
{
|
||||
test_snapshot (update_snapshot);
|
||||
|
||||
// do not draw, if there is nothing to draw
|
||||
if (mp_layout->cells () <= ci || vp.empty ()) {
|
||||
return;
|
||||
|
|
@ -1764,6 +1788,17 @@ RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_typ
|
|||
return;
|
||||
}
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = vp.begin (); b != vp.end (); ++b) {
|
||||
draw_layer (from_level, to_level, ci, trans, *b, level, fill, frame, vertex, text, update_snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level,
|
||||
lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot)
|
||||
{
|
||||
test_snapshot (update_snapshot);
|
||||
|
||||
const db::Cell &cell = mp_layout->cell (ci);
|
||||
db::Box bbox = cell.bbox (m_layer);
|
||||
db::Box cell_bbox = cell.bbox ();
|
||||
|
|
@ -1891,7 +1926,7 @@ RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_typ
|
|||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level)
|
||||
RedrawThreadWorker::draw_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &redraw_regions, int level)
|
||||
{
|
||||
if (drawing_context) {
|
||||
|
||||
|
|
@ -1904,7 +1939,7 @@ RedrawThreadWorker::draw_layer (bool drawing_context, db::cell_index_type ci, co
|
|||
text = m_planes[2 + plane_group * (planes_per_layer / 3)];
|
||||
vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
|
||||
draw_layer (m_from_level, m_to_level, ci, trans, vp, level, fill, frame, vertex, text, 0);
|
||||
draw_layer (m_from_level, m_to_level, ci, trans, redraw_regions, level, fill, frame, vertex, text, 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1919,7 +1954,7 @@ RedrawThreadWorker::draw_layer (bool drawing_context, db::cell_index_type ci, co
|
|||
text = m_planes[2 + plane_group * (planes_per_layer / 3)];
|
||||
vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
|
||||
draw_layer (m_from_level, m_to_level, ci, trans, vp, level, fill, frame, vertex, text, 0);
|
||||
draw_layer (m_from_level, m_to_level, ci, trans, redraw_regions, level, fill, frame, vertex, text, 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1934,7 +1969,7 @@ RedrawThreadWorker::draw_layer (bool drawing_context, db::cell_index_type ci, co
|
|||
text = m_planes[2 + plane_group * (planes_per_layer / 3)];
|
||||
vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
|
||||
draw_layer (m_from_level, 1, ci, trans, vp, level, fill, frame, vertex, text, 0);
|
||||
draw_layer (m_from_level, 1, ci, trans, redraw_regions, level, fill, frame, vertex, text, 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1947,7 +1982,7 @@ RedrawThreadWorker::draw_layer (bool drawing_context, db::cell_index_type ci, co
|
|||
text = m_planes[2 + plane_group * (planes_per_layer / 3)];
|
||||
vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
|
||||
draw_layer (1, m_to_level, ci, trans, vp, level, fill, frame, vertex, text, 0);
|
||||
draw_layer (1, m_to_level, ci, trans, redraw_regions, level, fill, frame, vertex, text, 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1990,7 +2025,7 @@ RedrawThreadWorker::cell_var_cached (db::cell_index_type ci, const db::CplxTrans
|
|||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::iterate_variants (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, db::CplxTrans trans, void (RedrawThreadWorker::*what) (bool, db::cell_index_type, const db::CplxTrans &, const db::Box &, int))
|
||||
RedrawThreadWorker::iterate_variants (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, db::CplxTrans trans, void (RedrawThreadWorker::*what) (bool, db::cell_index_type, const db::CplxTrans &, const std::vector<db::Box> &, int))
|
||||
{
|
||||
// save current state
|
||||
int from_level = m_from_level;
|
||||
|
|
@ -2050,7 +2085,7 @@ RedrawThreadWorker::iterate_variants (const std::vector <db::Box> &redraw_region
|
|||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::iterate_variants_rec (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, const db::CplxTrans &trans, int level, void (RedrawThreadWorker::*what) (bool, db::cell_index_type, const db::CplxTrans &, const db::Box &, int), bool drawing_context)
|
||||
RedrawThreadWorker::iterate_variants_rec (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, const db::CplxTrans &trans, int level, void (RedrawThreadWorker::*what) (bool, db::cell_index_type, const db::CplxTrans &, const std::vector<db::Box> &, int), bool drawing_context)
|
||||
{
|
||||
db::Cell::parent_inst_iterator p = mp_layout->cell (ci).begin_parent_insts ();
|
||||
int context_path_length = int (m_cellviews [m_cv_index].specific_path ().size ());
|
||||
|
|
@ -2092,19 +2127,25 @@ RedrawThreadWorker::iterate_variants_rec (const std::vector <db::Box> &redraw_re
|
|||
|
||||
} else {
|
||||
|
||||
std::vector<db::Box> actual_regions;
|
||||
actual_regions.reserve (redraw_regions.size ());
|
||||
|
||||
for (std::vector<db::Box>::const_iterator rr = redraw_regions.begin (); rr != redraw_regions.end (); ++rr) {
|
||||
|
||||
db::Coord lim = std::numeric_limits<db::Coord>::max ();
|
||||
db::DBox world (trans * db::Box (db::Point (-lim, -lim), db::Point (lim, lim)));
|
||||
db::Box vp = db::Box (trans.inverted () * (world & db::DBox (*rr)));
|
||||
vp &= mp_layout->cell (ci).bbox (); // this avoids problems when accessing designs through very large viewports
|
||||
|
||||
if (! vp.empty ()) {
|
||||
(this->*what) (drawing_context, ci, trans, vp, level);
|
||||
actual_regions.push_back (vp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! actual_regions.empty ()) {
|
||||
(this->*what) (drawing_context, ci, trans, actual_regions, level);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,20 +175,24 @@ protected:
|
|||
void perform_task (tl::Task *task);
|
||||
|
||||
private:
|
||||
void draw_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level);
|
||||
void draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &vp, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
|
||||
void draw_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
|
||||
void draw_layer (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
|
||||
void draw_layer_wo_cache (int from_level, int to_level, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector<db::Box> &vv, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text, const UpdateSnapshotCallback *update_snapshot);
|
||||
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &box, int level);
|
||||
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &box, int level);
|
||||
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &box, int level);
|
||||
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &box, int level, db::properties_id_type prop_id);
|
||||
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_text_layer (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text);
|
||||
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level);
|
||||
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, db::properties_id_type prop_id);
|
||||
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id);
|
||||
void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, const std::string &txt);
|
||||
void draw_cell_properties (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, db::properties_id_type prop_id);
|
||||
void draw_cell_shapes (const db::CplxTrans &trans, const db::Cell &cell, const db::Box &vp, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text);
|
||||
void test_snapshot (const UpdateSnapshotCallback *update_snapshot);
|
||||
void transfer ();
|
||||
void iterate_variants (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, db::CplxTrans trans, void (RedrawThreadWorker::*what) (bool, db::cell_index_type ci, const db::CplxTrans &, const db::Box &, int level));
|
||||
void iterate_variants_rec (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, const db::CplxTrans &trans, int level, void (RedrawThreadWorker::*what) (bool, db::cell_index_type ci, const db::CplxTrans &, const db::Box &, int level), bool spread);
|
||||
void iterate_variants (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, db::CplxTrans trans, void (RedrawThreadWorker::*what) (bool, db::cell_index_type ci, const db::CplxTrans &, const std::vector <db::Box> &, int level));
|
||||
void iterate_variants_rec (const std::vector <db::Box> &redraw_regions, db::cell_index_type ci, const db::CplxTrans &trans, int level, void (RedrawThreadWorker::*what) (bool, db::cell_index_type ci, const db::CplxTrans &, const std::vector <db::Box> &, int level), bool spread);
|
||||
bool cell_var_cached (db::cell_index_type ci, const db::CplxTrans &trans);
|
||||
bool drop_cell (const db::Cell &cell, const db::CplxTrans &trans);
|
||||
std::vector<db::Box> search_regions (const db::Box &cell_bbox, const db::Box &vp, int level);
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ BackgroundViewObject::z_order (int z)
|
|||
// ViewObject implementation
|
||||
|
||||
ViewObject::ViewObject (ViewObjectWidget *widget, bool _static)
|
||||
: mp_widget (widget), m_static (_static), m_visible (true)
|
||||
: mp_widget (widget), m_static (_static), m_visible (true), m_dismissable (false)
|
||||
{
|
||||
if (widget) {
|
||||
widget->m_objects.push_back (this);
|
||||
|
|
@ -178,6 +178,15 @@ ViewObject::~ViewObject ()
|
|||
redraw ();
|
||||
}
|
||||
|
||||
void
|
||||
ViewObject::set_dismissable (bool dismissable)
|
||||
{
|
||||
if (m_dismissable != dismissable) {
|
||||
m_dismissable = dismissable;
|
||||
redraw ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ViewObject::visible (bool vis)
|
||||
{
|
||||
|
|
@ -251,6 +260,7 @@ ViewService::set_cursor (lay::Cursor::cursor_shape cursor)
|
|||
|
||||
ViewObjectWidget::ViewObjectWidget (QWidget *parent, const char *name)
|
||||
: QWidget (parent),
|
||||
m_view_objects_dismissed (false),
|
||||
m_needs_update_static (false),
|
||||
m_needs_update_bg (false),
|
||||
mp_active_service (0),
|
||||
|
|
@ -888,7 +898,7 @@ ViewObjectWidget::do_render (const lay::Viewport &vp, lay::ViewObjectCanvas &can
|
|||
}
|
||||
|
||||
for (object_iterator obj = begin_objects (); obj != end_objects (); ++obj) {
|
||||
if (obj->m_static == st && obj->is_visible ()) {
|
||||
if (obj->m_static == st && obj->is_visible () && (! m_view_objects_dismissed || ! obj->get_dismissable ())) {
|
||||
BEGIN_PROTECTED_SILENT
|
||||
obj->render (vp, canvas);
|
||||
END_PROTECTED_SILENT
|
||||
|
|
@ -963,6 +973,16 @@ ViewObjectWidget::touch_bg ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ViewObjectWidget::set_dismiss_view_objects (bool dismiss)
|
||||
{
|
||||
if (dismiss != m_view_objects_dismissed) {
|
||||
m_view_objects_dismissed = dismiss;
|
||||
touch ();
|
||||
update ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ViewObjectWidget::objects_changed ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -513,6 +513,23 @@ public:
|
|||
return const_cast<ViewObjectWidget *> (mp_widget.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the marker can be dismissed (made invisible)
|
||||
*
|
||||
* Markers with this flag set to true can be hidden by using ViewObjectCanvas::show_markers.
|
||||
*/
|
||||
bool get_dismissable () const
|
||||
{
|
||||
return m_dismissable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the marker can be dismissed (made invisible)
|
||||
*
|
||||
* See \\get_dismissable for details.
|
||||
*/
|
||||
void set_dismissable (bool f);
|
||||
|
||||
/**
|
||||
* @brief Set the visibility state of the view object
|
||||
*
|
||||
|
|
@ -561,6 +578,7 @@ private:
|
|||
tl::weak_ptr<ViewObjectWidget> mp_widget;
|
||||
bool m_static;
|
||||
bool m_visible;
|
||||
bool m_dismissable;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -905,6 +923,21 @@ public:
|
|||
*/
|
||||
void set_default_cursor (lay::Cursor::cursor_shape cursor);
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether dismissable view objects shall be drawn or not
|
||||
*
|
||||
* Markers with dismissable = false are always drawn. The default value is "false".
|
||||
*/
|
||||
void set_dismiss_view_objects (bool dismissed);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether dismissable markers shall be drawn or not
|
||||
*/
|
||||
bool dismiss_view_objects () const
|
||||
{
|
||||
return m_view_objects_dismissed;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Qt focus event handler
|
||||
|
|
@ -985,6 +1018,7 @@ private:
|
|||
tl::weak_collection<lay::BackgroundViewObject> m_background_objects;
|
||||
std::list<lay::ViewService *> m_services;
|
||||
std::list<ViewService *> m_grabbed;
|
||||
bool m_view_objects_dismissed;
|
||||
bool m_needs_update_static;
|
||||
bool m_needs_update_bg;
|
||||
lay::ViewService *mp_active_service;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ static const std::string cfg_sel_line_style ("sel-line-style");
|
|||
static const std::string cfg_sel_transient_mode ("sel-transient-mode");
|
||||
static const std::string cfg_sel_inside_pcells_mode ("sel-inside-pcells-mode");
|
||||
|
||||
static const std::string cfg_markers_visible ("markers-visible");
|
||||
|
||||
static const std::string cfg_min_inst_label_size ("min-inst-label-size");
|
||||
static const std::string cfg_cell_box_text_font ("inst-label-font");
|
||||
static const std::string cfg_cell_box_text_transform ("inst-label-transform");
|
||||
|
|
|
|||
|
|
@ -2177,36 +2177,42 @@ MarkerBrowserPage::do_update_markers ()
|
|||
|
||||
mp_markers.push_back (new lay::DMarker (mp_view));
|
||||
mp_markers.back ()->set (trans * polygon_value->value ());
|
||||
mp_markers.back ()->set_dismissable (true);
|
||||
m_markers_bbox += trans * polygon_value->value ().box ();
|
||||
|
||||
} else if (edge_pair_value) {
|
||||
|
||||
mp_markers.push_back (new lay::DMarker (mp_view));
|
||||
mp_markers.back ()->set (trans * edge_pair_value->value ());
|
||||
mp_markers.back ()->set_dismissable (true);
|
||||
m_markers_bbox += trans * db::DBox (edge_pair_value->value ().bbox ());
|
||||
|
||||
} else if (edge_value) {
|
||||
|
||||
mp_markers.push_back (new lay::DMarker (mp_view));
|
||||
mp_markers.back ()->set (trans * edge_value->value ());
|
||||
mp_markers.back ()->set_dismissable (true);
|
||||
m_markers_bbox += trans * db::DBox (edge_value->value ().bbox ());
|
||||
|
||||
} else if (box_value) {
|
||||
|
||||
mp_markers.push_back (new lay::DMarker (mp_view));
|
||||
mp_markers.back ()->set (trans * box_value->value ());
|
||||
mp_markers.back ()->set_dismissable (true);
|
||||
m_markers_bbox += trans * box_value->value ();
|
||||
|
||||
} else if (text_value) {
|
||||
|
||||
mp_markers.push_back (new lay::DMarker (mp_view));
|
||||
mp_markers.back ()->set (trans * text_value->value ());
|
||||
mp_markers.back ()->set_dismissable (true);
|
||||
m_markers_bbox += trans * text_value->value ().box ();
|
||||
|
||||
} else if (path_value) {
|
||||
|
||||
mp_markers.push_back (new lay::DMarker (mp_view));
|
||||
mp_markers.back ()->set (trans * path_value->value ());
|
||||
mp_markers.back ()->set_dismissable (true);
|
||||
m_markers_bbox += trans * path_value->value ().box ();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "tlClassRegistry.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlXMLParser.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
#include "rba.h"
|
||||
#include "pya.h"
|
||||
|
|
@ -213,15 +214,18 @@ void Macro::save_to (const std::string &path)
|
|||
}
|
||||
}
|
||||
|
||||
void Macro::load_from (const std::string &path)
|
||||
void Macro::load_from (const std::string &fn)
|
||||
{
|
||||
m_format = NoFormat;
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Loading macro from " << path;
|
||||
}
|
||||
std::pair<bool, std::string> f = format_from_filename (fn, m_interpreter, m_dsl_interpreter, m_autorun_default, m_format);
|
||||
if (f.first) {
|
||||
|
||||
if (format_from_suffix (path, m_interpreter, m_dsl_interpreter, m_autorun_default, m_format)) {
|
||||
const std::string &path = f.second;
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Loading macro from " << path;
|
||||
}
|
||||
|
||||
m_autorun = m_autorun_default;
|
||||
|
||||
|
|
@ -242,7 +246,7 @@ void Macro::load_from (const std::string &path)
|
|||
}
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to determine format for file from suffix ")) + path);
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to determine format for file from suffix or format spec ")) + fn);
|
||||
}
|
||||
|
||||
m_modified = true;
|
||||
|
|
@ -297,7 +301,24 @@ bool
|
|||
Macro::format_from_suffix (const std::string &fn, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format)
|
||||
{
|
||||
std::string suffix = tl::to_string (QFileInfo (tl::to_qstring (fn)).suffix ());
|
||||
return format_from_suffix_string (suffix, interpreter, dsl_name, autorun_pref, format);
|
||||
}
|
||||
|
||||
std::pair<bool, std::string>
|
||||
Macro::format_from_filename (const std::string &fn, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format)
|
||||
{
|
||||
tl::GlobPattern pat ("(*)\\[(*)\\]");
|
||||
std::vector<std::string> pat_parts;
|
||||
if (pat.match (fn, pat_parts) && pat_parts.size () == 2) {
|
||||
return std::make_pair (format_from_suffix_string (pat_parts[1], interpreter, dsl_name, autorun_pref, format), pat_parts[0]);
|
||||
} else {
|
||||
return std::make_pair (format_from_suffix (fn, interpreter, dsl_name, autorun_pref, format), fn);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Macro::format_from_suffix_string (const std::string &suffix, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format)
|
||||
{
|
||||
interpreter = None;
|
||||
dsl_name = std::string ();
|
||||
format = NoFormat;
|
||||
|
|
|
|||
|
|
@ -602,6 +602,8 @@ private:
|
|||
void on_menu_needs_update ();
|
||||
void on_changed ();
|
||||
void save_to (const std::string &path);
|
||||
static bool format_from_suffix_string (const std::string &suffix, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format);
|
||||
static std::pair<bool, std::string> format_from_filename (const std::string &fn, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format);
|
||||
|
||||
void set_autorun_default (bool f)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@ int run_pymodtest (tl::TestBase *_this, const std::string &fn)
|
|||
|
||||
std::string text;
|
||||
{
|
||||
tl::InputPipe pipe (std::string (STRINGIFY (PYTHON)) + " " + fp + " 2>&1");
|
||||
std::string cmd = std::string (STRINGIFY (PYTHON)) + " " + fp + " 2>&1";
|
||||
tl::info << cmd;
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
text = is.read_all ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ SOURCES = \
|
|||
tlThreadedWorkers.cc \
|
||||
tlThreads.cc \
|
||||
tlDeferredExecution.cc \
|
||||
tlUri.cc
|
||||
tlUri.cc \
|
||||
tlLongInt.cc
|
||||
|
||||
HEADERS = \
|
||||
tlAlgorithm.h \
|
||||
|
|
@ -101,14 +102,14 @@ HEADERS = \
|
|||
tlCommandLineParser.h \
|
||||
tlUnitTest.h \
|
||||
tlInt128Support.h \
|
||||
tlHttpStreamCurl.h \
|
||||
tlDefs.h \
|
||||
tlXMLParser.h \
|
||||
tlXMLWriter.h \
|
||||
tlThreadedWorkers.h \
|
||||
tlThreads.h \
|
||||
tlDeferredExecution.h \
|
||||
tlUri.h
|
||||
tlUri.h \
|
||||
tlLongInt.h
|
||||
|
||||
equals(HAVE_CURL, "1") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "tlLongInt.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,178 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdint.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include "tlLongInt.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
typedef tl::long_int<4, uint8_t, uint16_t> li_type;
|
||||
typedef int32_t i_type;
|
||||
|
||||
typedef tl::long_uint<4, uint8_t, uint16_t> lui_type;
|
||||
typedef uint32_t ui_type;
|
||||
|
||||
i_type to_i (li_type x)
|
||||
{
|
||||
return i_type (x);
|
||||
}
|
||||
|
||||
ui_type to_i (lui_type x)
|
||||
{
|
||||
return ui_type (x);
|
||||
}
|
||||
|
||||
li_type to_e (i_type x)
|
||||
{
|
||||
return li_type (x);
|
||||
}
|
||||
|
||||
lui_type to_e (ui_type x)
|
||||
{
|
||||
return lui_type (x);
|
||||
}
|
||||
|
||||
template <class I1, class LI1, class I2, class LI2>
|
||||
static void run_test_int (tl::TestBase *_this, I1 a, I2 b)
|
||||
{
|
||||
typedef typename LI1::basic_type basic_type;
|
||||
if (tl::verbose ()) {
|
||||
printf("Long int test with pair (%ld,%ld)\n", long (a), long (b));
|
||||
}
|
||||
|
||||
LI1 ae = to_e (a);
|
||||
LI2 be = to_e (b);
|
||||
LI1 r;
|
||||
|
||||
EXPECT_EQ (to_i (ae), a);
|
||||
EXPECT_EQ (to_i (be), b);
|
||||
|
||||
EXPECT_EQ (to_i (ae + be), a + b);
|
||||
r = ae;
|
||||
r += be;
|
||||
EXPECT_EQ (to_i (r), a + b);
|
||||
EXPECT_EQ (to_i (ae + basic_type (2)), a + basic_type (2));
|
||||
r = ae;
|
||||
r += basic_type (2);
|
||||
EXPECT_EQ (to_i (r), a + basic_type (2));
|
||||
|
||||
EXPECT_EQ (to_i (ae - be), a - b);
|
||||
r = ae;
|
||||
r -= be;
|
||||
EXPECT_EQ (to_i (r), a - b);
|
||||
EXPECT_EQ (to_i (ae - basic_type (2)), a - basic_type (2));
|
||||
r = ae;
|
||||
r -= basic_type (2);
|
||||
EXPECT_EQ (to_i (r), a - basic_type (2));
|
||||
|
||||
EXPECT_EQ (ae == be, a == b);
|
||||
EXPECT_EQ (ae != be, a != b);
|
||||
EXPECT_EQ (ae < be, a < b);
|
||||
EXPECT_EQ (ae <= be, a <= b);
|
||||
EXPECT_EQ (ae > be, a > b);
|
||||
EXPECT_EQ (ae >= be, a >= b);
|
||||
EXPECT_EQ (ae.is_zero (), a == 0);
|
||||
|
||||
EXPECT_EQ (to_i (ae * be), a * b);
|
||||
r = ae;
|
||||
r *= be;
|
||||
EXPECT_EQ (to_i (r), a * b);
|
||||
|
||||
if (b != 0) {
|
||||
EXPECT_EQ (to_i (ae / be), a / b);
|
||||
r = ae;
|
||||
r /= be;
|
||||
EXPECT_EQ (to_i (r), a / b);
|
||||
EXPECT_EQ (to_i (ae % be), a % b);
|
||||
r = ae;
|
||||
r %= be;
|
||||
EXPECT_EQ (to_i (r), a % b);
|
||||
}
|
||||
}
|
||||
|
||||
template <class I1, class LI1, class I2, class LI2>
|
||||
static void run_test (tl::TestBase *_this, I1 a, I2 b)
|
||||
{
|
||||
run_test_int<I1, LI1, I2, LI2> (_this, a, b);
|
||||
run_test_int<I1, LI1, I2, LI2> (_this, a, a);
|
||||
run_test_int<I1, LI1, I2, LI2> (_this, b, b);
|
||||
run_test_int<I1, LI1, I2, LI2> (_this, b, a);
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 0, 1);
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 256, 257);
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 256, 2);
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 65535, 65536);
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 65535, 2);
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 0xfffffffe, 0xffffffff);
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, 0xfffffffe, 2);
|
||||
for (unsigned int i = 0; i < 100000; ++i) {
|
||||
run_test<i_type, li_type, i_type, li_type> (_this, rand () * rand (), rand () * rand ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 0, 1);
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 256, 257);
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 256, 2);
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 65535, 65536);
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 65535, 2);
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 0xfffffffe, 0xffffffff);
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, 0xfffffffe, 2);
|
||||
for (unsigned int i = 0; i < 100000; ++i) {
|
||||
run_test<ui_type, lui_type, i_type, li_type> (_this, rand () * rand (), rand () * rand ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(3)
|
||||
{
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 0, 1);
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 256, 257);
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 256, 2);
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 65535, 65536);
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 65535, 2);
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 0xfffffffe, 0xffffffff);
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, 0xfffffffe, 2);
|
||||
for (unsigned int i = 0; i < 100000; ++i) {
|
||||
run_test<i_type, li_type, ui_type, lui_type> (_this, rand () * rand (), rand () * rand ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(4)
|
||||
{
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 0, 1);
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 256, 257);
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 256, 2);
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 65535, 65536);
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 65535, 2);
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 0xfffffffe, 0xffffffff);
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, 0xfffffffe, 2);
|
||||
for (unsigned int i = 0; i < 100000; ++i) {
|
||||
run_test<ui_type, lui_type, ui_type, lui_type> (_this, rand () * rand (), rand () * rand ());
|
||||
}
|
||||
}
|
||||
|
|
@ -357,7 +357,7 @@ void run_thread_tests (tl::TestBase *_this, int wait)
|
|||
s_sum[3].reset ();
|
||||
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
job.schedule (new MyTask (10000));
|
||||
job.schedule (new MyTask (100000));
|
||||
}
|
||||
|
||||
job.start ();
|
||||
|
|
|
|||
|
|
@ -28,11 +28,12 @@ SOURCES = \
|
|||
tlThreads.cc \
|
||||
tlUtils.cc \
|
||||
tlVariant.cc \
|
||||
tlInt128Support.cc \
|
||||
tlXMLParser.cc \
|
||||
tlUri.cc \
|
||||
tlWebDAV.cc \
|
||||
tlHttpStream.cc \
|
||||
tlInt128Support.cc \
|
||||
tlLongInt.cc \
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
import os, subprocess
|
||||
import sys
|
||||
from macbuild.build4mac_util import WalkFrameworkPaths, PerformChanges, DetectChanges
|
||||
from pathlib import Path
|
||||
|
||||
# bundlePath = AbsMacPkgDir
|
||||
bundlePath = os.getcwd() + '/qt5.pkg.macos-HighSierra-release/klayout.app'
|
||||
bundleExecPathAbs = '%s/Contents/MacOS/' % bundlePath
|
||||
pythonOriginalFrameworkPath = '/usr/local/opt/python/Frameworks/Python.framework'
|
||||
pythonFrameworkPath = '%s/Contents/Frameworks/Python.framework' % bundlePath
|
||||
|
||||
|
||||
print("[1] Copying Python Framework")
|
||||
shell_commands = list()
|
||||
shell_commands.append(f"rm -rf {pythonFrameworkPath}")
|
||||
shell_commands.append(f"rsync -a --safe-links {pythonOriginalFrameworkPath}/ {pythonFrameworkPath}")
|
||||
shell_commands.append(f"mkdir {pythonFrameworkPath}/Versions/3.6/lib/python3.6/site-packages/")
|
||||
shell_commands.append(f"cp -RL {pythonOriginalFrameworkPath}/Versions/3.6/lib/python3.6/site-packages/{{pip*,pkg_resources,setuptools*,wheel*}} " +
|
||||
f"{pythonFrameworkPath}/Versions/3.6/lib/python3.6/site-packages/")
|
||||
shell_commands.append(f"rm -rf {pythonFrameworkPath}/Versions/3.6/lib/python3.6/test")
|
||||
shell_commands.append(f"rm -rf {pythonFrameworkPath}/Versions/3.6/Resources")
|
||||
shell_commands.append(f"rm -rf {pythonFrameworkPath}/Versions/3.6/bin")
|
||||
|
||||
for command in shell_commands:
|
||||
if subprocess.call( command, shell=True ) != 0:
|
||||
msg = "command failed: %s"
|
||||
print( msg % command, file=sys.stderr )
|
||||
exit(1)
|
||||
|
||||
print("[2] Relinking dylib dependencies inside Python.framework")
|
||||
depdict = WalkFrameworkPaths(pythonFrameworkPath)
|
||||
appPythonFrameworkPath = '@executable_path/../Frameworks/Python.framework/'
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
usrLocalPath = '/usr/local/opt/'
|
||||
appUsrLocalPath = '@executable_path/../Frameworks/'
|
||||
depdict = WalkFrameworkPaths(pythonFrameworkPath)
|
||||
PerformChanges(depdict, [(usrLocalPath, appUsrLocalPath)], bundleExecPathAbs, libdir=True)
|
||||
|
||||
print("[3] Relinking dylib dependencies for klayout")
|
||||
klayoutPath = bundleExecPathAbs
|
||||
depdict = WalkFrameworkPaths(klayoutPath, filter_regex=r'klayout$')
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
libKlayoutPath = bundleExecPathAbs + '../Frameworks'
|
||||
depdict = WalkFrameworkPaths(libKlayoutPath, filter_regex=r'libklayout')
|
||||
PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
print("[4] Patching site.py, pip/, and distutils/")
|
||||
site_module = f"{pythonFrameworkPath}/Versions/3.6/lib/python3.6/site.py"
|
||||
with open(site_module, 'r') as site:
|
||||
buf = site.readlines()
|
||||
with open(site_module, 'w') as site:
|
||||
import re
|
||||
for line in buf:
|
||||
# This will fool pip into thinking it's inside a virtual environment
|
||||
# and install new packates to the correct site-packages
|
||||
if re.match("^PREFIXES", line) is not None:
|
||||
line = line + "sys.real_prefix = sys.prefix\n"
|
||||
# do not allow installation in the user folder.
|
||||
if re.match("^ENABLE_USER_SITE", line) is not None:
|
||||
line = "ENABLE_USER_SITE = False\n"
|
||||
site.write(line)
|
||||
|
||||
pip_module = f"{pythonFrameworkPath}/Versions/3.6/lib/python3.6/site-packages/pip/__init__.py"
|
||||
with open(pip_module, 'r') as pip:
|
||||
buf = pip.readlines()
|
||||
with open(pip_module, 'w') as pip:
|
||||
import re
|
||||
for line in buf:
|
||||
# this will reject user's configuration of pip, forcing the isolated mode
|
||||
line = re.sub("return isolated$", "return isolated or True", line)
|
||||
pip.write(line)
|
||||
|
||||
distutilsconfig = f"{pythonFrameworkPath}/Versions/3.6/lib/python3.6/distutils/distutils.cfg"
|
||||
with open(distutilsconfig, 'r') as file:
|
||||
buf = file.readlines()
|
||||
with open(distutilsconfig, 'w') as file:
|
||||
import re
|
||||
for line in buf:
|
||||
# This will cause all packages to be installed to sys.prefix
|
||||
if re.match('prefix=', line) is not None:
|
||||
continue
|
||||
file.write(line)
|
||||
|
||||
|
||||
# pythonPath = bundleExecPathAbs + '../Frameworks/Python.framework/Versions/3.6/bin/'
|
||||
# # pythonOriginalPrefixPath = '/usr/local/opt/python/Frameworks/Python.framework/Versions/3.6'
|
||||
# # appPythonBinPath = '@executable_path/../'
|
||||
# depdict = WalkFrameworkPaths(pythonPath, filter_regex=r'python')
|
||||
# print(depdict)
|
||||
# PerformChanges(depdict, [(pythonOriginalFrameworkPath, appPythonFrameworkPath),
|
||||
# (Path(pythonOriginalFrameworkPath).resolve(), appPythonFrameworkPath)], bundleExecPathAbs)
|
||||
|
||||
# usrLocalPath = '/usr/local/lib/'
|
||||
# appUsrLocalPath = '@executable_path/../Frameworks/'
|
||||
# depdict = WalkFrameworkPaths(pythonFrameworkPath)
|
||||
# PerformChanges(depdict, [(usrLocalPath, appUsrLocalPath)], bundleExecPathAbs)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import site; print(site.getsitepackages())
|
||||
|
||||
import pip
|
||||
installed_packages = pip.get_installed_distributions()
|
||||
installed_packages_list = sorted(["%s==%s" % (i.key, i.version)
|
||||
for i in installed_packages])
|
||||
print(installed_packages_list)
|
||||
|
||||
print("-------------")
|
||||
|
||||
if pip.main(['install', '--upgrade', 'numpy']) > 0:
|
||||
exit(1)
|
||||
print("-------------")
|
||||
|
||||
|
||||
print("Importing numpy")
|
||||
import numpy
|
||||
print("-------------")
|
||||
|
||||
|
||||
import sys;
|
||||
print("Executing from: ", sys.executable)
|
||||
print("-------------")
|
||||
|
||||
import os
|
||||
print("Environment variables:")
|
||||
for variable, value in os.environ.items():
|
||||
print(variable, ":", value)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue