mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into wip
This commit is contained in:
commit
e965f87f58
|
|
@ -0,0 +1,10 @@
|
|||
# Set update schedule for GitHub Actions
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
# Check for updates to GitHub Actions every week
|
||||
interval: "monthly"
|
||||
|
|
@ -4,8 +4,11 @@ name: Build Python Wheels
|
|||
|
||||
on:
|
||||
pull_request:
|
||||
# Running on PRs is enough
|
||||
# push:
|
||||
# Running on PRs and main branch only
|
||||
# pull requests should be able to access cache from main branch
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
|
|
@ -28,12 +31,13 @@ jobs:
|
|||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
android: false
|
||||
dotnet: false
|
||||
haskell: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: false # not working currently
|
||||
- uses: hmarr/debug-action@v2
|
||||
- name: Cancel Workflow Action
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
- uses: actions/checkout@v3
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
|
@ -48,12 +52,13 @@ jobs:
|
|||
HOST_CCACHE_DIR="$(ccache -k cache_dir)"
|
||||
mkdir -p $HOST_CCACHE_DIR
|
||||
- name: Build wheels # check https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions
|
||||
uses: pypa/cibuildwheel@v2.12.0
|
||||
uses: pypa/cibuildwheel@v2.13.1
|
||||
# to supply options, put them in 'env', like:
|
||||
# env:
|
||||
# CIBW_SOME_OPTION: value
|
||||
env:
|
||||
CIBW_BUILD: ${{ matrix.cibuild }}
|
||||
|
||||
- name: Download Cache from Docker (linux only)
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
# hack until https://github.com/pypa/cibuildwheel/issues/1030 is fixed
|
||||
|
|
@ -65,24 +70,21 @@ jobs:
|
|||
mv ./wheelhouse/.ccache $HOST_CCACHE_DIR
|
||||
ls -la $HOST_CCACHE_DIR
|
||||
ccache -s
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
# The following was taken from https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/
|
||||
# The following was taken from https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/
|
||||
make_sdist:
|
||||
name: Make SDist
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # Optional, use if you use setuptools_scm
|
||||
submodules: true # Optional, use if you have submodules
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build SDist
|
||||
run: pipx run build --sdist
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: dist/*.tar.gz
|
||||
|
||||
|
|
@ -90,29 +92,29 @@ jobs:
|
|||
needs: [build, make_sdist]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: artifact
|
||||
path: dist
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@v1.4.2
|
||||
- uses: pypa/gh-action-pypi-publish@v1.8.7
|
||||
continue-on-error: true # might fail if we don't bump the version
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.test_pypi_password }}
|
||||
repository_url: https://test.pypi.org/legacy/
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
||||
upload_to_pypi:
|
||||
needs: [build, make_sdist]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: artifact
|
||||
path: dist
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@v1.4.2
|
||||
- uses: pypa/gh-action-pypi-publish@v1.8.7
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.pypi_password }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
name: cleanup caches by a branch
|
||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
|
||||
# Caches are very large and must be deleted to prioritize main branch's caches.
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
|
||||
REPO=${{ github.repository }}
|
||||
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
|
||||
|
||||
echo "Fetching list of cache key"
|
||||
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
|
||||
|
||||
## Setting this to not fail the workflow while deleting cache keys.
|
||||
set +e
|
||||
echo "Deleting caches..."
|
||||
for cacheKey in $cacheKeysForPR
|
||||
do
|
||||
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
|
||||
done
|
||||
echo "Done"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
64
Changelog
64
Changelog
|
|
@ -1,3 +1,67 @@
|
|||
0.28.10 (2023-07-05):
|
||||
* Bugfix: %GITHUB%/issues/1397 LayoutMetaInfo serialization/deserialization problem
|
||||
* Bugfix: %GITHUB%/issues/1404 Better support for editing mode in Qt-less LayoutView
|
||||
* Bugfix: %GITHUB%/issues/1407 Clip functions do not support polygons with holes
|
||||
* Bugfix: %GITHUB%/issues/1409 Text edit issue (internal error)
|
||||
* Enhancements:
|
||||
- Made 'time' parameter optional for MainWindow#message
|
||||
- strmxor performance with --deep enhanced
|
||||
|
||||
0.28.9 (2023-06-10):
|
||||
* Enhancement: %GITHUB%/issues/1281 Layout diff can ignore shape or instance duplicates
|
||||
* Bugfix: %GITHUB%/issues/1393 GDS2Text format not supported in Python module
|
||||
* Bugfix: "add meta info" did not take "persisted" flag
|
||||
* Enhancement: "profile" feature for DRC and LVS
|
||||
* Enhancement: DRC can write to multiple targets now
|
||||
- new functions "new_report", "new_target": create output channel objects
|
||||
that can be used to redirect "output" to specific other channels
|
||||
* Bugfix: GDS2 reader should not segfault on certain broken files
|
||||
* Enhancement: performance improvement of hierarchical XOR in certain cases
|
||||
* Enhancement: New methods
|
||||
- Layout#copy_layer, Layout#move_layer and Layout#clear_layer with shape type selector
|
||||
- Shapes#clear with shape type selector
|
||||
|
||||
0.28.8 (2023-05-23):
|
||||
* Enhancement: %GITHUB%/issues/1314 Storing (arbitrary) data in metadata
|
||||
- Meta information can be attached to layout and cells
|
||||
- Meta information has a string key and arbitrary value (hash, list supported)
|
||||
- Optionally, meta information can be made persistent and
|
||||
is stored in the (KLayout specific) context section of GDS2 and OASIS
|
||||
- Meta information is shown in the user properties dialog, but is not editable
|
||||
- Meta information is similar, but not the same than user properties
|
||||
* Enhancement: %GITHUB%/issues/1324 Feature request: hide empty groups
|
||||
* Enhancement: %GITHUB%/issues/1345 feature request: create a def single/mulitpart path import option
|
||||
* Enhancement: %GITHUB%/issues/1348 "Reload Files" popup prevents closing KLayout
|
||||
* Enhancement: %GITHUB%/issues/1349 Add application events for indicating start/finish of restoring session
|
||||
* Bugfix: %GITHUB%/issues/1353 Bug in RecursiveInstanceIterator
|
||||
* Enhancement: %GITHUB%/issues/1357 Add binding for QObject::findChildren
|
||||
* Bugfix: %GITHUB%/issues/1360 LayoutView not promoted to correct class after Plugin initialization
|
||||
* Bugfix: %GITHUB%/issues/1366 Slow merging of polygons from width check edge pairs
|
||||
* Bugfix: %GITHUB%/issues/1373 Region "+" skips shapes with user properties on second input
|
||||
* Enhancement: Ruby debugger performance improvement - with debugger enabled, Ruby script execution was very slow
|
||||
* Enhancement: Polygon "decompose_convex" tries harder to avoid generating thin slivers
|
||||
* (Significant) Enhancement: Selection of labels now considers label area, not just label origin point
|
||||
* Bugfix: Making 'R', 'L' and 'C' parameters for the respective Spice elements beside "value"
|
||||
* Enhancement: Zoom In/Out menu functions now use the current mouse position for the zoom fixpoint (important when binding them to a key)
|
||||
* Bugfix: More consistent behavior of RBA/pya: enum classes are properly made available (was for example RBA::Qt::Qt_Keys instead of RBA::Qt_Keys and pya.Qt.Keys was no fully initialized type object)
|
||||
* Bugfix: Netlist reader: anonymous circuits (without definition) will not fail because of unknown parameters
|
||||
* Bugfix: Closed paths lost last point after editing in partial edit mode
|
||||
* Enhancement: Somewhat better grid snapping in partial edit mode
|
||||
* Bugfixes/enhancements: Macro editor
|
||||
- fixed missing icons for "back" and "forward"
|
||||
- enhancements for "search & replace"
|
||||
- Ctrl+R and Ctrl+Shift+R for replace and "replace all"
|
||||
- Fixed tool tips for buttons
|
||||
|
||||
0.28.7 (2023-04-22):
|
||||
* Enhancement: %GITHUB%/issues/1320 Support for .lib statement in Spice
|
||||
* Bugfix: %GITHUB%/issues/1321 Tilde expansion in paths (e.g. "~/test.gds") on Linux
|
||||
* Enhancement: %GITHUB%/issues/1322 RBA/pya: Manipulation of NetTracerTechnologComponent
|
||||
* Bugfix: %GITHUB%/issues/1327 Python module: segfault on exit when hierarchy iterators are alive
|
||||
* Bugfix: %GITHUB%/issues/1328 Width of layer selection boxes fixed and too small for long layer names
|
||||
* Enhancement: %GITHUB%/issues/1339 RBA/pya: A method to get the QWidget for a LayoutView
|
||||
* Enhancement: Better compatibility of Spice reader with ngspice
|
||||
|
||||
0.28.6 (2023-03-16):
|
||||
* Enhancement: %GITHUB%/issues/1249 Include expanded/collapsed state of layer properties into session
|
||||
* Bugfix: %GITHUB%/issues/1265 Issues installing klayout with pip on macOS related to libpng
|
||||
|
|
|
|||
|
|
@ -1,3 +1,31 @@
|
|||
klayout (0.28.10-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Wed, 05 Jul 2023 18:37:13 +0200
|
||||
|
||||
klayout (0.28.9-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Sat, 10 Jun 2023 09:27:25 +0200
|
||||
|
||||
klayout (0.28.8-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Mon, 22 May 2023 23:10:56 +0200
|
||||
|
||||
klayout (0.28.7-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Sat, 22 Apr 2023 15:18:27 +0200
|
||||
|
||||
klayout (0.28.6-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
|
|
|
|||
|
|
@ -14,10 +14,8 @@ recursive-include src/rdb/rdb *.cc *.h
|
|||
recursive-include src/tl/tl *.cc *.h
|
||||
recursive-include src/version *.cc *.h
|
||||
recursive-include src/pymod *.pyi
|
||||
include src/plugins/*/db_plugin/*.cc
|
||||
include src/plugins/*/*/db_plugin/*.cc
|
||||
include src/plugins/*/db_plugin/*.h
|
||||
include src/plugins/*/*/db_plugin/*.h
|
||||
recursive-include src/plugins/*/db_plugin *.cc *.h
|
||||
recursive-include src/plugins/*/*/db_plugin *.cc *.h
|
||||
recursive-include src/plugins/common *.h
|
||||
include version.sh
|
||||
include src/py.typed
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
# Solves issue #1346
|
||||
# Deprecate patch when Github Actions provides Apple Silicon runners.
|
||||
# WARNING: Only run this in a CI runner
|
||||
|
||||
# Issue: klayout depends on libpng, which is loaded by homebrew.
|
||||
# But M1 wheels are cross-compiled in an intel host, so by default
|
||||
# libpng.dylib has an x86 architecture. This prevents linking the library
|
||||
# in the tl library.
|
||||
|
||||
# Patch solution: manually download libpng arm64 pre-built library from homebrew
|
||||
|
||||
# Reading
|
||||
# https://stackoverflow.com/questions/55110564/how-can-i-install-a-homebrew-bottle-designed-for-a-different-previous-version
|
||||
# https://github.com/Homebrew/homebrew-core/blob/6abea16e917b12d6af4912736f66eb8d42bf089b/Formula/libpng.rb
|
||||
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
|
||||
# Check if we're about to build an arm64 wheel. WARNING universal wheels not supported
|
||||
if [ "$_PYTHON_HOST_PLATFORM" == "macosx-11.0-arm64" ]
|
||||
then
|
||||
# Exit early if done
|
||||
test -f /tmp/libpng-apple-silicon-installed && exit 0
|
||||
curl -L -H "Authorization: Bearer QQ==" -o /tmp/libpng-1.6.39.arm64_big_sur.bottle.1.tar.gz https://ghcr.io/v2/homebrew/core/libpng/blobs/sha256:cf59cedc91afc6f2f3377567ba82b99b97744c60925a5d1df6ecf923fdb2f234
|
||||
brew reinstall -f /tmp/libpng-1.6.39.arm64_big_sur.bottle.1.tar.gz || exit 1
|
||||
touch /tmp/libpng-apple-silicon-installed
|
||||
elif [ -f "/tmp/libpng-apple-silicon-installed" ]; then
|
||||
brew reinstall -f libpng && rm -f /tmp/libpng-apple-silicon-installed
|
||||
fi
|
||||
|
|
@ -196,7 +196,7 @@ Ruby31MacPorts = { 'exe': '/opt/local/bin/ruby3.1',
|
|||
# install with 'sudo port install ruby32'
|
||||
# [Key Type Name] = 'MP32'
|
||||
Ruby32MacPorts = { 'exe': '/opt/local/bin/ruby3.2',
|
||||
'inc': '/opt/local/include/ruby-3.2.1',
|
||||
'inc': '/opt/local/include/ruby-3.2.2',
|
||||
'lib': '/opt/local/lib/libruby.3.2.dylib'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ test-command = [
|
|||
# Disable building PyPy wheels on all platforms
|
||||
skip = "pp*"
|
||||
|
||||
# Skip trying to test arm64 builds on Intel Macs
|
||||
test-skip = "*-macosx_arm64 *-macosx_universal2:arm64"
|
||||
|
||||
[tool.cibuildwheel.linux]
|
||||
# beware: the before-all script does not persist environment variables!
|
||||
# No point in defining $PATH or $CCACHE_DIR
|
||||
|
|
@ -28,5 +31,13 @@ before-all = [
|
|||
"brew install libpng",
|
||||
"brew deps --tree --installed",
|
||||
]
|
||||
|
||||
# TEMP while Github Actions does not provide an Apple Silicon runner
|
||||
# TODO Simply remove it when it's available
|
||||
archs = ["x86_64", "arm64"]
|
||||
before-build = [
|
||||
"ccache -s",
|
||||
"bash {project}/ci-scripts/macos/libpng-patch.sh",
|
||||
]
|
||||
# Repair macOS wheels (include libpng with the wheel, for example)
|
||||
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v --ignore-missing-dependencies {wheel}"
|
||||
|
|
@ -231,7 +231,7 @@ hs.urls.each do |url|
|
|||
t = HEADER + xml2html(t) + TAIL
|
||||
|
||||
tt = nil
|
||||
if File.exists?(fn)
|
||||
if File.exist?(fn)
|
||||
File.open(fn, "rb") { |f| tt = f.read }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +1,40 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
# Generates LVS and DRC documentation
|
||||
# Generates pyi stubs
|
||||
#
|
||||
# Run this script from a valid build below the repository root, e.g.
|
||||
# <repo-root>/build-debug. It needs to have a "pymod" installation in
|
||||
# <repo-root>/build-debug. It needs to have a "pymod" installation in
|
||||
# current directory.
|
||||
|
||||
inst=$(realpath $(dirname $0))
|
||||
scripts=${inst}/drc_lvs_doc
|
||||
ld=$(realpath .)
|
||||
|
||||
pymod="$ld/pymod"
|
||||
## Detect if klayout pymod libraries are installed
|
||||
python=
|
||||
for try_python in python python3; do
|
||||
if $try_python -c "import klayout.tl" >/dev/null 2>&1; then
|
||||
python=$try_python
|
||||
fi
|
||||
done
|
||||
|
||||
export LD_LIBRARY_PATH=$ld
|
||||
export PYTHONPATH=$pymod
|
||||
if [ "$python" = "" ]; then
|
||||
echo "*** Searching for pymod..."
|
||||
|
||||
pymod_src=$ld/../src/pymod
|
||||
if ! [ -e $pymod_src ]; then
|
||||
echo "*** ERROR: missing pymod sources ($pymod_src) - did you run the script from the build folder below the source tree?"
|
||||
exit 1
|
||||
fi
|
||||
ld=$(realpath .)
|
||||
pymod="$ld/pymod"
|
||||
|
||||
if ! [ -e $pymod ]; then
|
||||
echo "*** ERROR: missing pymod folder ($pymod) - did you run the script from the build folder?"
|
||||
exit 1
|
||||
export LD_LIBRARY_PATH=$ld
|
||||
export PYTHONPATH=$pymod
|
||||
|
||||
pymod_src=$ld/../src/pymod
|
||||
if ! [ -e $pymod_src ]; then
|
||||
echo "*** ERROR: missing pymod sources ($pymod_src) - did you run the script from the build folder below the source tree?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -e $pymod ]; then
|
||||
echo "*** ERROR: missing pymod folder ($pymod) - did you run the script from the build folder?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
python=
|
||||
|
|
@ -38,20 +49,21 @@ if [ "$python" = "" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
pyi_srcdir="$inst/../src/pymod/distutils_src/klayout"
|
||||
|
||||
echo "Generating stubs for tl .."
|
||||
$python $inst/stubgen.py tl >$pymod_src/distutils_src/klayout/tlcore.pyi
|
||||
$python $inst/stubgen.py tl >$pyi_srcdir/tlcore.pyi
|
||||
|
||||
echo "Generating stubs for db .."
|
||||
$python $inst/stubgen.py db tl >$pymod_src/distutils_src/klayout/dbcore.pyi
|
||||
$python $inst/stubgen.py db tl >$pyi_srcdir/dbcore.pyi
|
||||
|
||||
echo "Generating stubs for rdb .."
|
||||
$python $inst/stubgen.py rdb tl,db >$pymod_src/distutils_src/klayout/rdbcore.pyi
|
||||
$python $inst/stubgen.py rdb tl,db >$pyi_srcdir/rdbcore.pyi
|
||||
|
||||
echo "Generating stubs for lay .."
|
||||
$python $inst/stubgen.py lay tl,db,rdb >$pymod_src/distutils_src/klayout/laycore.pyi
|
||||
$python $inst/stubgen.py lay tl,db,rdb >$pyi_srcdir/laycore.pyi
|
||||
|
||||
echo "Generating stubs for lib .."
|
||||
$python $inst/stubgen.py lib tl,db >$pymod_src/distutils_src/klayout/libcore.pyi
|
||||
$python $inst/stubgen.py lib tl,db >$pyi_srcdir/libcore.pyi
|
||||
|
||||
echo "Done."
|
||||
|
||||
|
|
|
|||
|
|
@ -62,15 +62,56 @@ DECL
|
|||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Provides the definitions for QObject::findChild
|
||||
# Provides the definitions for QObject::findChild and QObject::findChildren
|
||||
|
||||
def add_native_impl_QObject_findChild()
|
||||
|
||||
# alternative implementation for QObject::findChild using QObject for T
|
||||
add_native_impl("QObject", <<'CODE', <<'DECL')
|
||||
QObject *find_child_impl (QObject *object, const QString &name) { return object->findChild<QObject *> (name); }
|
||||
|
||||
#if QT_VERSION < 0x50000
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChild<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChildren<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegExp &re)
|
||||
{
|
||||
return object->findChildren<QObject *> (re);
|
||||
}
|
||||
#else
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChild<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegularExpression &re, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (re, options);
|
||||
}
|
||||
#endif
|
||||
CODE
|
||||
gsi::method_ext("findChild", &find_child_impl, "@brief Specialisation for findChild (uses QObject as T).")
|
||||
#if QT_VERSION < 0x50000
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#else
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#endif
|
||||
DECL
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
# This script regenerates the Python stubs from the sources
|
||||
|
||||
# clean up
|
||||
rm -rf build dist
|
||||
|
||||
python3 setup.py build
|
||||
python3 setup.py bdist_wheel
|
||||
python3 -m venv create python3-venv-make_stubs
|
||||
|
||||
. python3-venv-make_stubs/bin/activate
|
||||
|
||||
pip3 install ./dist/*.whl
|
||||
|
||||
./scripts/make_stubs.sh
|
||||
|
||||
|
|
@ -85,15 +85,12 @@ Requires: libqt4-x11 >= 4.8.6
|
|||
# OpenSuSE Leap 15 requirements
|
||||
Requires: ruby >= 2.5
|
||||
Requires: python3 >= 3.6
|
||||
Requires: libqt4-x11 >= 4.8.7
|
||||
%define buildopt -j2
|
||||
%endif
|
||||
|
||||
%if "%{target_system}" == "opensuse15"
|
||||
# OpenSuSE Leap 15 requirements
|
||||
Requires: ruby >= 2.5
|
||||
Requires: python3 >= 3.6
|
||||
Requires: libqt4-x11 >= 4.8.7
|
||||
Requires: libqt5-qtbase >= 5.15.2
|
||||
Requires: libQt5PrintSupport5 >= 5.15.2
|
||||
Requires: libQt5Designer5 >= 5.15.2
|
||||
Requires: libQt5Multimedia5 >= 5.15.2
|
||||
Requires: libQt5Svg5 >= 5.15.2
|
||||
Requires: libQt5XmlPatterns5 >= 5.15.2
|
||||
%define buildopt -j2
|
||||
%endif
|
||||
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -805,11 +805,13 @@ for pi in dbpi_dirs:
|
|||
mod_name = "_" + os.path.split(os.path.split(pi)[-2])[-1] + "_dbpi"
|
||||
|
||||
pi_sources = glob.glob(os.path.join(pi, "*.cc"))
|
||||
pi_sources += glob.glob(os.path.join(pi, "contrib", "*.cc"))
|
||||
|
||||
pi_ext = Library(
|
||||
config.root + ".db_plugins." + mod_name,
|
||||
define_macros=config.macros() + [("MAKE_DB_PLUGIN_LIBRARY", 1)],
|
||||
include_dirs=[
|
||||
pi,
|
||||
os.path.join("src", "plugins", "common"),
|
||||
_db_path,
|
||||
_tl_path,
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ GenericReaderOptions::GenericReaderOptions ()
|
|||
|
||||
m_lefdef_read_lef_with_def = load_options.get_option_by_name ("lefdef_config.read_lef_with_def").to_bool ();
|
||||
m_lefdef_separate_groups = load_options.get_option_by_name ("lefdef_config.separate_groups").to_bool ();
|
||||
m_lefdef_joined_paths = load_options.get_option_by_name ("lefdef_config.joined_paths").to_bool ();
|
||||
m_lefdef_map_file = load_options.get_option_by_name ("lefdef_config.map_file").to_string ();
|
||||
m_lefdef_macro_resolution_mode = load_options.get_option_by_name ("lefdef_config.macro_resolution_mode").to_int ();
|
||||
}
|
||||
|
|
@ -441,6 +442,11 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
|
|||
"This option is used together with '--" + m_long_prefix + "lefdef-produce-regions'. If given, the region polygons will be put "
|
||||
"into a cell hierarchy where the cells indicate the region groups.\n"
|
||||
)
|
||||
<< tl::arg (group +
|
||||
"#--" + m_long_prefix + "lefdef-joined-paths", &m_lefdef_joined_paths, "Specifies to produce joined paths for wires",
|
||||
"If given, multi-segment paths are created for wires if possible (this will fail for 45 degree segments for example). "
|
||||
"By default, individual straight segments will be produced."
|
||||
)
|
||||
<< tl::arg (group +
|
||||
"#!--" + m_long_prefix + "lefdef-dont-produce-via-geometry", &m_lefdef_produce_via_geometry, "Skips vias when producing geometry",
|
||||
"If this option is given, no via geometry will be produced."
|
||||
|
|
@ -793,6 +799,7 @@ GenericReaderOptions::configure (db::LoadLayoutOptions &load_options)
|
|||
load_options.set_option_by_name ("lefdef_config.lef_files", tl::Variant (m_lefdef_lef_files.begin (), m_lefdef_lef_files.end ()));
|
||||
load_options.set_option_by_name ("lefdef_config.read_lef_with_def", m_lefdef_read_lef_with_def);
|
||||
load_options.set_option_by_name ("lefdef_config.separate_groups", m_lefdef_separate_groups);
|
||||
load_options.set_option_by_name ("lefdef_config.joined_paths", m_lefdef_joined_paths);
|
||||
load_options.set_option_by_name ("lefdef_config.map_file", m_lefdef_map_file);
|
||||
load_options.set_option_by_name ("lefdef_config.macro_resolution_mode", m_lefdef_macro_resolution_mode);
|
||||
load_options.set_option_by_name ("lefdef_config.macro_resolution_mode", m_lefdef_macro_resolution_mode);
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ private:
|
|||
std::vector<std::string> m_lefdef_lef_files;
|
||||
bool m_lefdef_read_lef_with_def;
|
||||
bool m_lefdef_separate_groups;
|
||||
bool m_lefdef_joined_paths;
|
||||
std::string m_lefdef_map_file;
|
||||
int m_lefdef_macro_resolution_mode;
|
||||
std::vector<std::string> m_lefdef_lef_layout_files;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ BD_PUBLIC int strmcmp (int argc, char *argv[])
|
|||
std::string infile_a, infile_b;
|
||||
std::string top_a, top_b;
|
||||
bool silent = false;
|
||||
bool ignore_duplicates = false;
|
||||
bool no_text_orientation = true;
|
||||
bool no_text_details = true;
|
||||
bool no_properties = false;
|
||||
|
|
@ -106,6 +107,10 @@ BD_PUBLIC int strmcmp (int argc, char *argv[])
|
|||
<< tl::arg ("--expand-arrays", &flatten_array_insts, "Expands array instances before compare",
|
||||
"With this option, arrays are equivalent single instances are treated identical."
|
||||
)
|
||||
<< tl::arg ("-1|--ignore-duplicates", &ignore_duplicates, "Ignore duplicate instances and shapes",
|
||||
"With this option, duplicate instances or shapes are ignored and duplication "
|
||||
"does not count as a difference."
|
||||
)
|
||||
<< tl::arg ("-l|--layer-details", &dont_summarize_missing_layers, "Prints details about differences for missing layers",
|
||||
"With this option, missing layers are treated as \"empty\" and details about differences to "
|
||||
"other, non-empty layers are printed. Essentially the content of the non-empty counterpart "
|
||||
|
|
@ -155,6 +160,9 @@ BD_PUBLIC int strmcmp (int argc, char *argv[])
|
|||
if (silent) {
|
||||
flags |= db::layout_diff::f_silent;
|
||||
}
|
||||
if (ignore_duplicates) {
|
||||
flags |= db::layout_diff::f_ignore_duplicates;
|
||||
}
|
||||
if (no_text_orientation) {
|
||||
flags |= db::layout_diff::f_no_text_orientation;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -754,6 +754,7 @@ bool run_deep_xor (const XORData &xor_data)
|
|||
{
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_threads (xor_data.threads);
|
||||
dss.set_wants_all_cells (true); // saves time for less cell mapping operations
|
||||
|
||||
double dbu = std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ());
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ SOURCES = \
|
|||
gsiDeclDbLibrary.cc \
|
||||
gsiDeclDbManager.cc \
|
||||
gsiDeclDbMatrix.cc \
|
||||
gsiDeclDbMetaInfo.cc \
|
||||
gsiDeclDbPath.cc \
|
||||
gsiDeclDbPoint.cc \
|
||||
gsiDeclDbPolygon.cc \
|
||||
|
|
|
|||
|
|
@ -538,7 +538,7 @@ public:
|
|||
* @brief Default ctor
|
||||
*/
|
||||
box_scanner2 (bool report_progress = false, const std::string &progress_desc = std::string ())
|
||||
: m_fill_factor (2), m_scanner_thr (100),
|
||||
: m_fill_factor (2), m_scanner_thr (100), m_scanner_thr1 (10),
|
||||
m_report_progress (report_progress), m_progress_desc (progress_desc)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -564,6 +564,26 @@ public:
|
|||
return m_scanner_thr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the scanner threshold per class
|
||||
*
|
||||
* This value determines for how many elements in one class the implementation switches to the scanner
|
||||
* implementation instead of the plain element-by-element interaction test.
|
||||
* The default value is 10.
|
||||
*/
|
||||
void set_scanner_threshold1 (size_t n)
|
||||
{
|
||||
m_scanner_thr1 = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the scanner threshold per class
|
||||
*/
|
||||
size_t scanner_threshold1 () const
|
||||
{
|
||||
return m_scanner_thr1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the fill factor
|
||||
*
|
||||
|
|
@ -667,7 +687,7 @@ private:
|
|||
container_type1 m_pp1;
|
||||
container_type2 m_pp2;
|
||||
double m_fill_factor;
|
||||
size_t m_scanner_thr;
|
||||
size_t m_scanner_thr, m_scanner_thr1;
|
||||
bool m_report_progress;
|
||||
std::string m_progress_desc;
|
||||
|
||||
|
|
@ -732,7 +752,7 @@ private:
|
|||
rec.finish2 (i->first, i->second);
|
||||
}
|
||||
|
||||
} else if (m_pp1.size () + m_pp2.size () <= m_scanner_thr) {
|
||||
} else if (m_pp1.size () + m_pp2.size () <= m_scanner_thr || m_pp2.size () <= m_scanner_thr1 || m_pp1.size () <= m_scanner_thr1) {
|
||||
|
||||
// below m_scanner_thr elements use the brute force approach which is faster in that case
|
||||
|
||||
|
|
|
|||
|
|
@ -187,6 +187,17 @@ Cell::clear (unsigned int index)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::clear (unsigned int index, unsigned int types)
|
||||
{
|
||||
shapes_map::iterator s = m_shapes_map.find(index);
|
||||
if (s != m_shapes_map.end() && ! s->second.empty ()) {
|
||||
mp_layout->invalidate_bboxes (index); // HINT: must come before the change is done!
|
||||
s->second.clear (types);
|
||||
m_bbox_needs_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
Cell::shapes_type &
|
||||
Cell::shapes (unsigned int index)
|
||||
{
|
||||
|
|
@ -344,6 +355,20 @@ Cell::copy (unsigned int src, unsigned int dest)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::copy (unsigned int src, unsigned int dest, unsigned int types)
|
||||
{
|
||||
if (src != dest) {
|
||||
shapes (dest).insert (shapes (src), types);
|
||||
} else {
|
||||
// When duplicating the layer, first create a copy to avoid problems with non-stable containers
|
||||
// Hint: using the assignment and not the copy ctor does not copy the db::Manager association.
|
||||
db::Shapes shape_copy;
|
||||
shape_copy.insert (shapes (src), types);
|
||||
shapes (dest).insert (shape_copy);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::move (unsigned int src, unsigned int dest)
|
||||
{
|
||||
|
|
@ -353,6 +378,15 @@ Cell::move (unsigned int src, unsigned int dest)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::move (unsigned int src, unsigned int dest, unsigned int types)
|
||||
{
|
||||
if (src != dest) {
|
||||
copy (src, dest, types);
|
||||
clear (src, types);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::swap (unsigned int i1, unsigned int i2)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -182,6 +182,13 @@ public:
|
|||
*/
|
||||
void copy (unsigned int src, unsigned int dest);
|
||||
|
||||
/**
|
||||
* @brief Copy the shapes from layer src to dest (only shapes from given classes)
|
||||
*
|
||||
* The target layer is not overwritten. Instead, the shapes are added to the target layer's shapes.
|
||||
*/
|
||||
void copy (unsigned int src, unsigned int dest, unsigned int types);
|
||||
|
||||
/**
|
||||
* @brief Move the shapes from layer src to dest
|
||||
*
|
||||
|
|
@ -189,6 +196,13 @@ public:
|
|||
*/
|
||||
void move (unsigned int src, unsigned int dest);
|
||||
|
||||
/**
|
||||
* @brief Move the shapes from layer src to dest (only shapes from given classes)
|
||||
*
|
||||
* The target layer is not overwritten. Instead, the shapes are added to the target layer's shapes.
|
||||
*/
|
||||
void move (unsigned int src, unsigned int dest, unsigned int types);
|
||||
|
||||
/**
|
||||
* @brief Swap the layers given
|
||||
*/
|
||||
|
|
@ -199,7 +213,12 @@ public:
|
|||
*/
|
||||
void clear (unsigned int index);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Clear the shapes on the given layer (only the shapes from the given classes)
|
||||
*/
|
||||
void clear (unsigned int index, unsigned int types);
|
||||
|
||||
/**
|
||||
* @brief Erase a cell instance given by a instance proxy
|
||||
*
|
||||
* Erasing a cell instance will destroy the sorting order and invalidate
|
||||
|
|
|
|||
|
|
@ -151,10 +151,6 @@ public:
|
|||
|
||||
}
|
||||
|
||||
std::set<db::cell_index_type> callers_b;
|
||||
m_layout_b.cell (cell_b).collect_caller_cells (callers_b, selection_cone_b, -1);
|
||||
callers_b.insert (cell_b);
|
||||
|
||||
m_repr_set = false;
|
||||
|
||||
std::map<db::cell_index_type, db::ICplxTrans>::const_iterator r = m_repr.find (cell_b);
|
||||
|
|
@ -164,7 +160,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::set<db::cell_index_type> callers_b;
|
||||
m_layout_b.cell (cell_b).collect_caller_cells (callers_b, selection_cone_b, -1);
|
||||
callers_b.insert (cell_b);
|
||||
|
||||
trans_set_t trans (m_trans);
|
||||
|
||||
double mag = m_layout_b.dbu () / m_layout_a.dbu ();
|
||||
|
|
@ -356,7 +356,7 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &
|
|||
&& (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ())
|
||||
&& (! include_cells || include_cells->find (*b) != include_cells->end ())) {
|
||||
|
||||
db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b));
|
||||
db::cell_index_type new_cell = layout_a.add_cell (layout_b, *b);
|
||||
new_cells.push_back (new_cell);
|
||||
new_cells_b.push_back (*b);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ VariantsCollectorBase::separate_variants (db::Layout &layout, db::Cell &top_cell
|
|||
var_name += "$VAR" + tl::to_string (index);
|
||||
|
||||
ci_var = layout.add_cell (var_name.c_str ());
|
||||
layout.add_meta_info (ci_var, layout.begin_meta (*c), layout.end_meta (*c));
|
||||
copy_shapes (layout, ci_var, *c);
|
||||
|
||||
// a new entry for the variant
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ clip_cell (const db::Layout &layout,
|
|||
target_cell.shapes (l).insert (db::PathRef (path, target_layout.shape_repository ()));
|
||||
}
|
||||
|
||||
} else if (sh->is_polygon () || sh->is_simple_polygon () || sh->is_path ()) {
|
||||
} else if (sh->is_simple_polygon () || sh->is_path ()) {
|
||||
|
||||
db::SimplePolygon poly;
|
||||
|
||||
|
|
@ -371,17 +371,12 @@ clip_cell (const db::Layout &layout,
|
|||
db::Path path;
|
||||
sh->path (path);
|
||||
poly = path.simple_polygon ();
|
||||
} else if (sh->is_polygon ()) {
|
||||
db::Polygon ppoly;
|
||||
sh->polygon (ppoly);
|
||||
poly = db::SimplePolygon (ppoly);
|
||||
} else {
|
||||
sh->simple_polygon (poly);
|
||||
}
|
||||
|
||||
std::vector <db::SimplePolygon> clipped_polygons;
|
||||
|
||||
if (! poly.box ().inside (clip_box)) {
|
||||
std::vector <db::SimplePolygon> clipped_polygons;
|
||||
clip_poly (poly, clip_box, clipped_polygons);
|
||||
for (std::vector <db::SimplePolygon>::const_iterator cp = clipped_polygons.begin (); cp != clipped_polygons.end (); ++cp) {
|
||||
if (sh->has_prop_id ()) {
|
||||
|
|
@ -398,6 +393,29 @@ clip_cell (const db::Layout &layout,
|
|||
}
|
||||
}
|
||||
|
||||
} else if (sh->is_polygon ()) {
|
||||
|
||||
db::Polygon poly;
|
||||
sh->polygon (poly);
|
||||
|
||||
if (! poly.box ().inside (clip_box)) {
|
||||
std::vector <db::Polygon> clipped_polygons;
|
||||
clip_poly (poly, clip_box, clipped_polygons);
|
||||
for (std::vector <db::Polygon>::const_iterator cp = clipped_polygons.begin (); cp != clipped_polygons.end (); ++cp) {
|
||||
if (sh->has_prop_id ()) {
|
||||
target_cell.shapes (l).insert (db::PolygonRefWithProperties (db::PolygonRef (*cp, target_layout.shape_repository ()), sh->prop_id ()));
|
||||
} else {
|
||||
target_cell.shapes (l).insert (db::PolygonRef (*cp, target_layout.shape_repository ()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (sh->has_prop_id ()) {
|
||||
target_cell.shapes (l).insert (db::PolygonRefWithProperties (db::PolygonRef (poly, target_layout.shape_repository ()), sh->prop_id ()));
|
||||
} else {
|
||||
target_cell.shapes (l).insert (db::PolygonRef (poly, target_layout.shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (sh->is_text ()) {
|
||||
|
||||
if (sh->bbox ().inside (clip_box)) {
|
||||
|
|
@ -556,7 +574,7 @@ make_clip_variants (const db::Layout &layout,
|
|||
for (std::map <std::pair <db::cell_index_type, db::Box>, db::cell_index_type>::iterator v = variants.begin (); v != variants.end (); ++v) {
|
||||
if (v->first.second != layout.cell (v->first.first).bbox () || &layout != &target_layout) {
|
||||
// need for a new cell
|
||||
v->second = target_layout.add_cell (layout.cell_name (v->first.first));
|
||||
v->second = target_layout.add_cell (layout, v->first.first);
|
||||
} else {
|
||||
v->second = v->first.first;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ ClipboardData::do_insert (db::Layout &layout, const db::ICplxTrans *trans, db::C
|
|||
cell_map.insert (std::make_pair (c->cell_index (), pc->cell_index ()));
|
||||
} else {
|
||||
// fallback: create a new cell
|
||||
cell_map.insert (std::make_pair (c->cell_index (), layout.add_cell (m_layout.cell_name (c->cell_index ()))));
|
||||
db::cell_index_type ci = layout.add_cell (m_layout, c->cell_index ());
|
||||
cell_map.insert (std::make_pair (c->cell_index (), ci));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -217,7 +218,8 @@ ClipboardData::do_insert (db::Layout &layout, const db::ICplxTrans *trans, db::C
|
|||
cell_map.insert (std::make_pair (c->cell_index (), tc));
|
||||
}
|
||||
} else {
|
||||
cell_map.insert (std::make_pair (c->cell_index (), layout.add_cell (m_layout.cell_name (c->cell_index ()))));
|
||||
db::cell_index_type ci = layout.add_cell (m_layout, c->cell_index ());
|
||||
cell_map.insert (std::make_pair (c->cell_index (), ci));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -313,7 +315,7 @@ ClipboardData::cell_for_cell (const db::Layout &layout, db::cell_index_type cell
|
|||
return cm->second;
|
||||
}
|
||||
|
||||
db::cell_index_type target_cell_index = m_layout.add_cell (layout.cell_name (cell_index));
|
||||
db::cell_index_type target_cell_index = m_layout.add_cell (layout, cell_index);
|
||||
m_cell_index_map.insert (std::make_pair (cell_index, target_cell_index));
|
||||
|
||||
if (incomplete) {
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ ColdProxy::cold_proxies_per_lib_name (const std::string &libname)
|
|||
}
|
||||
}
|
||||
|
||||
ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info)
|
||||
: Cell (ci, layout), mp_context_info (new ProxyContextInfo (info))
|
||||
ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOrCellContextInfo &info)
|
||||
: Cell (ci, layout), mp_context_info (new LayoutOrCellContextInfo (info))
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
tl::MutexLocker locker (&s_map_mutex);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
struct ProxyContextInfo;
|
||||
struct LayoutOrCellContextInfo;
|
||||
|
||||
/**
|
||||
* @brief A cell specialization: a cold proxy representing a library or PCell which has gone out of scope
|
||||
|
|
@ -53,7 +53,7 @@ public:
|
|||
*
|
||||
* Creates a cold proxy represented by the ProxyContextInfo data.
|
||||
*/
|
||||
ColdProxy (db::cell_index_type ci, db::Layout &layout, const ProxyContextInfo &info);
|
||||
ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOrCellContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
|
|
@ -68,7 +68,7 @@ public:
|
|||
/**
|
||||
* @brief Get the library id
|
||||
*/
|
||||
const ProxyContextInfo &context_info () const
|
||||
const LayoutOrCellContextInfo &context_info () const
|
||||
{
|
||||
return *mp_context_info;
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ public:
|
|||
virtual std::string get_qualified_name () const;
|
||||
|
||||
private:
|
||||
ProxyContextInfo *mp_context_info;
|
||||
LayoutOrCellContextInfo *mp_context_info;
|
||||
|
||||
ColdProxy (const ColdProxy &d);
|
||||
ColdProxy &operator= (const ColdProxy &d);
|
||||
|
|
|
|||
|
|
@ -962,10 +962,31 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
|
|||
|
||||
// Implement XOR as (A-B)+(B-A) - only this implementation
|
||||
// is compatible with the local processor scheme
|
||||
DeepLayer n1 (and_or_not_with (other_deep, false, property_constraint));
|
||||
DeepLayer n2 (other_deep->and_or_not_with (this, false, property_constraint));
|
||||
|
||||
// Prepare a version of "other_deep" that is mapped into the hierarchy space
|
||||
// of "this"
|
||||
std::unique_ptr<DeepRegion> other_deep_mapped;
|
||||
if (&other_deep->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
// shallow copy for reconfiguration (progress etc.)
|
||||
other_deep_mapped.reset (new DeepRegion (other_deep->deep_layer ()));
|
||||
} else {
|
||||
// deep copy with mapped hierarchy
|
||||
other_deep_mapped.reset (new DeepRegion (deep_layer ().derived ()));
|
||||
other_deep_mapped->deep_layer ().add_from (other_deep->deep_layer ());
|
||||
}
|
||||
|
||||
other_deep_mapped->set_strict_handling (strict_handling ());
|
||||
other_deep_mapped->set_base_verbosity (base_verbosity ());
|
||||
if (report_progress ()) {
|
||||
other_deep_mapped->enable_progress (progress_desc () + tl::to_string (tr (" - reverse part")));
|
||||
} else {
|
||||
other_deep_mapped->disable_progress ();
|
||||
}
|
||||
|
||||
DeepLayer n1 (and_or_not_with (other_deep_mapped.get (), false, property_constraint));
|
||||
DeepLayer n2 (other_deep_mapped->and_or_not_with (this, false, property_constraint));
|
||||
n1.add_from (n2);
|
||||
|
||||
return new DeepRegion (n1);
|
||||
|
||||
}
|
||||
|
|
@ -1895,6 +1916,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (pc_always_different (options.prop_constraint)) {
|
||||
// TODO: this forces merged primaries, so maybe that is not a good optimization?
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -487,13 +487,13 @@ static unsigned int init_layer (db::Layout &layout, const db::RecursiveShapeIter
|
|||
}
|
||||
|
||||
DeepShapeStore::DeepShapeStore ()
|
||||
: m_keep_layouts (true)
|
||||
: m_keep_layouts (true), m_wants_all_cells (false)
|
||||
{
|
||||
++s_instance_count;
|
||||
}
|
||||
|
||||
DeepShapeStore::DeepShapeStore (const std::string &topcell_name, double dbu)
|
||||
: m_keep_layouts (true)
|
||||
: m_keep_layouts (true), m_wants_all_cells (false)
|
||||
{
|
||||
++s_instance_count;
|
||||
|
||||
|
|
@ -765,6 +765,16 @@ double DeepShapeStore::max_area_ratio () const
|
|||
return m_state.max_area_ratio ();
|
||||
}
|
||||
|
||||
void DeepShapeStore::set_wants_all_cells (bool f)
|
||||
{
|
||||
m_wants_all_cells = f;
|
||||
}
|
||||
|
||||
bool DeepShapeStore::wants_all_cells () const
|
||||
{
|
||||
return m_wants_all_cells;
|
||||
}
|
||||
|
||||
void DeepShapeStore::set_reject_odd_polygons (bool f)
|
||||
{
|
||||
m_state.set_reject_odd_polygons (f);
|
||||
|
|
@ -929,6 +939,8 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
|
|||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
builder.set_wants_all_cells (m_wants_all_cells);
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
||||
|
|
|
|||
|
|
@ -727,6 +727,23 @@ public:
|
|||
*/
|
||||
int threads () const;
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether the working layouts will store the whole original hierarchy
|
||||
*
|
||||
* Setting this flag to true will make the deep shape store copy the
|
||||
* hierarchy exactly from the origin layouts. This will take somewhat
|
||||
* more memory but avoid future cell hierarchy mapping operations.
|
||||
*
|
||||
* If set to false, only the needed parts of the hierarchy are copied.
|
||||
* This part may need to grow when further operations are triggered.
|
||||
*/
|
||||
void set_wants_all_cells (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether the working layouts will store the whole original hierarchy
|
||||
*/
|
||||
bool wants_all_cells () const;
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether to reject odd polygons
|
||||
*
|
||||
|
|
@ -878,6 +895,7 @@ private:
|
|||
DeepShapeStoreState m_state;
|
||||
std::list<DeepShapeStoreState> m_state_stack;
|
||||
bool m_keep_layouts;
|
||||
bool m_wants_all_cells;
|
||||
tl::Mutex m_lock;
|
||||
|
||||
struct DeliveryMappingCacheKey
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
const double fill_factor = 1.5;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Some utilities ..
|
||||
|
||||
|
|
@ -1095,14 +1097,14 @@ EdgeProcessor::clear ()
|
|||
}
|
||||
|
||||
static void
|
||||
add_hparallel_cutpoints (WorkEdge &e1, WorkEdge &e2, std::vector <CutPoints> &cutpoints)
|
||||
add_hparallel_cutpoints (WorkEdge &e1, WorkEdge &e2, const db::Box &cell, std::vector <CutPoints> &cutpoints)
|
||||
{
|
||||
db::Coord e1_xmin = std::min (e1.x1 (), e1.x2 ());
|
||||
db::Coord e1_xmax = std::max (e1.x1 (), e1.x2 ());
|
||||
if (e2.x1 () > e1_xmin && e2.x1 () < e1_xmax) {
|
||||
if (e2.x1 () > e1_xmin && e2.x1 () < e1_xmax && cell.contains (e2.p1 ())) {
|
||||
e1.make_cutpoints (cutpoints)->add (e2.p1 (), &cutpoints, false);
|
||||
}
|
||||
if (e2.x2 () > e1_xmin && e2.x2 () < e1_xmax) {
|
||||
if (e2.x2 () > e1_xmin && e2.x2 () < e1_xmax && cell.contains (e2.p2 ())) {
|
||||
e1.make_cutpoints (cutpoints)->add (e2.p2 (), &cutpoints, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -1125,14 +1127,28 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
|||
std::vector <WorkEdge>::iterator f = current;
|
||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
||||
|
||||
while (f != future && edge_xmin (*f) <= x) {
|
||||
++f;
|
||||
}
|
||||
size_t n = 0;
|
||||
db::Coord xx = x;
|
||||
|
||||
db::Coord xx = std::numeric_limits <db::Coord>::max ();
|
||||
if (f != future) {
|
||||
xx = edge_xmin (*f);
|
||||
}
|
||||
// fetch as many cells as to fill in roughly 50% more
|
||||
// (this is an empirical performance improvement factor)
|
||||
do {
|
||||
|
||||
while (f != future && edge_xmin (*f) <= xx) {
|
||||
++f;
|
||||
}
|
||||
|
||||
if (f != future) {
|
||||
xx = edge_xmin (*f);
|
||||
} else {
|
||||
xx = std::numeric_limits <db::Coord>::max ();
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
n = std::distance (c, f);
|
||||
}
|
||||
|
||||
} while (f != future && std::distance (c, f) < long (n * fill_factor));
|
||||
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("edges %d..%d:", x, xx);
|
||||
|
|
@ -1165,15 +1181,15 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
|||
|
||||
// parallel horizontal edges: produce the end points of each other edge as cutpoints
|
||||
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
||||
add_hparallel_cutpoints (*c1, *c2, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cutpoints);
|
||||
add_hparallel_cutpoints (*c1, *c2, cell, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cell, cutpoints);
|
||||
}
|
||||
|
||||
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
|
||||
if (cp.first) {
|
||||
if (cp.first && cell.contains (cp.second)) {
|
||||
|
||||
// add a cut point to c1 and c2 (c2 only if necessary)
|
||||
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
|
|
@ -1197,7 +1213,7 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
|||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
|
||||
if (cp.first) {
|
||||
if (cp.first && cell.contains (cp.second)) {
|
||||
|
||||
// add a cut point to c1 and c2
|
||||
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
|
|
@ -1336,10 +1352,9 @@ public:
|
|||
static void
|
||||
get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector <WorkEdge>::iterator current, std::vector <WorkEdge>::iterator future, db::Coord y, db::Coord yy, bool with_h)
|
||||
{
|
||||
std::vector <WorkEdge *> p1_weak; // holds weak interactions of edge endpoints with other edges
|
||||
std::vector <WorkEdge *> ip_weak;
|
||||
double dy = y - 0.5;
|
||||
double dyy = yy + 0.5;
|
||||
std::vector <std::pair<const WorkEdge *, WorkEdge *> > p1_weak; // holds weak interactions of edge endpoints with other edges
|
||||
|
||||
std::sort (current, future, edge_xmin_at_yinterval_double_compare<db::Coord> (dy, dyy));
|
||||
|
||||
|
|
@ -1356,14 +1371,28 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
std::vector <WorkEdge>::iterator f = current;
|
||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
||||
|
||||
while (f != future && edge_xmin_at_yinterval_double (*f, dy, dyy) <= x) {
|
||||
++f;
|
||||
}
|
||||
size_t n = 0;
|
||||
db::Coord xx = x;
|
||||
|
||||
db::Coord xx = std::numeric_limits <db::Coord>::max ();
|
||||
if (f != future) {
|
||||
xx = edge_xmin_at_yinterval_double (*f, dy, dyy);
|
||||
}
|
||||
// fetch as many cells as to fill in roughly 50% more
|
||||
// (this is an empirical performance improvement factor)
|
||||
do {
|
||||
|
||||
while (f != future && edge_xmin_at_yinterval_double (*f, dy, dyy) <= xx) {
|
||||
++f;
|
||||
}
|
||||
|
||||
if (f != future) {
|
||||
xx = edge_xmin_at_yinterval_double (*f, dy, dyy);
|
||||
} else {
|
||||
xx = std::numeric_limits <db::Coord>::max ();
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
n = std::distance (c, f);
|
||||
}
|
||||
|
||||
} while (f != future && std::distance (c, f) < long (n * fill_factor));
|
||||
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("edges %d..%d:", x, xx);
|
||||
|
|
@ -1377,9 +1406,10 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
|
||||
db::Box cell (x, y, xx, yy);
|
||||
|
||||
for (std::vector <WorkEdge>::iterator c1 = c; c1 != f; ++c1) {
|
||||
std::set<db::Point> weak_points; // holds points that need to go in all other edges
|
||||
p1_weak.clear ();
|
||||
|
||||
p1_weak.clear ();
|
||||
for (std::vector <WorkEdge>::iterator c1 = c; c1 != f; ++c1) {
|
||||
|
||||
bool c1p1_in_cell = cell.contains (c1->p1 ());
|
||||
bool c1p2_in_cell = cell.contains (c1->p2 ());
|
||||
|
|
@ -1398,46 +1428,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
|
||||
// parallel horizontal edges: produce the end points of each other edge as cutpoints
|
||||
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
||||
add_hparallel_cutpoints (*c1, *c2, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cutpoints);
|
||||
add_hparallel_cutpoints (*c1, *c2, cell, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cell, cutpoints);
|
||||
}
|
||||
|
||||
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
||||
if (cp.first) {
|
||||
|
||||
bool on_edge1 = is_point_on_exact (*c1, cp.second);
|
||||
|
||||
// add a cut point to c1 and c2 (points not on the edge give strong attractors)
|
||||
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge1);
|
||||
if (with_h) {
|
||||
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, false);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
if (on_edge1) {
|
||||
printf ("weak intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
||||
} else {
|
||||
printf ("intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
||||
}
|
||||
#endif
|
||||
|
||||
// The new cutpoint must be inserted into other edges as well.
|
||||
ip_weak.clear ();
|
||||
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);
|
||||
}
|
||||
}
|
||||
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
|
||||
(*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 ());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cp.first && cell.contains (cp.second)) {
|
||||
// Stash the cutpoint as it must be inserted into other edges as well.
|
||||
weak_points.insert (cp.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1478,41 +1479,9 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
||||
if (cp.first) {
|
||||
|
||||
bool on_edge1 = true;
|
||||
bool on_edge2 = is_point_on_exact (*c2, cp.second);
|
||||
|
||||
// add a cut point to c1 and c2
|
||||
if (with_h || c1->dy () != 0) {
|
||||
on_edge1 = is_point_on_exact (*c1, cp.second);
|
||||
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge1);
|
||||
}
|
||||
|
||||
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge2);
|
||||
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
if (!on_edge1 || !on_edge2) {
|
||||
printf ("intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
||||
} else {
|
||||
printf ("weak intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
||||
}
|
||||
#endif
|
||||
|
||||
// The new cutpoint must be inserted into other edges as well.
|
||||
ip_weak.clear ();
|
||||
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);
|
||||
}
|
||||
}
|
||||
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
|
||||
(*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 ());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cp.first && cell.contains (cp.second)) {
|
||||
// Stash the cutpoint as it must be inserted into other edges as well.
|
||||
weak_points.insert (cp.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1532,7 +1501,7 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
#endif
|
||||
c2->make_cutpoints (cutpoints)->add (c1->p1 (), &cutpoints, true);
|
||||
} else {
|
||||
p1_weak.push_back (&*c2);
|
||||
p1_weak.push_back (std::make_pair (c1.operator-> (), c2.operator-> ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1540,39 +1509,71 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
|
||||
}
|
||||
|
||||
if (! p1_weak.empty ()) {
|
||||
}
|
||||
|
||||
bool strong = false;
|
||||
for (std::vector<WorkEdge *>::const_iterator cp = p1_weak.begin (); cp != p1_weak.end () && ! strong; ++cp) {
|
||||
if ((*cp)->data > 0 && cutpoints [(*cp)->data - 1].strong_cutpoints) {
|
||||
strong = true;
|
||||
}
|
||||
}
|
||||
// insert weak intersection points into all relevant edges - weak into edges
|
||||
// where the point is on and strong into edges where the point is on in a fuzzy way.
|
||||
|
||||
p1_weak.back ()->make_cutpoints (cutpoints);
|
||||
size_t n = p1_weak.back ()->data - 1;
|
||||
for (std::vector<WorkEdge *>::const_iterator cp = p1_weak.begin (); cp != p1_weak.end (); ++cp) {
|
||||
for (auto wp = weak_points.begin (); wp != weak_points.end (); ++wp) {
|
||||
|
||||
(*cp)->make_cutpoints (cutpoints);
|
||||
size_t nn = (*cp)->data - 1;
|
||||
if (strong) {
|
||||
cutpoints [nn].add (c1->p1 (), &cutpoints);
|
||||
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
||||
if ((with_h || cc->dy () != 0) && is_point_on_fuzzy (*cc, *wp)) {
|
||||
bool on_edge = is_point_on_exact (*cc, *wp);
|
||||
cc->make_cutpoints (cutpoints)->add (*wp, &cutpoints, !on_edge);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("Insert strong attractor %s in %s.\n", c1->p1 ().to_string ().c_str (), (*cp)->to_string ().c_str ());
|
||||
#endif
|
||||
if (!on_edge) {
|
||||
printf ("intersection point %s gives strong cutpoint in %s.\n", wp->to_string ().c_str (), cc->to_string ().c_str ());
|
||||
} else {
|
||||
cutpoints [nn].add_attractor (c1->p1 (), n);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("Insert weak attractor %s in %s.\n", c1->p1 ().to_string ().c_str (), (*cp)->to_string ().c_str ());
|
||||
#endif
|
||||
printf ("intersection point %s gives weak cutpoint in %s.\n", wp->to_string ().c_str (), cc->to_string ().c_str ());
|
||||
}
|
||||
|
||||
n = nn;
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// go through the list of "p1 to other edges" and insert p1 either as cutpoint
|
||||
// (if there are other strong cutpoints already) or weak attractor.
|
||||
|
||||
auto p1w_from = p1_weak.begin ();
|
||||
while (p1w_from != p1_weak.end ()) {
|
||||
|
||||
bool strong = false;
|
||||
auto p1w_to = p1w_from;
|
||||
while (p1w_to != p1_weak.end () && p1w_to->first == p1w_from->first) {
|
||||
if (p1w_to->second->data > 0 && cutpoints [p1w_to->second->data - 1].strong_cutpoints) {
|
||||
strong = true;
|
||||
}
|
||||
++p1w_to;
|
||||
}
|
||||
|
||||
db::Point p1 = p1w_from->first->p1 ();
|
||||
|
||||
p1w_to [-1].second->make_cutpoints (cutpoints);
|
||||
size_t n = p1w_to [-1].second->data - 1;
|
||||
|
||||
for (auto cp = p1w_from; cp != p1w_to; ++cp) {
|
||||
|
||||
cp->second->make_cutpoints (cutpoints);
|
||||
size_t nn = cp->second->data - 1;
|
||||
if (strong) {
|
||||
cutpoints [nn].add (p1, &cutpoints);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("Insert strong attractor %s in %s.\n", cp->first->p1 ().to_string ().c_str (), cp->second->to_string ().c_str ());
|
||||
#endif
|
||||
} else {
|
||||
cutpoints [nn].add_attractor (p1, n);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("Insert weak attractor %s in %s.\n", cp->first->p1 ().to_string ().c_str (), cp->second->to_string ().c_str ());
|
||||
#endif
|
||||
}
|
||||
|
||||
n = nn;
|
||||
|
||||
}
|
||||
|
||||
p1w_from = p1w_to;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2259,7 +2260,7 @@ EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::
|
|||
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
||||
}
|
||||
|
||||
size_t n = std::distance (current, future);
|
||||
size_t n = 0;
|
||||
db::Coord yy = y;
|
||||
|
||||
// Use as many scanlines as to fetch approx. 50% new edges into the scanline (this
|
||||
|
|
@ -2276,7 +2277,11 @@ EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::
|
|||
yy = std::numeric_limits <db::Coord>::max ();
|
||||
}
|
||||
|
||||
} while (future != mp_work_edges->end () && std::distance (current, future) < long (n + n / 2));
|
||||
if (n == 0) {
|
||||
n = std::distance (current, future);
|
||||
}
|
||||
|
||||
} while (future != mp_work_edges->end () && std::distance (current, future) < long (n * fill_factor));
|
||||
|
||||
bool is90 = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,8 @@ struct DetectTagEdgeSink
|
|||
DetectTagEdgeSink (int tag)
|
||||
: fail_tag (tag), result (true) { }
|
||||
|
||||
virtual void put (const db::Edge &) { }
|
||||
|
||||
virtual void put (const db::Edge &, int tag)
|
||||
{
|
||||
if (tag == fail_tag) {
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ RegionDelegate *FlatRegion::add (const Region &other) const
|
|||
if (other_flat) {
|
||||
|
||||
new_region->raw_polygons ().insert (other_flat->raw_polygons ().get_layer<db::Polygon, db::unstable_layer_tag> ().begin (), other_flat->raw_polygons ().get_layer<db::Polygon, db::unstable_layer_tag> ().end ());
|
||||
new_region->raw_polygons ().insert (other_flat->raw_polygons ().get_layer<db::PolygonWithProperties, db::unstable_layer_tag> ().begin (), other_flat->raw_polygons ().get_layer<db::PolygonWithProperties, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -343,6 +344,7 @@ RegionDelegate *FlatRegion::add_in_place (const Region &other)
|
|||
if (other_flat) {
|
||||
|
||||
polygons.insert (other_flat->raw_polygons ().get_layer<db::Polygon, db::unstable_layer_tag> ().begin (), other_flat->raw_polygons ().get_layer<db::Polygon, db::unstable_layer_tag> ().end ());
|
||||
polygons.insert (other_flat->raw_polygons ().get_layer<db::PolygonWithProperties, db::unstable_layer_tag> ().begin (), other_flat->raw_polygons ().get_layer<db::PolygonWithProperties, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
|
|
|
|||
|
|
@ -101,17 +101,22 @@ hershey_count_edges (const std::string &s, unsigned int f)
|
|||
HersheyFont *fp = fonts [f];
|
||||
size_t n = 0;
|
||||
|
||||
for (const char *cp = s.c_str (); *cp; ++cp) {
|
||||
for (const char *cp = s.c_str (); *cp; ) {
|
||||
|
||||
unsigned char c = (unsigned char) *cp;
|
||||
if (c == '\012' || c == '\015') {
|
||||
if (c == '\015' && cp[1] == '\012') {
|
||||
++cp;
|
||||
if (tl::skip_newline (cp)) {
|
||||
|
||||
// skip new line - they don't contribute edges
|
||||
|
||||
} else {
|
||||
|
||||
uint32_t c = tl::utf32_from_utf8 (cp);
|
||||
|
||||
if (c < fp->end_char && c >= fp->start_char) {
|
||||
n += fp->chars [c - fp->start_char].edge_end - fp->chars [c - fp->start_char].edge_start;
|
||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||
n += fp->chars [invalid_char - fp->start_char].edge_end - fp->chars [invalid_char - fp->start_char].edge_start;
|
||||
}
|
||||
} else if (c < fp->end_char && c >= fp->start_char) {
|
||||
n += fp->chars [c - fp->start_char].edge_end - fp->chars [c - fp->start_char].edge_start;
|
||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||
n += fp->chars [invalid_char - fp->start_char].edge_end - fp->chars [invalid_char - fp->start_char].edge_start;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -142,22 +147,27 @@ hershey_text_box (const std::string &s, unsigned int f)
|
|||
int w = 0;
|
||||
int h = fp->ymax;
|
||||
|
||||
for (const char *cp = s.c_str (); *cp; ++cp) {
|
||||
for (const char *cp = s.c_str (); *cp; ) {
|
||||
|
||||
if (tl::skip_newline (cp)) {
|
||||
|
||||
unsigned char c = (unsigned char) *cp;
|
||||
if (c == '\012' || c == '\015') {
|
||||
if (c == '\015' && cp[1] == '\012') {
|
||||
++cp;
|
||||
}
|
||||
if (w > wl) {
|
||||
wl = w;
|
||||
}
|
||||
|
||||
hl += line_spacing + h - fp->ymin;
|
||||
w = 0;
|
||||
} else if (c < fp->end_char && c >= fp->start_char) {
|
||||
w += fp->chars [c - fp->start_char].width;
|
||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||
w += fp->chars [invalid_char - fp->start_char].width;
|
||||
|
||||
} else {
|
||||
|
||||
uint32_t c = tl::utf32_from_utf8 (cp);
|
||||
|
||||
if (c < fp->end_char && c >= fp->start_char) {
|
||||
w += fp->chars [c - fp->start_char].width;
|
||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||
w += fp->chars [invalid_char - fp->start_char].width;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -167,32 +177,39 @@ hershey_text_box (const std::string &s, unsigned int f)
|
|||
}
|
||||
hl += h;
|
||||
|
||||
return db::DBox (0, 0, wl, hl);
|
||||
return db::DBox (0, fp->ymin, wl, hl);
|
||||
}
|
||||
|
||||
void
|
||||
hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halign, VAlign valign, std::vector<db::DPoint> &linestarts)
|
||||
void
|
||||
hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halign, VAlign valign, std::vector<db::DPoint> &linestarts, double &left, double &bottom)
|
||||
{
|
||||
left = 0.0;
|
||||
bottom = 0.0;
|
||||
|
||||
HersheyFont *fp = fonts [f];
|
||||
|
||||
int hl = 0;
|
||||
int w = 0;
|
||||
int h = fp->ymax;
|
||||
|
||||
for (const char *cp = s.c_str (); *cp; ++cp) {
|
||||
for (const char *cp = s.c_str (); *cp; ) {
|
||||
|
||||
if (tl::skip_newline (cp)) {
|
||||
|
||||
unsigned char c = (unsigned char) *cp;
|
||||
if (c == '\012' || c == '\015') {
|
||||
if (c == '\015' && cp[1] == '\012') {
|
||||
++cp;
|
||||
}
|
||||
linestarts.push_back (db::DPoint (w, -hl));
|
||||
hl += line_spacing + h - fp->ymin;
|
||||
w = 0;
|
||||
} else if (c < fp->end_char && c >= fp->start_char) {
|
||||
w += fp->chars [c - fp->start_char].width;
|
||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||
w += fp->chars [invalid_char - fp->start_char].width;
|
||||
|
||||
} else {
|
||||
|
||||
uint32_t c = tl::utf32_from_utf8 (cp);
|
||||
|
||||
if (c < fp->end_char && c >= fp->start_char) {
|
||||
w += fp->chars [c - fp->start_char].width;
|
||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||
w += fp->chars [invalid_char - fp->start_char].width;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -220,21 +237,26 @@ hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halig
|
|||
p += db::DVector (0, l->y ());
|
||||
}
|
||||
*l = p;
|
||||
if (l == linestarts.begin ()) {
|
||||
left = l->x ();
|
||||
bottom = l->y ();
|
||||
} else {
|
||||
left = std::min (left, l->x ());
|
||||
bottom = std::min (bottom, l->y ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// basic_hershey_edge_iterator implementation
|
||||
|
||||
basic_hershey_edge_iterator::basic_hershey_edge_iterator (const std::string &s, unsigned int f, const std::vector<db::DPoint> &line_starts)
|
||||
: m_line (0), m_string (s), m_edge (0), m_edge_end (0), m_index (0), m_linestarts (line_starts)
|
||||
: m_line (0), m_string (s), m_edge (0), m_edge_end (0), m_linestarts (line_starts)
|
||||
{
|
||||
m_fp = fonts [f];
|
||||
m_end = (unsigned int) m_string.size ();
|
||||
m_new_char = true;
|
||||
mp_cp = m_string.c_str ();
|
||||
|
||||
if (m_linestarts.size () == 0) {
|
||||
if (m_linestarts.empty ()) {
|
||||
m_linestarts.push_back (db::DPoint (0.0, 0.0));
|
||||
}
|
||||
m_pos = m_linestarts [0];
|
||||
|
|
@ -243,66 +265,47 @@ basic_hershey_edge_iterator::basic_hershey_edge_iterator (const std::string &s,
|
|||
bool
|
||||
basic_hershey_edge_iterator::at_end () const
|
||||
{
|
||||
return m_index >= m_end;
|
||||
return *mp_cp == 0 && m_edge == m_edge_end;
|
||||
}
|
||||
|
||||
db::DEdge
|
||||
basic_hershey_edge_iterator::get ()
|
||||
{
|
||||
while (m_new_char && !at_end ()) {
|
||||
|
||||
unsigned char c = (unsigned char) (m_index < m_end ? m_string [m_index] : ' ');
|
||||
while (m_edge == m_edge_end && *mp_cp) {
|
||||
|
||||
m_pos += m_delta;
|
||||
|
||||
if (c < m_fp->end_char && c >= m_fp->start_char) {
|
||||
m_edge = m_edge_end = 0;
|
||||
m_delta = db::DVector ();
|
||||
|
||||
m_edge = m_fp->chars [c - m_fp->start_char].edge_start;
|
||||
m_edge_end = m_fp->chars [c - m_fp->start_char].edge_end;
|
||||
m_delta = db::DVector (m_fp->chars [c - m_fp->start_char].width, 0);
|
||||
if (tl::skip_newline (mp_cp)) {
|
||||
|
||||
} else if (c != '\012' && c != '\015'
|
||||
&& invalid_char < m_fp->end_char
|
||||
&& invalid_char >= m_fp->start_char) {
|
||||
++m_line;
|
||||
|
||||
m_edge = m_fp->chars [invalid_char - m_fp->start_char].edge_start;
|
||||
m_edge_end = m_fp->chars [invalid_char - m_fp->start_char].edge_end;
|
||||
m_delta = db::DVector (m_fp->chars [invalid_char - m_fp->start_char].width, 0);
|
||||
if (m_line >= m_linestarts.size ()) {
|
||||
db::DPoint last;
|
||||
last = m_linestarts.back ();
|
||||
last += db::DVector (0, -(m_fp->ymax - m_fp->ymin + line_spacing));
|
||||
m_linestarts.push_back (last);
|
||||
}
|
||||
m_pos = m_linestarts [m_line];
|
||||
|
||||
} else {
|
||||
|
||||
m_edge = m_edge_end = 0;
|
||||
m_delta = db::DVector ();
|
||||
uint32_t c = tl::utf32_from_utf8 (mp_cp);
|
||||
|
||||
}
|
||||
|
||||
if (m_edge == m_edge_end) {
|
||||
|
||||
if (c == '\012' || c == '\015') {
|
||||
if (c == '\015' && m_string.size () > m_index + 1 && m_string [m_index] == '\012') {
|
||||
++m_index;
|
||||
}
|
||||
++m_line;
|
||||
if (m_line >= m_linestarts.size ()) {
|
||||
m_linestarts.push_back (m_linestarts.back () + db::DVector (0.0, -(m_fp->ymax - m_fp->ymin + line_spacing)));
|
||||
}
|
||||
m_pos = m_linestarts [m_line];
|
||||
if (c < m_fp->start_char || c >= m_fp->end_char) {
|
||||
c = invalid_char;
|
||||
}
|
||||
|
||||
++m_index;
|
||||
if (c < m_fp->end_char && c >= m_fp->start_char) {
|
||||
m_edge = m_fp->chars [c - m_fp->start_char].edge_start;
|
||||
m_edge_end = m_fp->chars [c - m_fp->start_char].edge_end;
|
||||
m_delta = db::DVector (m_fp->chars [c - m_fp->start_char].width, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
m_new_char = false;
|
||||
}
|
||||
}
|
||||
|
||||
while (m_line >= m_linestarts.size ()) {
|
||||
db::DPoint last;
|
||||
if (m_linestarts.size () > 0) {
|
||||
last = m_linestarts.back ();
|
||||
last += db::DVector (0, -(m_fp->ymax - m_fp->ymin + line_spacing));
|
||||
}
|
||||
m_linestarts.push_back (last);
|
||||
}
|
||||
|
||||
if (!at_end ()) {
|
||||
|
|
@ -316,16 +319,9 @@ basic_hershey_edge_iterator::get ()
|
|||
void
|
||||
basic_hershey_edge_iterator::inc ()
|
||||
{
|
||||
if (m_new_char) {
|
||||
get ();
|
||||
}
|
||||
|
||||
if (! at_end ()) {
|
||||
++m_edge;
|
||||
if (m_edge == m_edge_end) {
|
||||
++m_index;
|
||||
m_new_char = true;
|
||||
}
|
||||
get ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ struct HersheyFont;
|
|||
DB_PUBLIC int hershey_font_width (unsigned int f);
|
||||
DB_PUBLIC int hershey_font_height (unsigned int f);
|
||||
DB_PUBLIC db::DBox hershey_text_box (const std::string &s, unsigned int f);
|
||||
DB_PUBLIC void hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halign, VAlign valign, std::vector<db::DPoint> &linestarts);
|
||||
DB_PUBLIC void hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halign, VAlign valign, std::vector<db::DPoint> &linestarts, double &left, double &bottom);
|
||||
DB_PUBLIC std::vector<std::string> hershey_font_names ();
|
||||
DB_PUBLIC size_t hershey_count_edges (const std::string &s, unsigned int f);
|
||||
|
||||
|
|
@ -51,11 +51,10 @@ public:
|
|||
void inc ();
|
||||
|
||||
private:
|
||||
bool m_new_char;
|
||||
unsigned int m_line;
|
||||
const char *mp_cp;
|
||||
std::string m_string;
|
||||
unsigned int m_edge, m_edge_end;
|
||||
unsigned int m_index, m_end;
|
||||
std::vector<db::DPoint> m_linestarts;
|
||||
db::DPoint m_pos;
|
||||
db::DVector m_delta;
|
||||
|
|
@ -138,7 +137,8 @@ struct DB_PUBLIC_TEMPLATE hershey
|
|||
hershey ()
|
||||
: m_string (),
|
||||
m_font (DefaultFont),
|
||||
m_scale (1.0)
|
||||
m_scale (1.0),
|
||||
m_left (0.0), m_bottom (0.0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -151,7 +151,8 @@ struct DB_PUBLIC_TEMPLATE hershey
|
|||
hershey (const std::string &s, Font f)
|
||||
: m_string (s),
|
||||
m_font (f),
|
||||
m_scale (1.0)
|
||||
m_scale (1.0),
|
||||
m_left (0.0), m_bottom (0.0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -177,14 +178,13 @@ struct DB_PUBLIC_TEMPLATE hershey
|
|||
/**
|
||||
* @brief Obtain the size of the text
|
||||
*
|
||||
* @return The bounding box of the text with the scaling applied
|
||||
* @return The bounding box of the text with the scaling and justification applied
|
||||
*/
|
||||
box<C> bbox () const
|
||||
db::DBox bbox () const
|
||||
{
|
||||
db::DBox b = hershey_text_box (m_string, m_font);
|
||||
db::point<C> p1 (coord_traits::rounded (b.p1 ().x () / m_scale), coord_traits::rounded (b.p1 ().y () / m_scale));
|
||||
db::point<C> p2 (coord_traits::rounded (b.p2 ().x () / m_scale), coord_traits::rounded (b.p2 ().y () / m_scale));
|
||||
return box<C> (p1, p2);
|
||||
b.move (db::DVector (m_left, m_bottom));
|
||||
return b * m_scale;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -220,11 +220,11 @@ struct DB_PUBLIC_TEMPLATE hershey
|
|||
|
||||
db::DPoint p1 (b.p1 ().x () / m_scale, b.p1 ().y () / m_scale);
|
||||
db::DPoint p2 (b.p2 ().x () / m_scale, b.p2 ().y () / m_scale);
|
||||
hershey_justify (m_string, m_font, db::DBox (p1, p2), halign, valign, m_linestarts);
|
||||
hershey_justify (m_string, m_font, db::DBox (p1, p2), halign, valign, m_linestarts, m_left, m_bottom);
|
||||
|
||||
} else {
|
||||
|
||||
if (b.width () > 0 && b.height () > 0) {
|
||||
if (coord_traits::less (0, b.width ()) && coord_traits::less (0, b.height ())) {
|
||||
|
||||
db::DBox tbx (hershey_text_box (m_string, m_font));
|
||||
double fx = double (b.width ()) / double (tbx.width ());
|
||||
|
|
@ -232,11 +232,11 @@ struct DB_PUBLIC_TEMPLATE hershey
|
|||
double f = std::min (fx, fy);
|
||||
m_scale = f * (1.0 - 2.0 * margin);
|
||||
|
||||
} else if (b.width () > 0) {
|
||||
} else if (coord_traits::less (0, b.width ())) {
|
||||
|
||||
m_scale = double (b.width ()) / double (hershey_font_width (m_font));
|
||||
|
||||
} else if (b.height () > 0) {
|
||||
} else if (coord_traits::less (0, b.height ())) {
|
||||
|
||||
m_scale = double (b.height ()) / double (hershey_font_height (m_font));
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ struct DB_PUBLIC_TEMPLATE hershey
|
|||
if (m_scale > 1e-6) {
|
||||
db::DPoint p1 (b.p1 ().x () / m_scale, b.p1 ().y () / m_scale);
|
||||
db::DPoint p2 (b.p2 ().x () / m_scale, b.p2 ().y () / m_scale);
|
||||
hershey_justify (m_string, m_font, db::DBox (p1, p2), halign, valign, m_linestarts);
|
||||
hershey_justify (m_string, m_font, db::DBox (p1, p2), halign, valign, m_linestarts, m_left, m_bottom);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -294,6 +294,7 @@ private:
|
|||
Font m_font;
|
||||
double m_scale;
|
||||
std::vector <db::DPoint> m_linestarts;
|
||||
double m_left, m_bottom;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@ cronology::events::event_collection<event_compute_results, event_compute_local_c
|
|||
namespace db
|
||||
{
|
||||
|
||||
// Heuristic parameter to control the recursion of the cell-to-cell intruder
|
||||
// detection: do not recurse if the intruder cell's bounding box is smaller
|
||||
// than the overlap box times this factor.
|
||||
const double area_ratio_for_recursion = 3.0;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Shape reference translator
|
||||
|
||||
|
|
@ -370,6 +375,32 @@ db::Box safe_box_enlarged (const db::Box &box, db::Coord dx, db::Coord dy)
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Debugging utility: dump the cell contexts
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
static void dump_cell_contexts (local_processor_contexts<TS, TI, TR> &contexts, const db::Layout *subject_layout, const db::Layout *intruder_layout)
|
||||
{
|
||||
for (auto cc = contexts.begin (); cc != contexts.end (); ++cc) {
|
||||
tl::info << "Cell " << subject_layout->cell_name (cc->first->cell_index ()) << ":";
|
||||
int i = 0;
|
||||
for (auto c = cc->second.begin (); c != cc->second.end (); ++c) {
|
||||
tl::info << " Context #" << ++i;
|
||||
tl::info << " Instances:";
|
||||
for (auto i = c->first.first.begin (); i != c->first.first.end (); ++i) {
|
||||
const db::CellInstArray &ci = *i;
|
||||
tl::info << " " << intruder_layout->cell_name (ci.object ().cell_index ()) << " @ " << ci.complex_trans (*ci.begin ()).to_string () << " (" << ci.size () << ")";
|
||||
}
|
||||
tl::info << " Shapes:";
|
||||
for (auto i = c->first.second.begin (); i != c->first.second.end (); ++i) {
|
||||
for (auto s = i->second.begin (); s != i->second.end (); ++s) {
|
||||
tl::info << " " << intruder_layout->get_properties (i->first).to_string () << ": " << s->to_string ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// LocalProcessorCellContext implementation
|
||||
|
||||
|
|
@ -1208,7 +1239,8 @@ private:
|
|||
void
|
||||
collect_instance_interactions (const db::CellInstArray *inst1, const db::CellInstArray *inst2)
|
||||
{
|
||||
// TODO: this algorithm is not in particular effective for identical arrays
|
||||
// TODO: this algorithm is not in particular effective for identical arrays or for arrays
|
||||
// vs. single instances
|
||||
|
||||
const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ());
|
||||
const db::Cell &cell2 = mp_intruder_layout->cell (inst2->object ().cell_index ());
|
||||
|
|
@ -1247,7 +1279,7 @@ private:
|
|||
db::Box ibox2 = tn2 * cell2.bbox (m_intruder_layer).enlarged (db::Vector (m_dist, m_dist));
|
||||
|
||||
db::Box cbox = ibox1 & ibox2;
|
||||
if (! cbox.empty () && cell1.has_shapes_touching (m_subject_layer, safe_box_enlarged (tni1 * cbox, -1, -1))) {
|
||||
if (! cbox.empty () && (cbox == ibox1 || cell1.has_shapes_touching (m_subject_layer, safe_box_enlarged (tni1 * cbox, -1, -1)))) {
|
||||
|
||||
db::ICplxTrans tn21 = tni1 * tn2;
|
||||
|
||||
|
|
@ -1282,9 +1314,11 @@ private:
|
|||
db::ICplxTrans tni2 = tn21.inverted () * tni1;
|
||||
db::Box tbox2 = safe_box_enlarged (tni2 * cbox, -1, -1);
|
||||
|
||||
if (! intruder_cell.shapes (m_intruder_layer).begin_touching (tbox2, ShapeIterator::All).at_end ()) {
|
||||
// do not recurse further if we're overlapping with shapes from the intruder
|
||||
// or the intruder cell is not much bigger than the region of interest (cbox)
|
||||
if (intruder_cell.bbox (m_intruder_layer).area () < area_ratio_for_recursion * cbox.area ()
|
||||
|| ! intruder_cell.shapes (m_intruder_layer).begin_touching (tbox2, ShapeIterator::All).at_end ()) {
|
||||
|
||||
// we're overlapping with shapes from the intruder - do not recursive further
|
||||
interactions.push_back (std::make_pair (intruder_cell.cell_index (), tn21));
|
||||
return;
|
||||
|
||||
|
|
@ -1782,6 +1816,11 @@ template <class TS, class TI, class TR>
|
|||
void
|
||||
local_processor<TS, TI, TR>::compute_results (local_processor_contexts<TS, TI, TR> &contexts, const local_operation<TS, TI, TR> *op, const std::vector<unsigned int> &output_layers) const
|
||||
{
|
||||
#if 0
|
||||
// debugging
|
||||
dump_cell_contexts (contexts, mp_subject_layout, mp_intruder_layout ? mp_intruder_layout : mp_subject_layout);
|
||||
#endif
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 10, tl::to_string (tr ("Computing results for ")) + description (op));
|
||||
|
||||
// avoids updates while we work on the layout
|
||||
|
|
|
|||
|
|
@ -152,13 +152,13 @@ static std::pair<bool, std::set<db::Box> > compute_clip_variant (const db::Box &
|
|||
}
|
||||
|
||||
HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, const db::ICplxTrans &trans, HierarchyBuilderShapeReceiver *pipe)
|
||||
: mp_target (target), m_initial_pass (true), m_cm_new_entry (false), m_target_layer (target_layer), m_trans (trans)
|
||||
: mp_target (target), m_initial_pass (true), m_cm_new_entry (false), m_target_layer (target_layer), m_wants_all_cells (false), m_trans (trans)
|
||||
{
|
||||
set_shape_receiver (pipe);
|
||||
}
|
||||
|
||||
HierarchyBuilder::HierarchyBuilder (db::Layout *target, const db::ICplxTrans &trans, HierarchyBuilderShapeReceiver *pipe)
|
||||
: mp_target (target), m_initial_pass (true), m_cm_new_entry (false), m_target_layer (0), m_trans (trans)
|
||||
: mp_target (target), m_initial_pass (true), m_cm_new_entry (false), m_target_layer (0), m_wants_all_cells (false), m_trans (trans)
|
||||
{
|
||||
set_shape_receiver (pipe);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,6 +295,7 @@ public:
|
|||
*/
|
||||
void set_shape_receiver (HierarchyBuilderShapeReceiver *pipe);
|
||||
|
||||
virtual bool wants_all_cells () const { return m_wants_all_cells; }
|
||||
virtual void begin (const RecursiveShapeIterator *iter);
|
||||
virtual void end (const RecursiveShapeIterator *iter);
|
||||
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
|
|
@ -311,6 +312,14 @@ public:
|
|||
m_target_layer = target_layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the target layer - shapes will be put there
|
||||
*/
|
||||
void set_wants_all_cells (bool f)
|
||||
{
|
||||
m_wants_all_cells = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the builder - performs a new initial pass
|
||||
*/
|
||||
|
|
@ -416,6 +425,7 @@ private:
|
|||
cell_map_type::const_iterator m_cm_entry;
|
||||
bool m_cm_new_entry;
|
||||
unsigned int m_target_layer;
|
||||
bool m_wants_all_cells;
|
||||
std::vector<std::pair<bool, std::vector<db::Cell *> > > m_cell_stack;
|
||||
db::Cell *mp_initial_cell;
|
||||
|
||||
|
|
|
|||
|
|
@ -258,12 +258,12 @@ private:
|
|||
// -----------------------------------------------------------------
|
||||
// Implementation of the ProxyContextInfo class
|
||||
|
||||
ProxyContextInfo
|
||||
ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
|
||||
LayoutOrCellContextInfo
|
||||
LayoutOrCellContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
|
||||
{
|
||||
ProxyContextInfo info;
|
||||
LayoutOrCellContextInfo info;
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = from; i != to; ++i) {
|
||||
for (auto i = from; i != to; ++i) {
|
||||
|
||||
tl::Extractor ex (i->c_str ());
|
||||
|
||||
|
|
@ -290,6 +290,20 @@ ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, st
|
|||
|
||||
info.cell_name = ex.skip ();
|
||||
|
||||
} else if (ex.test ("META(")) {
|
||||
|
||||
std::pair<std::string, std::pair<tl::Variant, std::string> > vv;
|
||||
|
||||
ex.read_word_or_quoted (vv.first);
|
||||
if (ex.test (",")) {
|
||||
ex.read_word_or_quoted (vv.second.second);
|
||||
}
|
||||
ex.test (")");
|
||||
ex.test ("=");
|
||||
ex.read (vv.second.first);
|
||||
|
||||
info.meta_info.insert(vv);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -298,12 +312,12 @@ ProxyContextInfo::deserialize (std::vector<std::string>::const_iterator from, st
|
|||
}
|
||||
|
||||
void
|
||||
ProxyContextInfo::serialize (std::vector<std::string> &strings)
|
||||
LayoutOrCellContextInfo::serialize (std::vector<std::string> &strings)
|
||||
{
|
||||
if (! lib_name.empty ()) {
|
||||
strings.push_back ("LIB=" + lib_name);
|
||||
}
|
||||
for (std::map<std::string, tl::Variant> ::const_iterator p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) {
|
||||
for (auto p = pcell_parameters.begin (); p != pcell_parameters.end (); ++p) {
|
||||
strings.push_back ("P(" + tl::to_word_or_quoted_string (p->first) + ")=" + p->second.to_parsable_string ());
|
||||
}
|
||||
if (! pcell_name.empty ()) {
|
||||
|
|
@ -312,6 +326,32 @@ ProxyContextInfo::serialize (std::vector<std::string> &strings)
|
|||
if (! cell_name.empty ()) {
|
||||
strings.push_back ("CELL=" + cell_name);
|
||||
}
|
||||
|
||||
std::string mv;
|
||||
for (auto m = meta_info.begin (); m != meta_info.end (); ++m) {
|
||||
mv.clear ();
|
||||
mv += "META(";
|
||||
mv += tl::to_word_or_quoted_string (m->first);
|
||||
if (! m->second.second.empty ()) {
|
||||
mv += ",";
|
||||
mv += tl::to_word_or_quoted_string (m->second.second);
|
||||
}
|
||||
mv += ")=";
|
||||
mv += m->second.first.to_parsable_string ();
|
||||
strings.push_back (mv);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutOrCellContextInfo::has_proxy_info () const
|
||||
{
|
||||
return !pcell_name.empty () || !lib_name.empty ();
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutOrCellContextInfo::has_meta_info () const
|
||||
{
|
||||
return !meta_info.empty ();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
|
@ -481,7 +521,13 @@ Layout::operator= (const Layout &d)
|
|||
}
|
||||
|
||||
m_dbu = d.m_dbu;
|
||||
|
||||
m_meta_info = d.m_meta_info;
|
||||
m_meta_info_by_cell = d.m_meta_info_by_cell;
|
||||
m_meta_info_names = d.m_meta_info_names;
|
||||
m_meta_info_name_map = d.m_meta_info_name_map;
|
||||
|
||||
m_tech_name = d.m_tech_name;
|
||||
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -593,7 +639,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -606,7 +652,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -633,7 +679,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
if (! cn.first) {
|
||||
|
||||
// unlink this proxy: substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -650,7 +696,7 @@ Layout::set_technology_name (const std::string &tech)
|
|||
db::cell_index_type ci = (*lp)->Cell::cell_index ();
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
get_context_info (ci, info);
|
||||
create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -1204,6 +1250,11 @@ Layout::take_cell (cell_index_type ci)
|
|||
|
||||
m_cell_ptrs [ci] = 0;
|
||||
|
||||
auto mi = m_meta_info_by_cell.find (ci);
|
||||
if (mi != m_meta_info_by_cell.end ()) {
|
||||
m_meta_info_by_cell.erase (mi);
|
||||
}
|
||||
|
||||
// Using free cell indices does have one significant drawback:
|
||||
// The cellview references cannot be uniquely classified as being invalid - because the
|
||||
// ID might be reused. This causes problems, when a cell is being deleted and subsequently a
|
||||
|
|
@ -1252,7 +1303,24 @@ Layout::uniquify_cell_name (const char *name) const
|
|||
}
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
cell_index_type
|
||||
Layout::add_cell (const db::Layout &other, db::cell_index_type ci)
|
||||
{
|
||||
cell_index_type ci_new = add_cell (other.cell_name (ci));
|
||||
cell (ci_new).set_ghost_cell (other.cell (ci).is_ghost_cell ());
|
||||
|
||||
if (&other == this) {
|
||||
add_meta_info (ci_new, other.begin_meta (ci), other.end_meta (ci));
|
||||
} else {
|
||||
for (auto m = other.begin_meta (ci); m != other.end_meta (ci); ++m) {
|
||||
add_meta_info (ci_new, meta_info_name_id (other.meta_info_name (m->first)), m->second);
|
||||
}
|
||||
}
|
||||
|
||||
return ci_new;
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::add_cell (const char *name)
|
||||
{
|
||||
std::string b;
|
||||
|
|
@ -1748,6 +1816,58 @@ Layout::do_update ()
|
|||
delete pr;
|
||||
}
|
||||
|
||||
static Layout::meta_info_map s_empty_meta;
|
||||
|
||||
Layout::meta_info_iterator
|
||||
Layout::begin_meta (db::cell_index_type ci) const
|
||||
{
|
||||
auto m = m_meta_info_by_cell.find (ci);
|
||||
if (m != m_meta_info_by_cell.end ()) {
|
||||
return m->second.begin ();
|
||||
} else {
|
||||
return s_empty_meta.begin ();
|
||||
}
|
||||
}
|
||||
|
||||
Layout::meta_info_iterator
|
||||
Layout::end_meta (db::cell_index_type ci) const
|
||||
{
|
||||
auto m = m_meta_info_by_cell.find (ci);
|
||||
if (m != m_meta_info_by_cell.end ()) {
|
||||
return m->second.end ();
|
||||
} else {
|
||||
return s_empty_meta.end ();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
Layout::meta_info_name (Layout::meta_info_name_id_type name_id) const
|
||||
{
|
||||
static std::string empty;
|
||||
return name_id < m_meta_info_names.size () ? m_meta_info_names[name_id] : empty;
|
||||
}
|
||||
|
||||
Layout::meta_info_name_id_type
|
||||
Layout::meta_info_name_id (const std::string &name)
|
||||
{
|
||||
auto n = m_meta_info_name_map.find (name);
|
||||
if (n != m_meta_info_name_map.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
size_t id = m_meta_info_names.size ();
|
||||
m_meta_info_names.push_back (name);
|
||||
m_meta_info_name_map.insert (std::make_pair (name, id));
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
Layout::meta_info_name_id_type
|
||||
Layout::meta_info_name_id (const std::string &name) const
|
||||
{
|
||||
auto n = m_meta_info_name_map.find (name);
|
||||
return n != m_meta_info_name_map.end () ? n->second : std::numeric_limits<meta_info_name_id_type>::max ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::clear_meta ()
|
||||
{
|
||||
|
|
@ -1755,42 +1875,79 @@ Layout::clear_meta ()
|
|||
}
|
||||
|
||||
void
|
||||
Layout::add_meta_info (const MetaInfo &i)
|
||||
Layout::add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i)
|
||||
{
|
||||
for (meta_info::iterator m = m_meta_info.begin (); m != m_meta_info.end (); ++m) {
|
||||
if (m->name == i.name) {
|
||||
*m = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_meta_info.push_back (i);
|
||||
m_meta_info[name_id] = i;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::remove_meta_info (const std::string &name)
|
||||
Layout::remove_meta_info (meta_info_name_id_type name_id)
|
||||
{
|
||||
for (meta_info::iterator m = m_meta_info.begin (); m != m_meta_info.end (); ++m) {
|
||||
if (m->name == name) {
|
||||
m_meta_info.erase (m);
|
||||
return;
|
||||
}
|
||||
m_meta_info.erase (name_id);
|
||||
}
|
||||
|
||||
const MetaInfo &
|
||||
Layout::meta_info (meta_info_name_id_type name_id) const
|
||||
{
|
||||
auto n = m_meta_info.find (name_id);
|
||||
static MetaInfo null_value;
|
||||
return n != m_meta_info.end () ? n->second : null_value;
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::has_meta_info (meta_info_name_id_type name_id) const
|
||||
{
|
||||
return m_meta_info.find (name_id) != m_meta_info.end ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::clear_meta (db::cell_index_type ci)
|
||||
{
|
||||
m_meta_info_by_cell.erase (ci);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i)
|
||||
{
|
||||
m_meta_info_by_cell[ci][name_id] = i;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id)
|
||||
{
|
||||
auto c = m_meta_info_by_cell.find (ci);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
c->second.erase (name_id);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
Layout::meta_info_value (const std::string &name) const
|
||||
const MetaInfo &
|
||||
Layout::meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const
|
||||
{
|
||||
for (meta_info::const_iterator m = m_meta_info.begin (); m != m_meta_info.end (); ++m) {
|
||||
if (m->name == name) {
|
||||
return m->value;
|
||||
auto c = m_meta_info_by_cell.find (ci);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
auto i = c->second.find (name_id);
|
||||
if (i != c->second.end ()) {
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::string s_empty;
|
||||
return s_empty;
|
||||
static MetaInfo null_value;
|
||||
return null_value;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Layout::has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const
|
||||
{
|
||||
auto c = m_meta_info_by_cell.find (ci);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
return c->second.find (name_id) != c->second.end ();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::swap_layers (unsigned int a, unsigned int b)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (a) != LayoutLayers::Free);
|
||||
|
|
@ -1814,7 +1971,19 @@ Layout::move_layer (unsigned int src, unsigned int dest)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Layout::move_layer (unsigned int src, unsigned int dest, unsigned int flags)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (src) != LayoutLayers::Free);
|
||||
tl_assert (m_layers.layer_state (dest) != LayoutLayers::Free);
|
||||
|
||||
// move the shapes
|
||||
for (iterator c = begin (); c != end (); ++c) {
|
||||
c->move (src, dest, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::copy_layer (unsigned int src, unsigned int dest)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (src) != LayoutLayers::Free);
|
||||
|
|
@ -1826,7 +1995,19 @@ Layout::copy_layer (unsigned int src, unsigned int dest)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Layout::copy_layer (unsigned int src, unsigned int dest, unsigned int flags)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (src) != LayoutLayers::Free);
|
||||
tl_assert (m_layers.layer_state (dest) != LayoutLayers::Free);
|
||||
|
||||
// copy the shapes
|
||||
for (iterator c = begin (); c != end (); ++c) {
|
||||
c->copy (src, dest, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::clear_layer (unsigned int n)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (n) != LayoutLayers::Free);
|
||||
|
|
@ -1837,7 +2018,18 @@ Layout::clear_layer (unsigned int n)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
Layout::clear_layer (unsigned int n, unsigned int flags)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (n) != LayoutLayers::Free);
|
||||
|
||||
// clear the shapes
|
||||
for (iterator c = begin (); c != end (); ++c) {
|
||||
c->clear (n, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::delete_layer (unsigned int n)
|
||||
{
|
||||
tl_assert (m_layers.layer_state (n) != LayoutLayers::Free);
|
||||
|
|
@ -2369,10 +2561,85 @@ Layout::get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl
|
|||
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::has_context_info () const
|
||||
{
|
||||
for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::has_context_info (cell_index_type cell_index) const
|
||||
{
|
||||
auto c = m_meta_info_by_cell.find (cell_index);
|
||||
if (c != m_meta_info_by_cell.end ()) {
|
||||
for (auto i = c->second.begin (); i != c->second.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db::Cell &cref = cell (cell_index);
|
||||
if (cref.is_proxy () && ! cref.is_top ()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (std::vector <std::string> &strings) const
|
||||
{
|
||||
LayoutOrCellContextInfo info;
|
||||
if (! get_context_info (info)) {
|
||||
return false;
|
||||
} else {
|
||||
info.serialize (strings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (LayoutOrCellContextInfo &info) const
|
||||
{
|
||||
for (auto i = m_meta_info.begin (); i != m_meta_info.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
std::pair<tl::Variant, std::string> &mi = info.meta_info [m_meta_info_names [i->first] ];
|
||||
mi.first = i->second.value;
|
||||
mi.second = i->second.description;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to)
|
||||
{
|
||||
fill_meta_info_from_context (LayoutOrCellContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (const LayoutOrCellContextInfo &context_info)
|
||||
{
|
||||
if (! context_info.meta_info.empty ()) {
|
||||
for (auto i = context_info.meta_info.begin (); i != context_info.meta_info.end (); ++i) {
|
||||
meta_info_name_id_type name_id = meta_info_name_id (i->first);
|
||||
m_meta_info [name_id] = MetaInfo (i->second.second, i->second.first, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, std::vector <std::string> &strings) const
|
||||
{
|
||||
ProxyContextInfo info;
|
||||
LayoutOrCellContextInfo info;
|
||||
if (! get_context_info (cell_index, info)) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -2382,8 +2649,22 @@ Layout::get_context_info (cell_index_type cell_index, std::vector <std::string>
|
|||
}
|
||||
|
||||
bool
|
||||
Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) const
|
||||
Layout::get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &info) const
|
||||
{
|
||||
bool any_meta = false;
|
||||
|
||||
auto cmi = m_meta_info_by_cell.find (cell_index);
|
||||
if (cmi != m_meta_info_by_cell.end ()) {
|
||||
for (auto i = cmi->second.begin (); i != cmi->second.end (); ++i) {
|
||||
if (i->second.persisted) {
|
||||
std::pair<tl::Variant, std::string> &mi = info.meta_info [m_meta_info_names [i->first] ];
|
||||
mi.first = i->second.value;
|
||||
mi.second = i->second.description;
|
||||
any_meta = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db::Cell *cptr = &cell (cell_index);
|
||||
|
||||
const db::ColdProxy *cold_proxy = dynamic_cast <const db::ColdProxy *> (cptr);
|
||||
|
|
@ -2399,7 +2680,7 @@ Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) co
|
|||
|
||||
const db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
||||
if (! lib) {
|
||||
return false; // abort
|
||||
return any_meta; // abort
|
||||
} else {
|
||||
|
||||
// one level of library indirection
|
||||
|
|
@ -2432,6 +2713,27 @@ Layout::get_context_info (cell_index_type cell_index, ProxyContextInfo &info) co
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to)
|
||||
{
|
||||
fill_meta_info_from_context (cell_index, LayoutOrCellContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
void
|
||||
Layout::fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info)
|
||||
{
|
||||
if (! context_info.meta_info.empty ()) {
|
||||
|
||||
meta_info_map &mi = m_meta_info_by_cell [cell_index];
|
||||
|
||||
for (auto i = context_info.meta_info.begin (); i != context_info.meta_info.end (); ++i) {
|
||||
meta_info_name_id_type name_id = meta_info_name_id (i->first);
|
||||
mi [name_id] = MetaInfo (i->second.second, i->second.first, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::restore_proxies (ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
|
|
@ -2463,11 +2765,11 @@ Layout::recover_proxy_as (cell_index_type cell_index, std::vector <std::string>:
|
|||
return false;
|
||||
}
|
||||
|
||||
return recover_proxy_as (cell_index, ProxyContextInfo::deserialize (from, to), layer_mapping);
|
||||
return recover_proxy_as (cell_index, LayoutOrCellContextInfo::deserialize (from, to), layer_mapping);
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &info, ImportLayerMapping *layer_mapping)
|
||||
Layout::recover_proxy_as (cell_index_type cell_index, const LayoutOrCellContextInfo &info, ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
|
||||
|
|
@ -2517,11 +2819,11 @@ Layout::recover_proxy (std::vector <std::string>::const_iterator from, std::vect
|
|||
return 0;
|
||||
}
|
||||
|
||||
return recover_proxy (ProxyContextInfo::deserialize (from, to));
|
||||
return recover_proxy (LayoutOrCellContextInfo::deserialize (from, to));
|
||||
}
|
||||
|
||||
db::Cell *
|
||||
Layout::recover_proxy (const ProxyContextInfo &info)
|
||||
Layout::recover_proxy (const LayoutOrCellContextInfo &info)
|
||||
{
|
||||
if (! info.lib_name.empty ()) {
|
||||
|
||||
|
|
@ -2549,7 +2851,7 @@ Layout::recover_proxy (const ProxyContextInfo &info)
|
|||
}
|
||||
|
||||
db::Cell *
|
||||
Layout::recover_proxy_no_lib (const ProxyContextInfo &info)
|
||||
Layout::recover_proxy_no_lib (const LayoutOrCellContextInfo &info)
|
||||
{
|
||||
if (! info.pcell_name.empty ()) {
|
||||
|
||||
|
|
@ -2646,7 +2948,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
|||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::create_cold_proxy (const db::ProxyContextInfo &info)
|
||||
Layout::create_cold_proxy (const db::LayoutOrCellContextInfo &info)
|
||||
{
|
||||
// create a new unique name
|
||||
std::string b;
|
||||
|
|
@ -2677,7 +2979,7 @@ Layout::create_cold_proxy (const db::ProxyContextInfo &info)
|
|||
}
|
||||
|
||||
void
|
||||
Layout::create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type target_cell_index)
|
||||
Layout::create_cold_proxy_as (const db::LayoutOrCellContextInfo &info, cell_index_type target_cell_index)
|
||||
{
|
||||
tl_assert (m_cell_ptrs [target_cell_index] != 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -417,15 +417,19 @@ public:
|
|||
/**
|
||||
* @brief A binary object representing context information for regenerating library proxies and PCells
|
||||
*/
|
||||
struct DB_PUBLIC ProxyContextInfo
|
||||
struct DB_PUBLIC LayoutOrCellContextInfo
|
||||
{
|
||||
std::string lib_name;
|
||||
std::string cell_name;
|
||||
std::string pcell_name;
|
||||
std::map<std::string, tl::Variant> pcell_parameters;
|
||||
std::map<std::string, std::pair<tl::Variant, std::string> > meta_info;
|
||||
|
||||
static ProxyContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
|
||||
static LayoutOrCellContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
|
||||
void serialize (std::vector<std::string> &strings);
|
||||
|
||||
bool has_proxy_info () const;
|
||||
bool has_meta_info () const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -465,8 +469,9 @@ public:
|
|||
typedef pcell_name_map::const_iterator pcell_iterator;
|
||||
typedef std::map<std::pair<lib_id_type, cell_index_type>, cell_index_type> lib_proxy_map;
|
||||
typedef LayerIterator layer_iterator;
|
||||
typedef std::vector<MetaInfo> meta_info;
|
||||
typedef meta_info::const_iterator meta_info_iterator;
|
||||
typedef size_t meta_info_name_id_type;
|
||||
typedef std::map<meta_info_name_id_type, MetaInfo> meta_info_map;
|
||||
typedef meta_info_map::const_iterator meta_info_iterator;
|
||||
|
||||
/**
|
||||
* @brief A helper functor to compare "const char *" by the content
|
||||
|
|
@ -756,6 +761,14 @@ public:
|
|||
*/
|
||||
cell_index_type add_cell (const char *name = 0);
|
||||
|
||||
/**
|
||||
* @brief Adds a cell using another cell as a template
|
||||
*
|
||||
* This method will use the name of the other cell and initialize the
|
||||
* new cell with the meta info from the other cell.
|
||||
*/
|
||||
cell_index_type add_cell (const db::Layout &other, db::cell_index_type ci);
|
||||
|
||||
/**
|
||||
* @brief Add a cell without a name
|
||||
*
|
||||
|
|
@ -1014,27 +1027,69 @@ public:
|
|||
/**
|
||||
* @brief Creates a cold proxy representing the given context information
|
||||
*/
|
||||
cell_index_type create_cold_proxy (const db::ProxyContextInfo &info);
|
||||
cell_index_type create_cold_proxy (const db::LayoutOrCellContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief Subsitutes the given cell by a cold proxy representing the given context information
|
||||
*/
|
||||
void create_cold_proxy_as (const db::ProxyContextInfo &info, cell_index_type cell_index);
|
||||
void create_cold_proxy_as (const db::LayoutOrCellContextInfo &info, cell_index_type cell_index);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether layout context info is provided / needed
|
||||
*/
|
||||
bool has_context_info() const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether layout context info is provided / needed
|
||||
*/
|
||||
bool has_context_info(cell_index_type cell_index) const;
|
||||
|
||||
/**
|
||||
* @brief Get the context information for the layout (for writing into a file)
|
||||
*
|
||||
* The context information is a sequence of strings which is pushed onto the given
|
||||
* vector. It can be used to fill meta information with fill_meta_info_from_context.
|
||||
*/
|
||||
bool get_context_info (std::vector <std::string> &strings) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the context information as a binary object
|
||||
*/
|
||||
bool get_context_info (LayoutOrCellContextInfo &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the context
|
||||
*/
|
||||
void fill_meta_info_from_context (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the binary context
|
||||
*/
|
||||
void fill_meta_info_from_context (const LayoutOrCellContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Get the context information for a given cell (for writing into a file)
|
||||
*
|
||||
* The context information is a sequence of strings which is pushed onto the given
|
||||
* vector. It can be used to recover a respective proxy cell with the recover_proxy method.
|
||||
* If the given cell is not a valid proxy or library references are missing, the method
|
||||
* will return false.
|
||||
* vector. It can be used to recover a respective proxy cell with the recover_proxy method
|
||||
* or to fill meta information using fill_meta_info_from_context.
|
||||
*/
|
||||
bool get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the context information as a binary object
|
||||
*/
|
||||
bool get_context_info (cell_index_type cell_index, ProxyContextInfo &context_info) const;
|
||||
bool get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &context_info) const;
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the context
|
||||
*/
|
||||
void fill_meta_info_from_context (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);
|
||||
|
||||
/**
|
||||
* @brief Fills the layout's meta information from the binary context
|
||||
*/
|
||||
void fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given context info.
|
||||
|
|
@ -1050,7 +1105,7 @@ public:
|
|||
/**
|
||||
* @brief Recover a proxy cell from the given binary context info object.
|
||||
*/
|
||||
db::Cell *recover_proxy (const ProxyContextInfo &context_info);
|
||||
db::Cell *recover_proxy (const LayoutOrCellContextInfo &context_info);
|
||||
|
||||
/**
|
||||
* @brief Recover a proxy cell from the given context info.
|
||||
|
|
@ -1072,7 +1127,7 @@ public:
|
|||
*
|
||||
* See the string-based version of "recover_proxy_as" for details.
|
||||
*/
|
||||
bool recover_proxy_as (cell_index_type cell_index, const ProxyContextInfo &context_info, ImportLayerMapping *layer_mapping = 0);
|
||||
bool recover_proxy_as (cell_index_type cell_index, const LayoutOrCellContextInfo &context_info, ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Restores proxies as far as possible
|
||||
|
|
@ -1322,7 +1377,15 @@ public:
|
|||
*/
|
||||
void move_layer (unsigned int src, unsigned int dest);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Move a layer (selected shape types only)
|
||||
*
|
||||
* Move a layer from the source to the target. The target is not cleared before, so that this method
|
||||
* merges shapes from the source with the target layer. The source layer is empty after that operation.
|
||||
*/
|
||||
void move_layer (unsigned int src, unsigned int dest, unsigned int flags);
|
||||
|
||||
/**
|
||||
* @brief Copy a layer
|
||||
*
|
||||
* Copy a layer from the source to the target. The target is not cleared before, so that this method
|
||||
|
|
@ -1330,14 +1393,29 @@ public:
|
|||
*/
|
||||
void copy_layer (unsigned int src, unsigned int dest);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Copy a layer (selected shape types only)
|
||||
*
|
||||
* Copy a layer from the source to the target. The target is not cleared before, so that this method
|
||||
* merges shapes from the source with the target layer.
|
||||
*/
|
||||
void copy_layer (unsigned int src, unsigned int dest, unsigned int flags);
|
||||
|
||||
/**
|
||||
* @brief Clear a layer
|
||||
*
|
||||
* Clears the layer: removes all shapes.
|
||||
*/
|
||||
void clear_layer (unsigned int n);
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Clear a layer (selected shapes only)
|
||||
*
|
||||
* Clears the layer: removes the shapes of the type given the flags (ShapeIterator::shapes_type)
|
||||
*/
|
||||
void clear_layer (unsigned int n, unsigned int flags);
|
||||
|
||||
/**
|
||||
* @brief Delete a layer
|
||||
*
|
||||
* This does free the shapes of the cells and remembers the
|
||||
|
|
@ -1812,6 +1890,31 @@ public:
|
|||
return m_meta_info.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivers the meta information (begin iterator) per cell
|
||||
*/
|
||||
meta_info_iterator begin_meta (db::cell_index_type ci) const;
|
||||
|
||||
/**
|
||||
* @brief Delivers the meta information (end iterator) per cell
|
||||
*/
|
||||
meta_info_iterator end_meta (db::cell_index_type ci) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the meta informatio name by ID
|
||||
*/
|
||||
const std::string &meta_info_name (meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the meta information name ID for a specific string
|
||||
*/
|
||||
meta_info_name_id_type meta_info_name_id (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the meta information name ID for a specific string (const version)
|
||||
*/
|
||||
meta_info_name_id_type meta_info_name_id (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Clears the meta information
|
||||
*/
|
||||
|
|
@ -1819,22 +1922,146 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Adds meta information
|
||||
* The given meta information object is appended at the end of the meta information list.
|
||||
* The given meta information object is added to the meta information list.
|
||||
* If a meta info object with the same name already exists it is overwritten.
|
||||
*/
|
||||
void add_meta_info (const MetaInfo &i);
|
||||
void add_meta_info (const std::string &name, const MetaInfo &i)
|
||||
{
|
||||
add_meta_info (meta_info_name_id (name), i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds meta information (variant with name ID)
|
||||
*/
|
||||
void add_meta_info (meta_info_name_id_type name_id, const MetaInfo &i);
|
||||
|
||||
/**
|
||||
* @brief Adds meta information from a sequence
|
||||
*/
|
||||
template <class I>
|
||||
void add_meta_info (const I &b, const I &e)
|
||||
{
|
||||
for (I i = b; i != e; ++i) {
|
||||
m_meta_info.insert (b, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name
|
||||
* The method will do nothing if no object with that name exists.
|
||||
*/
|
||||
void remove_meta_info (const std::string &name);
|
||||
void remove_meta_info (const std::string &name)
|
||||
{
|
||||
remove_meta_info (meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name ID
|
||||
*/
|
||||
void remove_meta_info (meta_info_name_id_type name_id);
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name
|
||||
* If no object with that name exists, an empty string is returned
|
||||
*/
|
||||
const std::string &meta_info_value (const std::string &name) const;
|
||||
const MetaInfo &meta_info (const std::string &name) const
|
||||
{
|
||||
return meta_info (meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name ID
|
||||
*/
|
||||
const MetaInfo &meta_info (meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present
|
||||
*/
|
||||
bool has_meta_info (const std::string &name) const
|
||||
{
|
||||
return has_meta_info (meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present
|
||||
*/
|
||||
bool has_meta_info (meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Clears the meta information for a specific cell
|
||||
*/
|
||||
void clear_meta (db::cell_index_type ci);
|
||||
|
||||
/**
|
||||
* @brief Adds meta information for a given cell
|
||||
* The given meta information object is to the meta information list for the given cell.
|
||||
* If a meta info object with the same name already exists it is overwritten.
|
||||
*/
|
||||
void add_meta_info (db::cell_index_type ci, const std::string &name, const MetaInfo &i)
|
||||
{
|
||||
add_meta_info (ci, meta_info_name_id (name), i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds meta information for a given cell (version with name ID)
|
||||
* The given meta information object is appended at the end of the meta information list.
|
||||
* If a meta info object with the same name already exists it is overwritten.
|
||||
*/
|
||||
void add_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id, const MetaInfo &i);
|
||||
|
||||
/**
|
||||
* @brief Adds meta information from a sequence
|
||||
*/
|
||||
template <class I>
|
||||
void add_meta_info (db::cell_index_type ci, const I &b, const I &e)
|
||||
{
|
||||
for (I i = b; i != e; ++i) {
|
||||
m_meta_info_by_cell [ci].insert (b, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present for the given cell
|
||||
*/
|
||||
bool has_meta_info (db::cell_index_type ci, const std::string &name) const
|
||||
{
|
||||
return has_meta_info (ci, meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a meta info with the given name is present for the given cell
|
||||
*/
|
||||
bool has_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name from the given cell
|
||||
* The method will do nothing if no object with that name exists.
|
||||
*/
|
||||
void remove_meta_info (db::cell_index_type ci, const std::string &name)
|
||||
{
|
||||
remove_meta_info (ci, meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the meta information object with the given name ID from the given cell
|
||||
* The method will do nothing if no object with that name exists.
|
||||
*/
|
||||
void remove_meta_info (db::cell_index_type ci, meta_info_name_id_type name_id);
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name for the given cell
|
||||
* If no object with that name exists, an empty string is returned
|
||||
*/
|
||||
const MetaInfo &meta_info (db::cell_index_type ci, const std::string &name) const
|
||||
{
|
||||
return meta_info (ci, meta_info_name_id (name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the meta info value for a meta info object with the given name ID for the given cell
|
||||
* If no object with that name exists, an empty string is returned
|
||||
*/
|
||||
const MetaInfo &meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief This event is triggered when the technology changes
|
||||
|
|
@ -1876,7 +2103,11 @@ private:
|
|||
lib_proxy_map m_lib_proxy_map;
|
||||
bool m_do_cleanup;
|
||||
bool m_editable;
|
||||
meta_info m_meta_info;
|
||||
std::map<std::string, meta_info_name_id_type> m_meta_info_name_map;
|
||||
std::vector<std::string> m_meta_info_names;
|
||||
meta_info_map m_meta_info;
|
||||
std::map<db::cell_index_type, meta_info_map> m_meta_info_by_cell;
|
||||
|
||||
std::string m_tech_name;
|
||||
tl::Mutex m_lock;
|
||||
|
||||
|
|
@ -1920,7 +2151,7 @@ private:
|
|||
/**
|
||||
* @brief Recovers a proxy without considering the library from context_info
|
||||
*/
|
||||
db::Cell *recover_proxy_no_lib (const ProxyContextInfo &context_info);
|
||||
db::Cell *recover_proxy_no_lib (const LayoutOrCellContextInfo &context_info);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1952,7 +2183,7 @@ public:
|
|||
explicit LayoutLocker (db::Layout *layout = 0, bool no_update = false)
|
||||
: mp_layout (layout), m_no_update (no_update)
|
||||
{
|
||||
if (mp_layout) {
|
||||
if (mp_layout.get ()) {
|
||||
mp_layout->start_changes ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1965,7 +2196,7 @@ public:
|
|||
LayoutLocker (const LayoutLocker &other)
|
||||
: mp_layout (other.mp_layout), m_no_update (other.m_no_update)
|
||||
{
|
||||
if (mp_layout) {
|
||||
if (mp_layout.get ()) {
|
||||
mp_layout->start_changes ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1976,17 +2207,17 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
set (other.mp_layout, other.m_no_update);
|
||||
set (const_cast<db::Layout *> (other.mp_layout.get ()), other.m_no_update);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
tl::weak_ptr<db::Layout> mp_layout;
|
||||
bool m_no_update;
|
||||
|
||||
void set (db::Layout *layout, bool no_update)
|
||||
{
|
||||
if (mp_layout) {
|
||||
if (mp_layout.get ()) {
|
||||
if (m_no_update) {
|
||||
mp_layout->end_changes_no_update ();
|
||||
} else {
|
||||
|
|
@ -1995,7 +2226,7 @@ private:
|
|||
}
|
||||
mp_layout = layout;
|
||||
m_no_update = no_update;
|
||||
if (mp_layout) {
|
||||
if (mp_layout.get ()) {
|
||||
mp_layout->start_changes ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,10 @@ collect_cells (const db::Layout &l, const db::Cell *top, std::map <std::string,
|
|||
}
|
||||
|
||||
static void
|
||||
collect_insts_of_unmapped_cells (const db::Layout & /*l*/, const db::Cell *cell, unsigned int /*flags*/, const std::map <db::cell_index_type, db::cell_index_type> &cci, std::vector <db::CellInstArrayWithProperties> &insts)
|
||||
collect_insts_of_unmapped_cells (const db::Layout & /*l*/, const db::Cell *cell, unsigned int /*flags*/, const std::map <db::cell_index_type, db::cell_index_type> &cci, std::vector <db::CellInstArrayWithProperties> &insts, bool no_duplicates)
|
||||
{
|
||||
size_t n_before = insts.size ();
|
||||
|
||||
for (db::Cell::const_iterator i = cell->begin (); !i.at_end (); ++i) {
|
||||
|
||||
std::map <db::cell_index_type, db::cell_index_type>::const_iterator ccii = cci.find (i->cell_index ());
|
||||
|
|
@ -81,6 +83,13 @@ collect_insts_of_unmapped_cells (const db::Layout & /*l*/, const db::Cell *cell,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
if (no_duplicates) {
|
||||
|
||||
std::sort (insts.begin () + n_before, insts.end ());
|
||||
insts.erase (std::unique (insts.begin () + n_before, insts.end ()), insts.end ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -102,7 +111,7 @@ rewrite_instances_to (std::vector <db::CellInstArrayWithProperties> &insts, unsi
|
|||
}
|
||||
|
||||
static void
|
||||
collect_insts (const db::Layout & /*l*/, const db::Cell *cell, unsigned int flags, const std::map <db::cell_index_type, db::cell_index_type> &cci, std::vector <db::CellInstArrayWithProperties> &insts, PropertyMapper &pn)
|
||||
collect_insts (const db::Layout & /*l*/, const db::Cell *cell, unsigned int flags, const std::map <db::cell_index_type, db::cell_index_type> &cci, std::vector <db::CellInstArrayWithProperties> &insts, PropertyMapper &pn, bool no_duplicates)
|
||||
{
|
||||
insts.clear ();
|
||||
|
||||
|
|
@ -148,6 +157,10 @@ collect_insts (const db::Layout & /*l*/, const db::Cell *cell, unsigned int flag
|
|||
}
|
||||
|
||||
std::sort (insts.begin (), insts.end ());
|
||||
|
||||
if (no_duplicates) {
|
||||
insts.erase (std::unique (insts.begin (), insts.end ()), insts.end ());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -178,10 +191,10 @@ int compare_seq (I b1, I e1, I b2, I e2, Op op)
|
|||
/**
|
||||
* @brief Reduces two vectors to the common objects as determined by the compare operator
|
||||
* If the iterate parameter is true, the reduction is repeated until no more reduction can be
|
||||
* achieved. This is useful with tolerances since the sorted is not strict in that case.
|
||||
* achieved. This is useful with tolerances since the sorting is not strict in that case.
|
||||
*/
|
||||
template <class X, class Op>
|
||||
void reduce (std::vector<X> &a, std::vector<X> &b, Op op, bool iterate)
|
||||
void reduce (std::vector<X> &a, std::vector<X> &b, Op op, bool iterate, bool no_duplicates)
|
||||
{
|
||||
do {
|
||||
|
||||
|
|
@ -196,12 +209,29 @@ void reduce (std::vector<X> &a, std::vector<X> &b, Op op, bool iterate)
|
|||
|
||||
while (ra != a.end () && rb != b.end ()) {
|
||||
if (op (*ra, *rb)) {
|
||||
*wa++ = *ra++;
|
||||
typename std::vector<X>::const_iterator r = ra++;
|
||||
*wa = *r;
|
||||
while (no_duplicates && ra != a.end () && !op (*ra, *r) && !op(*r, *ra)) {
|
||||
++ra;
|
||||
}
|
||||
++wa;
|
||||
} else if (op (*rb, *ra)) {
|
||||
*wb++ = *rb++;
|
||||
typename std::vector<X>::const_iterator r = rb++;
|
||||
*wb = *r;
|
||||
while (no_duplicates && rb != b.end () && !op (*rb, *r) && !op(*r, *rb)) {
|
||||
++rb;
|
||||
}
|
||||
++wb;
|
||||
} else {
|
||||
++ra;
|
||||
++rb;
|
||||
typename std::vector<X>::const_iterator r;
|
||||
r = ra++;
|
||||
while (no_duplicates && ra != a.end () && !op (*ra, *r) && !op(*r, *ra)) {
|
||||
++ra;
|
||||
}
|
||||
r = rb++;
|
||||
while (no_duplicates && rb != b.end () && !op (*rb, *r) && !op(*r, *rb)) {
|
||||
++rb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,14 +241,22 @@ void reduce (std::vector<X> &a, std::vector<X> &b, Op op, bool iterate)
|
|||
|
||||
if (ra != wa) {
|
||||
while (ra != a.end ()) {
|
||||
*wa++ = *ra++;
|
||||
typename std::vector<X>::const_iterator r = ra++;
|
||||
*wa++ = *r;
|
||||
while (no_duplicates && ra != a.end () && !op (*ra, *r) && !op(*r, *ra)) {
|
||||
++ra;
|
||||
}
|
||||
}
|
||||
a.erase (wa, a.end ());
|
||||
}
|
||||
|
||||
if (rb != wb) {
|
||||
while (rb != b.end ()) {
|
||||
*wb++ = *rb++;
|
||||
typename std::vector<X>::const_iterator r = rb++;
|
||||
*wb++ = *r;
|
||||
while (no_duplicates && rb != b.end () && !op (*rb, *r) && !op(*r, *rb)) {
|
||||
++rb;
|
||||
}
|
||||
}
|
||||
b.erase (wb, b.end ());
|
||||
}
|
||||
|
|
@ -405,7 +443,7 @@ struct PolygonCompareOpWithTolerance
|
|||
m_eb.push_back (*e);
|
||||
}
|
||||
|
||||
reduce (m_ea, m_eb, EdgeCompareOpWithTolerance (m_tolerance), m_tolerance > 0);
|
||||
reduce (m_ea, m_eb, EdgeCompareOpWithTolerance (m_tolerance), m_tolerance > 0, false);
|
||||
|
||||
return compare_seq (m_ea.begin (), m_ea.end (), m_eb.begin (), m_eb.end (), EdgeCompareOpWithTolerance (m_tolerance)) < 0;
|
||||
}
|
||||
|
|
@ -665,6 +703,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
}
|
||||
|
||||
bool verbose = (flags & layout_diff::f_verbose);
|
||||
bool no_duplicates = (flags & layout_diff::f_ignore_duplicates);
|
||||
|
||||
db::Layout n, na, nb;
|
||||
na.properties_repository () = a.properties_repository ();
|
||||
|
|
@ -897,20 +936,20 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
r.bbox_differs (cell_a->bbox (), cell_b->bbox ());
|
||||
}
|
||||
|
||||
collect_insts (a, cell_a, flags, common_cell_indices_a, insts_a, prop_normalize_a);
|
||||
collect_insts (b, cell_b, flags, common_cell_indices_b, insts_b, prop_normalize_b);
|
||||
collect_insts (a, cell_a, flags, common_cell_indices_a, insts_a, prop_normalize_a, no_duplicates);
|
||||
collect_insts (b, cell_b, flags, common_cell_indices_b, insts_b, prop_normalize_b, no_duplicates);
|
||||
|
||||
std::vector <db::CellInstArrayWithProperties> anotb;
|
||||
std::set_difference (insts_a.begin (), insts_a.end (), insts_b.begin (), insts_b.end (), std::back_inserter (anotb));
|
||||
|
||||
rewrite_instances_to (anotb, flags, common_cells_a, prop_remap_to_a);
|
||||
collect_insts_of_unmapped_cells (a, cell_a, flags, common_cell_indices_a, anotb);
|
||||
collect_insts_of_unmapped_cells (a, cell_a, flags, common_cell_indices_a, anotb, no_duplicates);
|
||||
|
||||
std::vector <db::CellInstArrayWithProperties> bnota;
|
||||
std::set_difference (insts_b.begin (), insts_b.end (), insts_a.begin (), insts_a.end (), std::back_inserter (bnota));
|
||||
|
||||
rewrite_instances_to (bnota, flags, common_cells_b, prop_remap_to_b);
|
||||
collect_insts_of_unmapped_cells (b, cell_b, flags, common_cell_indices_b, bnota);
|
||||
collect_insts_of_unmapped_cells (b, cell_b, flags, common_cell_indices_b, bnota, no_duplicates);
|
||||
|
||||
if (! anotb.empty () || ! bnota.empty ()) {
|
||||
|
||||
|
|
@ -979,7 +1018,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
collect_polygons (b, cell_b, layer_b, flags, polygons_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (polygons_a, polygons_b, make_polygon_compare_func (tolerance), tolerance > 0);
|
||||
reduce (polygons_a, polygons_b, make_polygon_compare_func (tolerance), tolerance > 0, no_duplicates);
|
||||
|
||||
if (!polygons_a.empty () || !polygons_b.empty ()) {
|
||||
differs = true;
|
||||
|
|
@ -1007,7 +1046,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
collect_paths (b, cell_b, layer_b, flags, paths_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (paths_a, paths_b, make_path_compare_func (tolerance), tolerance > 0);
|
||||
reduce (paths_a, paths_b, make_path_compare_func (tolerance), tolerance > 0, no_duplicates);
|
||||
|
||||
if (!paths_a.empty () || !paths_b.empty ()) {
|
||||
differs = true;
|
||||
|
|
@ -1034,7 +1073,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
collect_texts (b, cell_b, layer_b, flags, texts_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (texts_a, texts_b, make_text_compare_func (tolerance), tolerance > 0);
|
||||
reduce (texts_a, texts_b, make_text_compare_func (tolerance), tolerance > 0, no_duplicates);
|
||||
|
||||
if (!texts_a.empty () || !texts_b.empty ()) {
|
||||
differs = true;
|
||||
|
|
@ -1061,7 +1100,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
collect_boxes (b, cell_b, layer_b, flags, boxes_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (boxes_a, boxes_b, make_box_compare_func (tolerance), tolerance > 0);
|
||||
reduce (boxes_a, boxes_b, make_box_compare_func (tolerance), tolerance > 0, no_duplicates);
|
||||
|
||||
if (!boxes_a.empty () || !boxes_b.empty ()) {
|
||||
differs = true;
|
||||
|
|
@ -1088,7 +1127,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
collect_edges (b, cell_b, layer_b, flags, edges_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (edges_a, edges_b, make_edge_compare_func (tolerance), tolerance > 0);
|
||||
reduce (edges_a, edges_b, make_edge_compare_func (tolerance), tolerance > 0, no_duplicates);
|
||||
|
||||
if (!edges_a.empty () || !edges_b.empty ()) {
|
||||
differs = true;
|
||||
|
|
@ -1113,7 +1152,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
collect_edge_pairs (b, cell_b, layer_b, flags, edge_pairs_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0);
|
||||
reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0, no_duplicates);
|
||||
|
||||
if (!edge_pairs_a.empty () || !edge_pairs_b.empty ()) {
|
||||
differs = true;
|
||||
|
|
|
|||
|
|
@ -74,12 +74,15 @@ const unsigned int f_paths_as_polygons = 0x100;
|
|||
// Derive smart cell mapping instead of name mapping (available only if top cells are specified)
|
||||
const unsigned int f_smart_cell_mapping = 0x200;
|
||||
|
||||
// Don't summarize missing layers
|
||||
// Don't summarize missing layers - print them in detail
|
||||
const unsigned int f_dont_summarize_missing_layers = 0x400;
|
||||
|
||||
// Ignore text details (font, size, presentation)
|
||||
const unsigned int f_no_text_details = 0x800;
|
||||
|
||||
// Ignore duplicate instances or shapes
|
||||
const unsigned int f_ignore_duplicates = 0x1000;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ merge_layouts (db::Layout &target,
|
|||
std::map<db::cell_index_type, db::cell_index_type> new_cell_mapping;
|
||||
for (std::set<db::cell_index_type>::const_iterator c = all_cells_to_copy.begin (); c != all_cells_to_copy.end (); ++c) {
|
||||
if (cell_mapping.find (*c) == cell_mapping.end ()) {
|
||||
new_cell_mapping.insert (std::make_pair (*c, target.add_cell (source.cell_name (*c))));
|
||||
new_cell_mapping.insert (std::make_pair (*c, target.add_cell (source, *c)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ merge_layouts (db::Layout &target,
|
|||
// provide the property mapper
|
||||
db::PropertyMapper pm (&target, &source);
|
||||
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Merge cells")), all_cells_to_copy.size (), 1);
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Merge layouts")), all_cells_to_copy.size (), 1);
|
||||
|
||||
// actually to the mapping
|
||||
for (std::set<db::cell_index_type>::const_iterator c = all_cells_to_copy.begin (); c != all_cells_to_copy.end (); ++c) {
|
||||
|
|
@ -346,7 +346,7 @@ copy_or_move_shapes (db::Layout &target,
|
|||
// provide the property mapper
|
||||
db::PropertyMapper pm (&target, &source);
|
||||
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Merge cells")), all_cells_to_copy.size () * layer_mapping.size (), 1);
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Copy shapes")), all_cells_to_copy.size () * layer_mapping.size (), 1);
|
||||
|
||||
// and copy
|
||||
for (std::set<db::cell_index_type>::const_iterator c = all_cells_to_copy.begin (); c != all_cells_to_copy.end (); ++c) {
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ Library::remap_to (db::Library *other)
|
|||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ Library::remap_to (db::Library *other)
|
|||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ Library::remap_to (db::Library *other)
|
|||
if (! cn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,31 +31,34 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
// Switch for version-agnostic code
|
||||
#define KLAYOUT_META_INFO_V2
|
||||
|
||||
/**
|
||||
* @brief A structure describing the meta information from the reader
|
||||
*
|
||||
* In the meta information block, the reader provides additional information
|
||||
* about the file and content etc.
|
||||
* "name" is a unique name that can be used to identify the information.
|
||||
* "description" is a "speaking" description of the information.
|
||||
* "value" is the value of the specific part of meta information.
|
||||
*/
|
||||
struct DB_PUBLIC MetaInfo
|
||||
{
|
||||
MetaInfo (const std::string &n, const std::string &d, const std::string &v)
|
||||
: name (n), description (d), value (v)
|
||||
MetaInfo (const std::string &d, const tl::Variant &v, bool p = false)
|
||||
: description (d), value (v), persisted (p)
|
||||
{
|
||||
// .. nothing else ..
|
||||
}
|
||||
|
||||
MetaInfo ()
|
||||
: persisted (false)
|
||||
{
|
||||
// .. nothing else ..
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string value;
|
||||
tl::Variant value;
|
||||
bool persisted;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -63,7 +66,6 @@ struct DB_PUBLIC MetaInfo
|
|||
*/
|
||||
inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const MetaInfo &v, bool no_self, void *parent)
|
||||
{
|
||||
db::mem_stat (stat, purpose, cat, v.name, no_self, parent);
|
||||
db::mem_stat (stat, purpose, cat, v.description, no_self, parent);
|
||||
db::mem_stat (stat, purpose, cat, v.value, no_self, parent);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ class SpiceReaderStream
|
|||
{
|
||||
public:
|
||||
SpiceReaderStream ();
|
||||
SpiceReaderStream (const std::string &lib);
|
||||
~SpiceReaderStream ();
|
||||
|
||||
void set_stream (tl::InputStream &stream);
|
||||
|
|
@ -85,9 +86,11 @@ public:
|
|||
int line_number () const;
|
||||
std::string source () const;
|
||||
bool at_end () const;
|
||||
const std::string &lib () const { return m_lib; }
|
||||
|
||||
void swap (SpiceReaderStream &other)
|
||||
{
|
||||
std::swap (m_lib, other.m_lib);
|
||||
std::swap (mp_stream, other.mp_stream);
|
||||
std::swap (m_owns_stream, other.m_owns_stream);
|
||||
std::swap (mp_text_stream, other.mp_text_stream);
|
||||
|
|
@ -103,6 +106,7 @@ private:
|
|||
int m_line_number;
|
||||
std::string m_stored_line;
|
||||
bool m_has_stored_line;
|
||||
std::string m_lib;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -112,6 +116,12 @@ SpiceReaderStream::SpiceReaderStream ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
SpiceReaderStream::SpiceReaderStream (const std::string &lib)
|
||||
: mp_stream (0), m_owns_stream (false), mp_text_stream (0), m_line_number (0), m_stored_line (), m_has_stored_line (false), m_lib (lib)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
SpiceReaderStream::~SpiceReaderStream ()
|
||||
{
|
||||
close ();
|
||||
|
|
@ -383,6 +393,7 @@ private:
|
|||
std::vector<std::string> m_paths;
|
||||
std::map<std::string, int> m_file_id_per_path;
|
||||
std::list<SpiceReaderStream> m_streams;
|
||||
std::list<std::string> m_in_lib;
|
||||
SpiceReaderStream m_stream;
|
||||
int m_file_id;
|
||||
std::map<std::string, SpiceCachedCircuit *> m_cached_circuits;
|
||||
|
|
@ -393,7 +404,7 @@ private:
|
|||
std::set<std::string> m_global_net_names;
|
||||
std::vector<std::string> m_global_nets;
|
||||
|
||||
void push_stream (const std::string &path);
|
||||
void push_stream (const std::string &path, const std::string &lib = std::string ());
|
||||
void pop_stream ();
|
||||
bool at_end ();
|
||||
void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets);
|
||||
|
|
@ -500,7 +511,7 @@ SpiceCircuitDict::read (tl::InputStream &stream)
|
|||
}
|
||||
|
||||
void
|
||||
SpiceCircuitDict::push_stream (const std::string &path)
|
||||
SpiceCircuitDict::push_stream (const std::string &path, const std::string &lib)
|
||||
{
|
||||
tl::URI current_uri (m_stream.source ());
|
||||
tl::URI new_uri (path);
|
||||
|
|
@ -516,7 +527,7 @@ SpiceCircuitDict::push_stream (const std::string &path)
|
|||
istream = new tl::InputStream (current_uri.resolved (new_uri).to_abstract_path ());
|
||||
}
|
||||
|
||||
m_streams.push_back (SpiceReaderStream ());
|
||||
m_streams.push_back (SpiceReaderStream (lib));
|
||||
m_streams.back ().swap (m_stream);
|
||||
m_stream.set_stream (istream);
|
||||
|
||||
|
|
@ -568,24 +579,73 @@ SpiceCircuitDict::get_line ()
|
|||
if (m_streams.empty ()) {
|
||||
break;
|
||||
} else {
|
||||
if (! m_stream.lib ().empty ()) {
|
||||
m_in_lib.pop_back ();
|
||||
}
|
||||
pop_stream ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
bool consider_line = m_in_lib.empty () || (! m_stream.lib ().empty () && m_stream.lib () == m_in_lib.back ());
|
||||
|
||||
tl::Extractor ex (lp.first.c_str ());
|
||||
if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
|
||||
|
||||
std::string path;
|
||||
ex.read_word_or_quoted (path, allowed_name_chars);
|
||||
|
||||
push_stream (path);
|
||||
if (consider_line) {
|
||||
std::string libname = m_stream.lib ();
|
||||
push_stream (path, libname);
|
||||
if (! libname.empty ()) {
|
||||
m_in_lib.push_back (libname);
|
||||
}
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
|
||||
} else if (ex.test_without_case (".lib")) {
|
||||
|
||||
std::string path_or_libname;
|
||||
|
||||
ex.read_word_or_quoted (path_or_libname, allowed_name_chars);
|
||||
if (! ex.at_end ()) {
|
||||
|
||||
std::string libname;
|
||||
ex.read_word_or_quoted (libname, allowed_name_chars);
|
||||
|
||||
if (consider_line) {
|
||||
libname = mp_netlist->normalize_name (libname);
|
||||
push_stream (path_or_libname, libname);
|
||||
if (! libname.empty ()) {
|
||||
m_in_lib.push_back (std::string ());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::string libname = mp_netlist->normalize_name (path_or_libname);
|
||||
m_in_lib.push_back (libname);
|
||||
ex.expect_end ();
|
||||
|
||||
}
|
||||
|
||||
} else if (ex.test_without_case (".endl")) {
|
||||
|
||||
if (! m_in_lib.empty ()) {
|
||||
m_in_lib.pop_back ();
|
||||
} else {
|
||||
warn (tl::to_string (tr ("Ignoring .endl without .lib")));
|
||||
}
|
||||
|
||||
ex.expect_end ();
|
||||
|
||||
} else if (ex.at_end () || ex.test ("*")) {
|
||||
|
||||
// skip empty and comment lines
|
||||
|
||||
} else {
|
||||
} else if (consider_line) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s,
|
|||
|
||||
// a parameter
|
||||
std::string pn = mp_netlist ? mp_netlist->normalize_name (n) : tl::to_upper_case (n);
|
||||
pv [pn] = read_value (ex, variables);
|
||||
pv [pn] = read_value (ex, variables, pv);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -304,46 +304,86 @@ void NetlistSpiceReaderDelegate::parse_element (const std::string &s, const std:
|
|||
// (same for C, L instead of R)
|
||||
|
||||
if (nn.size () < 2) {
|
||||
error (tl::to_string (tr ("Not enough specs for a R, C or L device")));
|
||||
error (tl::to_string (tr ("Not enough specs (nodes, value, model) for a R, C or L device")));
|
||||
} else if (nn.size () > 5) {
|
||||
error (tl::to_string (tr ("Too many specs (nodes, value, model) for a R, C or L device")));
|
||||
}
|
||||
|
||||
// Variations are (here for "C" element):
|
||||
// (1) Cname n1 n2 C=value [other params]
|
||||
// (2) Cname n1 n2 value [params]
|
||||
// (3) Cname n1 n2 model C=value [other params]
|
||||
// Cname n1 n2 n3 C=value [other params] -> not supported, cannot tell from (3) without further analysis
|
||||
// (4) Cname n1 n2 model value [params]
|
||||
// Cname n1 n2 n3 value [params] -> not supported, cannot tell from (4) without further analysis
|
||||
// (5) Cname n1 n2 n3 model C=value [other params]
|
||||
// (6) Cname n1 n2 value model [params]
|
||||
// (7) Cname n1 n2 n3 model value [params]
|
||||
// (8) Cname n1 n2 n3 value model [params]
|
||||
|
||||
auto rv = pv.find (element);
|
||||
if (rv != pv.end ()) {
|
||||
|
||||
// value given by parameter
|
||||
value = rv->second.to_double ();
|
||||
|
||||
if (nn.size () >= 3) {
|
||||
// Rname n1 n2 model [params]
|
||||
// Rname n1 n2 n3 model [params]
|
||||
model = nn.back ();
|
||||
nn.pop_back ();
|
||||
bool has_value = false;
|
||||
if (nn.size () == 2) {
|
||||
if (rv != pv.end ()) {
|
||||
value = rv->second.to_double (); // (1)
|
||||
has_value = true;
|
||||
}
|
||||
|
||||
} else if (nn.size () >= 3) {
|
||||
|
||||
} else if (nn.size () == 3) {
|
||||
if (try_read_value (nn.back (), value, variables)) {
|
||||
|
||||
// Rname n1 n2 value
|
||||
// Rname n1 n2 n3 value
|
||||
has_value = true; // (2)
|
||||
nn.pop_back ();
|
||||
|
||||
} else {
|
||||
|
||||
// Rname n1 n2 value model [params]
|
||||
// Rname n1 n2 n3 value model [params]
|
||||
model = nn.back (); // (3)
|
||||
nn.pop_back ();
|
||||
if (rv != pv.end ()) {
|
||||
value = rv->second.to_double ();
|
||||
has_value = true;
|
||||
}
|
||||
}
|
||||
} else if (nn.size () == 4) {
|
||||
if (try_read_value (nn.back (), value, variables)) {
|
||||
has_value = true; // (4)
|
||||
nn.pop_back ();
|
||||
} else if (rv != pv.end ()) {
|
||||
value = rv->second.to_double (); // (5)
|
||||
has_value = true;
|
||||
model = nn.back ();
|
||||
nn.pop_back ();
|
||||
if (! try_read_value (nn.back (), value, variables)) {
|
||||
error (tl::to_string (tr ("Can't find a value for a R, C or L device")));
|
||||
} else {
|
||||
nn.pop_back ();
|
||||
}
|
||||
|
||||
} else if (try_read_value (nn[2], value, variables)) {
|
||||
has_value = true; // (6)
|
||||
model = nn.back ();
|
||||
nn.pop_back ();
|
||||
nn.pop_back ();
|
||||
} else {
|
||||
model = nn.back (); // fall back to (5)
|
||||
nn.pop_back ();
|
||||
}
|
||||
} else {
|
||||
if (try_read_value (nn.back (), value, variables)) {
|
||||
has_value = true; // (7)
|
||||
nn.pop_back ();
|
||||
model = nn.back ();
|
||||
nn.pop_back ();
|
||||
} else if (try_read_value (nn[3], value, variables)) {
|
||||
has_value = true; // (8)
|
||||
model = nn.back ();
|
||||
nn.pop_back ();
|
||||
nn.pop_back ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (rv != pv.end ()) {
|
||||
pv.erase (rv);
|
||||
}
|
||||
|
||||
if (! has_value) {
|
||||
error (tl::to_string (tr ("Can't find a value for a R, C or L device")));
|
||||
}
|
||||
|
||||
// store the value under the element name always
|
||||
pv[element] = tl::Variant (value);
|
||||
|
||||
} else {
|
||||
|
||||
// others: n-terminal devices with a model (last node)
|
||||
|
|
@ -379,8 +419,6 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
std::map<std::string, tl::Variant> params = pv;
|
||||
std::vector<size_t> terminal_order;
|
||||
|
||||
size_t defp = std::numeric_limits<size_t>::max ();
|
||||
|
||||
double mult = 1.0;
|
||||
auto mp = params.find ("M");
|
||||
if (mp != params.end ()) {
|
||||
|
|
@ -424,8 +462,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
|
||||
// Apply multiplier (divider, according to ngspice manual)
|
||||
value /= mult;
|
||||
|
||||
defp = db::DeviceClassResistor::param_id_R;
|
||||
params["R"] = tl::Variant (value);
|
||||
|
||||
// Apply multiplier to other parameters
|
||||
static const char *scale_params[] = { "A", "P", "W" };
|
||||
|
|
@ -455,8 +492,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
|
||||
// Apply multiplier (divider, according to ngspice manual)
|
||||
value /= mult;
|
||||
|
||||
defp = db::DeviceClassInductor::param_id_L;
|
||||
params["L"] = tl::Variant (value);
|
||||
|
||||
} else if (element == "C") {
|
||||
|
||||
|
|
@ -488,8 +524,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
|
||||
// Apply multiplier
|
||||
value *= mult;
|
||||
|
||||
defp = db::DeviceClassCapacitor::param_id_C;
|
||||
params["C"] = tl::Variant (value);
|
||||
|
||||
// Apply multiplier to other parameters
|
||||
static const char *scale_params[] = { "A", "P" };
|
||||
|
|
@ -620,8 +655,6 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
|||
double pv = 0.0;
|
||||
if (v != params.end ()) {
|
||||
pv = v->second.to_double ();
|
||||
} else if (i->id () == defp) {
|
||||
pv = value;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -653,6 +686,13 @@ NetlistSpiceReaderDelegate::read_value (tl::Extractor &ex, const std::map<std::s
|
|||
return parser.read (ex);
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
NetlistSpiceReaderDelegate::read_value (tl::Extractor &ex, const std::map<std::string, tl::Variant> &variables1, const std::map<std::string, tl::Variant> &variables2)
|
||||
{
|
||||
NetlistSpiceReaderExpressionParser parser (&variables1, &variables2);
|
||||
return parser.read (ex);
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistSpiceReaderDelegate::try_read_value (const std::string &s, double &v, const std::map<std::string, tl::Variant> &variables)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -154,6 +154,11 @@ public:
|
|||
*/
|
||||
static tl::Variant read_value(tl::Extractor &ex, const std::map<std::string, tl::Variant> &variables);
|
||||
|
||||
/**
|
||||
* @brief Reads a value from the extractor (with formula evaluation and two levels of variables)
|
||||
*/
|
||||
static tl::Variant read_value(tl::Extractor &ex, const std::map<std::string, tl::Variant> &variables1, const std::map<std::string, tl::Variant> &variables2);
|
||||
|
||||
/**
|
||||
* @brief Tries to read a value from the extractor (with formula evaluation)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -47,8 +47,15 @@ static bool to_bool (const tl::Variant &v)
|
|||
NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale)
|
||||
: m_def_scale (def_scale)
|
||||
{
|
||||
static variables_type empty_variables;
|
||||
mp_variables = vars ? vars : &empty_variables;
|
||||
mp_variables1 = vars;
|
||||
mp_variables2 = 0;
|
||||
}
|
||||
|
||||
NetlistSpiceReaderExpressionParser::NetlistSpiceReaderExpressionParser (const variables_type *vars1, const variables_type *vars2, double def_scale)
|
||||
: m_def_scale (def_scale)
|
||||
{
|
||||
mp_variables1 = vars1;
|
||||
mp_variables2 = vars2;
|
||||
}
|
||||
|
||||
// expression syntax taken from ngspice:
|
||||
|
|
@ -264,13 +271,20 @@ NetlistSpiceReaderExpressionParser::read_atomic_value (tl::Extractor &ex, bool *
|
|||
|
||||
} else {
|
||||
|
||||
auto vi = mp_variables->find (var);
|
||||
if (vi != mp_variables->end ()) {
|
||||
return vi->second;
|
||||
} else {
|
||||
// keep word as string value
|
||||
return tl::Variant (var);
|
||||
if (mp_variables1) {
|
||||
auto vi = mp_variables1->find (var);
|
||||
if (vi != mp_variables1->end ()) {
|
||||
return vi->second;
|
||||
}
|
||||
}
|
||||
if (mp_variables2) {
|
||||
auto vi = mp_variables2->find (var);
|
||||
if (vi != mp_variables2->end ()) {
|
||||
return vi->second;
|
||||
}
|
||||
}
|
||||
// keep word as string value
|
||||
return tl::Variant (var);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ public:
|
|||
typedef std::map<std::string, tl::Variant> variables_type;
|
||||
|
||||
NetlistSpiceReaderExpressionParser (const variables_type *vars, double def_scale = 1.0);
|
||||
NetlistSpiceReaderExpressionParser (const variables_type *vars1, const variables_type *vars2, double def_scale = 1.0);
|
||||
|
||||
tl::Variant read (tl::Extractor &ex) const;
|
||||
tl::Variant read (const std::string &s) const;
|
||||
|
|
@ -53,7 +54,7 @@ public:
|
|||
bool try_read (const std::string &s, tl::Variant &v) const;
|
||||
|
||||
private:
|
||||
const variables_type *mp_variables;
|
||||
const variables_type *mp_variables1, *mp_variables2;
|
||||
double m_def_scale;
|
||||
|
||||
tl::Variant read_atomic_value (tl::Extractor &ex, bool *status) const;
|
||||
|
|
|
|||
|
|
@ -1044,6 +1044,19 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
// injecting a global std::swap for polygons into the
|
||||
// std namespace
|
||||
template <class C>
|
||||
void swap (db::polygon_contour<C> &a, db::polygon_contour<C> &b)
|
||||
{
|
||||
a.swap (b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace db
|
||||
|
|
@ -2047,7 +2060,7 @@ public:
|
|||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
*/
|
||||
template <class I>
|
||||
void insert_hole (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void insert_hole (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
{
|
||||
insert_hole (start, end, db::unit_trans<C> (), compress, remove_reflected);
|
||||
}
|
||||
|
|
@ -2073,21 +2086,17 @@ public:
|
|||
// add the hole
|
||||
contour_type &h = add_hole ();
|
||||
h.assign (start, end, op, true, compress, true /*normalize*/, remove_reflected);
|
||||
}
|
||||
|
||||
// and keep the list sorted by swapping the
|
||||
// elements and move the last one to the right
|
||||
// position
|
||||
// KLUDGE: this is probably a performance bottleneck from applications
|
||||
// with polygons with may holes ..
|
||||
if (holes () > 1) {
|
||||
typename contour_list_type::iterator ins_pos = std::lower_bound (m_ctrs.begin () + 1, m_ctrs.end () - 1, h);
|
||||
typename contour_list_type::iterator p = m_ctrs.end () - 1;
|
||||
if (ins_pos != p) {
|
||||
while (p != ins_pos) {
|
||||
p->swap (p [-1]);
|
||||
--p;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Sort the holes
|
||||
*
|
||||
* Sorting the holes makes certain algorithms more effective.
|
||||
*/
|
||||
void sort_holes ()
|
||||
{
|
||||
if (! m_ctrs.empty ()) {
|
||||
std::sort (m_ctrs.begin () + 1, m_ctrs.end ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2884,6 +2893,16 @@ public:
|
|||
tl_assert (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A dummy implementation of "sort_holes" provided for template instantiation
|
||||
*
|
||||
* Asserts, if begin called.
|
||||
*/
|
||||
void sort_holes ()
|
||||
{
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A dummy implementation of "hole" provided for template instantiation
|
||||
*
|
||||
|
|
@ -3530,7 +3549,7 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int
|
|||
namespace std
|
||||
{
|
||||
|
||||
// injecting a global std::swap for polygons into the
|
||||
// injecting a global std::swap for polygons into the
|
||||
// std namespace
|
||||
template <class C>
|
||||
void swap (db::polygon<C> &a, db::polygon<C> &b)
|
||||
|
|
|
|||
|
|
@ -865,6 +865,8 @@ PolygonGenerator::produce_poly (const PGPolyContour &c)
|
|||
|
||||
}
|
||||
|
||||
m_poly.sort_holes ();
|
||||
|
||||
}
|
||||
|
||||
mp_psink->put (m_poly);
|
||||
|
|
|
|||
|
|
@ -456,6 +456,8 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, c
|
|||
}
|
||||
}
|
||||
|
||||
hull->sort_holes ();
|
||||
|
||||
right_of_line->put (*hull);
|
||||
|
||||
}
|
||||
|
|
@ -859,6 +861,8 @@ smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv)
|
|||
}
|
||||
}
|
||||
|
||||
new_poly.sort_holes ();
|
||||
|
||||
}
|
||||
|
||||
return new_poly;
|
||||
|
|
@ -1351,6 +1355,8 @@ do_extract_rad (const db::polygon<C> &polygon, double &rinner, double &router, u
|
|||
|
||||
}
|
||||
|
||||
new_polygon->sort_holes ();
|
||||
|
||||
} else {
|
||||
|
||||
if (! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, (std::vector<db::point<C> > *) 0, false)) {
|
||||
|
|
@ -1542,6 +1548,8 @@ do_compute_rounded (const db::polygon<C> &polygon, double rinner, double router,
|
|||
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/);
|
||||
}
|
||||
|
||||
new_poly.sort_holes ();
|
||||
|
||||
return new_poly;
|
||||
}
|
||||
|
||||
|
|
@ -2300,9 +2308,11 @@ static void decompose_convex_helper (int depth, PreferredOrientation po, const d
|
|||
|
||||
db::Box bbox = sp.box ();
|
||||
db::coord_traits<db::Coord>::area_type atot = 0;
|
||||
db::coord_traits<db::Coord>::distance_type min_edge = std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max ();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
db::Edge ep (sp.hull ()[(i + n - 1) % n], sp.hull ()[i]);
|
||||
atot += db::vprod (ep.p2 () - db::Point (), ep.p1 () - db::Point ());
|
||||
min_edge = std::min (min_edge, ep.length ());
|
||||
}
|
||||
|
||||
std::set<db::Point> skipped;
|
||||
|
|
@ -2449,9 +2459,14 @@ static void decompose_convex_helper (int depth, PreferredOrientation po, const d
|
|||
int cr = 0;
|
||||
if (x.second == efc.p1 ()) {
|
||||
if (db::vprod (efc, efp) < 0) {
|
||||
cr = 2; // cut terminates at another concave corner
|
||||
cr = 3; // cut terminates at another concave corner
|
||||
} else {
|
||||
cr = 1; // cut terminates at a convex corner
|
||||
cr = 2; // cut terminates at a convex corner
|
||||
}
|
||||
} else {
|
||||
db::coord_traits<db::Coord>::distance_type el = std::min (x.second.distance (efc.p1 ()), x.second.distance (efc.p2 ()));
|
||||
if (el >= min_edge) {
|
||||
cr = 1; // does not induce shorter edge than we have so far
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2882,6 +2897,8 @@ snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vecto
|
|||
|
||||
}
|
||||
|
||||
pnew.sort_holes ();
|
||||
|
||||
return pnew;
|
||||
}
|
||||
|
||||
|
|
@ -2921,6 +2938,8 @@ scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx,
|
|||
|
||||
}
|
||||
|
||||
pnew.sort_holes ();
|
||||
|
||||
return pnew;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -447,8 +447,8 @@ RecursiveInstanceIterator::next (RecursiveInstanceReceiver *receiver)
|
|||
} else {
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
next_instance (receiver);
|
||||
}
|
||||
next_instance (receiver);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -463,35 +463,42 @@ RecursiveInstanceIterator::next_instance (RecursiveInstanceReceiver *receiver) c
|
|||
{
|
||||
while (true) {
|
||||
|
||||
if (! m_inst.at_end ()) {
|
||||
while (true) {
|
||||
|
||||
if (int (m_inst_iterators.size ()) < m_max_depth && (m_all_targets || m_target_tree.find (m_inst->cell_index ()) != m_target_tree.end ())) {
|
||||
down (receiver);
|
||||
}
|
||||
if (! m_inst.at_end ()) {
|
||||
|
||||
} else {
|
||||
if (int (m_inst_iterators.size ()) < m_max_depth && (m_all_targets || m_target_tree.find (m_inst->cell_index ()) != m_target_tree.end ())) {
|
||||
down (receiver);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (! m_inst_iterators.empty ()) {
|
||||
// no more instances: up and next instance
|
||||
up (receiver);
|
||||
} else {
|
||||
|
||||
if (! m_inst_iterators.empty ()) {
|
||||
// no more instances: up and next instance
|
||||
up (receiver);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! m_inst.at_end ()) {
|
||||
if (! needs_visit ()) {
|
||||
++m_inst_array;
|
||||
if (! m_inst_array.at_end ()) {
|
||||
new_inst_member (receiver);
|
||||
} else {
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
}
|
||||
if (m_inst.at_end ()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (! needs_visit ()) {
|
||||
++m_inst_array;
|
||||
if (! m_inst_array.at_end ()) {
|
||||
new_inst_member (receiver);
|
||||
} else {
|
||||
break;
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -693,7 +693,11 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
// determine whether the cell is empty with respect to the layers specified
|
||||
bool is_empty = false;
|
||||
if (! m_has_layers) {
|
||||
if (receiver && receiver->wants_all_cells ()) {
|
||||
|
||||
// don't skip empty cells in that case
|
||||
|
||||
} else if (! m_has_layers) {
|
||||
|
||||
is_empty = mp_layout->cell (m_inst->cell_index ()).bbox (m_layer).empty ();
|
||||
|
||||
|
|
|
|||
|
|
@ -913,6 +913,11 @@ public:
|
|||
*/
|
||||
virtual ~RecursiveShapeReceiver () { }
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the receivers wants the full hierarchy and not just non-empty cells
|
||||
*/
|
||||
virtual bool wants_all_cells () const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Called once when the iterator begins pushing
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -81,6 +81,12 @@ inline bool needs_translate (object_tag<Sh> /*tag*/)
|
|||
return tl::is_equal_type<typename shape_traits<Sh>::can_deref, tl::True> () || tl::is_equal_type<typename shape_traits<Sh>::is_array, tl::True> ();
|
||||
}
|
||||
|
||||
inline bool type_mask_applies (const db::LayerBase *layer, unsigned int flags)
|
||||
{
|
||||
unsigned int tm = layer->type_mask ();
|
||||
return (((flags & db::ShapeIterator::Properties) == 0 || (tm & db::ShapeIterator::Properties) != 0) && (flags & tm) != 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// layer_op implementation
|
||||
|
||||
|
|
@ -214,7 +220,13 @@ Shapes::insert (const Shapes &d)
|
|||
}
|
||||
|
||||
void
|
||||
Shapes::do_insert (const Shapes &d)
|
||||
Shapes::insert (const Shapes &d, unsigned int flags)
|
||||
{
|
||||
do_insert (d, flags);
|
||||
}
|
||||
|
||||
void
|
||||
Shapes::do_insert (const Shapes &d, unsigned int flags)
|
||||
{
|
||||
// shortcut for "nothing to do"
|
||||
if (d.empty ()) {
|
||||
|
|
@ -228,10 +240,12 @@ Shapes::do_insert (const Shapes &d)
|
|||
|
||||
m_layers.reserve (d.m_layers.size ());
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
m_layers.push_back ((*l)->clone ());
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
manager ()->queue (this, new FullLayerOp (true, m_layers.back ()));
|
||||
if (type_mask_applies (*l, flags)) {
|
||||
m_layers.push_back ((*l)->clone ());
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
manager ()->queue (this, new FullLayerOp (true, m_layers.back ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +253,9 @@ Shapes::do_insert (const Shapes &d)
|
|||
|
||||
} else {
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
(*l)->insert_into (this);
|
||||
if (type_mask_applies (*l, flags)) {
|
||||
(*l)->insert_into (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,14 +263,18 @@ Shapes::do_insert (const Shapes &d)
|
|||
|
||||
// the target is standalone - dereference
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
(*l)->deref_into (this);
|
||||
if (type_mask_applies (*l, flags)) {
|
||||
(*l)->deref_into (this);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// both shape containers are in separate spaces - translate
|
||||
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
|
||||
(*l)->translate_into (this, shape_repository (), array_repository ());
|
||||
if (type_mask_applies (*l, flags)) {
|
||||
(*l)->translate_into (this, shape_repository (), array_repository ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1046,6 +1066,41 @@ Shapes::clear ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Shapes::clear (unsigned int flags)
|
||||
{
|
||||
if (!m_layers.empty ()) {
|
||||
|
||||
invalidate_state (); // HINT: must come before the change is done!
|
||||
|
||||
tl::vector<LayerBase *> new_layers;
|
||||
|
||||
for (tl::vector<LayerBase *>::const_iterator l = m_layers.end (); l != m_layers.begin (); ) {
|
||||
|
||||
// because the undo stack will do a push, we need to remove layers from the back (this is the last undo
|
||||
// element to be executed)
|
||||
--l;
|
||||
|
||||
if (type_mask_applies (*l, flags)) {
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
check_is_editable_for_undo_redo ();
|
||||
manager ()->queue (this, new FullLayerOp (false, (*l)));
|
||||
} else {
|
||||
delete *l;
|
||||
}
|
||||
|
||||
} else {
|
||||
new_layers.push_back (*l);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_layers.swap (new_layers);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Shapes::reset_bbox_dirty ()
|
||||
{
|
||||
set_dirty (false);
|
||||
|
|
|
|||
|
|
@ -628,6 +628,18 @@ public:
|
|||
*/
|
||||
void insert (const Shapes &d);
|
||||
|
||||
/**
|
||||
* @brief Insert all shapes from another container using the given shape types only
|
||||
*
|
||||
* This method insert all shapes from the given shape container.
|
||||
*
|
||||
* HINT: This method can duplicate shape containers from one layout to another.
|
||||
* The current implementation does not translate property Id's.
|
||||
* It is mainly intended for 1-to-1 copies of layouts where the whole
|
||||
* property repository is copied.
|
||||
*/
|
||||
void insert (const Shapes &d, unsigned int types);
|
||||
|
||||
/**
|
||||
* @brief Assignment operator with transformation
|
||||
*
|
||||
|
|
@ -1219,6 +1231,11 @@ public:
|
|||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Clears the collection (given shape types only)
|
||||
*/
|
||||
void clear (unsigned int types);
|
||||
|
||||
/**
|
||||
* @brief Report the type mask of the objects stored herein
|
||||
*
|
||||
|
|
@ -1515,7 +1532,7 @@ private:
|
|||
db::Cell *mp_cell; // HINT: contains "dirty" in bit 0 and "editable" in bit 1
|
||||
|
||||
void invalidate_state ();
|
||||
void do_insert (const Shapes &d);
|
||||
void do_insert (const Shapes &d, unsigned int flags = db::ShapeIterator::All);
|
||||
void check_is_editable_for_undo_redo () const;
|
||||
|
||||
// gets the layers array
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclDbMetaInfo.h"
|
||||
|
||||
#include "gsiDeclDbHelpers.h"
|
||||
#include "dbLayout.h"
|
||||
|
|
@ -984,6 +983,58 @@ static db::Layout *layout (db::Cell *cell)
|
|||
return cell->layout ();
|
||||
}
|
||||
|
||||
static void cell_clear_meta_info (db::Cell *cell)
|
||||
{
|
||||
if (cell->layout ()) {
|
||||
cell->layout ()->clear_meta (cell->cell_index ());
|
||||
}
|
||||
}
|
||||
|
||||
static void cell_remove_meta_info (db::Cell *cell, const std::string &name)
|
||||
{
|
||||
if (cell->layout ()) {
|
||||
cell->layout ()->remove_meta_info (cell->cell_index (), name);
|
||||
}
|
||||
}
|
||||
|
||||
static void cell_add_meta_info (db::Cell *cell, const MetaInfo &mi)
|
||||
{
|
||||
if (cell->layout ()) {
|
||||
cell->layout ()->add_meta_info (cell->cell_index (), mi.name, db::MetaInfo (mi.description, mi.value, mi.persisted));
|
||||
}
|
||||
}
|
||||
|
||||
static const tl::Variant &cell_meta_info_value (db::Cell *cell, const std::string &name)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
static tl::Variant null_value;
|
||||
return null_value;
|
||||
} else {
|
||||
return cell->layout ()->meta_info (cell->cell_index (), name).value;
|
||||
}
|
||||
}
|
||||
|
||||
static MetaInfo *cell_meta_info (db::Cell *cell, const std::string &name)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
return 0;
|
||||
} else if (cell->layout ()->has_meta_info (cell->cell_index (), name)) {
|
||||
const db::MetaInfo &value = cell->layout ()->meta_info (cell->cell_index (), name);
|
||||
return new MetaInfo (name, value);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static gsi::MetaInfoIterator cell_each_meta_info (const db::Cell *cell)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
return gsi::MetaInfoIterator ();
|
||||
} else {
|
||||
return gsi::MetaInfoIterator (cell->layout (), cell->layout ()->begin_meta (cell->cell_index ()), cell->layout ()->end_meta (cell->cell_index ()));
|
||||
}
|
||||
}
|
||||
|
||||
static bool cell_has_prop_id (const db::Cell *c)
|
||||
{
|
||||
return c->prop_id () != 0;
|
||||
|
|
@ -1780,6 +1831,47 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("add_meta_info", &cell_add_meta_info, gsi::arg ("info"),
|
||||
"@brief Adds meta information to the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("clear_meta_info", &cell_clear_meta_info,
|
||||
"@brief Clears the meta information of the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("remove_meta_info", &cell_remove_meta_info, gsi::arg ("name"),
|
||||
"@brief Removes meta information from the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("meta_info_value", &cell_meta_info_value, gsi::arg ("name"),
|
||||
"@brief Gets the meta information value for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, a nil value will be returned.\n"
|
||||
"A more generic version that delivers all fields of the meta information is \\meta_info.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::factory_ext ("meta_info", &cell_meta_info, gsi::arg ("name"),
|
||||
"@brief Gets the meta information for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, a default object with empty fields will be returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::iterator_ext ("each_meta_info", &cell_each_meta_info,
|
||||
"@brief Iterates over the meta information of the cell\n"
|
||||
"See \\LayoutMetaInfo for details about cells and meta information.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method_ext ("write", &write_simple, gsi::arg ("file_name"),
|
||||
"@brief Writes the cell to a layout file\n"
|
||||
"The format of the file will be determined from the file name. Only the cell and "
|
||||
|
|
|
|||
|
|
@ -111,6 +111,21 @@ Class<db::DeepShapeStore> decl_dbDeepShapeStore ("db", "DeepShapeStore",
|
|||
gsi::method ("threads", &db::DeepShapeStore::threads,
|
||||
"@brief Gets the number of threads.\n"
|
||||
) +
|
||||
gsi::method ("wants_all_cells=", &db::DeepShapeStore::set_wants_all_cells, gsi::arg ("flag"),
|
||||
"@brief Sets a flag wether to copy the full hierarchy for the working layouts\n"
|
||||
"\n"
|
||||
"The DeepShapeStore object keeps a copy of the original hierarchy internally for the working layouts.\n"
|
||||
"By default, this hierarchy is mapping only non-empty cells. While the operations proceed, more cells "
|
||||
"may need to be added. This conservative approach saves some memory, but the update operations may "
|
||||
"reduce overall performance. Setting this flag to 'true' switches to a mode where the full "
|
||||
"hierarchy is copied always. This will take more memory but may save CPU time.\n"
|
||||
"\n"
|
||||
"This attribute has been introduced in version 0.28.10."
|
||||
) +
|
||||
gsi::method ("wants_all_cells", &db::DeepShapeStore::wants_all_cells,
|
||||
"@brief Gets a flag wether to copy the full hierarchy for the working layouts\n"
|
||||
"This attribute has been introduced in version 0.28.10."
|
||||
) +
|
||||
gsi::method ("reject_odd_polygons=", &db::DeepShapeStore::set_reject_odd_polygons, gsi::arg ("count"),
|
||||
"@brief Sets a flag indicating whether to reject odd polygons\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiDeclDbMetaInfo.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbClip.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
|
@ -902,39 +903,30 @@ static db::Cell *create_cell4 (db::Layout *layout, const std::string &name, cons
|
|||
return &layout->cell (layout->get_lib_proxy (lib, lib_cell));
|
||||
}
|
||||
|
||||
static db::MetaInfo *layout_meta_info_ctor (const std::string &name, const std::string &value, const std::string &description)
|
||||
static void layout_add_meta_info (db::Layout *layout, const MetaInfo &mi)
|
||||
{
|
||||
return new db::MetaInfo (name, description, value);
|
||||
layout->add_meta_info (mi.name, db::MetaInfo (mi.description, mi.value, mi.persisted));
|
||||
}
|
||||
|
||||
static void layout_meta_set_name (db::MetaInfo *mi, const std::string &n)
|
||||
static MetaInfo *layout_get_meta_info (db::Layout *layout, const std::string &name)
|
||||
{
|
||||
mi->name = n;
|
||||
if (layout->has_meta_info (name)) {
|
||||
const db::MetaInfo &value = layout->meta_info (name);
|
||||
return new MetaInfo (name, value);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_name (const db::MetaInfo *mi)
|
||||
static const tl::Variant &layout_get_meta_info_value (db::Layout *layout, const std::string &name)
|
||||
{
|
||||
return mi->name;
|
||||
const db::MetaInfo &value = layout->meta_info (name);
|
||||
return value.value;
|
||||
}
|
||||
|
||||
static void layout_meta_set_value (db::MetaInfo *mi, const std::string &n)
|
||||
static MetaInfoIterator layout_each_meta_info (const db::Layout *layout)
|
||||
{
|
||||
mi->value = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_value (const db::MetaInfo *mi)
|
||||
{
|
||||
return mi->value;
|
||||
}
|
||||
|
||||
static void layout_meta_set_description (db::MetaInfo *mi, const std::string &n)
|
||||
{
|
||||
mi->description = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_description (const db::MetaInfo *mi)
|
||||
{
|
||||
return mi->description;
|
||||
return MetaInfoIterator (layout, layout->begin_meta (), layout->end_meta ());
|
||||
}
|
||||
|
||||
static void scale_and_snap1 (db::Layout *layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d)
|
||||
|
|
@ -997,45 +989,6 @@ static void move_tree_shapes3 (db::Layout *layout, db::Layout &source_layout, co
|
|||
db::move_shapes (*layout, source_layout, trans, cm.source_cells (), cm.table (), lm.table ());
|
||||
}
|
||||
|
||||
Class<db::MetaInfo> decl_LayoutMetaInfo ("db", "LayoutMetaInfo",
|
||||
gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()),
|
||||
"@brief Creates a layout meta info object\n"
|
||||
"@param name The name\n"
|
||||
"@param value The value\n"
|
||||
"@param description An optional description text\n"
|
||||
) +
|
||||
gsi::method_ext ("name", &layout_meta_get_name,
|
||||
"@brief Gets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("name=", &layout_meta_set_name,
|
||||
"@brief Sets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value", &layout_meta_get_value,
|
||||
"@brief Gets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value=", &layout_meta_set_value,
|
||||
"@brief Sets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description", &layout_meta_get_description,
|
||||
"@brief Gets the description of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description=", &layout_meta_set_description,
|
||||
"@brief Sets the description of the layout meta info object\n"
|
||||
),
|
||||
"@brief A piece of layout meta information\n"
|
||||
"Layout meta information is basically additional data that can be attached to a layout. "
|
||||
"Layout readers may generate meta information and some writers will add layout information to "
|
||||
"the layout object. Some writers will also read meta information to determine certain attributes.\n"
|
||||
"\n"
|
||||
"Multiple layout meta information objects can be attached to one layout using \\Layout#add_meta_info. "
|
||||
"Meta information is identified by a unique name and carries a string value plus an optional description string. "
|
||||
"The description string is for information only and is not evaluated by code.\n"
|
||||
"\n"
|
||||
"See also \\Layout#each_meta_info and \\Layout#meta_info_value and \\Layout#remove_meta_info"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.25."
|
||||
);
|
||||
|
||||
static void dtransform (db::Layout *layout, const db::DTrans &trans)
|
||||
{
|
||||
db::CplxTrans dbu_trans (layout->dbu ());
|
||||
|
|
@ -1097,27 +1050,42 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.27.9."
|
||||
) +
|
||||
gsi::method ("add_meta_info", &db::Layout::add_meta_info, gsi::arg ("info"),
|
||||
gsi::method_ext ("add_meta_info", &layout_add_meta_info, gsi::arg ("info"),
|
||||
"@brief Adds meta information to the layout\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information."
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("remove_meta_info", &db::Layout::remove_meta_info, gsi::arg ("name"),
|
||||
gsi::method ("clear_meta_info", static_cast<void (db::Layout::*) ()> (&db::Layout::clear_meta),
|
||||
"@brief Clears the meta information of the layout\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information."
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
gsi::method ("remove_meta_info", static_cast<void (db::Layout::*) (const std::string &name)> (&db::Layout::remove_meta_info), gsi::arg ("name"),
|
||||
"@brief Removes meta information from the layout\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information."
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method ("meta_info_value", &db::Layout::meta_info_value, gsi::arg ("name"),
|
||||
gsi::method_ext ("meta_info_value", &layout_get_meta_info_value, gsi::arg ("name"),
|
||||
"@brief Gets the meta information value for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, an empty string will be returned.\n"
|
||||
"If no meta information with the given name exists, a nil value will be returned.\n"
|
||||
"A more generic version that delivers all fields of the meta information is \\meta_info.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
"This method has been introduced in version 0.25. Starting with version 0.28.8, the value is of variant type instead of string only.\n"
|
||||
) +
|
||||
gsi::iterator ("each_meta_info", &db::Layout::begin_meta, &db::Layout::end_meta,
|
||||
gsi::factory_ext ("meta_info", &layout_get_meta_info, gsi::arg ("name"),
|
||||
"@brief Gets the meta information for a given name\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information.\n"
|
||||
"\n"
|
||||
"If no meta information with the given name exists, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8.\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_meta_info", &layout_each_meta_info,
|
||||
"@brief Iterates over the meta information of the layout\n"
|
||||
"See \\LayoutMetaInfo for details about layouts and meta information.\n"
|
||||
"\n"
|
||||
|
|
@ -1714,29 +1682,53 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"@param a The first of the layers to swap.\n"
|
||||
"@param b The second of the layers to swap.\n"
|
||||
) +
|
||||
gsi::method ("move_layer", &db::Layout::move_layer, gsi::arg ("src"), gsi::arg ("dest"),
|
||||
gsi::method ("move_layer", static_cast<void (db::Layout::*) (unsigned int, unsigned int)> (&db::Layout::move_layer), gsi::arg ("src"), gsi::arg ("dest"),
|
||||
"@brief Moves a layer\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.19.\n"
|
||||
"\n"
|
||||
"Move a layer from the source to the target. The target is not cleared before, so that this method \n"
|
||||
"merges shapes from the source with the target layer. The source layer is empty after that operation.\n"
|
||||
"Moves a layer from the source to the destination layer. The target is not cleared before, so that this method \n"
|
||||
"merges shapes from the source with the destination layer. The source layer is empty after that operation.\n"
|
||||
"\n"
|
||||
"@param src The layer index of the source layer.\n"
|
||||
"@param dest The layer index of the destination layer.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.19.\n"
|
||||
) +
|
||||
gsi::method ("copy_layer", &db::Layout::copy_layer, gsi::arg ("src"), gsi::arg ("dest"),
|
||||
gsi::method ("move_layer", static_cast<void (db::Layout::*) (unsigned int, unsigned int, unsigned int)> (&db::Layout::move_layer), gsi::arg ("src"), gsi::arg ("dest"), gsi::arg ("flags"),
|
||||
"@brief Moves a layer (selected shape types only)\n"
|
||||
"\n"
|
||||
"Moves a layer from the source to the destination layer. The target is not cleared before, so that this method \n"
|
||||
"merges shapes from the source with the destination layer. The copied shapes are removed from the source layer.\n"
|
||||
"\n"
|
||||
"@param src The layer index of the source layer.\n"
|
||||
"@param dest The layer index of the destination layer.\n"
|
||||
"@param flags A combination of the shape type flags from \\Shapes, S... constants\n"
|
||||
"\n"
|
||||
"This method variant has been introduced in version 0.28.9.\n"
|
||||
) +
|
||||
gsi::method ("copy_layer", static_cast<void (db::Layout::*) (unsigned int, unsigned int)> (&db::Layout::copy_layer), gsi::arg ("src"), gsi::arg ("dest"),
|
||||
"@brief Copies a layer\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.19.\n"
|
||||
"\n"
|
||||
"Copy a layer from the source to the target. The target is not cleared before, so that this method \n"
|
||||
"merges shapes from the source with the target layer.\n"
|
||||
"Copies a layer from the source to the destination layer. The destination layer is not cleared before, so that this method \n"
|
||||
"merges shapes from the source with the destination layer.\n"
|
||||
"\n"
|
||||
"@param src The layer index of the source layer.\n"
|
||||
"@param dest The layer index of the destination layer.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.19.\n"
|
||||
) +
|
||||
gsi::method ("clear_layer", &db::Layout::clear_layer, gsi::arg ("layer_index"),
|
||||
gsi::method ("copy_layer", static_cast<void (db::Layout::*) (unsigned int, unsigned int, unsigned int)> (&db::Layout::copy_layer), gsi::arg ("src"), gsi::arg ("dest"), gsi::arg ("flags"),
|
||||
"@brief Copies a layer (selected shape types only)\n"
|
||||
"\n"
|
||||
"Copies a layer from the source to the destination layer. The destination layer is not cleared before, so that this method \n"
|
||||
"merges shapes from the source with the destination layer.\n"
|
||||
"\n"
|
||||
"@param src The layer index of the source layer.\n"
|
||||
"@param dest The layer index of the destination layer.\n"
|
||||
"@param flags A combination of the shape type flags from \\Shapes, S... constants\n"
|
||||
"\n"
|
||||
"This method variant has been introduced in version 0.28.9.\n"
|
||||
) +
|
||||
gsi::method ("clear_layer", static_cast<void (db::Layout::*) (unsigned int)> (&db::Layout::clear_layer), gsi::arg ("layer_index"),
|
||||
"@brief Clears a layer\n"
|
||||
"\n"
|
||||
"Clears the layer: removes all shapes.\n"
|
||||
|
|
@ -1744,6 +1736,16 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"This method was introduced in version 0.19.\n"
|
||||
"\n"
|
||||
"@param layer_index The index of the layer to delete.\n"
|
||||
) +
|
||||
gsi::method ("clear_layer", static_cast<void (db::Layout::*) (unsigned int, unsigned int)> (&db::Layout::clear_layer), gsi::arg ("layer_index"), gsi::arg ("flags"),
|
||||
"@brief Clears a layer (given shape types only)\n"
|
||||
"\n"
|
||||
"Clears the layer: removes all shapes for the given shape types.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.28.9.\n"
|
||||
"\n"
|
||||
"@param layer_index The index of the layer to delete.\n"
|
||||
"@param flags The type selector for the shapes to delete (see \\Shapes class, S... constants).\n"
|
||||
) +
|
||||
gsi::method ("delete_layer", &db::Layout::delete_layer, gsi::arg ("layer_index"),
|
||||
"@brief Deletes a layer\n"
|
||||
|
|
|
|||
|
|
@ -397,6 +397,10 @@ static unsigned int f_silent () {
|
|||
return db::layout_diff::f_silent;
|
||||
}
|
||||
|
||||
static unsigned int f_ignore_duplicates () {
|
||||
return db::layout_diff::f_ignore_duplicates;
|
||||
}
|
||||
|
||||
static unsigned int f_no_text_orientation () {
|
||||
return db::layout_diff::f_no_text_orientation;
|
||||
}
|
||||
|
|
@ -448,6 +452,13 @@ gsi::Class<LayoutDiff> decl_LayoutDiff ("db", "LayoutDiff",
|
|||
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
|
||||
"compared with other constants to form a flag set."
|
||||
) +
|
||||
gsi::constant ("IgnoreDuplicates", &f_ignore_duplicates,
|
||||
"@brief Ignore duplicate instances or shapes\n"
|
||||
"With this option present, duplicate instances or shapes are ignored and "
|
||||
"duplication does not count as a difference.\n"
|
||||
"\n"
|
||||
"This option has been introduced in version 0.28.9."
|
||||
) +
|
||||
gsi::constant ("NoTextOrientation", &f_no_text_orientation,
|
||||
"@brief Ignore text orientation\n"
|
||||
"This constant can be used for the flags parameter of \\compare_layouts and \\compare_cells. It can be "
|
||||
|
|
|
|||
|
|
@ -0,0 +1,168 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2023 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 "gsiDecl.h"
|
||||
#include "gsiDeclDbMetaInfo.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static MetaInfo *layout_meta_info_ctor (const std::string &name, const tl::Variant &value, const std::string &description, bool persisted)
|
||||
{
|
||||
return new MetaInfo (name, description, value, persisted);
|
||||
}
|
||||
|
||||
static void layout_meta_set_name (MetaInfo *mi, const std::string &n)
|
||||
{
|
||||
mi->name = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_name (const MetaInfo *mi)
|
||||
{
|
||||
return mi->name;
|
||||
}
|
||||
|
||||
static void layout_meta_set_value (MetaInfo *mi, const tl::Variant &n)
|
||||
{
|
||||
mi->value = n;
|
||||
}
|
||||
|
||||
static const tl::Variant &layout_meta_get_value (const MetaInfo *mi)
|
||||
{
|
||||
return mi->value;
|
||||
}
|
||||
|
||||
static void layout_meta_set_description (MetaInfo *mi, const std::string &n)
|
||||
{
|
||||
mi->description = n;
|
||||
}
|
||||
|
||||
static const std::string &layout_meta_get_description (const MetaInfo *mi)
|
||||
{
|
||||
return mi->description;
|
||||
}
|
||||
|
||||
static void layout_meta_set_persisted (MetaInfo *mi, bool f)
|
||||
{
|
||||
mi->persisted = f;
|
||||
}
|
||||
|
||||
static bool layout_meta_get_persisted (const MetaInfo *mi)
|
||||
{
|
||||
return mi->persisted;
|
||||
}
|
||||
|
||||
|
||||
Class<MetaInfo> decl_LayoutMetaInfo ("db", "LayoutMetaInfo",
|
||||
gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()), gsi::arg ("persisted", false),
|
||||
"@brief Creates a layout meta info object\n"
|
||||
"@param name The name\n"
|
||||
"@param value The value\n"
|
||||
"@param description An optional description text\n"
|
||||
"@param persisted If true, the meta information will be persisted in some file formats, like GDS2\n"
|
||||
"\n"
|
||||
"The 'persisted' attribute has been introduced in version 0.28.8.\n"
|
||||
) +
|
||||
gsi::method_ext ("name", &layout_meta_get_name,
|
||||
"@brief Gets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("name=", &layout_meta_set_name, gsi::arg ("name"),
|
||||
"@brief Sets the name of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value", &layout_meta_get_value,
|
||||
"@brief Gets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("value=", &layout_meta_set_value, gsi::arg ("value"),
|
||||
"@brief Sets the value of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description", &layout_meta_get_description,
|
||||
"@brief Gets the description of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("description=", &layout_meta_set_description, gsi::arg ("description"),
|
||||
"@brief Sets the description of the layout meta info object\n"
|
||||
) +
|
||||
gsi::method_ext ("is_persisted?", &layout_meta_get_persisted,
|
||||
"@brief Gets a value indicating whether the meta information will be persisted\n"
|
||||
"This predicate was introduced in version 0.28.8.\n"
|
||||
) +
|
||||
gsi::method_ext ("persisted=", &layout_meta_set_persisted, gsi::arg ("flag"),
|
||||
"@brief Sets a value indicating whether the meta information will be persisted\n"
|
||||
"This predicate was introduced in version 0.28.8.\n"
|
||||
),
|
||||
"@brief A piece of layout meta information\n"
|
||||
"Layout meta information is basically additional data that can be attached to a layout. "
|
||||
"Layout readers may generate meta information and some writers will add layout information to "
|
||||
"the layout object. Some writers will also read meta information to determine certain attributes.\n"
|
||||
"\n"
|
||||
"Multiple layout meta information objects can be attached to one layout using \\Layout#add_meta_info. "
|
||||
"Meta information is identified by a unique name and carries a string value plus an optional description string. "
|
||||
"The description string is for information only and is not evaluated by code.\n"
|
||||
"\n"
|
||||
"Meta information can be attached to the layout object and to cells. It is similar to "
|
||||
"user properties. The differences are:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li Meta information is stored differently in GDS and OASIS files using the context information added "
|
||||
" by KLayout to annotated PCell or library cells too. Hence meta information does not pollute "
|
||||
" the standard user properties space. @/li\n"
|
||||
"@li The value of meta information can be complex serializable types such as lists, hashes and elementary "
|
||||
" objects such as \\Box or \\DBox. Scalar types include floats and booleans. @/li\n"
|
||||
"@li Meta information keys are strings and are supported also for GDS which only accepts integer number "
|
||||
" keys for user properties. @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"Elementary (serializable) objects are: \\Box, \\DBox, \\Edge, \\DEdge, \\EdgePair, \\DEdgePair, "
|
||||
"\\EdgePairs, \\Edges, \\LayerProperties, \\Matrix2d, \\Matrix3d, \\Path, \\DPath, \\Point, \\DPoint, "
|
||||
"\\Polygon, \\DPolygon, \\SimplePolygon, \\DSimplePolygon, \\Region, \\Text, \\DText, \\Texts, "
|
||||
"\\Trans, \\DTrans, \\CplxTrans, \\ICplxTrans, \\DCplxTrans, \\VCplxTrans, \\Vector, \\DVector "
|
||||
"(list may not be complete).\n"
|
||||
"\n"
|
||||
"KLayout itself also generates meta information with specific keys. "
|
||||
"For disambiguation, namespaces can be established by prefixing "
|
||||
"the key strings with some unique identifier in XML fashion, like a domain name - "
|
||||
"e.g. 'example.com:key'.\n"
|
||||
"\n"
|
||||
"@b Note: @/b only meta information marked with \\is_persisted? == true is stored in GDS or OASIS files. "
|
||||
"This is not the default setting, so you need to explicitly set that flag.\n"
|
||||
"\n"
|
||||
"See also \\Layout#each_meta_info, \\Layout#meta_info_value, \\Layout#meta_info and \\Layout#remove_meta_info as "
|
||||
"well as the corresponding \\Cell methods.\n"
|
||||
"\n"
|
||||
"An example of how to attach persisted meta information to a cell is here:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"ly = RBA::Layout::new\n"
|
||||
"c1 = ly.create_cell(\"C1\")\n"
|
||||
"\n"
|
||||
"mi = RBA::LayoutMetaInfo::new(\"the-answer\", 42.0)\n"
|
||||
"mi.persisted = true\n"
|
||||
"c1.add_meta_info(mi)\n"
|
||||
"\n"
|
||||
"# will now hold this piece of meta information attached to cell 'C1':\n"
|
||||
"ly.write(\"to.gds\")\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.25 and was extended in version 0.28.8."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2023 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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HDR_gsiDeclDbMetaInfo
|
||||
#define _HDR_gsiDeclDbMetaInfo
|
||||
|
||||
#include "dbLayout.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlObject.h"
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
struct MetaInfo
|
||||
{
|
||||
MetaInfo (const std::string &n, const std::string &d, const tl::Variant &v, bool p)
|
||||
: name (n), description (d), value (v), persisted (p)
|
||||
{ }
|
||||
|
||||
MetaInfo (const std::string &n, const db::MetaInfo &mi)
|
||||
: name (n), description (mi.description), value (mi.value), persisted (mi.persisted)
|
||||
{ }
|
||||
|
||||
MetaInfo ()
|
||||
: name (), description (), value (), persisted (false)
|
||||
{ }
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
tl::Variant value;
|
||||
bool persisted;
|
||||
};
|
||||
|
||||
struct MetaInfoIterator
|
||||
{
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef MetaInfo value_type;
|
||||
typedef void difference_type;
|
||||
typedef MetaInfo reference;
|
||||
typedef void pointer;
|
||||
|
||||
MetaInfoIterator ()
|
||||
: mp_layout (), m_b (), m_e ()
|
||||
{ }
|
||||
|
||||
MetaInfoIterator (const db::Layout *layout, db::Layout::meta_info_iterator b, db::Layout::meta_info_iterator e)
|
||||
: mp_layout (const_cast<db::Layout *> (layout)), m_b (b), m_e (e)
|
||||
{ }
|
||||
|
||||
bool at_end () const
|
||||
{
|
||||
return !mp_layout || m_b == m_e;
|
||||
}
|
||||
|
||||
void operator++ ()
|
||||
{
|
||||
if (mp_layout) {
|
||||
++m_b;
|
||||
}
|
||||
}
|
||||
|
||||
MetaInfo operator* () const
|
||||
{
|
||||
if (mp_layout) {
|
||||
return MetaInfo (mp_layout->meta_info_name (m_b->first), m_b->second);
|
||||
} else {
|
||||
return MetaInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tl::weak_ptr<db::Layout> mp_layout;
|
||||
db::Layout::meta_info_iterator m_b, m_e;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -926,6 +926,11 @@ struct polygon_defs
|
|||
return c->insert_hole (&pts[0], &pts[0] + sizeof (pts) / sizeof (pts[0]));
|
||||
}
|
||||
|
||||
static void sort_holes (C *c)
|
||||
{
|
||||
c->sort_holes ();
|
||||
}
|
||||
|
||||
static C *from_string (const char *s)
|
||||
{
|
||||
tl::Extractor ex (s);
|
||||
|
|
@ -1249,6 +1254,14 @@ struct polygon_defs
|
|||
"@brief Iterates over the points that make up the nth hole\n"
|
||||
"The hole number must be less than the number of holes (see \\holes)"
|
||||
) +
|
||||
method_ext ("sort_holes", &sort_holes,
|
||||
"@brief Brings the holes in a specific order\n"
|
||||
"This function is normalize the hole order so the comparison of two "
|
||||
"polygons does not depend on the order the holes were inserted. "
|
||||
"Polygons generated by KLayout's alorithms have their holes sorted.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.8."
|
||||
) +
|
||||
method_ext ("size", &size_xy, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
|
||||
"@brief Sizes the polygon (biasing)\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -108,47 +108,47 @@ static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin (const db
|
|||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin (flags));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_all (const db::Shapes *s)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_all (const db::Shapes *s)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin (db::ShapeIterator::All));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_overlapping (const db::Shapes *s, unsigned int flags, const db::Box ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_overlapping (region, flags));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_doverlapping (const db::Shapes *s, unsigned int flags, const db::DBox ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_overlapping_all (const db::Shapes *s, const db::Box ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_overlapping_all (const db::Shapes *s, const db::Box ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_overlapping (region, db::ShapeIterator::All));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_doverlapping_all (const db::Shapes *s, const db::DBox ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_doverlapping_all (const db::Shapes *s, const db::DBox ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_overlapping (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_touching (const db::Shapes *s, unsigned int flags, const db::Box ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_touching (region, flags));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_dtouching (const db::Shapes *s, unsigned int flags, const db::DBox ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, flags));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_touching_all (const db::Shapes *s, const db::Box ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_touching_all (const db::Shapes *s, const db::Box ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_touching (region, db::ShapeIterator::All));
|
||||
}
|
||||
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator>begin_dtouching_all (const db::Shapes *s, const db::DBox ®ion)
|
||||
static gsi::layout_locking_iterator1<db::Shapes::shape_iterator> begin_dtouching_all (const db::Shapes *s, const db::DBox ®ion)
|
||||
{
|
||||
return gsi::layout_locking_iterator1<db::Shapes::shape_iterator> (s->layout (), s->begin_touching (db::CplxTrans (shapes_dbu (s)).inverted () * region, db::ShapeIterator::All));
|
||||
}
|
||||
|
|
@ -251,12 +251,7 @@ static void insert_shapes (db::Shapes *sh, const db::Shapes &s)
|
|||
|
||||
static void insert_shapes_with_flags (db::Shapes *sh, const db::Shapes &s, unsigned int flags)
|
||||
{
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (sh->layout ());
|
||||
for (db::Shapes::shape_iterator i = s.begin (flags); !i.at_end(); ++i) {
|
||||
sh->insert (*i);
|
||||
}
|
||||
sh->insert (s, flags);
|
||||
}
|
||||
|
||||
static void insert_shapes_with_trans (db::Shapes *sh, const db::Shapes &s, const db::ICplxTrans &trans)
|
||||
|
|
@ -1264,9 +1259,15 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"@brief Returns a value indicating whether the shapes container is empty\n"
|
||||
"This method has been introduced in version 0.20.\n"
|
||||
) +
|
||||
gsi::method ("clear", &db::Shapes::clear,
|
||||
gsi::method ("clear", static_cast<void (db::Shapes::*) ()> (&db::Shapes::clear),
|
||||
"@brief Clears the shape container\n"
|
||||
"This method has been introduced in version 0.16. It can only be used in editable mode."
|
||||
"This method has been introduced in version 0.16."
|
||||
) +
|
||||
gsi::method ("clear", static_cast<void (db::Shapes::*) (unsigned int)> (&db::Shapes::clear), gsi::arg ("flags"),
|
||||
"@brief Clears certain shape types from the shape container\n"
|
||||
"Only shapes matching the shape types from 'flags' are removed. 'flags' is a combination of the S... constants.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.9."
|
||||
) +
|
||||
gsi::method_ext ("size", &shapes_size,
|
||||
"@brief Gets the number of shapes in this container\n"
|
||||
|
|
@ -1296,10 +1297,19 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"returned for future references."
|
||||
) +
|
||||
gsi::method ("SAll|#s_all", &s_all,
|
||||
"@brief Indicates that all shapes shall be retrieved"
|
||||
"@brief Indicates that all shapes shall be retrieved\n"
|
||||
"You can use this constant to construct 'except' classes - e.g. "
|
||||
"to specify 'all shape types except boxes' use\n"
|
||||
"\n"
|
||||
"@code SAll - SBoxes @/code\n"
|
||||
) +
|
||||
gsi::method ("SAllWithProperties|#s_all_with_properties", &s_all_with_properties,
|
||||
"@brief Indicates that all shapes with properties shall be retrieved"
|
||||
"@brief Indicates that all shapes with properties shall be retrieved\n"
|
||||
"Using this selector means to retrieve only shapes with properties."
|
||||
"You can use this constant to construct 'except' classes - e.g. "
|
||||
"to specify 'all shape types with properties except boxes' use\n"
|
||||
"\n"
|
||||
"@code SAllWithProperties - SBoxes @/code\n"
|
||||
) +
|
||||
gsi::method ("SPolygons|#s_polygons", &s_polygons,
|
||||
"@brief Indicates that polygons shall be retrieved"
|
||||
|
|
@ -1333,7 +1343,10 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"@brief Indicates that user objects shall be retrieved"
|
||||
) +
|
||||
gsi::method ("SProperties|#s_properties", &s_properties,
|
||||
"@brief Indicates that only shapes with properties shall be retrieved"
|
||||
"@brief Indicates that only shapes with properties shall be retrieved\n"
|
||||
"You can or-combine this flag with the plain shape types to select a "
|
||||
"certain shape type, but only those shapes with properties. For example to "
|
||||
"select boxes with properties, use 'SProperties | SBoxes'."
|
||||
) +
|
||||
gsi::method_ext ("dump_mem_statistics", &dump_mem_statistics, gsi::arg<bool> ("detailed", false),
|
||||
"@hide"
|
||||
|
|
|
|||
|
|
@ -938,6 +938,7 @@ TEST(two_1)
|
|||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.set_scanner_threshold1 (0);
|
||||
bs.process (tr, 1, bc1, bc2);
|
||||
EXPECT_EQ (tr.str, "[i](2-12)(2-14)(4-12)(4-14)(2-15)(4-15)(5-12)(5-14)(5-15)(2-13)(4-13)(3-12)(3-14)(3-13)(3-15)(5-13)(0-10)<2><5><4><3><12><15><14><13>(0-11)(1-10)(1-11)<0><1><10><11>[f]");
|
||||
}
|
||||
|
|
@ -974,6 +975,7 @@ TEST(two_1a)
|
|||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.set_scanner_threshold1 (0);
|
||||
bs.process (tr, 1, bc1, bc2);
|
||||
EXPECT_EQ (tr.str, "[i](2-11)(2-12)(1-11)(1-12)<1><2><11><12>(0-10)<0><10>[f]");
|
||||
}
|
||||
|
|
@ -1010,6 +1012,7 @@ TEST(two_1b)
|
|||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.set_scanner_threshold1 (0);
|
||||
EXPECT_EQ (bs.process (tr, 1, bc1, bc2), true);
|
||||
EXPECT_EQ (tr.str, "[i](1-12)(2-12)(1-11)(2-11)<1><2><11><12>(0-10)<0><10>[f]");
|
||||
|
||||
|
|
@ -1046,14 +1049,15 @@ TEST(two_1c)
|
|||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.set_scanner_threshold1 (0);
|
||||
EXPECT_EQ (bs.process (tr, 1, bc1, bc2), true);
|
||||
EXPECT_EQ (tr.str, "[i]<0><10>(1-12)(2-12)(1-11)(2-11)<1><2><12><11>[f]");
|
||||
}
|
||||
|
||||
void run_test2_two (tl::TestBase *_this, size_t n, double ff, db::Coord spread, bool touch = true)
|
||||
void run_test2_two (tl::TestBase *_this, size_t n1, size_t n2, double ff, db::Coord spread, bool touch = true, bool no_shortcut = true)
|
||||
{
|
||||
std::vector<db::Box> bb;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
for (size_t i = 0; i < n1; ++i) {
|
||||
db::Coord x = rand () % spread;
|
||||
db::Coord y = rand () % spread;
|
||||
bb.push_back (db::Box (x, y, x + 100, y + 100));
|
||||
|
|
@ -1061,7 +1065,7 @@ void run_test2_two (tl::TestBase *_this, size_t n, double ff, db::Coord spread,
|
|||
}
|
||||
|
||||
std::vector<db::SimplePolygon> bb2;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
for (size_t i = 0; i < n2; ++i) {
|
||||
db::Coord x = rand () % spread;
|
||||
db::Coord y = rand () % spread;
|
||||
bb2.push_back (db::SimplePolygon (db::Box (x, y, x + 100, y + 100)));
|
||||
|
|
@ -1082,7 +1086,10 @@ void run_test2_two (tl::TestBase *_this, size_t n, double ff, db::Coord spread,
|
|||
db::box_convert<db::SimplePolygon> bc2;
|
||||
{
|
||||
tl::SelfTimer timer ("box-scanner");
|
||||
bs.set_scanner_threshold (0);
|
||||
if (no_shortcut) {
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.set_scanner_threshold1 (0);
|
||||
}
|
||||
bs.process (tr, touch ? 1 : 0, bc1, bc2);
|
||||
}
|
||||
|
||||
|
|
@ -1118,45 +1125,60 @@ void run_test2_two (tl::TestBase *_this, size_t n, double ff, db::Coord spread,
|
|||
|
||||
TEST(two_2a)
|
||||
{
|
||||
run_test2_two(_this, 10, 0.0, 1000);
|
||||
run_test2_two(_this, 10, 10, 0.0, 1000);
|
||||
run_test2_two(_this, 10, 10, 0.0, 1000, true, false /*sub-threshold*/);
|
||||
}
|
||||
|
||||
TEST(two_2b)
|
||||
{
|
||||
run_test2_two(_this, 10, 0.0, 100);
|
||||
run_test2_two(_this, 10, 10, 0.0, 100);
|
||||
run_test2_two(_this, 10, 10, 0.0, 100, true, false /*sub-threshold*/);
|
||||
}
|
||||
|
||||
TEST(two_2c)
|
||||
{
|
||||
run_test2_two(_this, 10, 0.0, 10);
|
||||
run_test2_two(_this, 10, 10, 0.0, 10);
|
||||
run_test2_two(_this, 10, 10, 0.0, 10, true, false /*sub-threshold*/);
|
||||
}
|
||||
|
||||
TEST(two_2d)
|
||||
{
|
||||
run_test2_two(_this, 1000, 0.0, 1000);
|
||||
run_test2_two(_this, 1000, 1000, 0.0, 1000);
|
||||
}
|
||||
|
||||
TEST(two_2e)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 1000);
|
||||
run_test2_two(_this, 1000, 1000, 2, 1000);
|
||||
}
|
||||
|
||||
TEST(two_2f)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 1000, false);
|
||||
run_test2_two(_this, 1000, 1000, 2, 1000, false);
|
||||
}
|
||||
|
||||
TEST(two_2g)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 500);
|
||||
run_test2_two(_this, 1000, 1000, 2, 500);
|
||||
}
|
||||
|
||||
TEST(two_2h)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 100);
|
||||
run_test2_two(_this, 1000, 1000, 2, 100);
|
||||
}
|
||||
|
||||
TEST(two_2i)
|
||||
{
|
||||
run_test2_two(_this, 10000, 2, 10000);
|
||||
run_test2_two(_this, 10000, 1000, 2, 10000);
|
||||
}
|
||||
|
||||
TEST(two_2j)
|
||||
{
|
||||
run_test2_two(_this, 3, 1000, 0.0, 1000);
|
||||
run_test2_two(_this, 3, 1000, 0.0, 1000, true, false /*sub-threshold*/);
|
||||
}
|
||||
|
||||
TEST(two_2k)
|
||||
{
|
||||
run_test2_two(_this, 1000, 3, 0.0, 1000);
|
||||
run_test2_two(_this, 1000, 3, 0.0, 1000, true, false /*sub-threshold*/);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2781,3 +2781,40 @@ TEST(135b)
|
|||
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)");
|
||||
}
|
||||
|
||||
// issue #1366
|
||||
TEST(136)
|
||||
{
|
||||
db::Layout layout_1;
|
||||
unsigned int l_l20000d0;
|
||||
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/bool/";
|
||||
fn += "issue_1366.oas";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
reader.read (layout_1, options);
|
||||
|
||||
l_l20000d0 = layout_1.get_layer (db::LayerProperties (20000, 0));
|
||||
}
|
||||
|
||||
db::ShapeProcessor proc;
|
||||
|
||||
db::Layout lr;
|
||||
lr.dbu (0.0001);
|
||||
db::Cell *lr_top = &lr.cell (lr.add_cell ("TOP"));
|
||||
|
||||
unsigned int lr_l100d0 = lr.insert_layer (db::LayerProperties (100, 0));
|
||||
|
||||
proc.merge (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l_l20000d0,
|
||||
lr_top->shapes (lr_l100d0), false /*hierarchical*/, 0, true /*resolve holes*/, true /*min coherence*/);
|
||||
|
||||
std::string au_fn (tl::testdata ());
|
||||
au_fn += "/bool/";
|
||||
au_fn += "issue_1366_au.gds";
|
||||
|
||||
db::compare_layouts (_this, lr, au_fn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1278,3 +1278,9 @@ TEST(FlatOperation)
|
|||
run_test_bool22_flat (_this, "hlp17_flat.oas", TMAndNot, 100, 101);
|
||||
}
|
||||
|
||||
TEST(Arrays)
|
||||
{
|
||||
// Large arrays, NOT
|
||||
run_test_bool2 (_this, "hlp18.oas", TMNot, 100);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ public:
|
|||
void begin_edge_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b);
|
||||
void end_edge_differences ();
|
||||
void begin_edge_pair_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b);
|
||||
void end_edge_pair_differences ();
|
||||
void begin_text_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &b);
|
||||
void end_text_differences ();
|
||||
|
|
@ -102,6 +105,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties &
|
|||
}
|
||||
if (ci.properties_id () != 0) {
|
||||
m_os << " [" << ci.properties_id () << "]" << std::endl;
|
||||
} else {
|
||||
m_os << "" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -339,6 +344,26 @@ TestDifferenceReceiver::end_edge_differences ()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::begin_edge_pair_differences ()
|
||||
{
|
||||
m_os << "layout_diff: edge pairs differ for layer " << m_layer.to_string () << " in cell " << m_cellname << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b)
|
||||
{
|
||||
m_os << "Not in b but in a:" << std::endl;
|
||||
print_diffs (pr, a, b);
|
||||
m_os << "Not in a but in b:" << std::endl;
|
||||
print_diffs (pr, b, a);
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::end_edge_pair_differences ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TestDifferenceReceiver::begin_text_differences ()
|
||||
{
|
||||
|
|
@ -466,7 +491,9 @@ TEST(1)
|
|||
" c4 m45 *1 -10,20\n"
|
||||
" c4 m45 *1 -10,20\n"
|
||||
"Not in b but in a:\n"
|
||||
" c5x r0 *1 10,-20 c5x m45 *1 -10,20Not in a but in b:\n"
|
||||
" c5x r0 *1 10,-20\n"
|
||||
" c5x m45 *1 -10,20\n"
|
||||
"Not in a but in b:\n"
|
||||
);
|
||||
|
||||
g = h;
|
||||
|
|
@ -928,7 +955,7 @@ TEST(3)
|
|||
c2h.shapes (0).insert (db::Polygon (db::Box (1, 2, 1003, 1006)));
|
||||
|
||||
r.clear ();
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r);
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r);
|
||||
|
||||
EXPECT_EQ (eq, false);
|
||||
EXPECT_EQ (r.text (),
|
||||
|
|
@ -942,7 +969,7 @@ TEST(3)
|
|||
);
|
||||
|
||||
r.clear ();
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 1, r);
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 1, r);
|
||||
|
||||
EXPECT_EQ (eq, false);
|
||||
EXPECT_EQ (r.text (),
|
||||
|
|
@ -1476,4 +1503,205 @@ TEST(7)
|
|||
EXPECT_EQ (r.text (), "");
|
||||
}
|
||||
|
||||
TEST(8)
|
||||
{
|
||||
db::Layout g;
|
||||
g.insert_layer (0);
|
||||
g.set_properties (0, db::LayerProperties (17, 0));
|
||||
g.insert_layer (1);
|
||||
g.set_properties (1, db::LayerProperties (42, 1));
|
||||
|
||||
db::cell_index_type c1i = g.add_cell ("c1");
|
||||
db::cell_index_type c2i = g.add_cell ("c2x");
|
||||
db::cell_index_type c3i = g.add_cell ("c3");
|
||||
db::cell_index_type c4i = g.add_cell ("c4");
|
||||
db::cell_index_type c5i = g.add_cell ("c5x");
|
||||
|
||||
{
|
||||
|
||||
db::Cell &c1 (g.cell (c1i));
|
||||
db::Cell &c2 (g.cell (c2i));
|
||||
db::Cell &c3 (g.cell (c3i));
|
||||
db::Cell &c4 (g.cell (c4i));
|
||||
db::Cell &c5 (g.cell (c5i));
|
||||
c2.shapes (0).insert (db::Box (0, 1, 2, 3));
|
||||
|
||||
db::FTrans f (1, true);
|
||||
db::Vector p (-10, 20);
|
||||
db::Trans t (f.rot (), p);
|
||||
db::Vector pp (10, -20);
|
||||
db::Trans tt (0, pp);
|
||||
|
||||
// c4->c1 (aref)
|
||||
c4.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1.cell_index ()), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3));
|
||||
// c5->c1
|
||||
c5.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1.cell_index ()), t));
|
||||
// c3->c5 (3x)
|
||||
c3.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c5.cell_index ()), t));
|
||||
c3.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c5.cell_index ()), tt));
|
||||
c3.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c5.cell_index ()), t));
|
||||
// c4->c3
|
||||
c4.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c3.cell_index ()), t));
|
||||
// c4->c1
|
||||
c4.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1.cell_index ()), tt));
|
||||
// c2->c1 (2x)
|
||||
c2.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1.cell_index ()), t));
|
||||
c2.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1.cell_index ()), tt));
|
||||
// c2->c4 (2x)
|
||||
c2.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c4.cell_index ()), t));
|
||||
c2.insert (db::array <db::CellInst, db::Trans> (db::CellInst (c4.cell_index ()), t));
|
||||
|
||||
}
|
||||
|
||||
db::Layout h = g;
|
||||
|
||||
TestDifferenceReceiver r;
|
||||
bool eq;
|
||||
|
||||
g.cell (c2i).shapes (0).insert (db::Box (1, 2, 1001, 1002));
|
||||
g.cell (c2i).shapes (0).insert (db::Box (2, 3, 1002, 1003));
|
||||
g.cell (c2i).shapes (0).insert (db::Box (2, 3, 1002, 1003));
|
||||
g.cell (c2i).shapes (0).insert (db::Box (3, 4, 1003, 1004));
|
||||
g.cell (c2i).shapes (0).insert (db::Box (3, 4, 1003, 1004));
|
||||
|
||||
h.cell (c2i).shapes (0).insert (db::Box (1, 2, 1001, 1002));
|
||||
h.cell (c2i).shapes (0).insert (db::Box (1, 2, 1001, 1002));
|
||||
h.cell (c2i).shapes (0).insert (db::Box (2, 3, 1002, 1003));
|
||||
h.cell (c2i).shapes (0).insert (db::Box (4, 5, 1004, 1005));
|
||||
h.cell (c2i).shapes (0).insert (db::Box (4, 5, 1004, 1005));
|
||||
|
||||
r.clear ();
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r);
|
||||
|
||||
EXPECT_EQ (eq, false);
|
||||
EXPECT_EQ (r.text (),
|
||||
"layout_diff: boxes differ for layer 17/0 in cell c2x\n"
|
||||
"Not in b but in a:\n"
|
||||
" (2,3;1002,1003)\n"
|
||||
" (3,4;1003,1004)\n"
|
||||
" (3,4;1003,1004)\n"
|
||||
"Not in a but in b:\n"
|
||||
" (1,2;1001,1002)\n"
|
||||
" (4,5;1004,1005)\n"
|
||||
" (4,5;1004,1005)\n"
|
||||
);
|
||||
|
||||
r.clear ();
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose + db::layout_diff::f_ignore_duplicates, 0, r);
|
||||
|
||||
EXPECT_EQ (eq, false);
|
||||
EXPECT_EQ (r.text (),
|
||||
"layout_diff: boxes differ for layer 17/0 in cell c2x\n"
|
||||
"Not in b but in a:\n"
|
||||
" (3,4;1003,1004)\n"
|
||||
"Not in a but in b:\n"
|
||||
" (4,5;1004,1005)\n"
|
||||
);
|
||||
|
||||
// duplicate instances
|
||||
{
|
||||
db::FTrans f (1, true);
|
||||
db::Vector p (-10, 20);
|
||||
db::Trans t (f.rot (), p);
|
||||
|
||||
h.cell(c4i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1i), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3));
|
||||
h.cell(c4i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1i), t));
|
||||
h.cell(c4i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1i), t));
|
||||
|
||||
g.cell(c5i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1i), t));
|
||||
g.cell(c5i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1i), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3));
|
||||
g.cell(c5i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c1i), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3));
|
||||
|
||||
db::cell_index_type c6i = g.add_cell ("c6");
|
||||
g.cell(c5i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c6i), t));
|
||||
g.cell(c5i).insert (db::array <db::CellInst, db::Trans> (db::CellInst (c6i), t));
|
||||
|
||||
}
|
||||
|
||||
r.clear ();
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r);
|
||||
|
||||
EXPECT_EQ (eq, false);
|
||||
EXPECT_EQ (r.text (),
|
||||
"layout_diff: cell c6 is not present in layout b, but in a\n"
|
||||
"layout_diff: boxes differ for layer 17/0 in cell c2x\n"
|
||||
"Not in b but in a:\n"
|
||||
" (2,3;1002,1003)\n"
|
||||
" (3,4;1003,1004)\n"
|
||||
" (3,4;1003,1004)\n"
|
||||
"Not in a but in b:\n"
|
||||
" (1,2;1001,1002)\n"
|
||||
" (4,5;1004,1005)\n"
|
||||
" (4,5;1004,1005)\n"
|
||||
"layout_diff: instances differ in cell c4\n"
|
||||
"list for a:\n"
|
||||
" c1 r0 *1 10,-20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c3 m45 *1 -10,20\n"
|
||||
"list for b:\n"
|
||||
" c1 r0 *1 10,-20\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c3 m45 *1 -10,20\n"
|
||||
"Not in b but in a:\n"
|
||||
"Not in a but in b:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
"layout_diff: instances differ in cell c5x\n"
|
||||
"list for a:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
"list for b:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
"Not in b but in a:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c6 m45 *1 -10,20\n"
|
||||
" c6 m45 *1 -10,20\n"
|
||||
"Not in a but in b:\n"
|
||||
);
|
||||
|
||||
r.clear ();
|
||||
eq = db::compare_layouts (g, h, db::layout_diff::f_verbose + db::layout_diff::f_ignore_duplicates, 0, r);
|
||||
|
||||
EXPECT_EQ (eq, false);
|
||||
EXPECT_EQ (r.text (),
|
||||
"layout_diff: cell c6 is not present in layout b, but in a\n"
|
||||
"layout_diff: boxes differ for layer 17/0 in cell c2x\n"
|
||||
"Not in b but in a:\n"
|
||||
" (3,4;1003,1004)\n"
|
||||
"Not in a but in b:\n"
|
||||
" (4,5;1004,1005)\n"
|
||||
"layout_diff: instances differ in cell c4\n"
|
||||
"list for a:\n"
|
||||
" c1 r0 *1 10,-20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c3 m45 *1 -10,20\n"
|
||||
"list for b:\n"
|
||||
" c1 r0 *1 10,-20\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c3 m45 *1 -10,20\n"
|
||||
"Not in b but in a:\n"
|
||||
"Not in a but in b:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
"layout_diff: instances differ in cell c5x\n"
|
||||
"list for a:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
"list for b:\n"
|
||||
" c1 m45 *1 -10,20\n"
|
||||
"Not in b but in a:\n"
|
||||
" c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n"
|
||||
" c6 m45 *1 -10,20\n"
|
||||
"Not in a but in b:\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ TEST(5)
|
|||
db::Layout l (&m);
|
||||
EXPECT_EQ (l.technology_name (), "");
|
||||
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
info.lib_name = "LIB";
|
||||
info.cell_name = "LIBCELL";
|
||||
|
||||
|
|
@ -624,7 +624,7 @@ TEST(6)
|
|||
|
||||
EXPECT_EQ (l.technology_name (), "");
|
||||
|
||||
db::ProxyContextInfo info;
|
||||
db::LayoutOrCellContextInfo info;
|
||||
info.lib_name = "Basic";
|
||||
info.pcell_name = "CIRCLE";
|
||||
info.pcell_parameters ["actual_radius"] = tl::Variant (10.0);
|
||||
|
|
@ -644,7 +644,7 @@ TEST(6)
|
|||
|
||||
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {CIRCLE}\nboundary 1 0 {-4142 -10000} {-10000 -4142} {-10000 4142} {-4142 10000} {4142 10000} {10000 4142} {10000 -4142} {4142 -10000} {-4142 -10000}\nend_cell\nend_lib\n");
|
||||
|
||||
db::ProxyContextInfo info2;
|
||||
db::LayoutOrCellContextInfo info2;
|
||||
l.get_context_info (cell->cell_index (), info2);
|
||||
info2.pcell_parameters ["actual_radius"] = tl::Variant (5.0);
|
||||
|
||||
|
|
@ -677,7 +677,7 @@ TEST(7_LayerProperties)
|
|||
db::Layout l (&m);
|
||||
|
||||
EXPECT_EQ (l.is_valid_layer (0), false);
|
||||
EXPECT_EQ (l.guiding_shape_layer (), 0);
|
||||
EXPECT_EQ (l.guiding_shape_layer (), (unsigned int) 0);
|
||||
EXPECT_EQ (l.is_special_layer (0), true);
|
||||
EXPECT_EQ (int (l.layers ()), 1);
|
||||
|
||||
|
|
@ -737,3 +737,61 @@ TEST(7_LayerProperties)
|
|||
EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (1, 0)), -1);
|
||||
EXPECT_EQ (l.get_layer_maybe (db::LayerProperties (2, 0)), -1);
|
||||
}
|
||||
|
||||
TEST(8_MetaInfo)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
||||
EXPECT_EQ (ly.meta_info_name_id ("a"), (unsigned int) 0);
|
||||
EXPECT_EQ (ly.meta_info_name_id ("b"), (unsigned int) 1);
|
||||
EXPECT_EQ (ly.meta_info_name_id ("a"), (unsigned int) 0);
|
||||
EXPECT_EQ (ly.has_context_info (), false);
|
||||
|
||||
ly.add_meta_info ("a", db::MetaInfo ("description", tl::Variant (17.5), false));
|
||||
ly.add_meta_info ("b", db::MetaInfo ("", tl::Variant ("value"), true));
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (), true);
|
||||
|
||||
EXPECT_EQ (ly.meta_info ("x").value.to_string (), "nil");
|
||||
EXPECT_EQ (ly.meta_info ("x").description, "");
|
||||
EXPECT_EQ (ly.meta_info ("x").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info ("a").value.to_string (), "17.5");
|
||||
EXPECT_EQ (ly.meta_info ("a").description, "description");
|
||||
EXPECT_EQ (ly.meta_info ("a").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (1).value.to_string (), "value");
|
||||
EXPECT_EQ (ly.meta_info (1).description, "");
|
||||
EXPECT_EQ (ly.meta_info (1).persisted, true);
|
||||
|
||||
db::cell_index_type ci = ly.add_cell ("X");
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (ci), false);
|
||||
|
||||
ly.add_meta_info (ci, "a", db::MetaInfo ("dd", tl::Variant (-1), false));
|
||||
ly.add_meta_info (ci, "b", db::MetaInfo ("d", tl::Variant ("u"), true));
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (ci), true);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (ci, "x").value.to_string (), "nil");
|
||||
EXPECT_EQ (ly.meta_info (ci, "x").description, "");
|
||||
EXPECT_EQ (ly.meta_info (ci, "x").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").value.to_string (), "-1");
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").description, "dd");
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").persisted, false);
|
||||
|
||||
EXPECT_EQ (ly.meta_info (ci, 1).value.to_string (), "u");
|
||||
EXPECT_EQ (ly.meta_info (ci, 1).description, "d");
|
||||
EXPECT_EQ (ly.meta_info (ci, 1).persisted, true);
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (), true);
|
||||
ly.clear_meta ();
|
||||
EXPECT_EQ (ly.has_context_info (), false);
|
||||
EXPECT_EQ (ly.meta_info ("a").value.to_string (), "nil");
|
||||
|
||||
EXPECT_EQ (ly.has_context_info (ci), true);
|
||||
ly.clear_meta (ci);
|
||||
EXPECT_EQ (ly.has_context_info (ci), false);
|
||||
EXPECT_EQ (ly.meta_info (ci, "a").value.to_string (), "nil");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@ TEST(11_ErrorOnCircuitRedefinition)
|
|||
msg = ex.msg ();
|
||||
}
|
||||
|
||||
EXPECT_EQ (tl::replaced (msg, path, "?"), "Redefinition of circuit SUBCKT in ?, line 20");
|
||||
EXPECT_EQ (tl::replaced (msg, tl::absolute_file_path (path), "?"), "Redefinition of circuit SUBCKT in ?, line 20");
|
||||
}
|
||||
|
||||
TEST(12_IgnoreDuplicateGlobals)
|
||||
|
|
@ -580,7 +580,7 @@ TEST(14_IncludeWithError)
|
|||
reader.read (is, nl);
|
||||
EXPECT_EQ (true, false); // must not happen
|
||||
} catch (tl::Exception &ex) {
|
||||
EXPECT_EQ (ex.msg (), "'M' element must have four nodes in " + std::string (tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14x.cir")) + ", line 3");
|
||||
EXPECT_EQ (ex.msg (), "'M' element must have four nodes in " + std::string (tl::absolute_file_path (tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader14x.cir"))) + ", line 3");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -752,6 +752,90 @@ TEST(19_ngspice_ref)
|
|||
);
|
||||
}
|
||||
|
||||
// using parameters evaluated before inside formulas
|
||||
TEST(19b_ngspice_ref)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader19b.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit .TOP ();\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=4,V=1.5)' XPMOS (D=Q,G=I,S=VDD,B=VDD);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=4,V=1.5)' XNMOS (D=Q,G=I,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY0 (D=VSS,G=VSS,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY1 (D=VSS,G=VSS,S=VSS,B=VSS);\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY2 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
" subcircuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' XDUMMY3 (D=VDD,G=VDD,S=VDD,B=VDD);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15,NF=4,V=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15,NF=4,V=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=6,AS=0.32625,AD=0.2175,PS=3.99,PD=2.66);\n"
|
||||
"end;\n"
|
||||
"circuit 'NMOS4_STANDARD(L=0.15,NF=2,V=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__NFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n"
|
||||
"end;\n"
|
||||
"circuit 'PMOS4_STANDARD(L=0.15,NF=2,V=1.5)' (D=D,G=G,S=S,B=B);\n"
|
||||
" device SKY130_FD_PR__PFET_01V8 M1 (S=S,G=G,D=D,B=B) (L=0.15,W=3,AS=0.435,AD=0.2175,PS=4.16,PD=2.08);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
// issue #1319, clarification
|
||||
TEST(20_precendence)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader20.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit TEST ();\n"
|
||||
" device CAP '1' (A=A,B=B) (C=5e-12,A=0,P=0);\n"
|
||||
" device CAP '2A' (A=A,B=B) (C=2.5e-12,A=0,P=0);\n"
|
||||
" device CAP '2B' (A=A,B=B) (C=2.5e-12,A=0,P=0);\n"
|
||||
" device CAP_MODEL1 '3' (A=A,B=B) (C=5e-12,A=0,P=0);\n"
|
||||
" device CAP3 '4' (A=A,B=B,W=CAP_MODEL1) (C=2.5e-12,A=0,P=0);\n"
|
||||
" device CAP_MODEL2 '5' (A=A,B=B,W=C) (C=5e-12,A=0,P=0);\n"
|
||||
" device CAP_MODEL1 '6' (A=A,B=B) (C=2.5e-12,A=0,P=0);\n"
|
||||
" device CAP_MODEL2 '7A' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0);\n"
|
||||
" device CAP_MODEL2 '7B' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0);\n"
|
||||
" device CAP_MODEL2 '8' (A=A,B=B,W=C) (C=2.5e-12,A=0,P=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
// issue #1320, .lib support
|
||||
TEST(21_lib)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader21.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit .TOP ();\n"
|
||||
" device CAP '10' (A='1',B='2') (C=1e-12,A=0,P=0);\n"
|
||||
" device CAP '1' (A='1',B='2') (C=1e-10,A=0,P=0);\n"
|
||||
" device CAP '2A' (A='1',B='2') (C=1.01e-10,A=0,P=0);\n"
|
||||
" device CAP '2B' (A='1',B='2') (C=1.02e-10,A=0,P=0);\n"
|
||||
" device CAP '100' (A='1',B='2') (C=1.5e-11,A=0,P=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(100_ExpressionParser)
|
||||
{
|
||||
std::map<std::string, tl::Variant> vars;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ TEST(1)
|
|||
db::Polygon pp;
|
||||
pp.insert_hole (c3.begin (), c3.end ());
|
||||
pp.insert_hole (c2.begin (), c2.end ());
|
||||
pp.sort_holes ();
|
||||
pp.assign_hull (c1.begin (), c1.end ());
|
||||
EXPECT_EQ (pp.area (), 1000*100-2*380*80);
|
||||
EXPECT_EQ (pp.area2 (), 2*(1000*100-2*380*80));
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@
|
|||
#include "dbRecursiveInstanceIterator.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "dbReader.h"
|
||||
#include "tlString.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
std::string collect(db::RecursiveInstanceIterator &s, const db::Layout &layout)
|
||||
std::string collect (db::RecursiveInstanceIterator &s, const db::Layout &layout)
|
||||
{
|
||||
std::string res;
|
||||
while (! s.at_end ()) {
|
||||
|
|
@ -47,13 +49,26 @@ std::string collect(db::RecursiveInstanceIterator &s, const db::Layout &layout)
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string collect_with_copy(db::RecursiveInstanceIterator s, const db::Layout &layout)
|
||||
std::string collect_with_copy (db::RecursiveInstanceIterator s, const db::Layout &layout)
|
||||
{
|
||||
s.reset ();
|
||||
return collect (s, layout);
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
std::string collect2 (db::RecursiveInstanceIterator &s, const db::Layout &layout)
|
||||
{
|
||||
std::string res;
|
||||
while (! s.at_end ()) {
|
||||
if (! res.empty ()) {
|
||||
res += "\n";
|
||||
}
|
||||
res += std::string (layout.cell_name (s->inst_ptr.cell_index ())) + "@" + (s.trans () * s.instance ().complex_trans ()).to_string ();
|
||||
++s;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
db::Manager m (true);
|
||||
db::Layout g (&m);
|
||||
|
|
@ -660,3 +675,117 @@ TEST(5)
|
|||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "");
|
||||
}
|
||||
|
||||
// issue-1353
|
||||
TEST(6)
|
||||
{
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/gds/issue-1353.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
std::string x;
|
||||
|
||||
db::cell_index_type c1 = layout.cell_by_name ("TOP_CELL_3_C").second;
|
||||
db::cell_index_type c2 = layout.cell_by_name ("TOP_CELL_3_B").second;
|
||||
db::RecursiveInstanceIterator i1 (layout, layout.cell (c1));
|
||||
|
||||
x = collect2(i1, layout);
|
||||
EXPECT_EQ (x,
|
||||
// depth-first traversal
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,0\n"
|
||||
"CHILD_CELL_3_1@r0 *1 30000,0\n"
|
||||
"CHILD_CELL_3@r0 *1 30000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,0\n"
|
||||
"CHILD_CELL_3_1@r0 *1 55000,0\n"
|
||||
"CHILD_CELL_3@r0 *1 55000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,20000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 55000,20000\n"
|
||||
"CHILD_CELL_3@r0 *1 55000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,40000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 55000,40000\n"
|
||||
"CHILD_CELL_3@r0 *1 55000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,0\n"
|
||||
"CHILD_CELL_3_1@r0 *1 75000,0\n"
|
||||
"CHILD_CELL_3@r0 *1 75000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,20000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 75000,20000\n"
|
||||
"CHILD_CELL_3@r0 *1 75000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,40000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 75000,40000\n"
|
||||
"CHILD_CELL_3@r0 *1 75000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,0\n"
|
||||
"CHILD_CELL_3_1@r0 *1 95000,0\n"
|
||||
"CHILD_CELL_3@r0 *1 95000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,20000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 95000,20000\n"
|
||||
"CHILD_CELL_3@r0 *1 95000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,40000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 95000,40000\n"
|
||||
"CHILD_CELL_3@r0 *1 95000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,20000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 30000,20000\n"
|
||||
"CHILD_CELL_3@r0 *1 30000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,40000\n"
|
||||
"CHILD_CELL_3_1@r0 *1 30000,40000\n"
|
||||
"CHILD_CELL_3@r0 *1 30000,40000"
|
||||
);
|
||||
|
||||
std::set<db::cell_index_type> t;
|
||||
t.insert (layout.cell_by_name ("TOP_CELL_3_1_1").second);
|
||||
i1.set_targets (t);
|
||||
|
||||
x = collect2(i1, layout);
|
||||
EXPECT_EQ (x,
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,40000"
|
||||
);
|
||||
|
||||
db::RecursiveInstanceIterator i2 (layout, layout.cell (c2));
|
||||
i2.set_targets (t);
|
||||
|
||||
x = collect2(i2, layout);
|
||||
EXPECT_EQ (x,
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 55000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 75000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,0\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 95000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 30000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 120000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 120000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 120000,0"
|
||||
);
|
||||
|
||||
std::set<db::cell_index_type> sc;
|
||||
sc.insert (layout.cell_by_name ("CHILD_CELL_3").second);
|
||||
i2.unselect_cells (sc);
|
||||
|
||||
x = collect2(i2, layout);
|
||||
EXPECT_EQ (x,
|
||||
"CHILD_CELL_3_1_1@r0 *1 120000,20000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 120000,40000\n"
|
||||
"CHILD_CELL_3_1_1@r0 *1 120000,0"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2081,6 +2081,24 @@ TEST(50_PropertiesFlat)
|
|||
EXPECT_EQ (s.at_end (), true);
|
||||
}
|
||||
|
||||
// "+" operator with properties (issue #1373)
|
||||
TEST(50b_PropertiesFlat)
|
||||
{
|
||||
db::Region r, rr;
|
||||
|
||||
r.insert (db::Box (0, 0, 10, 20));
|
||||
rr.insert (db::Box (0, 0, 100, 200));
|
||||
rr.insert (db::BoxWithProperties (db::Box (1, 2, 101, 202), 1));
|
||||
|
||||
EXPECT_EQ ((db::Region () + rr).to_string (), "(0,0;0,200;100,200;100,0);(1,2;1,202;101,202;101,2)");
|
||||
EXPECT_EQ ((rr + db::Region ()).to_string (), "(0,0;0,200;100,200;100,0);(1,2;1,202;101,202;101,2)");
|
||||
EXPECT_EQ ((r + rr).to_string (), "(0,0;0,20;10,20;10,0);(0,0;0,200;100,200;100,0);(1,2;1,202;101,202;101,2)");
|
||||
|
||||
r += rr;
|
||||
|
||||
EXPECT_EQ (r.to_string (), "(0,0;0,20;10,20;10,0);(0,0;0,200;100,200;100,0);(1,2;1,202;101,202;101,2)");
|
||||
}
|
||||
|
||||
TEST(51_PropertiesFlatFromLayout)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
|
|||
|
|
@ -1925,6 +1925,51 @@ TEST(7)
|
|||
}
|
||||
}
|
||||
|
||||
// copy, move, clear with shape types
|
||||
TEST(8)
|
||||
{
|
||||
db::Manager m (true);
|
||||
|
||||
db::Layout layout (true, &m);
|
||||
unsigned int lindex1 = layout.insert_layer ();
|
||||
unsigned int lindex2 = layout.insert_layer ();
|
||||
|
||||
db::Cell &topcell = layout.cell (layout.add_cell ("TOP"));
|
||||
|
||||
topcell.shapes (lindex1).insert (db::Box (1, 2, 3, 4));
|
||||
topcell.shapes (lindex1).insert (db::Polygon (db::Box (1, 2, 3, 4)));
|
||||
|
||||
{
|
||||
db::Transaction trans (&m, "T1");
|
||||
topcell.shapes (lindex2).insert (topcell.shapes (lindex1));
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "polygon (1,2;1,4;3,4;3,2) #0\nbox (1,2;3,4) #0\n");
|
||||
}
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "");
|
||||
|
||||
{
|
||||
db::Transaction trans (&m, "T1");
|
||||
topcell.shapes (lindex2).insert (topcell.shapes (lindex1), db::ShapeIterator::Boxes);
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "box (1,2;3,4) #0\n");
|
||||
}
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "");
|
||||
|
||||
topcell.shapes (lindex2).insert (topcell.shapes (lindex1));
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "polygon (1,2;1,4;3,4;3,2) #0\nbox (1,2;3,4) #0\n");
|
||||
|
||||
{
|
||||
db::Transaction trans (&m, "T1");
|
||||
topcell.shapes (lindex2).clear (db::ShapeIterator::Polygons);
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), "box (1,2;3,4) #0\n");
|
||||
}
|
||||
|
||||
m.undo ();
|
||||
EXPECT_EQ (shapes_to_string (_this, topcell.shapes (lindex2)), shapes_to_string (_this, topcell.shapes (lindex1)));
|
||||
}
|
||||
|
||||
TEST(10A)
|
||||
{
|
||||
if (db::default_editable_mode ()) {
|
||||
|
|
|
|||
|
|
@ -1182,6 +1182,36 @@ See <a href="/about/drc_ref_netter.xml#netlist">Netter#netlist</a> for a descrip
|
|||
<p>
|
||||
See <a href="/about/drc_ref_netter.xml">Netter</a> for more details
|
||||
</p>
|
||||
<a name="new_report"/><h2>"new_report" - Creates a new report database object for use in "output"</h2>
|
||||
<keyword name="new_report"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>new_report(description [, filename [, cellname ] ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method creates an independent report object. This object
|
||||
can be used in "output" to send a layer to a different report than
|
||||
the default report or target.
|
||||
</p><p>
|
||||
Arguments are the same than for <a href="/about/drc_ref_global.xml#report">report</a>.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_layer.xml#output">Layer#output</a> for details about this feature.
|
||||
</p>
|
||||
<a name="new_target"/><h2>"new_target" - Creates a new layout target object for use in "output"</h2>
|
||||
<keyword name="new_target"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>new_target(what [, cellname])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method creates an independent target object. This object
|
||||
can be used in "output" to send a layer to a different layout file than
|
||||
the default report or target.
|
||||
</p><p>
|
||||
Arguments are the same than for <a href="/about/drc_ref_global.xml#target">target</a>.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_layer.xml#output">Layer#output</a> for details about this feature.
|
||||
</p>
|
||||
<a name="no_borders"/><h2>"no_borders" - Reset the tile borders</h2>
|
||||
<keyword name="no_borders"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1413,6 +1443,21 @@ See <a href="/about/drc_ref_source.xml#polygons">Source#polygons</a> for a descr
|
|||
The primary input of the universal DRC function is the layer the <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> function
|
||||
is called on.
|
||||
</p>
|
||||
<a name="profile"/><h2>"profile" - Profiles the script and provides a runtime + memory statistics</h2>
|
||||
<keyword name="profile"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>profile</tt></li>
|
||||
<li><tt>profile(n)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
Turns profiling on or off (default). In profiling mode, the
|
||||
system will collect statistics about rules executed, their execution time
|
||||
and memory information. The argument specifies how many operations to
|
||||
print at the end of the run. Without an argument, all operations are
|
||||
printed. Passing "false" for the argument will disable profiling. This is the
|
||||
default.
|
||||
</p>
|
||||
<a name="props_copy"/><h2>"props_copy" - Specifies "copy properties" on operations supporting user properties constraints</h2>
|
||||
<keyword name="props_copy"/>
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -2217,6 +2217,26 @@ a single <class_doc href="LayerInfo">LayerInfo</class_doc> object.
|
|||
</p><p>
|
||||
See <a href="/about/drc_ref_global.xml#report">report</a> and <a href="/about/drc_ref_global.xml#target">target</a> on how to configure output to a target layout
|
||||
or report database.
|
||||
</p><p>
|
||||
See also <a href="/about/drc_ref_global.xml#new_target">new_target</a> and <a href="/about/drc_ref_global.xml#new_report">new_report</a> on how to create additional
|
||||
targets for output. This allows saving certain layers to different files than
|
||||
the standard target or report. To do so, create a new target or report using one
|
||||
of these functions and pass that object to the corresponding "output" call as
|
||||
an additional argument.
|
||||
</p><p>
|
||||
Example:
|
||||
</p><p>
|
||||
<pre>
|
||||
check1 = ...
|
||||
check2 = ...
|
||||
check3 = ...
|
||||
|
||||
second_report = new_report("Only for check2", "check2.lyrdb")
|
||||
|
||||
check1.output("Check 1")
|
||||
check2.output("Check 2", second_report)
|
||||
check3.output("Check 3")
|
||||
</pre>
|
||||
</p>
|
||||
<a name="outside"/><h2>"outside" - Selects edges or polygons of self which are outside edges or polygons from the other layer</h2>
|
||||
<keyword name="outside"/>
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ l.output("OUT")
|
|||
l.output(17, 0, "OUT")</pre>
|
||||
|
||||
<p>
|
||||
Output can be sent to other layouts using the "target" function:
|
||||
Output can be sent to other layouts using the <a href="/about/drc_ref_global.xml#target">target</a> function:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
|
@ -196,7 +196,7 @@ target("@2")
|
|||
target("out.gds", "OUT_TOP")</pre>
|
||||
|
||||
<p>
|
||||
Output can also be sent to a report database:
|
||||
Output can also be sent to a report database using the <a href="/about/drc_ref_global.xml#report">report</a> function:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
|
@ -234,6 +234,38 @@ l.output("check1", "The first check")</pre>
|
|||
unpredictable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is possible to open "side" reports and targets and send layers to these
|
||||
outputs without closing the default output.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To open a "side report", use <a href="/about/drc_ref_global.xml#new_report">new_report</a>
|
||||
in the same way you use "report". Instead of switching the output, this function will return a
|
||||
new report object that can be included in the argument list of "output"
|
||||
for the layer that is to be sent to that side report:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
# opens a new side report
|
||||
side_report = new_report("Another report")
|
||||
...
|
||||
# Send data from layer l to new category "check1" to the side report
|
||||
l.output(side_report, "check1", "The first check")</pre>
|
||||
|
||||
<p>
|
||||
In the same way, "side targets" can be opened using <a href="/about/drc_ref_global.xml#new_target">new_target</a>.
|
||||
Such side targets open a way to write certain layers to other layout files.
|
||||
This is very handy for debugging:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
# opens a new side target for debugging
|
||||
debug_out = new_target("debug.gds")
|
||||
...
|
||||
# Send data from layer l to the debug output, layer 100/0
|
||||
l.output(debug_out, 100, 0)</pre>
|
||||
|
||||
|
||||
<h2>Dimension specifications</h2>
|
||||
|
||||
|
|
@ -710,12 +742,12 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
layer = input(1, 0)
|
||||
layer.raw.sized(0.1).output(100, 0)
|
||||
layer = input(1, 0)
|
||||
layer.raw.sized(0.1).output(100, 0)
|
||||
|
||||
# this check will now be done on a raw layer, since the
|
||||
# previous raw call was putting the layer into raw mode
|
||||
layer.width(0.2).ouput(101, 0)</pre>
|
||||
# this check will now be done on a raw layer, since the
|
||||
# previous raw call was putting the layer into raw mode
|
||||
layer.width(0.2).ouput(101, 0)</pre>
|
||||
|
||||
<p>
|
||||
The following two images show the effect of raw and clean mode:
|
||||
|
|
@ -792,20 +824,18 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
drc_w = input(1, 0).width(0.2)
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
drc_w = input(1, 0).width(0.2)
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
can be written as:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
drc_w = input(1, 0).drc(width < 0.2)
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
drc_w = input(1, 0).drc(width < 0.2)
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
The <a href="/about/drc_ref_layer.xml#drc">drc</a> method is the "universal DRC" method.
|
||||
|
|
@ -845,12 +875,11 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
drc_sep = l1.drc(separation(l2) <= 0.5)
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
drc_sep = l1.drc(separation(l2) <= 0.5)
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
Options are also specified together with the measurement and follow the same notation
|
||||
|
|
@ -858,10 +887,9 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
drc_w = input(1, 0).drc(width(projection) < 0.2)
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
drc_w = input(1, 0).drc(width(projection) < 0.2)
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
However, the universal DRC is much more than a convenient way to write checks:
|
||||
|
|
@ -879,10 +907,9 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
drc_ws = input(1, 0).drc((width < 0.2) & (space < 0.3))
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
drc_ws = input(1, 0).drc((width < 0.2) & (space < 0.3))
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
The boolean AND is computed between the edges on the primary shape and returns the
|
||||
|
|
@ -891,12 +918,11 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
drc_ws1 = input(1, 0).width(0.2).edges
|
||||
drc_ws2 = input(1, 0).space(0.3).edges
|
||||
drc_ws = drc_ws1 & drc_ws2
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
drc_ws1 = input(1, 0).width(0.2).edges
|
||||
drc_ws2 = input(1, 0).space(0.3).edges
|
||||
drc_ws = drc_ws1 & drc_ws2
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
The reason is that performing the boolean computation in the local loop can be
|
||||
|
|
@ -933,11 +959,10 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
...
|
||||
drc_w = input(1, 0).width(0.2)
|
||||
log("Number of width violations: #{drc_w.data.size}")
|
||||
...
|
||||
</pre>
|
||||
...
|
||||
drc_w = input(1, 0).width(0.2)
|
||||
log("Number of width violations: #{drc_w.data.size}")
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
The <a href="/about/drc_ref_global.xml#error">error</a> function can be used to output error messages
|
||||
|
|
@ -946,11 +971,23 @@ overlaps = layer.size(0.2).raw.merged(2)</pre>
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
log_file("drc_log.txt")
|
||||
verbose(true)
|
||||
info("This message will be sent to the log file")
|
||||
...
|
||||
</pre>
|
||||
log_file("drc_log.txt")
|
||||
verbose(true)
|
||||
info("This message will be sent to the log file")
|
||||
...</pre>
|
||||
|
||||
<p>
|
||||
The <a href="/about/drc_ref_global.xml#profile">profile</a> function will collect profiling
|
||||
information during the DRC run. At the end of the script, the operations are printed to the log
|
||||
output, sorted by their CPU time and approximate memory footprint. "profile" can be given a
|
||||
numerical argument indicating the number of operations to print. Lower-ranking operations are
|
||||
skipped in that case. By default, all operations are printed.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
# enables profiling
|
||||
profile
|
||||
...</pre>
|
||||
|
||||
|
||||
<h2>The tiling option</h2>
|
||||
|
|
@ -1003,8 +1040,7 @@ threads(4)
|
|||
# Disable tiling
|
||||
flat
|
||||
|
||||
... non-tiled operations ...
|
||||
</pre>
|
||||
... non-tiled operations ...</pre>
|
||||
|
||||
<p>
|
||||
Some operations implicitly specify a tile border. If the tile border is known (see length example above), explicit borders
|
||||
|
|
|
|||
|
|
@ -155,17 +155,12 @@ X$2 VSS IN OUT SUBSTRATE NMOS PARAMS: L=0.25 W=0.9 AS=0.405 AD=0.405 PS=2.7
|
|||
|
||||
<p>
|
||||
Currently SPICE is understood with some limitations:
|
||||
Only a subset of elements is implemented by default. These are
|
||||
"M" (gives "MOS4" device classes), "Q" (gives BJT3 or BJT4 device
|
||||
classes), "R" (gives Resistor device classes), "C" (gives
|
||||
Capacitor device classes) and "D" (gives diode device classes).
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Parametrized circuits are not permitted except for device subcircuits
|
||||
(with a delegate)</li>
|
||||
<li>Only a subset of elements is implemented by default. These are
|
||||
"M" (gives "MOS4" device classes), "Q" (gives BJT3 or BJT4 device
|
||||
classes), "R" (gives Resistor device classes), "C" (gives
|
||||
Capacitor device classes) and "D" (gives diode device classes).</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
As for the SPICE reader, a delegate can be provided to customize the reader.
|
||||
For doing so, subclass the <class_doc href="NetlistSpiceReaderDelegate"/>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,125 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
class OutputChannel
|
||||
def initialize(engine)
|
||||
@engine = engine
|
||||
end
|
||||
def is_rdb?
|
||||
false
|
||||
end
|
||||
def cellname=(cellname)
|
||||
# reimplement
|
||||
end
|
||||
def cell
|
||||
# reimplement
|
||||
end
|
||||
def write
|
||||
# reimplement
|
||||
end
|
||||
def finish(final)
|
||||
# reimplement
|
||||
end
|
||||
def write
|
||||
# reimplement
|
||||
end
|
||||
def layout
|
||||
nil
|
||||
end
|
||||
def rdb
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
class LayoutOutputChannel < OutputChannel
|
||||
|
||||
def initialize(engine, layout, cell, file_name)
|
||||
super(engine)
|
||||
@layout = layout
|
||||
@cell = cell
|
||||
@file_name = file_name
|
||||
end
|
||||
|
||||
def cellname=(cellname)
|
||||
@cell = @layout.cell(cellname) || @layout.create_cell(cellname)
|
||||
end
|
||||
|
||||
def is_rdb?
|
||||
false
|
||||
end
|
||||
|
||||
def finish(final, view)
|
||||
write
|
||||
end
|
||||
|
||||
def write
|
||||
if @file_name
|
||||
opt = RBA::SaveLayoutOptions::new
|
||||
gzip = opt.set_format_from_filename(@file_name)
|
||||
@engine.info("Writing layout file: #{@file_name} ..")
|
||||
@layout.write(@file_name, gzip, opt)
|
||||
end
|
||||
end
|
||||
|
||||
def layout
|
||||
@layout
|
||||
end
|
||||
|
||||
def cell
|
||||
@cell
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class RDBOutputChannel < OutputChannel
|
||||
|
||||
def initialize(engine, rdb, rdb_index, cellname, file_name)
|
||||
super(engine)
|
||||
@rdb = rdb
|
||||
@rdb_index = rdb_index
|
||||
@cell = cellname && rdb.create_cell(cellname)
|
||||
@file_name = file_name
|
||||
end
|
||||
|
||||
def cellname=(cellname)
|
||||
@cell = nil
|
||||
@rdb.each_cell do |c|
|
||||
if c.name == cellname
|
||||
@cell = c
|
||||
end
|
||||
end
|
||||
@cell ||= @rdb.create_cell(cellname)
|
||||
end
|
||||
|
||||
def is_rdb?
|
||||
true
|
||||
end
|
||||
|
||||
def finish(final, view)
|
||||
write
|
||||
if final && view
|
||||
view.show_rdb(@rdb_index, view.active_cellview_index)
|
||||
end
|
||||
end
|
||||
|
||||
def write
|
||||
if @file_name
|
||||
rdb_file = @engine._make_path(@file_name)
|
||||
@engine.info("Writing report database: #{rdb_file} ..")
|
||||
@rdb.save(rdb_file)
|
||||
end
|
||||
end
|
||||
|
||||
def rdb
|
||||
@rdb
|
||||
end
|
||||
|
||||
def cell
|
||||
@cell
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# The DRC engine
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -40,11 +159,9 @@ module DRC
|
|||
@def_source = nil
|
||||
@dbu_read = false
|
||||
use_dbu(@def_layout && @def_layout.dbu)
|
||||
@output_layout = nil
|
||||
@output_rdb = nil
|
||||
@output_rdb_file = nil
|
||||
@output_rdb_cell = nil
|
||||
@show_l2ndb = nil
|
||||
@def_output = nil
|
||||
@other_outputs = []
|
||||
@output_l2ndb_file = nil
|
||||
@target_netlist_file = nil
|
||||
@target_netlist_format = nil
|
||||
|
|
@ -70,6 +187,9 @@ module DRC
|
|||
dss._destroy
|
||||
|
||||
@verbose = false
|
||||
@profile = false
|
||||
@profile_n = 0
|
||||
@profile_info = {}
|
||||
|
||||
@in_context = nil
|
||||
|
||||
|
|
@ -711,6 +831,26 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name profile
|
||||
# @brief Profiles the script and provides a runtime + memory statistics
|
||||
# @synopsis profile
|
||||
# @synopsis profile(n)
|
||||
# Turns profiling on or off (default). In profiling mode, the
|
||||
# system will collect statistics about rules executed, their execution time
|
||||
# and memory information. The argument specifies how many operations to
|
||||
# print at the end of the run. Without an argument, all operations are
|
||||
# printed. Passing "false" for the argument will disable profiling. This is the
|
||||
# default.
|
||||
|
||||
def profile(n = 0)
|
||||
if !n.is_a?(1.class) && n != nil && n != false
|
||||
raise("Argument to 'profile' must be either an integer number or nil")
|
||||
end
|
||||
@profile = !!n
|
||||
@profile_n = [n || 0, 0].max
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name verbose?
|
||||
# @brief Returns true, if verbose mode is enabled
|
||||
|
|
@ -1340,46 +1480,42 @@ module DRC
|
|||
|
||||
self._context("report") do
|
||||
|
||||
@output_rdb_file = filename
|
||||
# finish what we got so far
|
||||
_finish(false)
|
||||
|
||||
name = filename && File::basename(filename)
|
||||
name ||= "DRC"
|
||||
|
||||
@output_rdb_index = nil
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
if view
|
||||
if self._rdb_index
|
||||
@output_rdb = RBA::ReportDatabase::new("") # reuse existing name
|
||||
@output_rdb_index = view.replace_rdb(self._rdb_index, @output_rdb)
|
||||
else
|
||||
@output_rdb = RBA::ReportDatabase::new(name)
|
||||
@output_rdb_index = view.add_rdb(@output_rdb)
|
||||
end
|
||||
else
|
||||
@output_rdb = RBA::ReportDatabase::new(name)
|
||||
end
|
||||
|
||||
@output_layout = nil
|
||||
@output_cell = nil
|
||||
@output_layout_file = nil
|
||||
|
||||
cn = nil
|
||||
cn ||= @def_cell && @def_cell.name
|
||||
cn ||= source && source.cell_name
|
||||
cn ||= cellname
|
||||
|
||||
cn || raise("No cell name specified - either the source was not specified before 'report' or there is no default source. In the latter case, specify a cell name as the third parameter")
|
||||
|
||||
@output_rdb_cell = @output_rdb.create_cell(cn)
|
||||
@output_rdb.generator = self._generator
|
||||
@output_rdb.top_cell_name = cn
|
||||
@output_rdb.description = description
|
||||
@def_output = nil
|
||||
@def_output = _make_report(description, filename, cellname)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name new_report
|
||||
# @brief Creates a new report database object for use in "output"
|
||||
# @synopsis new_report(description [, filename [, cellname ] ])
|
||||
#
|
||||
# This method creates an independent report object. This object
|
||||
# can be used in "output" to send a layer to a different report than
|
||||
# the default report or target.
|
||||
#
|
||||
# Arguments are the same than for \global#report.
|
||||
#
|
||||
# See \Layer#output for details about this feature.
|
||||
|
||||
def new_report(description, filename = nil, cellname = nil)
|
||||
|
||||
output = nil
|
||||
|
||||
self._context("new_report") do
|
||||
output = _make_report(description, filename, cellname)
|
||||
@other_outputs << output
|
||||
end
|
||||
|
||||
output
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name report_netlist
|
||||
# @brief Specifies an extracted netlist report for output
|
||||
|
|
@ -1456,25 +1592,13 @@ module DRC
|
|||
# finish what we got so far
|
||||
_flush
|
||||
|
||||
if @output_rdb
|
||||
|
||||
cell = nil
|
||||
@output_rdb.each_cell do |c|
|
||||
if c.name == cellname
|
||||
cell = c
|
||||
end
|
||||
if ! @def_output
|
||||
if @def_layout
|
||||
# establish a new default output from the default layout on this occasion
|
||||
@def_output = LayoutOutputChannel::new(self, @def_layout, cellname.to_s, nil)
|
||||
end
|
||||
|
||||
cell ||= @output_rdb.create_cell(cellname)
|
||||
@output_rdb_cell = cell
|
||||
|
||||
else
|
||||
|
||||
@output_layout ||= @def_layout
|
||||
if @output_layout
|
||||
@output_cell = @output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)
|
||||
end
|
||||
|
||||
@def_output.cellname = cellname.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1512,51 +1636,40 @@ module DRC
|
|||
|
||||
# finish what we got so far
|
||||
_finish(false)
|
||||
|
||||
if arg.is_a?(String)
|
||||
|
||||
if arg =~ /^@(\d+|\+)/
|
||||
view = RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
if $1 == "+"
|
||||
n = view.create_layout(true)
|
||||
cellname ||= (@def_cell ? @def_cell.name : "TOP")
|
||||
else
|
||||
n = $1.to_i - 1
|
||||
end
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
cv = view.cellview(n)
|
||||
cv.is_valid? || raise("Invalid layout @#{n + 1}")
|
||||
@output_layout = cv.layout
|
||||
@output_cell = cellname ? (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s)) : cv.cell
|
||||
cv.cell = @output_cell
|
||||
@output_layout_file = nil
|
||||
else
|
||||
@output_layout = RBA::Layout::new
|
||||
@output_cell = cellname && @output_layout.create_cell(cellname.to_s)
|
||||
@output_layout_file = arg
|
||||
end
|
||||
|
||||
elsif arg.is_a?(RBA::Layout)
|
||||
|
||||
@output_layout = arg
|
||||
@output_cell = cellname && (@output_layout.cell(cellname.to_s) || @output_layout.create_cell(cellname.to_s))
|
||||
@output_layout_file = nil
|
||||
|
||||
elsif arg.is_a?(RBA::Cell)
|
||||
|
||||
@output_layout = arg.layout
|
||||
@output_cell = arg
|
||||
@output_layout_file = nil
|
||||
|
||||
else
|
||||
raise("Invalid argument '" + arg.inspect + "'")
|
||||
end
|
||||
|
||||
@def_output = nil
|
||||
@def_output = _make_target(arg, cellname)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
# %DRC%
|
||||
# @name new_target
|
||||
# @brief Creates a new layout target object for use in "output"
|
||||
# @synopsis new_target(what [, cellname])
|
||||
#
|
||||
# This method creates an independent target object. This object
|
||||
# can be used in "output" to send a layer to a different layout file than
|
||||
# the default report or target.
|
||||
#
|
||||
# Arguments are the same than for \global#target.
|
||||
#
|
||||
# See \Layer#output for details about this feature.
|
||||
|
||||
def new_target(arg, cellname = nil)
|
||||
|
||||
output = nil
|
||||
|
||||
self._context("new_target") do
|
||||
output = _make_target(arg, cellname)
|
||||
@other_outputs << output
|
||||
end
|
||||
|
||||
output
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name box
|
||||
# @brief Creates a box object
|
||||
|
|
@ -2267,13 +2380,16 @@ CODE
|
|||
end
|
||||
|
||||
t = RBA::Timer::new
|
||||
|
||||
t.start
|
||||
self._process_events
|
||||
if @force_gc || Time::now - @time > 0.5
|
||||
if @force_gc || Time::now - @time > 0.5 || @profile
|
||||
GC.start # force a garbage collection before the operation to free unused memory
|
||||
@time = Time::now
|
||||
end
|
||||
mem_before = RBA::Timer::memory_size
|
||||
res = yield
|
||||
mem_after = RBA::Timer::memory_size
|
||||
t.stop
|
||||
|
||||
begin
|
||||
|
|
@ -2283,15 +2399,25 @@ CODE
|
|||
# Report result statistics
|
||||
_result_info(res, 1)
|
||||
|
||||
mem = RBA::Timer::memory_size
|
||||
if mem > 0
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1)
|
||||
if mem_after > 0
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem_after/(1024*1024))}M", 1)
|
||||
else
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if @profile
|
||||
|
||||
# calls, sys time (in sec), user time (in sec), memory added (in bytes)
|
||||
info = (@profile_info[desc] ||= [ 0, 0.0, 0.0, 0 ])
|
||||
info[0] += 1
|
||||
info[1] += t.sys
|
||||
info[2] += t.user
|
||||
info[3] += mem_after - mem_before
|
||||
|
||||
end
|
||||
|
||||
ensure
|
||||
|
||||
# disable progress again
|
||||
|
|
@ -2477,8 +2603,8 @@ CODE
|
|||
end
|
||||
|
||||
def _output_layout
|
||||
if @output_layout
|
||||
output = @output_layout
|
||||
if @def_output && @def_output.layout
|
||||
output = @def_output.layout
|
||||
else
|
||||
output = @def_layout
|
||||
output || raise("No output layout specified")
|
||||
|
|
@ -2487,19 +2613,79 @@ CODE
|
|||
end
|
||||
|
||||
def _output_cell
|
||||
if @output_layout
|
||||
if @output_cell
|
||||
output_cell = @output_cell
|
||||
if @def_output && @def_output.layout
|
||||
if @def_output.cell
|
||||
output_cell = @def_output.cell
|
||||
elsif @def_cell
|
||||
output_cell = @output_layout.cell(@def_cell.name) || @output_layout.create_cell(@def_cell.name)
|
||||
output_layout = @def_output.layout
|
||||
output_cell = output_layout.cell(@def_cell.name) || output_layout.create_cell(@def_cell.name)
|
||||
end
|
||||
output_cell || raise("No output cell specified (see 'target' instruction)")
|
||||
else
|
||||
output_cell = @output_cell || @def_cell
|
||||
output_cell = @def_cell
|
||||
output_cell || raise("No output cell specified")
|
||||
end
|
||||
output_cell
|
||||
end
|
||||
|
||||
def _dump_profile
|
||||
|
||||
if @profile_info.empty?
|
||||
return
|
||||
end
|
||||
|
||||
desc_title = "Operation"
|
||||
calls_title = "# calls"
|
||||
time_title = "Time (s)"
|
||||
memory_title = "Memory (k)"
|
||||
titles = [ desc_title, calls_title, time_title, memory_title ]
|
||||
|
||||
max_len_desc = [ @profile_info.keys.collect { |s| s.size }.max, desc_title.size ].max
|
||||
max_len_calls = [ @profile_info.values.collect { |v| v[0].to_s.size }.max, calls_title.size ].max
|
||||
max_len_time = [ @profile_info.values.collect { |v| ("%.3f" % (v[1] + v[2])).to_s.size }.max, time_title.size ].max
|
||||
max_len_mem = [ @profile_info.values.collect { |v| v[3].to_s.size }.max, memory_title.size ].max
|
||||
|
||||
fmt = "%-" + max_len_desc.to_s + "s " +
|
||||
"%-" + max_len_calls.to_s + "d " +
|
||||
"%-" + max_len_time.to_s + ".3f " +
|
||||
"%-" + max_len_mem.to_s + ".0f"
|
||||
|
||||
fmt_title = "%-" + max_len_desc.to_s + "s " +
|
||||
"%-" + max_len_calls.to_s + "s " +
|
||||
"%-" + max_len_time.to_s + "s " +
|
||||
"%-" + max_len_mem.to_s + "s"
|
||||
|
||||
pi = @profile_info.keys.collect { |s| [s] + @profile_info[s] }.collect do |desc,calls,sys_time,user_time,memory|
|
||||
[ desc, calls, sys_time + user_time, memory.to_f / 1024.0 ]
|
||||
end
|
||||
|
||||
self.log("")
|
||||
self.log("Operations by execution time\n")
|
||||
self.log(fmt_title % titles)
|
||||
n = 1
|
||||
pi.sort { |a,b| b[2] <=> a[2] }.each do |info|
|
||||
self.log(fmt % info)
|
||||
n += 1
|
||||
if @profile_n > 0 && n > @profile_n
|
||||
self.log("... (%d entries skipped)" % (pi.size - @profile_n))
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
self.log("")
|
||||
self.log("Operations by memory adder\n")
|
||||
self.log(fmt_title % titles)
|
||||
n = 1
|
||||
pi.sort { |a,b| b[3] <=> a[3] }.each do |info|
|
||||
self.log(fmt % info)
|
||||
n += 1
|
||||
if @profile_n > 0 && n > @profile_n
|
||||
self.log("... (%d entries skipped)" % (pi.size - @profile_n))
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def _start(job_description)
|
||||
|
||||
|
|
@ -2528,39 +2714,32 @@ CODE
|
|||
begin
|
||||
|
||||
_flush
|
||||
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
|
||||
# save the report database if requested
|
||||
if @output_rdb_file && final
|
||||
rdb_file = _make_path(@output_rdb_file)
|
||||
info("Writing report database: #{rdb_file} ..")
|
||||
@output_rdb.save(rdb_file)
|
||||
@def_output && @def_output.finish(final, view)
|
||||
|
||||
if final
|
||||
@other_outputs.each do |output|
|
||||
output.finish(final, view)
|
||||
end
|
||||
end
|
||||
if @output_rdb && final && view
|
||||
view.show_rdb(@output_rdb_index, view.active_cellview_index)
|
||||
end
|
||||
|
||||
# save the output file if requested
|
||||
if @output_layout && @output_layout_file
|
||||
opt = RBA::SaveLayoutOptions::new
|
||||
gzip = opt.set_format_from_filename(@output_layout_file)
|
||||
info("Writing layout file: #{@output_layout_file} ..")
|
||||
@output_layout.write(@output_layout_file, gzip, opt)
|
||||
|
||||
# dump the profile information
|
||||
if @profile && final
|
||||
_dump_profile
|
||||
end
|
||||
|
||||
# create the new layers as visual layers if necessary
|
||||
if view
|
||||
|
||||
output = @output_layout || @def_layout
|
||||
output = ( @def_output && @def_output.layout ) || @def_layout
|
||||
cv_index = nil
|
||||
view.cellviews.times do |cvi|
|
||||
view.cellview(cvi).layout == output && cv_index = cvi
|
||||
end
|
||||
if cv_index
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
|
||||
# clear selection
|
||||
view.cancel
|
||||
|
||||
|
|
@ -2634,13 +2813,10 @@ CODE
|
|||
ensure
|
||||
|
||||
@output_layers = []
|
||||
@output_layout = nil
|
||||
@output_layout_file = nil
|
||||
@output_cell = nil
|
||||
@output_rdb_file = nil
|
||||
@output_rdb_cell = nil
|
||||
@output_rdb = nil
|
||||
@output_rdb_index = nil
|
||||
@def_output = nil
|
||||
if final
|
||||
@other_outputs = []
|
||||
end
|
||||
@show_l2ndb = nil
|
||||
@output_l2ndb_file = nil
|
||||
|
||||
|
|
@ -2933,21 +3109,36 @@ CODE
|
|||
|
||||
def _output(data, *args)
|
||||
|
||||
if @output_rdb
|
||||
channel = args.find { |a| a.is_a?(OutputChannel) }
|
||||
if ! channel
|
||||
if ! @def_output
|
||||
@def_output = LayoutOutputChannel::new(self, self._output_layout, self._output_cell, nil)
|
||||
end
|
||||
channel = @def_output
|
||||
end
|
||||
|
||||
args = args.select { |a| !a.is_a?(OutputChannel) }
|
||||
|
||||
if channel.rdb
|
||||
|
||||
if args.size < 1
|
||||
raise("Invalid number of arguments - category name and optional description expected")
|
||||
end
|
||||
|
||||
cat = @output_rdb.create_category(args[0].to_s)
|
||||
output_rdb = channel.rdb
|
||||
output_cell = channel.cell
|
||||
|
||||
cat = output_rdb.create_category(args[0].to_s)
|
||||
args[1] && cat.description = args[1]
|
||||
|
||||
cat.scan_collection(@output_rdb_cell, RBA::CplxTrans::new(self.dbu), data)
|
||||
cat.scan_collection(output_cell, RBA::CplxTrans::new(self.dbu), data)
|
||||
|
||||
else
|
||||
end
|
||||
|
||||
output = self._output_layout
|
||||
output_cell = self._output_cell
|
||||
if channel.layout
|
||||
|
||||
output = channel.layout
|
||||
output_cell = channel.cell
|
||||
|
||||
info = nil
|
||||
if args.size == 1
|
||||
|
|
@ -2977,14 +3168,16 @@ CODE
|
|||
|
||||
begin
|
||||
|
||||
if !@used_output_layers[li]
|
||||
@output_layers.push(li)
|
||||
# Note: to avoid issues with output onto the input layer, we
|
||||
# output to a temp layer and later swap both. The simple implementation
|
||||
# did a clear here and the effect of that was that the data potentially
|
||||
# got invalidated.
|
||||
tmp = output.insert_layer(RBA::LayerInfo::new)
|
||||
@used_output_layers[li] = true
|
||||
if channel == @def_output
|
||||
if !@used_output_layers[li]
|
||||
@output_layers.push(li)
|
||||
# Note: to avoid issues with output onto the input layer, we
|
||||
# output to a temp layer and later swap both. The simple implementation
|
||||
# did a clear here and the effect of that was that the data potentially
|
||||
# got invalidated.
|
||||
tmp = output.insert_layer(RBA::LayerInfo::new)
|
||||
@used_output_layers[li] = true
|
||||
end
|
||||
end
|
||||
|
||||
# insert the data into the output layer
|
||||
|
|
@ -3020,7 +3213,111 @@ CODE
|
|||
@layout_sources[name] = src
|
||||
src
|
||||
end
|
||||
|
||||
def _make_report(description, filename, cellname)
|
||||
|
||||
output_rdb_file = filename
|
||||
|
||||
name = filename && File::basename(filename)
|
||||
name ||= "DRC"
|
||||
|
||||
output_rdb_index = nil
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
if view
|
||||
if self._rdb_index
|
||||
output_rdb = RBA::ReportDatabase::new("") # reuse existing name
|
||||
output_rdb_index = view.replace_rdb(self._rdb_index, output_rdb)
|
||||
else
|
||||
output_rdb = RBA::ReportDatabase::new(name)
|
||||
output_rdb_index = view.add_rdb(output_rdb)
|
||||
end
|
||||
else
|
||||
output_rdb = RBA::ReportDatabase::new(name)
|
||||
end
|
||||
|
||||
cn = cellname && cellname.to_s
|
||||
cn ||= @def_cell && @def_cell.name
|
||||
cn ||= source && source.cell_name
|
||||
|
||||
cn || raise("No cell name specified - either the source was not specified before 'report' or there is no default source. In the latter case, specify a cell name as the third parameter")
|
||||
|
||||
output_rdb.generator = self._generator
|
||||
output_rdb.top_cell_name = cn
|
||||
output_rdb.description = description
|
||||
|
||||
RDBOutputChannel::new(self, output_rdb, output_rdb_index, cn, output_rdb_file)
|
||||
|
||||
end
|
||||
|
||||
def _make_target(arg, cellname = nil)
|
||||
|
||||
if arg.is_a?(String)
|
||||
|
||||
if arg =~ /^@(\d+|\+)/
|
||||
|
||||
view = RBA::LayoutView::current
|
||||
view || raise("No view open")
|
||||
if $1 == "+"
|
||||
n = view.create_layout(true)
|
||||
cellname ||= (@def_cell ? @def_cell.name : "TOP")
|
||||
else
|
||||
n = $1.to_i - 1
|
||||
end
|
||||
|
||||
(n >= 0 && view.cellviews > n) || raise("Invalid layout index @#{n + 1}")
|
||||
|
||||
cv = view.cellview(n)
|
||||
cv.is_valid? || raise("Invalid layout @#{n + 1}")
|
||||
|
||||
output_layout = cv.layout
|
||||
output_cell = cellname ? (output_layout.cell(cellname.to_s) || output_layout.create_cell(cellname.to_s)) : cv.cell
|
||||
cv.cell = output_cell
|
||||
output_layout_file = nil
|
||||
|
||||
else
|
||||
|
||||
cn = cellname && cellname.to_s
|
||||
cn ||= @def_cell && @def_cell.name
|
||||
cn ||= @def_source && @def_source.cell_obj && @def_source.cell_obj.name
|
||||
|
||||
cn || raise("No cell name specified - either the source was not specified before 'report' or there is no default source. In the latter case, specify a cell name as the third parameter")
|
||||
|
||||
output_layout = RBA::Layout::new
|
||||
output_cell = output_layout.create_cell(cn)
|
||||
output_layout_file = arg
|
||||
|
||||
end
|
||||
|
||||
elsif arg.is_a?(RBA::Layout)
|
||||
|
||||
output_layout = arg
|
||||
|
||||
output_cell = cellname && (output_layout.cell(cellname.to_s) || output_layout.create_cell(cellname.to_s))
|
||||
if ! output_cell
|
||||
begin
|
||||
output_cell = output_layout.top_cell
|
||||
rescue
|
||||
raise("No cell name specified and the layout does not have a unique top cell - specify the name of the top cell to write the output to")
|
||||
end
|
||||
end
|
||||
|
||||
output_layout_file = nil
|
||||
|
||||
elsif arg.is_a?(RBA::Cell)
|
||||
|
||||
output_layout = arg.layout
|
||||
output_cell = arg
|
||||
output_layout_file = nil
|
||||
|
||||
else
|
||||
raise("Invalid argument '" + arg.inspect + "'")
|
||||
end
|
||||
|
||||
output = LayoutOutputChannel::new(self, output_layout, output_cell, output_layout_file)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2630,7 +2630,7 @@ CODE
|
|||
# @brief Returns the intersection points of intersecting edge segments for two edge collections
|
||||
# @synopsis layer.intersections(edges)
|
||||
# This operation is similar to the "&" operator, but it does also report intersection points
|
||||
# between non-colinear, but intersection edges. Such points are reported as point-like,
|
||||
# between non-colinear, but intersecting edges. Such points are reported as point-like,
|
||||
# degenerated edge objects.
|
||||
#
|
||||
# This method is available for edge layers. The argument must be an edge layer.
|
||||
|
|
@ -5007,6 +5007,26 @@ CODE
|
|||
#
|
||||
# See \global#report and \global#target on how to configure output to a target layout
|
||||
# or report database.
|
||||
#
|
||||
# See also \global#new_target and \global#new_report on how to create additional
|
||||
# targets for output. This allows saving certain layers to different files than
|
||||
# the standard target or report. To do so, create a new target or report using one
|
||||
# of these functions and pass that object to the corresponding "output" call as
|
||||
# an additional argument.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# @code
|
||||
# check1 = ...
|
||||
# check2 = ...
|
||||
# check3 = ...
|
||||
#
|
||||
# second_report = new_report("Only for check2", "check2.lyrdb")
|
||||
#
|
||||
# check1.output("Check 1")
|
||||
# check2.output("Check 2", second_report)
|
||||
# check3.output("Check 3")
|
||||
# @/code
|
||||
|
||||
def output(*args)
|
||||
@engine._context("output") do
|
||||
|
|
|
|||
|
|
@ -731,6 +731,75 @@ TEST(14_SwitchingTargets)
|
|||
db::compare_layouts (_this, layout2, au2, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(14b_SideTargetsAndReports)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_14b.drc";
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcSimpleTests_14b.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/drc/drcSimpleTests_au14b.gds";
|
||||
|
||||
std::string au2 = tl::testdata ();
|
||||
au2 += "/drc/drcSimpleTests_au14b_2.gds";
|
||||
|
||||
std::string au_report = tl::testdata ();
|
||||
au_report += "/drc/drcSimpleTests_au14b.lyrdb";
|
||||
|
||||
std::string au_report2 = tl::testdata ();
|
||||
au_report2 += "/drc/drcSimpleTests_au14b_2.lyrdb";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
std::string output2 = this->tmp_file ("tmp2.gds");
|
||||
std::string report = this->tmp_file ("tmp.lydrc");
|
||||
std::string report2 = this->tmp_file ("tmp2.lydrc");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_force_gc = true\n"
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
"$drc_test_target2 = '%s'\n"
|
||||
"$drc_test_report = '%s'\n"
|
||||
"$drc_test_report2 = '%s'\n"
|
||||
, input, output, output2, report, report2)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
|
||||
db::Layout layout2;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output2);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout2);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout2, au2, db::NoNormalization);
|
||||
|
||||
compare_text_files (report, au_report);
|
||||
compare_text_files (report2, au_report2);
|
||||
}
|
||||
|
||||
TEST(15_issue548)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
|
|
|
|||
|
|
@ -427,7 +427,9 @@ MainService::cm_flatten_insts ()
|
|||
|
||||
view ()->cancel_edits ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Flatten instances")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Flatten instances")));
|
||||
}
|
||||
|
||||
std::set<db::Layout *> needs_cleanup;
|
||||
|
||||
|
|
@ -470,7 +472,9 @@ MainService::cm_flatten_insts ()
|
|||
// The selection is no longer valid
|
||||
view ()->clear_selection ();
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -479,7 +483,9 @@ MainService::cm_move_hier_up ()
|
|||
view ()->cancel_edits ();
|
||||
check_no_guiding_shapes ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Move up in hierarchy")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Move up in hierarchy")));
|
||||
}
|
||||
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
|
@ -529,7 +535,9 @@ MainService::cm_move_hier_up ()
|
|||
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -735,7 +743,9 @@ MainService::cm_make_cell_variants ()
|
|||
|
||||
view ()->cancel_edits ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Make cell variants for selection")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Make cell variants for selection")));
|
||||
}
|
||||
|
||||
std::vector<lay::ObjectInstPath> new_selection;
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
|
@ -800,7 +810,7 @@ MainService::cm_make_cell_variants ()
|
|||
if (needs_variant) {
|
||||
|
||||
// need to create a variant: create a new cell
|
||||
db::cell_index_type new_cell_index = layout.add_cell (layout.cell_name (elem.inst_ptr.cell_index ()));
|
||||
db::cell_index_type new_cell_index = layout.add_cell (layout, elem.inst_ptr.cell_index ());
|
||||
|
||||
// prepare a new variant cell
|
||||
db::Cell &new_cell = layout.cell (new_cell_index);
|
||||
|
|
@ -906,7 +916,9 @@ MainService::cm_make_cell_variants ()
|
|||
i0 += n;
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -947,7 +959,9 @@ MainService::cm_resolve_arefs ()
|
|||
|
||||
std::vector<lay::ObjectInstPath> new_selection;
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Resolve array references")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Resolve array references")));
|
||||
}
|
||||
|
||||
for (std::vector<lay::ObjectInstPath>::const_iterator p = insts_to_resolve.begin (); p != insts_to_resolve.end (); ++p) {
|
||||
|
||||
|
|
@ -986,7 +1000,9 @@ MainService::cm_resolve_arefs ()
|
|||
|
||||
inst_service->set_selection (new_selection.begin (), new_selection.end ());
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1041,7 +1057,9 @@ MainService::cm_make_cell ()
|
|||
|
||||
view ()->cancel_edits ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Make cell from selection")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Make cell from selection")));
|
||||
}
|
||||
|
||||
db::cell_index_type target_ci = cv->layout ().add_cell (m_make_cell_name.c_str ());
|
||||
// create target cell
|
||||
|
|
@ -1090,7 +1108,9 @@ MainService::cm_make_cell ()
|
|||
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1106,7 +1126,9 @@ MainService::cm_convert_to_cell ()
|
|||
|
||||
try {
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Convert to static cell")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Convert to static cell")));
|
||||
}
|
||||
|
||||
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||
|
||||
|
|
@ -1158,10 +1180,14 @@ MainService::cm_convert_to_cell ()
|
|||
// The selection might no longer be valid
|
||||
view ()->clear_selection ();
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
|
@ -1265,7 +1291,9 @@ MainService::cm_convert_to_pcell ()
|
|||
|
||||
try {
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Convert to PCell")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Convert to PCell")));
|
||||
}
|
||||
|
||||
std::vector<edt::Service::obj_iterator> to_delete;
|
||||
std::vector<lay::ObjectInstPath> new_selection;
|
||||
|
|
@ -1351,10 +1379,14 @@ MainService::cm_convert_to_pcell ()
|
|||
#endif
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
|
@ -1546,7 +1578,9 @@ MainService::cm_round_corners ()
|
|||
ep.merge (out, primary, 0 /*min_wc*/, true /*resolve holes*/, true /*min coherence*/);
|
||||
|
||||
view ()->cancel_edits ();
|
||||
manager ()->transaction (tl::to_string (tr ("Corner rounding operation on selection")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Corner rounding operation on selection")));
|
||||
}
|
||||
|
||||
// Delete the current selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
|
@ -1586,7 +1620,9 @@ MainService::cm_round_corners ()
|
|||
}
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1672,7 +1708,9 @@ MainService::cm_size ()
|
|||
ep.size (primary, idx, idy, out, 2 /*mode, TODO: make variable*/, true /*resolve holes*/, true /*min coherence*/);
|
||||
|
||||
view ()->cancel_edits ();
|
||||
manager ()->transaction (tl::to_string (tr ("Sizing operation on selection")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Sizing operation on selection")));
|
||||
}
|
||||
|
||||
// Delete the current selection
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
|
@ -1712,7 +1750,9 @@ MainService::cm_size ()
|
|||
}
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1792,7 +1832,9 @@ MainService::boolean_op (int mode)
|
|||
}
|
||||
|
||||
view ()->cancel_edits ();
|
||||
manager ()->transaction (tl::to_string (tr ("Boolean operation on selection")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Boolean operation on selection")));
|
||||
}
|
||||
|
||||
// Delete the current selection
|
||||
// NOTE: we delete only those shapes from the primary layer and keep shapes from other layers.
|
||||
|
|
@ -1835,7 +1877,9 @@ MainService::boolean_op (int mode)
|
|||
}
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1955,7 +1999,9 @@ MainService::cm_align ()
|
|||
if (! prim_box.empty ()) {
|
||||
|
||||
view ()->cancel_edits ();
|
||||
manager ()->transaction (tl::to_string (tr ("Alignment")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Alignment")));
|
||||
}
|
||||
|
||||
// do the alignment
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
|
@ -1996,7 +2042,9 @@ MainService::cm_align ()
|
|||
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -2096,7 +2144,9 @@ MainService::cm_distribute ()
|
|||
|
||||
{
|
||||
view ()->cancel_edits ();
|
||||
manager ()->transaction (tl::to_string (tr ("Distribution")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Distribution")));
|
||||
}
|
||||
|
||||
// do the distribution
|
||||
for (std::vector<edt::Service *>::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
|
||||
|
|
@ -2111,7 +2161,9 @@ MainService::cm_distribute ()
|
|||
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -2151,10 +2203,12 @@ MainService::cm_make_array ()
|
|||
bool has_undo = (m_array_na * m_array_nb < 1000);
|
||||
|
||||
// No undo support currently - the undo buffering is pretty inefficient right now.
|
||||
if (! has_undo) {
|
||||
manager ()->clear ();
|
||||
} else {
|
||||
manager ()->transaction (tl::to_string (tr ("Make array")));
|
||||
if (manager ()) {
|
||||
if (! has_undo) {
|
||||
manager ()->clear ();
|
||||
} else {
|
||||
manager ()->transaction (tl::to_string (tr ("Make array")));
|
||||
}
|
||||
}
|
||||
|
||||
tl::RelativeProgress progress (tl::to_string (tr ("Make array")), (size_t (m_array_na) * size_t (m_array_nb) - 1) * n, 1000);
|
||||
|
|
@ -2221,7 +2275,7 @@ MainService::cm_make_array ()
|
|||
|
||||
}
|
||||
|
||||
if (has_undo) {
|
||||
if (has_undo && manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
}
|
||||
|
|
@ -2383,7 +2437,9 @@ MainService::cm_change_layer ()
|
|||
|
||||
view ()->cancel_edits ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Change layer")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Change layer")));
|
||||
}
|
||||
|
||||
db::Layout &layout = view ()->cellview (cv_index)->layout ();
|
||||
|
||||
|
|
@ -2441,7 +2497,9 @@ MainService::cm_change_layer ()
|
|||
// The selection is no longer valid
|
||||
view ()->clear_selection ();
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Nothing selected to switch layers for")));
|
||||
|
|
|
|||
|
|
@ -243,9 +243,14 @@ insert_point_path (const db::Path &p, const std::set<EdgeWithIndex> &sel, db::Po
|
|||
ctr.push_back (p1);
|
||||
if (! found && sel.find (EdgeWithIndex (db::Edge (p1, p2), n, n + 1, 0)) != sel.end ()) {
|
||||
// project the point onto the edge
|
||||
std::pair <bool, db::Point> projected = db::Edge (p1, p2).projected (ins);
|
||||
db::Edge e (p1, p2);
|
||||
std::pair <bool, db::Point> projected = e.projected (ins);
|
||||
if (projected.first) {
|
||||
ins = projected.second;
|
||||
if (e.is_ortho ()) {
|
||||
// NOTE: for skew edges we use the original point as the projected one usually
|
||||
// is off-grid.
|
||||
ins = projected.second;
|
||||
}
|
||||
ctr.push_back (ins);
|
||||
found = true;
|
||||
}
|
||||
|
|
@ -262,22 +267,28 @@ insert_point_path (const db::Path &p, const std::set<EdgeWithIndex> &sel, db::Po
|
|||
}
|
||||
|
||||
static void
|
||||
remove_redundant_points (std::vector <db::Point> &ctr)
|
||||
remove_redundant_points (std::vector <db::Point> &ctr, bool cyclic)
|
||||
{
|
||||
// compress contour (remove redundant points)
|
||||
// and assign to path
|
||||
|
||||
std::vector<db::Point>::iterator wp = ctr.begin ();
|
||||
std::vector<db::Point>::const_iterator rp = ctr.begin ();
|
||||
db::Point pm1 = *rp;
|
||||
if (wp != ctr.end ()) {
|
||||
++wp;
|
||||
++rp;
|
||||
db::Point pm1;
|
||||
if (rp != ctr.end ()) {
|
||||
if (cyclic) {
|
||||
pm1 = ctr.back ();
|
||||
} else {
|
||||
pm1 = ctr.front ();
|
||||
++wp;
|
||||
++rp;
|
||||
}
|
||||
while (rp != ctr.end ()) {
|
||||
db::Point p0 = *rp;
|
||||
if (p0 != pm1) {
|
||||
*wp++ = p0;
|
||||
}
|
||||
pm1 = p0;
|
||||
++rp;
|
||||
}
|
||||
}
|
||||
|
|
@ -304,7 +315,7 @@ del_points_path (const db::Path &p, const std::set<EdgeWithIndex> &sel)
|
|||
}
|
||||
}
|
||||
|
||||
remove_redundant_points (ctr);
|
||||
remove_redundant_points (ctr, false);
|
||||
new_path.assign (ctr.begin (), ctr.end ());
|
||||
|
||||
return new_path;
|
||||
|
|
@ -357,7 +368,7 @@ modify_path (db::Path &p, const std::map <PointWithIndex, db::Point> &new_points
|
|||
}
|
||||
|
||||
if (compress) {
|
||||
remove_redundant_points (ctr);
|
||||
remove_redundant_points (ctr, false);
|
||||
}
|
||||
|
||||
p.assign (ctr.begin (), ctr.end ());
|
||||
|
|
@ -384,10 +395,14 @@ insert_point_poly (const db::Polygon &p, const std::set<EdgeWithIndex> &sel, db:
|
|||
|
||||
ctr.push_back ((*e).p1 ());
|
||||
if (! found && sel.find (EdgeWithIndex (*e, n, nn, c)) != sel.end ()) {
|
||||
// project the point onto the edge
|
||||
// project the point onto the edge - use the first edge the point projects to
|
||||
std::pair <bool, db::Point> projected = (*e).projected (ins);
|
||||
if (projected.first) {
|
||||
ins = projected.second;
|
||||
if ((*e).is_ortho ()) {
|
||||
// NOTE: for skew edges we use the original point as the projected one usually
|
||||
// is off-grid.
|
||||
ins = projected.second;
|
||||
}
|
||||
ctr.push_back (ins);
|
||||
found = true;
|
||||
}
|
||||
|
|
@ -397,7 +412,7 @@ insert_point_poly (const db::Polygon &p, const std::set<EdgeWithIndex> &sel, db:
|
|||
|
||||
if (found) {
|
||||
|
||||
remove_redundant_points (ctr);
|
||||
remove_redundant_points (ctr, true);
|
||||
|
||||
new_poly = p;
|
||||
if (c == 0) {
|
||||
|
|
@ -433,7 +448,7 @@ del_points_poly (const db::Polygon &p, const std::set<EdgeWithIndex> &sel)
|
|||
}
|
||||
}
|
||||
|
||||
remove_redundant_points (ctr);
|
||||
remove_redundant_points (ctr, true);
|
||||
|
||||
if (c == 0) {
|
||||
new_poly.assign_hull (ctr.begin (), ctr.end (), false /*compress*/);
|
||||
|
|
@ -495,7 +510,7 @@ modify_polygon (db::Polygon &p,
|
|||
}
|
||||
|
||||
if (compress) {
|
||||
remove_redundant_points (ctr);
|
||||
remove_redundant_points (ctr, true);
|
||||
}
|
||||
|
||||
if (c == 0) {
|
||||
|
|
@ -727,7 +742,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
virtual void visit_cell (const db::Cell &cell, const db::Box &search_box, const db::ICplxTrans &t, int /*level*/);
|
||||
virtual void visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int level);
|
||||
|
||||
founds_vector_type m_founds;
|
||||
};
|
||||
|
|
@ -736,25 +751,25 @@ private:
|
|||
// PartialShapeFinder implementation
|
||||
|
||||
PartialShapeFinder::PartialShapeFinder (bool point_mode, bool top_level_sel, db::ShapeIterator::flags_type flags)
|
||||
: lay::ShapeFinder (point_mode, top_level_sel, flags)
|
||||
: lay::ShapeFinder (point_mode, top_level_sel, flags, 0)
|
||||
{
|
||||
set_test_count (point_sel_tests);
|
||||
}
|
||||
|
||||
void
|
||||
PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const db::ICplxTrans &t, int /*level*/)
|
||||
PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db::Box &scan_box, const db::DCplxTrans &vp, const db::ICplxTrans &t, int /*level*/)
|
||||
{
|
||||
if (! point_mode ()) {
|
||||
|
||||
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
|
||||
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (search_box))) {
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (scan_box))) {
|
||||
|
||||
checkpoint ();
|
||||
|
||||
const db::Shapes &shapes = cell.shapes (*l);
|
||||
|
||||
db::ShapeIterator shape = shapes.begin_touching (search_box, flags (), prop_sel (), inv_prop_sel ());
|
||||
db::ShapeIterator shape = shapes.begin_touching (scan_box, flags (), prop_sel (), inv_prop_sel ());
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
checkpoint ();
|
||||
|
|
@ -784,9 +799,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
|
|||
++ee;
|
||||
unsigned int nn = ee.at_end () ? 0 : n + 1;
|
||||
|
||||
if (search_box.contains ((*e).p1 ())) {
|
||||
if (hit_box.contains ((*e).p1 ())) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge ((*e).p1 (), (*e).p1 ()), n, n, c));
|
||||
if (search_box.contains ((*e).p2 ())) {
|
||||
if (hit_box.contains ((*e).p2 ())) {
|
||||
edges.push_back (EdgeWithIndex (*e, n, nn, c));
|
||||
}
|
||||
}
|
||||
|
|
@ -801,9 +816,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
|
|||
db::Point pl;
|
||||
unsigned int n = 0;
|
||||
for (db::Shape::point_iterator pt = shape->begin_point (); pt != shape->end_point (); ++pt, ++n) {
|
||||
if (search_box.contains (*pt)) {
|
||||
if (hit_box.contains (*pt)) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge (*pt, *pt), n, n, 0));
|
||||
if (pl_set && search_box.contains (pl)) {
|
||||
if (pl_set && hit_box.contains (pl)) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge (pl, *pt), n - 1, n, 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -825,9 +840,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
|
|||
++ee;
|
||||
unsigned int nn = ee.at_end () ? 0 : n + 1;
|
||||
|
||||
if (search_box.contains ((*e).p1 ())) {
|
||||
if (hit_box.contains ((*e).p1 ())) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge ((*e).p1 (), (*e).p1 ()), n, n, 0));
|
||||
if (search_box.contains ((*e).p2 ())) {
|
||||
if (hit_box.contains ((*e).p2 ())) {
|
||||
edges.push_back (EdgeWithIndex (*e, n, nn, 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -837,8 +852,23 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
|
|||
} else if (shape->is_text ()) {
|
||||
|
||||
db::Point tp (shape->text_trans () * db::Point ());
|
||||
if (search_box.contains (tp)) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
|
||||
if (text_info ()) {
|
||||
|
||||
db::CplxTrans t_dbu = db::CplxTrans (layout ().dbu ()) * t;
|
||||
db::Text text;
|
||||
shape->text (text);
|
||||
db::Box tb = t_dbu.inverted () * text_info ()->bbox (t_dbu * text, vp);
|
||||
if (tb.inside (hit_box)) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (hit_box.contains (tp)) {
|
||||
edges.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -860,14 +890,14 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
|
|||
|
||||
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
|
||||
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (search_box))) {
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (hit_box))) {
|
||||
|
||||
checkpoint ();
|
||||
|
||||
const db::Shapes &shapes = cell.shapes (*l);
|
||||
std::vector <EdgeWithIndex> edge_sel;
|
||||
|
||||
db::ShapeIterator shape = shapes.begin_touching (search_box, flags (), prop_sel (), inv_prop_sel ());
|
||||
db::ShapeIterator shape = shapes.begin_touching (scan_box, flags (), prop_sel (), inv_prop_sel ());
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
bool match = false;
|
||||
|
|
@ -968,11 +998,29 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &search_box,
|
|||
} else if (shape->is_text ()) {
|
||||
|
||||
db::Point tp (shape->text_trans () * db::Point ());
|
||||
if (search_box.contains (tp)) {
|
||||
d = tp.distance (search_box.center ());
|
||||
edge_sel.clear ();
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
|
||||
if (text_info ()) {
|
||||
|
||||
db::CplxTrans t_dbu = db::CplxTrans (layout ().dbu ()) * t;
|
||||
db::Text text;
|
||||
shape->text (text);
|
||||
db::Box tb (t_dbu.inverted () * text_info ()->bbox (t_dbu * text, vp));
|
||||
if (tb.contains (hit_box.center ())) {
|
||||
d = tp.distance (hit_box.center ());
|
||||
edge_sel.clear ();
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (hit_box.contains (tp)) {
|
||||
d = tp.distance (hit_box.center ());
|
||||
edge_sel.clear ();
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1740,7 +1788,9 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
// stop dragging
|
||||
ui ()->ungrab_mouse (this);
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Partial move")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Partial move")));
|
||||
}
|
||||
|
||||
// heuristically, if there is just one edge selected: do not confine to the movement
|
||||
// angle constraint - the edge usually is confined enough
|
||||
|
|
@ -1748,7 +1798,9 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
|
|||
|
||||
transform_selection (move_trans);
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1935,7 +1987,9 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt
|
|||
partial_objects::iterator r = m_selection.begin (); // we assert above that we have at least one selected element
|
||||
if (! r->first.is_cell_inst ()) {
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Insert point")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Insert point")));
|
||||
}
|
||||
|
||||
// snap the point
|
||||
db::DPoint new_point_d = snap (p);
|
||||
|
|
@ -2002,7 +2056,9 @@ PartialService::mouse_double_click_event (const db::DPoint &p, unsigned int butt
|
|||
|
||||
handle_guiding_shape_changes ();
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
selection_to_view ();
|
||||
|
||||
|
|
|
|||
|
|
@ -472,6 +472,8 @@ Service::selection_bbox ()
|
|||
// TODO: this is done multiple times - once for each service!
|
||||
TransformationVariants tv (view ());
|
||||
|
||||
lay::TextInfo text_info (view ());
|
||||
|
||||
db::DBox box;
|
||||
for (objects::const_iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
|
||||
|
||||
|
|
@ -486,7 +488,13 @@ Service::selection_bbox ()
|
|||
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (r->cv_index (), r->layer ());
|
||||
if (tv_list != 0) {
|
||||
for (std::vector<db::DCplxTrans>::const_iterator t = tv_list->begin (); t != tv_list->end (); ++t) {
|
||||
box += *t * (ctx_trans * r->shape ().bbox ());
|
||||
if (r->shape ().is_text ()) {
|
||||
db::Text text;
|
||||
r->shape ().text (text);
|
||||
box += *t * text_info.bbox (ctx_trans * text, *t);
|
||||
} else {
|
||||
box += *t * (ctx_trans * r->shape ().bbox ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "layMarker.h"
|
||||
#include "laySnap.h"
|
||||
#include "layObjectInstPath.h"
|
||||
#include "layTextInfo.h"
|
||||
#include "tlColor.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbShape.h"
|
||||
|
|
|
|||
|
|
@ -266,9 +266,13 @@ ShapeEditService::deliver_shape (const db::Polygon &poly)
|
|||
{
|
||||
if (m_combine_mode == CM_Add) {
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Create polygon")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create polygon")));
|
||||
}
|
||||
cell ().shapes (layer ()).insert (poly);
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -326,7 +330,9 @@ ShapeEditService::deliver_shape (const db::Polygon &poly)
|
|||
result = input;
|
||||
}
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Combine shape with background")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Combine shape with background")));
|
||||
}
|
||||
|
||||
// Erase existing shapes
|
||||
for (std::vector<db::Shape>::const_iterator s = shapes.begin (); s != shapes.end (); ++s) {
|
||||
|
|
@ -341,7 +347,9 @@ ShapeEditService::deliver_shape (const db::Polygon &poly)
|
|||
cell ().shapes (layer ()).insert (*p);
|
||||
}
|
||||
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -350,9 +358,13 @@ void
|
|||
ShapeEditService::deliver_shape (const db::Path &path)
|
||||
{
|
||||
if (m_combine_mode == CM_Add) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create path")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create path")));
|
||||
}
|
||||
cell ().shapes (layer ()).insert (path);
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
} else {
|
||||
deliver_shape (path.polygon ());
|
||||
}
|
||||
|
|
@ -362,9 +374,13 @@ void
|
|||
ShapeEditService::deliver_shape (const db::Box &box)
|
||||
{
|
||||
if (m_combine_mode == CM_Add) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create box")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create box")));
|
||||
}
|
||||
cell ().shapes (layer ()).insert (box);
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
} else {
|
||||
deliver_shape (db::Polygon (box));
|
||||
}
|
||||
|
|
@ -912,9 +928,13 @@ TextService::do_finish_edit ()
|
|||
{
|
||||
get_edit_layer ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Create text")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create text")));
|
||||
}
|
||||
cell ().shapes (layer ()).insert (get_text ());
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
commit_recent (view ());
|
||||
|
||||
|
|
@ -1634,11 +1654,15 @@ InstService::do_finish_edit ()
|
|||
throw tl::Exception (tl::to_string (tr ("Inserting this instance would create a recursive hierarchy")));
|
||||
}
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Create instance")), m_reference_transaction_id);
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Create instance")), m_reference_transaction_id);
|
||||
}
|
||||
m_reference_transaction_id = 0;
|
||||
db::Instance i = cv->layout ().cell (cv.cell_index ()).insert (inst);
|
||||
cv->layout ().cleanup ();
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
commit_recent (view ());
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,40 @@ static void _call_smo (const qt_gsi::GenericStaticMethod *, gsi::SerialArgs &, g
|
|||
ret.write<const QMetaObject &> (QObject::staticMetaObject);
|
||||
}
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name) { return object->findChild<QObject *> (name); }
|
||||
|
||||
#if QT_VERSION < 0x50000
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChild<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChildren<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegExp &re)
|
||||
{
|
||||
return object->findChildren<QObject *> (re);
|
||||
}
|
||||
#else
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChild<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegularExpression &re, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (re, options);
|
||||
}
|
||||
#endif
|
||||
|
||||
// bool QObject::blockSignals(bool b)
|
||||
|
||||
|
|
@ -757,7 +790,15 @@ static gsi::Methods methods_QObject () {
|
|||
}
|
||||
|
||||
qt_gsi::QtNativeClass<QObject> decl_QObject ("QtCore", "QObject_Native",
|
||||
gsi::method_ext("findChild", &find_child_impl, "@brief Specialisation for findChild (uses QObject as T).")
|
||||
#if QT_VERSION < 0x50000
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#else
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#endif
|
||||
+
|
||||
methods_QObject (),
|
||||
"@hide\n@alias QObject");
|
||||
|
|
|
|||
|
|
@ -52,7 +52,40 @@ static void _call_smo (const qt_gsi::GenericStaticMethod *, gsi::SerialArgs &, g
|
|||
ret.write<const QMetaObject &> (QObject::staticMetaObject);
|
||||
}
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name) { return object->findChild<QObject *> (name); }
|
||||
|
||||
#if QT_VERSION < 0x50000
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChild<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChildren<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegExp &re)
|
||||
{
|
||||
return object->findChildren<QObject *> (re);
|
||||
}
|
||||
#else
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChild<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegularExpression &re, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (re, options);
|
||||
}
|
||||
#endif
|
||||
|
||||
// bool QObject::blockSignals(bool b)
|
||||
|
||||
|
|
@ -847,7 +880,15 @@ static gsi::Methods methods_QObject () {
|
|||
}
|
||||
|
||||
qt_gsi::QtNativeClass<QObject> decl_QObject ("QtCore", "QObject_Native",
|
||||
gsi::method_ext("findChild", &find_child_impl, "@brief Specialisation for findChild (uses QObject as T).")
|
||||
#if QT_VERSION < 0x50000
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#else
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#endif
|
||||
+
|
||||
methods_QObject (),
|
||||
"@hide\n@alias QObject");
|
||||
|
|
|
|||
|
|
@ -52,7 +52,40 @@ static void _call_smo (const qt_gsi::GenericStaticMethod *, gsi::SerialArgs &, g
|
|||
ret.write<const QMetaObject &> (QObject::staticMetaObject);
|
||||
}
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name) { return object->findChild<QObject *> (name); }
|
||||
|
||||
#if QT_VERSION < 0x50000
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChild<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name)
|
||||
{
|
||||
return object->findChildren<QObject *> (name);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegExp &re)
|
||||
{
|
||||
return object->findChildren<QObject *> (re);
|
||||
}
|
||||
#else
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
QObject *find_child_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChild<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl (QObject *object, const QString &name, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (name, options);
|
||||
}
|
||||
QList<QObject *> find_children_impl2 (QObject *object, const QRegularExpression &re, Qt::FindChildOptions options)
|
||||
{
|
||||
return object->findChildren<QObject *> (re, options);
|
||||
}
|
||||
#endif
|
||||
|
||||
// bool QObject::blockSignals(bool b)
|
||||
|
||||
|
|
@ -771,7 +804,15 @@ static gsi::Methods methods_QObject () {
|
|||
}
|
||||
|
||||
qt_gsi::QtNativeClass<QObject> decl_QObject ("QtCore", "QObject_Native",
|
||||
gsi::method_ext("findChild", &find_child_impl, "@brief Specialisation for findChild (uses QObject as T).")
|
||||
#if QT_VERSION < 0x50000
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#else
|
||||
gsi::method_ext("findChild", &find_child_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChild (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl, gsi::arg("name", QString(), "null"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).") +
|
||||
gsi::method_ext("findChildren", &find_children_impl2, gsi::arg("re"), gsi::arg("options", Qt::FindChildrenRecursively, "Qt::FindChildrenRecursively"), "@brief Specialisation for findChildren (uses QObject as T).")
|
||||
#endif
|
||||
+
|
||||
methods_QObject (),
|
||||
"@hide\n@alias QObject");
|
||||
|
|
|
|||
|
|
@ -1481,9 +1481,13 @@ Service::menu_activated (const std::string &symbol)
|
|||
{
|
||||
if (symbol == "img::clear_all_images") {
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Clear all images")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Clear all images")));
|
||||
}
|
||||
clear_images ();
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
} else if (symbol == "img::add_image") {
|
||||
|
||||
|
|
@ -1601,10 +1605,14 @@ Service::add_image ()
|
|||
|
||||
clear_selection ();
|
||||
|
||||
manager ()->transaction (tl::to_string (tr ("Add image")));
|
||||
if (manager ()) {
|
||||
manager ()->transaction (tl::to_string (tr ("Add image")));
|
||||
}
|
||||
new_image->set_z_position (top_z_position ());
|
||||
mp_view->annotation_shapes ().insert (db::DUserObject (new_image));
|
||||
manager ()->commit ();
|
||||
if (manager ()) {
|
||||
manager ()->commit ();
|
||||
}
|
||||
|
||||
} else {
|
||||
delete new_image;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ClipDialog</class>
|
||||
<widget class="QDialog" name="ClipDialog" >
|
||||
<property name="geometry" >
|
||||
<widget class="QDialog" name="ClipDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
|
|
@ -9,49 +10,47 @@
|
|||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Clip Tool</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_3" >
|
||||
<property name="frameShape" >
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13" >
|
||||
<property name="text" >
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Clip result cell name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="le_cell_name" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<widget class="QLineEdit" name="le_cell_name">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<property name="text">
|
||||
<string>CLIP</string>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -61,13 +60,13 @@
|
|||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
|
|
@ -76,48 +75,48 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox" >
|
||||
<property name="title" >
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Clip Box Specification</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QFrame" name="frame" >
|
||||
<property name="frameShape" >
|
||||
<item row="2" column="0">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_box2" >
|
||||
<property name="text" >
|
||||
<widget class="QRadioButton" name="rb_box2">
|
||||
<property name="text">
|
||||
<string>Single box with ...</string>
|
||||
</property>
|
||||
<property name="autoExclusive" >
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
|
|
@ -128,40 +127,40 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QFrame" name="frame_2" >
|
||||
<property name="frameShape" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_box1" >
|
||||
<property name="text" >
|
||||
<widget class="QRadioButton" name="rb_box1">
|
||||
<property name="text">
|
||||
<string>Single box with ...</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive" >
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
|
|
@ -172,12 +171,12 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<item row="0" column="2">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>231</width>
|
||||
<height>20</height>
|
||||
|
|
@ -185,176 +184,180 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QRadioButton" name="rb_shapes" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="rb_shapes">
|
||||
<property name="text">
|
||||
<string>Shapes on layer (multi clip)</string>
|
||||
</property>
|
||||
<property name="autoExclusive" >
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2" >
|
||||
<widget class="QGroupBox" name="grp_box1" >
|
||||
<property name="title" >
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="grp_box1">
|
||||
<property name="title">
|
||||
<string>Box Boundaries</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label_6" >
|
||||
<property name="text" >
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>2nd corner</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>1st corner</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4" >
|
||||
<widget class="QLineEdit" name="le_y2" />
|
||||
<item row="1" column="4">
|
||||
<widget class="QLineEdit" name="le_y2"/>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="le_x2" />
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="le_x2"/>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QLineEdit" name="le_y1" />
|
||||
<item row="0" column="4">
|
||||
<widget class="QLineEdit" name="le_y1"/>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLineEdit" name="le_x1" />
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="le_x1"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2" >
|
||||
<widget class="QGroupBox" name="grp_box2" >
|
||||
<property name="title" >
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="grp_box2">
|
||||
<property name="title">
|
||||
<string>Box Center And Dimensions</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>h =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_8" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Dimensions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="label_9" >
|
||||
<property name="text" >
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>w =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_10" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Center</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_11" >
|
||||
<property name="text" >
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>x =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLabel" name="label_12" >
|
||||
<property name="text" >
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>y =</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4" >
|
||||
<widget class="QLineEdit" name="le_h" />
|
||||
<item row="1" column="4">
|
||||
<widget class="QLineEdit" name="le_h"/>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="le_w" />
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="le_w"/>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QLineEdit" name="le_y" />
|
||||
<item row="0" column="4">
|
||||
<widget class="QLineEdit" name="le_y"/>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLineEdit" name="le_x" />
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="le_x"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2" >
|
||||
<widget class="QRadioButton" name="rb_rulers" >
|
||||
<property name="text" >
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="rb_rulers">
|
||||
<property name="text">
|
||||
<string>From ruler start and end points (multi clip)</string>
|
||||
</property>
|
||||
<property name="autoExclusive" >
|
||||
<property name="autoExclusive">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="lay::LayerSelectionComboBox" name="cb_layer" />
|
||||
<item row="0" column="1">
|
||||
<widget class="lay::LayerSelectionComboBox" name="cb_layer">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
|
|
@ -363,12 +366,12 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="button_box" >
|
||||
<property name="orientation" >
|
||||
<widget class="QDialogButtonBox" name="button_box">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -406,11 +409,11 @@
|
|||
<receiver>ClipDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
|
|
@ -422,11 +425,11 @@
|
|||
<receiver>ClipDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
|
@ -70,8 +70,30 @@
|
|||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>15</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QFrame" name="frame_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
|
|
@ -131,10 +153,13 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
|
|
@ -142,20 +167,7 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QFrame" name="frame_6">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
|
|
@ -203,19 +215,6 @@
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_37">
|
||||
<property name="text">
|
||||
|
|
@ -251,6 +250,12 @@
|
|||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QStackedWidget" name="fill_area_stack">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
|
|
@ -277,10 +282,13 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>241</width>
|
||||
<height>40</height>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
|
|
@ -303,6 +311,9 @@
|
|||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
@ -409,6 +420,22 @@
|
|||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -94,10 +94,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="newFolderButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">New folder</p></body></html></string>
|
||||
<string>New folder</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -121,10 +118,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="addButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;">New</p></body></html></string>
|
||||
<string>New</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -141,10 +135,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="deleteButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;">Delete</p></body></html></string>
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -161,10 +152,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="renameButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rename</p></body></html></string>
|
||||
<string>Rename</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rename</string>
|
||||
|
|
@ -181,10 +169,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="importButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Import file</p></body></html></string>
|
||||
<string>Import file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Import</string>
|
||||
|
|
@ -208,7 +193,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="saveAllButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Save all files (Ctrl+Shift+S)</p></body></html></string>
|
||||
<string>Save all files (Ctrl+Shift+S)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -228,7 +213,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="saveButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Save current file (Ctrl+S)</p></body></html></string>
|
||||
<string>Save current file (Ctrl+S)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -333,8 +318,8 @@ p, li { white-space: pre-wrap; }
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/back_16.png</normaloff>:/back_16.png</iconset>
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/back_16px.png</normaloff>:/back_16px.png</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
|
|
@ -347,8 +332,8 @@ p, li { white-space: pre-wrap; }
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/forward_16.png</normaloff>:/forward_16.png</iconset>
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/forward_16px.png</normaloff>:/forward_16px.png</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
|
|
@ -365,10 +350,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="closeButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Close tab</p></body></html></string>
|
||||
<string>Close tab</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>close</string>
|
||||
|
|
@ -432,10 +414,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="stopButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stop script</p></body></html></string>
|
||||
<string>Stop script</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -452,10 +431,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="pauseButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pause script (Ctrl+F5)</p></body></html></string>
|
||||
<string>Pause script (Ctrl+F5)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -482,10 +458,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="breakpointButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set breakpoint (F9)</p></body></html></string>
|
||||
<string>Set breakpoint (F9)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -505,10 +478,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="clearBreakpointsButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Clear all breakpoints (Ctrl+Shift+F9)</p></body></html></string>
|
||||
<string>Clear all breakpoints (Ctrl+Shift+F9)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -535,10 +505,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="singleStepButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step into procedure (F11)</p></body></html></string>
|
||||
<string>Step into procedure (F11)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>S</string>
|
||||
|
|
@ -558,10 +525,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="nextStepButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Step over procedure or block (F10)</p></body></html></string>
|
||||
<string>Step over procedure or block (F10)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>N</string>
|
||||
|
|
@ -588,10 +552,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="dbgOn">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable or disable debugging</p></body></html></string>
|
||||
<string>Enable or disable debugging</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>DBG</string>
|
||||
|
|
@ -618,10 +579,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="propertiesButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Edit properties of macro</p></body></html></string>
|
||||
<string>Edit properties of macro</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>P</string>
|
||||
|
|
@ -638,10 +596,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="setupButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setup colors, formats, debugger</p></body></html></string>
|
||||
<string>Setup colors, formats, debugger</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>prop</string>
|
||||
|
|
@ -674,10 +629,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="findNextButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Find next</p></body></html></string>
|
||||
<string>Find next (Ctrl+F)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>N</string>
|
||||
|
|
@ -687,7 +639,7 @@ p, li { white-space: pre-wrap; }
|
|||
<normaloff>:/find_16px.png</normaloff>:/find_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F3</string>
|
||||
<string>Ctrl+F</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
|
|
@ -709,10 +661,7 @@ p, li { white-space: pre-wrap; }
|
|||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Show replace mode</p></body></html></string>
|
||||
<string>Show replace mode</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -764,10 +713,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="replaceNextButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Replace and find next</p></body></html></string>
|
||||
<string>Replace and find next (Ctrl+R)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RN</string>
|
||||
|
|
@ -777,7 +723,7 @@ p, li { white-space: pre-wrap; }
|
|||
<normaloff>:/replace_16px.png</normaloff>:/replace_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string/>
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
|
|
@ -787,10 +733,7 @@ p, li { white-space: pre-wrap; }
|
|||
<item>
|
||||
<widget class="QToolButton" name="replaceAllButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Replace all</p></body></html></string>
|
||||
<string>Replace all (Ctrl+Shift+R)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
|
|
@ -799,6 +742,9 @@ p, li { white-space: pre-wrap; }
|
|||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/replace_all_16px.png</normaloff>:/replace_all_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+R</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
@ -1497,14 +1443,6 @@ p, li { white-space: pre-wrap; }
|
|||
<string>Case Sensitive</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSearchReplace">
|
||||
<property name="text">
|
||||
<string>Search & Replace</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveAs">
|
||||
<property name="text">
|
||||
<string>Save As</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ReplacePropertiesBox</class>
|
||||
<widget class="QWidget" name="ReplacePropertiesBox" >
|
||||
<property name="geometry" >
|
||||
<widget class="QWidget" name="ReplacePropertiesBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
|
|
@ -9,32 +10,32 @@
|
|||
<height>265</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_54" >
|
||||
<property name="text" >
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_54">
|
||||
<property name="text">
|
||||
<string>Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" >
|
||||
<widget class="QLineEdit" name="box_height" />
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="box_height"/>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3" >
|
||||
<item row="3" column="0" colspan="3">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>40</height>
|
||||
|
|
@ -42,69 +43,79 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLabel" name="label_60" >
|
||||
<property name="text" >
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_60">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="layResources.qrc" >:/right_16px@2x.png</pixmap>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../icons/icons.qrc">:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_58" >
|
||||
<property name="text" >
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_58">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="layResources.qrc" >:/right_16px@2x.png</pixmap>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../icons/icons.qrc">:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="box_width" />
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="box_width"/>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_55" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_55">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="label_59" >
|
||||
<property name="text" >
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_59">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="layResources.qrc" >:/right_16px@2x.png</pixmap>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../icons/icons.qrc">:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_53" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_53">
|
||||
<property name="text">
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="lay::LayerSelectionComboBox" name="box_layer" />
|
||||
<item row="0" column="2">
|
||||
<widget class="lay::LayerSelectionComboBox" name="box_layer">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
@ -115,6 +126,8 @@
|
|||
<header>layWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -1,37 +1,38 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ReplacePropertiesPath</class>
|
||||
<widget class="QWidget" name="ReplacePropertiesPath" >
|
||||
<property name="geometry" >
|
||||
<widget class="QWidget" name="ReplacePropertiesPath">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>239</width>
|
||||
<width>246</width>
|
||||
<height>241</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_55" >
|
||||
<property name="text" >
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_55">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3" >
|
||||
<item row="2" column="0" colspan="3">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>40</height>
|
||||
|
|
@ -39,42 +40,52 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_54" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_54">
|
||||
<property name="text">
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="lay::LayerSelectionComboBox" name="path_layer" />
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="label_61" >
|
||||
<property name="text" >
|
||||
<string/>
|
||||
<item row="0" column="2">
|
||||
<widget class="lay::LayerSelectionComboBox" name="path_layer">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="layResources.qrc" >:/right_16px@2x.png</pixmap>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="path_width" />
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_62" >
|
||||
<property name="text" >
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_61">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="layResources.qrc" >:/right_16px@2x.png</pixmap>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../icons/icons.qrc">:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="path_width"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_62">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../icons/icons.qrc">:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -88,6 +99,8 @@
|
|||
<header>layWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ReplacePropertiesShape</class>
|
||||
<widget class="QWidget" name="ReplacePropertiesShape" >
|
||||
<property name="geometry" >
|
||||
<widget class="QWidget" name="ReplacePropertiesShape">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
|
|
@ -9,39 +10,19 @@
|
|||
<height>187</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_57" >
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="layResources.qrc" >:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_47" >
|
||||
<property name="text" >
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3" >
|
||||
<item row="2" column="0" colspan="3">
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>281</height>
|
||||
|
|
@ -49,18 +30,49 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="lay::LayerSelectionComboBox" name="shape_layer" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_47">
|
||||
<property name="text">
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="lay::LayerSelectionComboBox" name="shape_layer">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_57">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../icons/icons.qrc">:/right_16px@2x.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
|
@ -70,6 +82,8 @@
|
|||
<header>layWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue