Merge branch 'devel' into vias-development

This commit is contained in:
Matthias Koefferlein 2025-08-16 16:49:36 +02:00
commit 8c53fb934e
728 changed files with 45868 additions and 8543 deletions

View File

@ -22,14 +22,21 @@ jobs:
include: include:
- os: "macos-13" # intel runner - os: "macos-13" # intel runner
cibuild: "*macosx*" cibuild: "*macosx*"
cibw_arch: "macos_x86_64"
macos-arch: "x86_64" macos-arch: "x86_64"
- os: "macos-14" # M1 runner - os: "macos-14" # M1 runner
cibuild: "*macosx*" cibuild: "*macosx*"
cibw_arch: "macos_arm64"
macos-arch: "arm64" macos-arch: "arm64"
- os: "ubuntu-latest" - os: "ubuntu-latest"
cibuild: "*manylinux*" cibuild: "*manylinux*"
cibw_arch: "manylinux"
- os: "ubuntu-latest" - os: "ubuntu-latest"
cibuild: "*musllinux*" cibuild: "*musllinux*"
cibw_arch: "musllinux"
- os: "ubuntu-24.04-arm" # aarch64 manylinux on ARM runner
cibuild: "*manylinux*"
cibw_arch: "aarch64"
steps: steps:
- name: Free Disk Space (Ubuntu) - name: Free Disk Space (Ubuntu)
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
@ -44,29 +51,44 @@ jobs:
uses: styfle/cancel-workflow-action@0.12.1 uses: styfle/cancel-workflow-action@0.12.1
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: ccache - name: ccache
if: matrix.os != 'ubuntu-24.04-arm'
uses: hendrikmuhs/ccache-action@v1.2 uses: hendrikmuhs/ccache-action@v1.2
with: with:
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.cibuild }} # Make cache specific to OS key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.cibuild }} # Make cache specific to OS
max-size: "5G" max-size: "5G"
- name: Install dependencies - name: Install dependencies
if: matrix.os != 'ubuntu-24.04-arm'
run: | run: |
env env
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH
HOST_CCACHE_DIR="$(ccache -k cache_dir)" HOST_CCACHE_DIR="$(ccache -k cache_dir)"
mkdir -p $HOST_CCACHE_DIR mkdir -p $HOST_CCACHE_DIR
- name: Build wheels # check https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions - name: Build wheels (ARM)
uses: pypa/cibuildwheel@v2.22.0 if: matrix.os == 'ubuntu-24.04-arm'
# to supply options, put them in 'env', like: uses: pypa/cibuildwheel@v3.1.3
# env: env:
# CIBW_SOME_OPTION: value # override the default CentOS “yum install … ccache” and drop ccache
CIBW_BEFORE_ALL_LINUX: |
yum install -y \
zlib-devel \
curl-devel \
expat-devel \
libpng-devel
CIBW_BEFORE_BUILD_LINUX: "true"
CIBW_BUILD: ${{ matrix.cibuild }}
CIBW_ARCHS_LINUX: ${{ matrix.cibw_arch }}
- name: Build wheels (all other platforms)
if: matrix.os != 'ubuntu-24.04-arm'
uses: pypa/cibuildwheel@v3.1.3
env: env:
CIBW_BUILD: ${{ matrix.cibuild }} CIBW_BUILD: ${{ matrix.cibuild }}
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }} CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
CIBW_DEPENDENCY_VERSIONS_MACOS: cibw_constraints.txt CIBW_DEPENDENCY_VERSIONS_MACOS: cibw_constraints.txt
- name: Download Cache from Docker (linux only) - name: Download Cache from Docker (linux only)
if: ${{ runner.os == 'Linux' }} if: runner.os == 'Linux' && matrix.os != 'ubuntu-24.04-arm'
# hack until https://github.com/pypa/cibuildwheel/issues/1030 is fixed # hack until https://github.com/pypa/cibuildwheel/issues/1030 is fixed
run: | run: |
env env
@ -76,8 +98,9 @@ jobs:
mv ./wheelhouse/.ccache $HOST_CCACHE_DIR mv ./wheelhouse/.ccache $HOST_CCACHE_DIR
ls -la $HOST_CCACHE_DIR ls -la $HOST_CCACHE_DIR
ccache -s ccache -s
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: artifact-${{ matrix.os }}-${{ matrix.cibw_arch }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl 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/
@ -90,20 +113,21 @@ jobs:
- name: Build SDist - name: Build SDist
run: pipx run build --sdist run: pipx run build --sdist
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: artifact-sdist
path: dist/*.tar.gz path: dist/*.tar.gz
upload_to_test_pypy: upload_to_test_pypy:
needs: [build, make_sdist] needs: [build, make_sdist]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: artifact merge-multiple: true
path: dist path: dist
- uses: pypa/gh-action-pypi-publish@v1.12.3 - uses: pypa/gh-action-pypi-publish@v1.12.4
continue-on-error: true # might fail if we don't bump the version continue-on-error: true # might fail if we don't bump the version
with: with:
user: __token__ user: __token__
@ -115,12 +139,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published' if: github.event_name == 'release' && github.event.action == 'published'
steps: steps:
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v4
with: with:
name: artifact merge-multiple: true
path: dist path: dist
- uses: pypa/gh-action-pypi-publish@v1.12.3 - uses: pypa/gh-action-pypi-publish@v1.12.4
with: with:
user: __token__ user: __token__
password: ${{ secrets.pypi_password }} password: ${{ secrets.pypi_password }}

View File

@ -1,12 +1,11 @@
klayout is packaged by Peter C.S. Scholtens <peter.scholtens@xs4all.nl> klayout is packaged by Matthias Köfferlein <matthias@koefferlein.de>
and Matthias Köfferlein <matthias@koefferlein.de>
and was obtained from https://www.klayout.org/downloads/source/klayout-%VERSION%.tar.gz and was obtained from https://www.klayout.org/downloads/source/klayout-%VERSION%.tar.gz
Authors: Authors:
Matthias Köfferlein Matthias Köfferlein
Copyright: Copyright:
Copyright (C) 2006-2022 by Matthias Köfferlein. Copyright (C) 2006-2025 by Matthias Köfferlein.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

163
Changelog
View File

@ -1,3 +1,166 @@
0.30.3 (2025-08-05):
* Enhancement: %GITHUB%/issues/2044 Different combination modes on strm2xxx tools (+ and ,)
* Bugfix: %GITHUB%/issues/2073 Klayout fails to read CELLNAME S_CELL_OFFSET property on Windows on big files
* Bugfix: %GITHUB%/issues/2075 strm2oas ignores def net routing wire extensions
* Bugfix: %GITHUB%/issues/2081 strm2oas a.oas,c.oas o.oas coredumps
* Bugfix: %GITHUB%/issues/2087 DRC: Poor fill with skew step vectors (see more fill-related topics below)
* Bugfix: %GITHUB%/issues/2088 Fixed a use case that generated duplicate OASIS cell IDs
* Bugfix: %GITHUB%/issues/2094 Performance issue in the python code to insert Regions into Shapes
* Bugfix: %GITHUB%/issues/2100 RNetExtractor extracts wrong RNode locations with tesselation
* Bugfix: %GITHUB%/issues/2102 RNetExtractor internal error
* Bugfix: Fixed automatic execution of scripts after package installation
Now, restarting KLayout after package installation may not be needed
* Bugfix: File watcher dropped file after is was temporarily removed
* Bugfix: After deleting terminals from devices, reading old L2N/LVSDB files
made these terminal re-appear in the netlist browser.
* Enhancement: primary and secondary device parameters are separated in
the LVS netlist view, so it is easier to see which parameters are relevant
* Bugfix: Avoid a crash when reading OASIS files with broken code tables
in OASIS CBLOCKs
* Enhancement: New Ruby/Python functions: Macro#current and Macro attributes
(Macro#get_attribute, Macro#has_attribute, Macro#set_attribute, Macro#delete_attribute)
These features allow passing values in and out from a macro in other ways
than defining global variables and basically allow parameterized macros.
* Enhancement: Convenience function ObjectInstPath#cell
* Bugfix: Some layout queries did not render the correct path_dtrans
* Bugfix: "tap" feature
- was not selecting shapes that fully overlap the view
- texts are not considered as detecting them requires potentially search a large area
* Bugfix: Fixed a TODO from old issue #1470
* Enhancement: DRC function "def_output": A simple yet useful extension to obtain
the output layout and to manipulate it (within limits)
* Bugfixes and enhancements: fill feature (see also issue #2087)
- tiles in tiled mode most not overlap when the origin is not global as tiles may use different origins
- more efficient computation of remaining fill area
- fill pattern "margin" feature simplifies keeping distance to other fill
shapes or original features in multi-fill scenarios
- fixed MT issues when using the fill feature in tiled mode with multiple threads
- better compression of fill cell instances into arrays
* Enhancement: Ruby/Polygon methods set_properties and clear_properties for Cell, Layout, Shape and Instance
* Enhancement: a bunch of features that utilize expressions on polygons and other shapes
to attach properties, filter base on properties or compute values in properties
(aka "measurement features")
- PolygonFilterBase#expression_filter (to be used in Region#filter and Region#filtered)
can be used to filter polygons based on KLayout expressions, including properties
- PolygonPropertiesExpressions object (to be used in Region#process and Region#processed)
can be used to attach properties based on KLayout expressions, including other properties
- Same for Edges, EdgePairs and Texts
* Enhancement: handling of properties in shape merge in Region
- Region#join_properties_on_merge controls how properties and handled during shape merge
- New respective arguments in Region#merge, Region#merged
- New layer methods "merge_props" and "merged_props" in DRC (allows joining properties
from same shapes on different layers)
* Enhancement: net property evaluation using KLayout expressions.
Allows implementing more complex antenna rule checking schemes for example.
- Ruby/Python: LayoutToNetlist#evaluate_nets
- DRC: evaluate_nets
0.30.2 (2025-05-29):
* Enhancement: %GITHUB%/issues/2016 Lazy evaluation of PCell also when changing guiding shape properties
* Enhancement: %GITHUB%/issues/2041 strm2oas should read --lefdef-lefs and --lefdef-lef-layouts only once
* Enhancement: %GITHUB%/issues/2055 Check ports feature for LVS
* Enhancement: %GITHUB%/issues/2057 Feature request: nanometer scalebar
* Bugfix: %GITHUB%/issues/2060 Edges#with_angle fails for long edges
* Enhancement: Support for ARM Python packages (thanks, Troy!)
* Enhancement: PolygonNeighborHood now allows specifying a variant type
for anisotropic applications
* Bugfix: Lower case hex escapes in URI's were not handled correctly
* Bugfix: internally handling "%ld" sprintf as 64bit compatible for
better Linux/Windows compatibility (e.g. file position in error messages
was not printed correctly on Windows at positions >2G)
* Bugfix: LVS DB internal net names now are preserved and not renumbered
This way, log entries are consistent with net names and the generated netlist
names are consistent with LVS reports.
* Bugfix: "same_nets" net names are now case insensitive in both netlists
instead of schematic only. See https://github.com/IHP-GmbH/IHP-Open-PDK/issues/484
* Feature: Ruby/Python API for adding and removing log entries in LVS DBs
LayoutToNetlist#clear_log_entries and LayoutToNetlist#add_log_entry
* Feature: NetlistCrossReference#each_net_pair etc. functions take a single
Circuit or Net object instead of a pair (can be schematic or layout objects)
* Feature: Support functions for parasitic extraction - experimental
Currently, pieces for R extraction are available in the pex Python module space.
These are just first bits - see https://martinjankoehler.github.io/klayout-pex-website/doc/doc.html
for ongoing work.
* Feature: MALY jobdeck format support (reading) - experimental
0.30.1 (2025-04-27):
* Bugfix: %GITHUB%/issues/2011 Some DRC bugs fixed
* Bug: %GITHUB%/issues/2014 Bug fixes in LEF/DEF reader
* Enhancement: %GITHUB%/issues/2019 Support for Qt 6.9
* Bugfix: %GITHUB%/issues/2020 Strict weak ordering issue fixed in edge processor
* Enhancement: %GITHUB%/issues/2024 Option to configure grid density
* Bugfix: %GITHUB%/issues/2025 Brackets get added in List type PCell parameter edit field
* Bugfix: %GITHUB%/issues/2026 Display is dead after opening 2.5d view
* Bugfix: %GITHUB%/issues/2038 DEdgePairWithProperties not working properly in scripts
* Bugfix/Enhancement: some updates of "strmxor" tool
- strmxor was giving wrong results if cell variants are
present where one variant is covered entirely by a large shape
- Parallelization now happens on a per-layer basis (same as for
XOR tool in KLayout)
- Shape count was not consistent in deep mode
- All buddy tools print total runtime with -d11
0.30.0 (2025-03-25):
* Bug: %GITHUB%/issues/1996 More robust triangulation
* Bug: %GITHUB%/issues/2002 Path to polygon conversion issue
* Enhancement: Better support for user properties
The property management has been overhauled. Properties are not globally
scoped. The "Layout" class now provides class methods to convert property IDs
to property hashes and back. It is no longer required to know the origin of
a property ID.
Other changes are:
- New classes "BoxWithProperties", "EdgeWithProperties", "PolygonWithProperties",
"SimplePolygonWithProperties", "PathWithProperties", "EdgePairWithProperties",
"TextWithProperties" and corresponding "D..." classes.
Many functions accept these objects now in addition to the property-less "Box",
"Edge" etc. objects. Many functions now deliver property-annotated objects
instead of the plain ones.
- "EdgePairFilter#property_glob", "EdgePairFilter#property_filter", "EdgePairFilter#property_filter_bounded"
creates filters for edge pair objects, which can be used on "EdgePairs" containers to
filter by properties.
- The same is available for "EdgeFilter" (for filtering edges in "Edges" containers),
"PolygonFilter" (for filtering polygons in "Region" containers), and
"TextFilter" (for filtering texts in "Texts" containers)
- New method "process_with_properties" for "PolygonOperator", "EdgeOperator",
"EdgePairOperator" and "TextOperator"
* Enhancement: New class "PolygonNeighborhood"
This is a visitor to obtain all "neighboring" polygons for each polygon
in a Region. Currently, neighborhood is defined by the bounding box of
the primary polygons.
* Enhancement: Layout queries can use "$_" to refer to the current cell now
* Enhancement: New methods:
- "LayoutToNetlist#build_net", "build_nets" and "build_all_nets" do not
- "LayoutToNetlist#layer_index" from a name
- "LayoutToNetlist#texts_by_index" and "LayoutToNetlist#texts_by_name"
- "LayoutToNetlist#original_layout" and "LayoutToNetlist#original_top_cell"
- "LayoutToNetlist#polygons_of_net" and "LayoutToNetlist#texts_of_net"
- "Device#terminal_ref"
- New "text_prop" argument in Texts#polygons (texts can transfer their
string to the generated polygons as user properties)
- New methods "Polygon#delaunay", "DPolygon#delaunay", "SimplePolygon#delaunay"
and "DSimplePolygon#delaunay"
0.29.12 (2025-03-02):
* Bug: %GITHUB%/issues/1976 Crash on cross mode, lw > 1 and oversampling
* Bug: %GITHUB%/issues/1987 Build failure against Qt6.8
* Enhancement: %GITHUB%/issues/1989 API enhancements: several new split_... methods
on Edges, Region, EdgePairs and Texts, delivering a pair of containers with
selected and unselected objects.
* Bug: %GITHUB%/issues/1993 Tiling processor kept layout locks, causing DRC issues with "with_density"
* Bug: %GITHUB%/issues/1997 Can not find a file in Open Recent menu (a string unescaping bug)
* Bugfix: 'Save All' was not updating the dirty flag in the inactive tabs
* Bugfix: Fixing a crash when editing PCell parameters while the macro editor is open
* Bugfix: Fixed a potential Crash on "save all"
* Bugfix: Fixed a bug when returning a Region into a layout with cells unselected
* Bugfix: Tab title were not updated on cell rename
* Bugfix: Fixed a crash on certain layout queries
- For example "instances of cell .*.* where inst.trans.rot == 2" was crashing
* Bugfix: Fixing two problems with layer mapping
- Mapping "[*/*] 100/0:0/0" (for example) created 0/0 two times when the input contains 100/0 and 0/0. Now
it is a single layer only
- The mapping table generated from strings now uses layer indexes from a range that should not collide
with existing layer indexes.
0.29.11 (2025-01-17): 0.29.11 (2025-01-17):
* Bug: %GITHUB%/issues/1948 Crash by instantiate a Cell in a Library-Cell * Bug: %GITHUB%/issues/1948 Crash by instantiate a Cell in a Library-Cell
* Bug: %GITHUB%/issues/1953 Callback_impl & coerce_parameters_impl parameter display issue * Bug: %GITHUB%/issues/1953 Callback_impl & coerce_parameters_impl parameter display issue

View File

@ -1,3 +1,38 @@
klayout (0.30.3-1) unstable; urgency=low
* New features and bugfixes
- See changelog
-- Matthias Köfferlein <matthias@koefferlein.de> Tue, 05 Aug 2025 22:29:48 +0200
klayout (0.30.2-1) unstable; urgency=low
* New features and bugfixes
- See changelog
-- Matthias Köfferlein <matthias@koefferlein.de> Wed, 28 May 2025 22:44:45 +0200
klayout (0.30.1-1) unstable; urgency=low
* New features and bugfixes
- See changelog
-- Matthias Köfferlein <matthias@koefferlein.de> Sun, 27 Apr 2025 14:26:50 +0200
klayout (0.30.0-1) unstable; urgency=low
* New features and bugfixes
- See changelog
-- Matthias Köfferlein <matthias@koefferlein.de> Tue, 25 Mar 2025 00:00:00 +0100
klayout (0.29.12-1) unstable; urgency=low
* New features and bugfixes
- See changelog
-- Matthias Köfferlein <matthias@koefferlein.de> Sun, 02 Mar 2025 21:16:41 +0100
klayout (0.29.11-1) unstable; urgency=low klayout (0.29.11-1) unstable; urgency=low
* New features and bugfixes * New features and bugfixes

View File

@ -12,6 +12,7 @@ recursive-include src/pymod *.cc *.h
recursive-include src/rbastub *.cc *.h recursive-include src/rbastub *.cc *.h
recursive-include src/rdb/rdb *.cc *.h recursive-include src/rdb/rdb *.cc *.h
recursive-include src/tl/tl *.cc *.h recursive-include src/tl/tl *.cc *.h
recursive-include src/pex/pex *.cc *.h
recursive-include src/version *.cc *.h recursive-include src/version *.cc *.h
recursive-include src/pymod *.pyi recursive-include src/pymod *.pyi
recursive-include src/plugins/*/db_plugin *.cc *.h recursive-include src/plugins/*/db_plugin *.cc *.h

View File

@ -92,7 +92,8 @@ jobs:
displayName: 'Download and Extract KLayout bits' displayName: 'Download and Extract KLayout bits'
- script: | - script: |
python -m pip install --upgrade pip setuptools wheel # setuptools 67.0.0 is not working as of now (pypa/setuptools#4885)
python -m pip install --upgrade pip "setuptools<76.0.0" wheel
displayName: 'Update pip, setuptools and wheel' displayName: 'Update pip, setuptools and wheel'
- script: | - script: |

View File

@ -11,16 +11,18 @@ if [[ -f "/etc/centos-release" ]]; then
[ $s -eq 0 ] || exit $s [ $s -eq 0 ] || exit $s
if [[ -d "/usr/lib64/ccache" ]]; then if [[ -d "/usr/lib64/ccache" ]]; then
ln -s /usr/bin/ccache /usr/lib64/ccache/c++ for comp in c++ cc gcc g++; do
ln -s /usr/bin/ccache /usr/lib64/ccache/cc if ! [ -e /usr/lib64/ccache/$comp ]; then
ln -s /usr/bin/ccache /usr/lib64/ccache/gcc ln -s /usr/bin/ccache /usr/lib64/ccache/$comp
ln -s /usr/bin/ccache /usr/lib64/ccache/g++ fi
done
export PATH="/usr/lib64/ccache:$PATH" export PATH="/usr/lib64/ccache:$PATH"
elif [[ -d "/usr/lib/ccache" ]]; then elif [[ -d "/usr/lib/ccache" ]]; then
ln -s /usr/bin/ccache /usr/lib/ccache/c++ for comp in c++ cc gcc g++; do
ln -s /usr/bin/ccache /usr/lib/ccache/cc if ! [ -e /usr/lib/ccache/$comp ]; then
ln -s /usr/bin/ccache /usr/lib/ccache/gcc ln -s /usr/bin/ccache /usr/lib/ccache/$comp
ln -s /usr/bin/ccache /usr/lib/ccache/g++ fi
done
export PATH="/usr/lib/ccache:$PATH" export PATH="/usr/lib/ccache:$PATH"
fi fi

View File

@ -1,12 +1,12 @@
Relevant KLayout version: 0.29.11<br> Relevant KLayout version: 0.30.2<br>
Author: Kazzz-S<br> Author: Kazzz-S<br>
Last modified: 2025-01-19<br> Last modified: 2025-05-30<br>
# 1. Introduction # 1. Introduction
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.29.11 or later for different 64-bit macOS, including: This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.30.2 or later for different 64-bit macOS, including:
* Sonoma (14.x) : the primary development environment * Sequoia (15.x) : the primary development environment
* Ventura (13.x) : experimental * Sonoma (14.x) : experimental
* Sequoia (15.x) : -- ditto -- * Ventura (13.x) : -- ditto --
Building KLayout for the previous operating systems listed below has been discontinued.<br> Building KLayout for the previous operating systems listed below has been discontinued.<br>
Pre-built DMG packages are also not provided.<br> Pre-built DMG packages are also not provided.<br>
@ -18,7 +18,7 @@ Pre-built DMG packages are also not provided.<br>
* Sierra (10.12) * Sierra (10.12)
* El Capitan (10.11) * El Capitan (10.11)
Throughout this document, the primary target machine is **Intel x86_64** with **macOS Sonoma**.<br> Throughout this document, the primary target machine is **Intel x86_64** with **macOS Sequoia**.<br>
All Apple (M1|M2|M3|M4) chips are still untested, as the author does not own an (M1|M2|M3|M4) Mac.<br> All Apple (M1|M2|M3|M4) chips are still untested, as the author does not own an (M1|M2|M3|M4) Mac.<br>
However, some kind volunteers told me they successfully built on an Apple silicon machine.<br> However, some kind volunteers told me they successfully built on an Apple silicon machine.<br>
@ -43,7 +43,7 @@ If you have installed Anaconda3 under $HOME/opt/anaconda3/, make a symbolic link
/Applications/anaconda3/ ---> $HOME/opt/anaconda3/ /Applications/anaconda3/ ---> $HOME/opt/anaconda3/
``` ```
The migration work to "Qt6" is ongoing. You can try to use it; however, you might encounter some build and runtime errors.<br> The migration work to "Qt6" is ongoing. You can try to use it; however, you might encounter some build or runtime errors.<br>
If you use **Homebrew** to build KLayout >= 0.29.0, you need "Qt6" to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599).<br> If you use **Homebrew** to build KLayout >= 0.29.0, you need "Qt6" to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599).<br>
I have also tried migrating to "Python 3.12.x" (earlier, Python 3.11.x) in this version. I have also tried migrating to "Python 3.12.x" (earlier, Python 3.11.x) in this version.
@ -70,7 +70,7 @@ The operating system type is detected automatically.
``` ```
----------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------
<< Usage of 'build4mac.py' >> << Usage of 'build4mac.py' >>
for building KLayout 0.29.11 or later on different Apple macOS platforms. for building KLayout 0.30.2 or later on different Apple macOS platforms.
$ [python] ./build4mac.py $ [python] ./build4mac.py
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value
@ -123,7 +123,7 @@ $ [python] ./build4mac.py
``` ```
# 6. Use-cases # 6. Use-cases
In this section, the actual file and directory names are those obtained on macOS Sonoma.<br> In this section, the actual file and directory names are those obtained on macOS Sequoia.<br>
On different OS, those names differ accordingly. On different OS, those names differ accordingly.
### 6A. Standard build using the OS-bundled Ruby and Python with MacPorts Qt5 ### 6A. Standard build using the OS-bundled Ruby and Python with MacPorts Qt5
@ -141,7 +141,7 @@ Confirm that you have:
``` ```
As of this writing, the provided Python version is `3.9.6`. As of this writing, the provided Python version is `3.9.6`.
1. Invoke **`build4mac.py`** with the following options: **((Notes))** These options are the default values for Sonoma, Ventura, and Sequioa. 1. Invoke **`build4mac.py`** with the following options: **((Notes))** These options are the default values for Sequoia, Sonoma, and Ventura.
``` ```
$ cd /where/'build.sh'/exists $ cd /where/'build.sh'/exists
$ ./build4mac.py -q qt5macports -r sys -p sys $ ./build4mac.py -q qt5macports -r sys -p sys
@ -154,7 +154,7 @@ $ ./build4mac.py -q qt5macports -r sys -p sys
$ ./build4mac.py -q qt5macports -r sys -p sys -y $ ./build4mac.py -q qt5macports -r sys -p sys -y
``` ```
The application bundle **`klayout.app`** is located under:<br> The application bundle **`klayout.app`** is located under:<br>
**`ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys`** directory, where **`ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys`** directory, where
* "ST-" means this is a standard package. * "ST-" means this is a standard package.
* "qt5MP" means that Qt5 from MacPorts is used. * "qt5MP" means that Qt5 from MacPorts is used.
* "RsysPsys" means that Ruby is 2.6 provided by OS; Python is 3.9 provided by OS. * "RsysPsys" means that Ruby is 2.6 provided by OS; Python is 3.9 provided by OS.
@ -185,7 +185,7 @@ $ ./build4mac.py -q qt5macports -r mp33 -p mp312
$ ./build4mac.py -q qt5macports -r mp33 -p mp312 -Y $ ./build4mac.py -q qt5macports -r mp33 -p mp312 -Y
``` ```
The application bundle **`klayout.app`** is located under:<br> The application bundle **`klayout.app`** is located under:<br>
**`LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312`** directory, where **`LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312`** directory, where
* "LW-" means this is a lightweight package. * "LW-" means this is a lightweight package.
* "qt5MP" means that Qt5 from MacPorts is used. * "qt5MP" means that Qt5 from MacPorts is used.
* "Rmp33Pmp312" means that Ruby is 3.3 from MacPorts; Python is 3.12 from MacPorts. * "Rmp33Pmp312" means that Ruby is 3.3 from MacPorts; Python is 3.12 from MacPorts.
@ -218,7 +218,7 @@ $ ./build4mac.py -q qt6brew -r hb34 -p hb312
$ ./build4mac.py -q qt6brew -r hb34 -p hb312 -Y $ ./build4mac.py -q qt6brew -r hb34 -p hb312 -Y
``` ```
The application bundle **`klayout.app`** is located under:<br> The application bundle **`klayout.app`** is located under:<br>
**`LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312`** directory, where **`LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312`** directory, where
* "LW-" means this is a lightweight package. * "LW-" means this is a lightweight package.
* "qt6Brew" means that Qt6 from Homebrew is used. * "qt6Brew" means that Qt6 from Homebrew is used.
* "Rhb34Phb312" means that Ruby is 3.4 from Homebrew; Python is 3.12 from Homebrew. * "Rhb34Phb312" means that Ruby is 3.4 from Homebrew; Python is 3.12 from Homebrew.
@ -258,7 +258,7 @@ $ ./build4mac.py -q qt6brew -r sys -p hb311
$ ./build4mac.py -q qt6brew -r sys -p hb311 -y $ ./build4mac.py -q qt6brew -r sys -p hb311 -y
``` ```
The application bundle **`klayout.app`** is located under:<br> The application bundle **`klayout.app`** is located under:<br>
**`HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311`** directory, where **`HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311`** directory, where
* "HW-" means this is a heavyweight package because both Qt6 and Python Frameworks are deployed. * "HW-" means this is a heavyweight package because both Qt6 and Python Frameworks are deployed.
* "qt6Brew" means that Qt6 from Homebrew is used. * "qt6Brew" means that Qt6 from Homebrew is used.
* "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew. * "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew.
@ -300,14 +300,14 @@ $ ./build4mac.py -q qt5macports -r sys -p hb311
$ ./build4mac.py -q qt5macports -r sys -p hb311 -y $ ./build4mac.py -q qt5macports -r sys -p hb311 -y
``` ```
The application bundle **`klayout.app`** is located under:<br> The application bundle **`klayout.app`** is located under:<br>
**`HW-qt5MP.pkg.macos-Sonoma-release-RsysPhb311`** directory, where **`HW-qt5MP.pkg.macos-Sequoia-release-RsysPhb311`** directory, where
* "HW-" means this is a heavyweight package because both Qt5 and Python Frameworks are deployed. * "HW-" means this is a heavyweight package because both Qt5 and Python Frameworks are deployed.
* "qt5MP" means that Qt5 from MacPorts is used. * "qt5MP" means that Qt5 from MacPorts is used.
* "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew. * "RsysPhb311" means that Ruby is OS-bundled; Python is 3.11 from Homebrew.
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation. 4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
### 6F. Fully Anaconda3-flavored build with Anaconda3 Ruby 3.2 and Anaconda3 Python 3.12 ### 6F. Fully Anaconda3-flavored build with Anaconda3 Ruby 3.2 and Anaconda3 Python 3.12
0. Install Anaconda3 (Anaconda3-2024.06-1-MacOSX-x86_64.pkg), then install Ruby 3.2 and libgit2 by 0. Install Anaconda3 (Anaconda3-2024.10-1-MacOSX-x86_64.pkg), then install Ruby 3.2 and libgit2 by
``` ```
$ conda install ruby=3.2.2 $ conda install ruby=3.2.2
$ conda install libgit2=1.6.4 $ conda install libgit2=1.6.4
@ -327,7 +327,7 @@ $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3
$ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y $ ./build4mac.py -q qt5ana3 -r ana3 -p ana3 -Y
``` ```
The application bundle **`klayout.app`** is located under:<br> The application bundle **`klayout.app`** is located under:<br>
**`LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3`** directory, where **`LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3`** directory, where
* "LW-" means this is a lightweight package. * "LW-" means this is a lightweight package.
* "qt5Ana3" means that Qt5 from Anaconda3 is used. * "qt5Ana3" means that Qt5 from Anaconda3 is used.
* "Rana3Pana3" means that Ruby (3.2) is from Anaconda3; Python (3.12) is from Anaconda3. * "Rana3Pana3" means that Ruby (3.2) is from Anaconda3; Python (3.12) is from Anaconda3.
@ -394,11 +394,11 @@ makeDMG4mac.py -> macbuild/makeDMG4mac.py
2. Invoke **`makeDMG4mac.py`** with -p and -m options, for example, 2. Invoke **`makeDMG4mac.py`** with -p and -m options, for example,
``` ```
$ cd /where/'build.sh'/exists $ cd /where/'build.sh'/exists
$ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312 -m $ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312 -m
``` ```
This command will generate the two files below:<br> This command will generate the two files below:<br>
* **`LW-klayout-0.29.11-macOS-Sonoma-1-qt5MP-Rmp33Pmp312.dmg`** ---(1) the main DMG file * **`LW-klayout-0.30.2-macOS-Sequoia-1-qt5MP-Rmp33Pmp312.dmg`** ---(1) the main DMG file
* **`LW-klayout-0.29.11-macOS-Sonoma-1-qt5MP-Rmp33Pmp312.dmg.md5`** ---(2) MD5-value text file * **`LW-klayout-0.30.2-macOS-Sequoia-1-qt5MP-Rmp33Pmp312.dmg.md5`** ---(2) MD5-value text file
# Known issues # Known issues
Because we assume some specific versions of non-OS-standard Ruby and Python, updating Homebrew, MacPorts, or Anaconda3 may cause build- and link errors.<br> Because we assume some specific versions of non-OS-standard Ruby and Python, updating Homebrew, MacPorts, or Anaconda3 may cause build- and link errors.<br>

View File

@ -5,7 +5,7 @@
# File: "macbuild/build4mac.py" # File: "macbuild/build4mac.py"
# #
# The top Python script for building KLayout (http://www.klayout.de/index.php) # The top Python script for building KLayout (http://www.klayout.de/index.php)
# version 0.29.11 or later on different Apple Mac OSX platforms. # version 0.30.2 or later on different Apple Mac OSX platforms.
#=============================================================================== #===============================================================================
import sys import sys
import os import os
@ -45,7 +45,7 @@ def GenerateUsage(platform):
usage = "\n" usage = "\n"
usage += "-----------------------------------------------------------------------------------------------------------\n" usage += "-----------------------------------------------------------------------------------------------------------\n"
usage += "<< Usage of 'build4mac.py' >>\n" usage += "<< Usage of 'build4mac.py' >>\n"
usage += " for building KLayout 0.29.11 or later on different Apple macOS platforms.\n" usage += " for building KLayout 0.30.2 or later on different Apple macOS platforms.\n"
usage += "\n" usage += "\n"
usage += "$ [python] ./build4mac.py\n" usage += "$ [python] ./build4mac.py\n"
usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value\n" usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value\n"
@ -847,29 +847,30 @@ def Build_pymod_wheel(parameters):
cmd3_args = " <wheel file> \\\n" cmd3_args = " <wheel file> \\\n"
cmd4_args = " -m setup clean --all \\\n" cmd4_args = " -m setup clean --all \\\n"
#-------------------------------------------------------------------- #-----------------------------------------------------------------------------------
# [4] Make the consolidated command lines # [4] Make the consolidated command lines
#-------------------------------------------------------------------- # "caffeinate" makes the CPU run at full speed even when the screen is locked.
#-----------------------------------------------------------------------------------
command1 = "time" command1 = "time"
command1 += " \\\n %s \\\n" % parameters['python'] command1 += " \\\n caffeinate -i %s \\\n" % parameters['python']
command1 += cmd1_args command1 += cmd1_args
command1 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile'] command1 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command1 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0 command1 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
command2 = "time" command2 = "time"
command2 += " \\\n %s \\\n" % parameters['python'] command2 += " \\\n caffeinate -i %s \\\n" % parameters['python']
command2 += cmd2_args command2 += cmd2_args
command2 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile'] command2 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command2 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0 command2 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
command3 = "time" command3 = "time"
command3 += " \\\n %s \\\n" % deloc_cmd command3 += " \\\n caffeinate -i %s \\\n" % deloc_cmd
command3 += cmd3_args command3 += cmd3_args
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile'] command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0 command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
command4 = "time" command4 = "time"
command4 += " \\\n %s \\\n" % parameters['python'] command4 += " \\\n caffeinate -i %s \\\n" % parameters['python']
command4 += cmd4_args command4 += cmd4_args
command4 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile'] command4 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command4 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0 command4 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
@ -923,10 +924,10 @@ def Build_pymod_wheel(parameters):
# Refer to: https://github.com/Kazzz-S/klayout/issues/49#issuecomment-1432154118 # Refer to: https://github.com/Kazzz-S/klayout/issues/49#issuecomment-1432154118
# https://pypi.org/project/delocate/ # https://pypi.org/project/delocate/
#--------------------------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------------------------
cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl'] cmd3_args = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.30.2-cp312-cp312-macosx_10_15_x86_64.whl']
if len(cmd3_args) == 1: if len(cmd3_args) == 1:
command3 = "time" command3 = "time"
command3 += " \\\n %s \\\n" % deloc_cmd command3 += " \\\n caffeinate -i %s \\\n" % deloc_cmd
command3 += " %s \\\n" % cmd3_args[0] command3 += " %s \\\n" % cmd3_args[0]
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile'] command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0 command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
@ -953,13 +954,13 @@ def Build_pymod_wheel(parameters):
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# [5-C] Forcibly change the wheel file name for anaconda3 # [5-C] Forcibly change the wheel file name for anaconda3
# Ref. https://github.com/Kazzz-S/klayout/issues/53 # Ref. https://github.com/Kazzz-S/klayout/issues/53
# original: klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl # original: klayout-0.30.2-cp312-cp312-macosx_10_15_x86_64.whl
# | # |
# V # V
# new: klayout-0.29.7-cp312-cp312-macosx_10_9_x86_64.whl # new: klayout-0.30.2-cp312-cp312-macosx_10_9_x86_64.whl
#------------------------------------------------------------------------ #------------------------------------------------------------------------
if whlTarget == "ana3": if whlTarget == "ana3":
wheels = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.29.7-cp312-cp312-macosx_12_0_x86_64.whl'] wheels = glob.glob( "dist/*.whl" ) # like ['dist/klayout-0.30.2-cp312-cp312-macosx_10_15_x86_64.whl']
if not len(wheels) == 1: if not len(wheels) == 1:
print( "", file=sys.stderr ) print( "", file=sys.stderr )
print( "-------------------------------------------------------------", file=sys.stderr ) print( "-------------------------------------------------------------", file=sys.stderr )
@ -1114,11 +1115,12 @@ def Run_Build_Command(config, parameters):
else: else:
cmd_args += " \\\n -nopython" cmd_args += " \\\n -nopython"
#----------------------------------------------------- #-----------------------------------------------------------------------------------
# [4] Make the consolidated command line # [4] Make the consolidated command line
#----------------------------------------------------- # "caffeinate" makes the CPU run at full speed even when the screen is locked.
#-----------------------------------------------------------------------------------
command = "time" command = "time"
command += " \\\n %s" % parameters['build_cmd'] command += " \\\n caffeinate -i %s" % parameters['build_cmd']
command += cmd_args command += cmd_args
command += " 2>&1 | tee %s; \\\n" % parameters['logfile'] command += " 2>&1 | tee %s; \\\n" % parameters['logfile']
command += "test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0 command += "test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
@ -1831,33 +1833,33 @@ def Deploy_Binaries_For_Bundle(config, parameters):
#----------------------------------------------------------------------------------------------- #-----------------------------------------------------------------------------------------------
# [9] Special deployment of Python3.11 from Homebrew # [9] Special deployment of Python3.11 from Homebrew
# To use Python3.1 from Homebrew on Sonoma... # To use Python3.11 from Homebrew on Sequoia...
# in "/usr/local/opt/python@3.11/lib/" # in "/usr/local/opt/python@3.11/lib/"
# Python.framework -> ../Frameworks/Python.framework/ <=== this symbolic was needed # Python.framework -> ../Frameworks/Python.framework/ <=== this symbolic was needed
# pkgconfig/ # pkgconfig/
# #
# Use the "python3HB.py" tool to make different symbolic links [*] including the above one. # Use the "python3HB.py" tool to make different symbolic links [*] including the above one.
# Sonoma{kazzz-s} lib (1)% pwd # Sequoia{kazzz-s} lib (1)% pwd
# /usr/local/opt/python@3.11/lib # /usr/local/opt/python@3.11/lib
# Sonoma{kazzz-s} lib (2)% ll # Sequoia{kazzz-s} lib (2)% ll
# total 0 # total 0
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 . # drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
# drwxr-xr-x 14 kazzz-s admin 448 9 21 18:33 .. # drwxr-xr-x 14 kazzz-s admin 448 9 21 18:33 ..
# [*] lrwxr-xr-x 1 kazzz-s admin 31 9 21 23:03 Python.framework -> ../Frameworks/Python.framework/ # [*] lrwxr-xr-x 1 kazzz-s admin 31 9 21 23:03 Python.framework -> ../Frameworks/Python.framework/
# drwxr-xr-x 4 kazzz-s admin 128 9 7 10:03 pkgconfig # drwxr-xr-x 4 kazzz-s admin 128 9 7 10:03 pkgconfig
# #
# Sonoma{kazzz-s} Python.framework (3)% pwd # Sequoia{kazzz-s} Python.framework (3)% pwd
# /usr/local/opt/python@3.11/Frameworks/Python.framework/Versions # /usr/local/opt/python@3.11/Frameworks/Python.framework/Versions
# Sonoma{kazzz-s} Versions (4)% ll # Sequoia{kazzz-s} Versions (4)% ll
# total 0 # total 0
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 . # drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 .. # drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 ..
# drwxr-xr-x 9 kazzz-s admin 288 9 7 10:03 3.11 # drwxr-xr-x 9 kazzz-s admin 288 9 7 10:03 3.11
# [*] lrwxr-xr-x 1 kazzz-s admin 5 9 21 23:03 Current -> 3.11/ # [*] lrwxr-xr-x 1 kazzz-s admin 5 9 21 23:03 Current -> 3.11/
# #
# Sonoma{kazzz-s} Python.framework (5)% pwd # Sequoia{kazzz-s} Python.framework (5)% pwd
# /usr/local/opt/python@3.11/Frameworks/Python.framework # /usr/local/opt/python@3.11/Frameworks/Python.framework
# Sonoma{kazzz-s} Python.framework (6)% ll # Sequoia{kazzz-s} Python.framework (6)% ll
# total 0 # total 0
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 . # drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 .
# drwxr-xr-x 3 kazzz-s admin 96 9 7 10:03 .. # drwxr-xr-x 3 kazzz-s admin 96 9 7 10:03 ..

View File

@ -6,7 +6,7 @@
# #
# Here are dictionaries of ... # Here are dictionaries of ...
# different modules for building KLayout (http://www.klayout.de/index.php) # different modules for building KLayout (http://www.klayout.de/index.php)
# version 0.29.11 or later on different Apple Mac OSX platforms. # version 0.30.2 or later on different Apple Mac OSX platforms.
# #
# This file is imported by 'build4mac.py' script. # This file is imported by 'build4mac.py' script.
#=============================================================================== #===============================================================================
@ -192,7 +192,7 @@ RubySequoia = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions
# install with 'sudo port install ruby33' # install with 'sudo port install ruby33'
# [Key Type Name] = 'MP33' # [Key Type Name] = 'MP33'
Ruby33MacPorts = { 'exe': '/opt/local/bin/ruby3.3', Ruby33MacPorts = { 'exe': '/opt/local/bin/ruby3.3',
'inc': '/opt/local/include/ruby-3.3.6', 'inc': '/opt/local/include/ruby-3.3.9',
'lib': '/opt/local/lib/libruby.3.3.dylib' 'lib': '/opt/local/lib/libruby.3.3.dylib'
} }

View File

@ -6,7 +6,7 @@
# #
# Here are utility functions and classes ... # Here are utility functions and classes ...
# for building KLayout (http://www.klayout.de/index.php) # for building KLayout (http://www.klayout.de/index.php)
# version 0.29.7 or later on different Apple Mac OSX platforms. # version 0.30.2 or later on different Apple Mac OSX platforms.
# #
# This file is imported by 'build4mac.py' script. # This file is imported by 'build4mac.py' script.
#======================================================================================== #========================================================================================

View File

@ -5,7 +5,7 @@
# File: "macbuild/macQAT.py" # File: "macbuild/macQAT.py"
# #
# The top Python script to run "ut_runner" after building KLayout # The top Python script to run "ut_runner" after building KLayout
# (http://www.klayout.de/index.php) version 0.29.7 or later on different # (http://www.klayout.de/index.php) version 0.30.2 or later on different
# Apple Mac OSX platforms. # Apple Mac OSX platforms.
# #
# This script must be copied to a "*.macQAT/" directory to run. # This script must be copied to a "*.macQAT/" directory to run.

View File

@ -4,7 +4,7 @@
# File: "macbuild/macQAT.sh" # File: "macbuild/macQAT.sh"
# #
# The top Bash script to run "ut_runner" after building KLayout # The top Bash script to run "ut_runner" after building KLayout
# (http://www.klayout.de/index.php) version 0.29.7 or later on different # (http://www.klayout.de/index.php) version 0.30.2 or later on different
# Apple Mac OSX platforms. # Apple Mac OSX platforms.
# #
# This script must be copied to a "*.macQAT/" directory to run. # This script must be copied to a "*.macQAT/" directory to run.

View File

@ -4,7 +4,7 @@
# File: "macbuild/macQAT2.sh" # File: "macbuild/macQAT2.sh"
# #
# The top Bash script to run "ut_runner" after building KLayout # The top Bash script to run "ut_runner" after building KLayout
# (http://www.klayout.de/index.php) version 0.29.7 or later on different # (http://www.klayout.de/index.php) version 0.30.2 or later on different
# Apple Mac OSX platforms. # Apple Mac OSX platforms.
# #
# This script must be copied to a directory that can be found in $PATH. # This script must be copied to a directory that can be found in $PATH.

View File

@ -78,13 +78,13 @@ def SetGlobals():
Usage = "\n" Usage = "\n"
Usage += "---------------------------------------------------------------------------------------------------------\n" Usage += "---------------------------------------------------------------------------------------------------------\n"
Usage += "<< Usage of 'makeDMG4mac.py' >>\n" Usage += "<< Usage of 'makeDMG4mac.py' >>\n"
Usage += " for making a DMG file of KLayout 0.29.11 or later on different Apple macOS platforms.\n" Usage += " for making a DMG file of KLayout 0.30.2 or later on different Apple macOS platforms.\n"
Usage += "\n" Usage += "\n"
Usage += "$ [python] ./makeDMG4mac.py\n" Usage += "$ [python] ./makeDMG4mac.py\n"
Usage += " option & argument : descriptions | default value\n" Usage += " option & argument : descriptions | default value\n"
Usage += " ----------------------------------------------------------------------------------+-----------------\n" Usage += " ----------------------------------------------------------------------------------+-----------------\n"
Usage += " <-p|--pkg <dir>> : package directory created by `build4mac.py` with [-y|-Y] | ``\n" Usage += " <-p|--pkg <dir>> : package directory created by `build4mac.py` with [-y|-Y] | ``\n"
Usage += " : like 'LW-qt5MP.pkg.macos-Monterey-release-Rmp33Pmp311' | \n" Usage += " : like 'LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312' | \n"
Usage += " <-c|--clean> : clean the work directory | disabled\n" Usage += " <-c|--clean> : clean the work directory | disabled\n"
Usage += " <-m|--make> : make a compressed DMG file | disabled\n" Usage += " <-m|--make> : make a compressed DMG file | disabled\n"
Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n" Usage += " : <-c|--clean> and <-m|--make> are mutually exclusive | \n"
@ -218,17 +218,17 @@ def SetGlobals():
## To check the contents of the package directory ## To check the contents of the package directory
# #
# The package directory name should look like: # The package directory name should look like:
# * ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys # * ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3 # * LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312 --- (1) # * LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312 --- (1)
# * LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312 # * LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312
# * HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311 # * HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311
# #
# * ST-qt6MP.pkg.macos-Sonoma-release-RsysPsys # * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt6MP.pkg.macos-Sonoma-release-Rmp33Pmp312 # * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
# #
# Generated DMG will be, for example, # Generated DMG will be, for example,
# (1) ---> LW-klayout-0.29.7-macOS-Sonoma-1-qt6Brew-Rhb34Phb312.dmg # (1) ---> LW-klayout-0.30.2-macOS-Sequoia-1-qt6Brew-Rhb34Phb312.dmg
# #
# @return on success, positive integer in [MB] that tells approx. occupied disc space; # @return on success, positive integer in [MB] that tells approx. occupied disc space;
# on failure, -1 # on failure, -1
@ -268,15 +268,15 @@ def CheckPkgDirectory():
#----------------------------------------------------------------------------------------------- #-----------------------------------------------------------------------------------------------
# [2] Identify (Qt, Ruby, Python) from PkgDir # [2] Identify (Qt, Ruby, Python) from PkgDir
# * ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys # * ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3 # * LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312 # * LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312
# * LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312 # * LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312
# * HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311 # * HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311
# * EX-qt5MP.pkg.macos-Sonoma-release-Rhb34Pmp312 # * EX-qt5MP.pkg.macos-Sequoia-release-Rhb34Pmp312
# #
# * ST-qt6MP.pkg.macos-Sonoma-release-RsysPsys # * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt6MP.pkg.macos-Sonoma-release-Rmp33Pmp312 # * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
#----------------------------------------------------------------------------------------------- #-----------------------------------------------------------------------------------------------
# 0 1 2 3 4 5 6 7 # 0 1 2 3 4 5 6 7
patQRP = r'(ST|LW|HW|EX)([-])([qt5|qt6][0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-])(release|debug)([-])([0-9A-Za-z]+)' patQRP = r'(ST|LW|HW|EX)([-])([qt5|qt6][0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-])(release|debug)([-])([0-9A-Za-z]+)'
@ -424,7 +424,7 @@ def CheckPkgDirectory():
#------------------------------------------------------ #------------------------------------------------------
# [5] Check the occupied disk space # [5] Check the occupied disk space
#------------------------------------------------------ #------------------------------------------------------
command = "\du -sm %s" % DefaultBundleName command = r"\du -sm %s" % DefaultBundleName
sizeApp = int( os.popen(command).read().strip("\n").split("\t")[0] ) sizeApp = int( os.popen(command).read().strip("\n").split("\t")[0] )
#------------------------------------------------------ #------------------------------------------------------
@ -671,14 +671,14 @@ def MakeTargetDMGFile(msg=""):
imageDest = "%s/.background" % MountDir imageDest = "%s/.background" % MountDir
if not os.path.isdir(imageDest): if not os.path.isdir(imageDest):
os.mkdir(imageDest) os.mkdir(imageDest)
command = "\cp -p %s %s/%s" % (imageSrc, imageDest, BackgroundPNG) command = r"\cp -p %s %s/%s" % (imageSrc, imageDest, BackgroundPNG)
os.system(command) os.system(command)
#-------------------------------------------------------- #--------------------------------------------------------
# (6) Create a symbolic link to /Applications # (6) Create a symbolic link to /Applications
#-------------------------------------------------------- #--------------------------------------------------------
print( ">>> (6) Creating a symbolic link to /Applications..." ) print( ">>> (6) Creating a symbolic link to /Applications..." )
command = "\ln -s %s %s/%s" % (RootApplications, MountDir, RootApplications) command = r"\ln -s %s %s/%s" % (RootApplications, MountDir, RootApplications)
os.system(command) os.system(command)
#-------------------------------------------------------- #--------------------------------------------------------
@ -702,7 +702,7 @@ def MakeTargetDMGFile(msg=""):
print( ">>> (8) Copying the volume icon..." ) print( ">>> (8) Copying the volume icon..." )
iconsSrc = "macbuild/Resources/%s" % VolumeIcons iconsSrc = "macbuild/Resources/%s" % VolumeIcons
iconsDest = "%s/.VolumeIcon.icns" % MountDir iconsDest = "%s/.VolumeIcon.icns" % MountDir
command1 = "\cp -p %s %s" % (iconsSrc, iconsDest) command1 = r"\cp -p %s %s" % (iconsSrc, iconsDest)
command2 = "SetFile -c icnC %s" % iconsDest command2 = "SetFile -c icnC %s" % iconsDest
os.system(command1) os.system(command1)
sleep(2) sleep(2)
@ -713,7 +713,7 @@ def MakeTargetDMGFile(msg=""):
# (9) Change the permission # (9) Change the permission
#-------------------------------------------------------- #--------------------------------------------------------
print( ">>> (9) Changing permission to 755..." ) print( ">>> (9) Changing permission to 755..." )
command = "\chmod -Rf 755 %s &> /dev/null" % MountDir command = r"\chmod -Rf 755 %s &> /dev/null" % MountDir
os.system(command) os.system(command)
#-------------------------------------------------------- #--------------------------------------------------------

View File

@ -339,7 +339,7 @@ def Parse_CommandLine_Arguments():
Usage += " (3) $ ./nightlyBuild.py --test |\n" Usage += " (3) $ ./nightlyBuild.py --test |\n"
Usage += " (4) $ ./nightlyBuild.py --check (confirm the QA Test results) |\n" Usage += " (4) $ ./nightlyBuild.py --check (confirm the QA Test results) |\n"
Usage += " (5) $ ./nightlyBuild.py --makedmg 1 |\n" Usage += " (5) $ ./nightlyBuild.py --makedmg 1 |\n"
Usage += " (6) $ ./nightlyBuild.py --upload '0.29.7' |\n" Usage += " (6) $ ./nightlyBuild.py --upload '0.30.2' |\n"
Usage += " (7) $ ./nightlyBuild.py --cleandmg 1 |\n" Usage += " (7) $ ./nightlyBuild.py --cleandmg 1 |\n"
Usage += "-----------------------------------------------------------------------------+----------------------------\n" Usage += "-----------------------------------------------------------------------------+----------------------------\n"

View File

@ -18,7 +18,7 @@ qtVer,target,bdType
5,0,r 5,0,r
5,1,r 5,1,r
6,2,r 6,2,r
6,13,r 5,13,r
5,4,r 5,4,r
#6,0,r #6,0,r
#6,1,r #6,1,r

Can't render this file because it contains an unexpected character in line 5 and column 30.

View File

@ -33,8 +33,7 @@ def SetGlobals():
Usage += "\n" Usage += "\n"
Usage += " option & argument : descriptions | default value\n" Usage += " option & argument : descriptions | default value\n"
Usage += " -------------------------------------------------------------------+---------------\n" Usage += " -------------------------------------------------------------------+---------------\n"
Usage += " <-v|--version <number>>: in ['3.8', '3.9', '3.10', '3.11', '3.12', | ''\n" Usage += " <-v|--version <number>>: in ['3.11', '3.12','3.13'] | ''\n"
Usage += " '3.13'] |\n"
Usage += " [-u|-unlink] : unlink only | disabled\n" Usage += " [-u|-unlink] : unlink only | disabled\n"
Usage += " [-?|--?] : print this usage and exit | disabled\n" Usage += " [-?|--?] : print this usage and exit | disabled\n"
Usage += "----------------------------------------------------------------------+-----------------\n" Usage += "----------------------------------------------------------------------+-----------------\n"
@ -50,7 +49,7 @@ def Parse_CLI_Args():
p.add_option( '-v', '--version', p.add_option( '-v', '--version',
dest='version', dest='version',
help="python3 version=['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']" ) help="python3 version=['3.11', '3.12', '3.13']" )
p.add_option( '-u', '--unlink', p.add_option( '-u', '--unlink',
action='store_true', action='store_true',
@ -75,7 +74,7 @@ def Parse_CLI_Args():
Version = opt.version Version = opt.version
UnlinkOnly = opt.unlink UnlinkOnly = opt.unlink
if not Version in [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]: if not Version in [ '3.11', '3.12', '3.13' ]:
print( "! Unsupported Python 3 version <%s>" % Version ) print( "! Unsupported Python 3 version <%s>" % Version )
print(Usage) print(Usage)
sys.exit(0) sys.exit(0)

View File

@ -1,3 +1,7 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[tool.cibuildwheel] [tool.cibuildwheel]
build-verbosity = "3" build-verbosity = "3"
test-command = [ test-command = [

View File

@ -57,6 +57,9 @@ $python $inst/stubgen.py tl >$pyi_srcdir/tlcore.pyi
echo "Generating stubs for db .." echo "Generating stubs for db .."
$python $inst/stubgen.py db tl,lay,rdb >$pyi_srcdir/dbcore.pyi $python $inst/stubgen.py db tl,lay,rdb >$pyi_srcdir/dbcore.pyi
echo "Generating stubs for pex .."
$python $inst/stubgen.py pex tl,db >$pyi_srcdir/pexcore.pyi
echo "Generating stubs for rdb .." echo "Generating stubs for rdb .."
$python $inst/stubgen.py rdb tl,db >$pyi_srcdir/rdbcore.pyi $python $inst/stubgen.py rdb tl,db >$pyi_srcdir/rdbcore.pyi

View File

@ -18,6 +18,82 @@
load(File.join(File.dirname(__FILE__), "common.conf")) load(File.join(File.dirname(__FILE__), "common.conf"))
def add_native_operator_neq(engine, cls)
cls_id = cls.gsub("::", "_")
engine.drop_method cls, /::operator\s*==/
engine.drop_method cls, /::operator\s*!=/
engine.add_native_impl(cls, <<"CODE", <<"DECL")
static bool #{cls_id}_operator_eq(const #{cls} *a, const #{cls} &b) {
return *a == b;
}
static bool #{cls_id}_operator_ne(const #{cls} *a, const #{cls} &b) {
return !(*a == b);
}
CODE
gsi::method_ext("==", &#{cls_id}_operator_eq, gsi::arg ("other"), "@brief Method bool #{cls}::operator==(const #{cls} &) const") +
gsi::method_ext("!=", &#{cls_id}_operator_ne, gsi::arg ("other"), "@brief Method bool #{cls}::operator!=(const #{cls} &) const")
DECL
end
def add_native_operator_neqlt(engine, cls)
cls_id = cls.gsub("::", "_")
engine.drop_method cls, /::operator\s*==/
engine.drop_method cls, /::operator\s*!=/
engine.drop_method cls, /::operator\s*</
engine.add_native_impl(cls, <<"CODE", <<"DECL")
static bool #{cls_id}_operator_eq(const #{cls} *a, const #{cls} &b) {
return *a == b;
}
static bool #{cls_id}_operator_ne(const #{cls} *a, const #{cls} &b) {
return !(*a == b);
}
static bool #{cls_id}_operator_lt(const #{cls} *a, const #{cls} &b) {
return *a < b;
}
CODE
gsi::method_ext("==", &#{cls_id}_operator_eq, gsi::arg ("other"), "@brief Method bool #{cls}::operator==(const #{cls} &) const") +
gsi::method_ext("!=", &#{cls_id}_operator_ne, gsi::arg ("other"), "@brief Method bool #{cls}::operator!=(const #{cls} &) const") +
gsi::method_ext("<", &#{cls_id}_operator_lt, gsi::arg ("other"), "@brief Method bool #{cls}::operator<(const #{cls} &) const")
DECL
end
def add_native_operator_cmp(engine, cls)
cls_id = cls.gsub("::", "_")
engine.drop_method cls, /::operator\s*==/
engine.drop_method cls, /::operator\s*!=/
engine.drop_method cls, /::operator\s*</
engine.drop_method cls, /::operator\s*<=/
engine.drop_method cls, /::operator\s*>/
engine.drop_method cls, /::operator\s*>=/
engine.add_native_impl(cls, <<"CODE", <<"DECL")
static bool #{cls_id}_operator_eq(const #{cls} *a, const #{cls} &b) {
return *a == b;
}
static bool #{cls_id}_operator_ne(const #{cls} *a, const #{cls} &b) {
return *a != b;
}
static bool #{cls_id}_operator_le(const #{cls} *a, const #{cls} &b) {
return *a <= b;
}
static bool #{cls_id}_operator_lt(const #{cls} *a, const #{cls} &b) {
return *a < b;
}
static bool #{cls_id}_operator_ge(const #{cls} *a, const #{cls} &b) {
return *a >= b;
}
static bool #{cls_id}_operator_gt(const #{cls} *a, const #{cls} &b) {
return *a > b;
}
CODE
gsi::method_ext("==", &#{cls_id}_operator_eq, gsi::arg ("other"), "@brief Method bool #{cls}::operator==(const #{cls} &) const") +
gsi::method_ext("!=", &#{cls_id}_operator_ne, gsi::arg ("other"), "@brief Method bool #{cls}::operator!=(const #{cls} &) const") +
gsi::method_ext("<=", &#{cls_id}_operator_le, gsi::arg ("other"), "@brief Method bool #{cls}::operator<=(const #{cls} &) const") +
gsi::method_ext("<", &#{cls_id}_operator_lt, gsi::arg ("other"), "@brief Method bool #{cls}::operator<(const #{cls} &) const") +
gsi::method_ext(">=", &#{cls_id}_operator_ge, gsi::arg ("other"), "@brief Method bool #{cls}::operator>=(const #{cls} &) const") +
gsi::method_ext(">", &#{cls_id}_operator_gt, gsi::arg ("other"), "@brief Method bool #{cls}::operator>(const #{cls} &) const")
DECL
end
# -------------------------------------------------------------- # --------------------------------------------------------------
# all modules # all modules
@ -460,8 +536,6 @@ drop_method "QTextCodec", /QTextCodec::codecForName\(const\s+QByteArray/ # clash
drop_method "QTextCodec", /QTextCodec::toUnicode\(const\s+QByteArray/ # clashes with const char * variant drop_method "QTextCodec", /QTextCodec::toUnicode\(const\s+QByteArray/ # clashes with const char * variant
drop_method "QTextCodec", /QTextCodec::fromUnicode\(const\s+QChar\s+\*/ # requires real QChar * drop_method "QTextCodec", /QTextCodec::fromUnicode\(const\s+QChar\s+\*/ # requires real QChar *
drop_method "QTextEncoder", /QTextEncoder::fromUnicode\(const\s+QChar\s+\*/ # requires real QChar * drop_method "QTextEncoder", /QTextEncoder::fromUnicode\(const\s+QChar\s+\*/ # requires real QChar *
drop_method "QTimeZone", /::operator\s*==/ # no longer supported on Qt 6.7
drop_method "QTimeZone", /::operator\s*!=/ # no longer supported on Qt 6.7
drop_method "", /::operator\s*==\(const\s+QVariant\s*&\w+,\s*const\s+QVariantComparisonHelper/ # requires QVariantComparisonHelper drop_method "", /::operator\s*==\(const\s+QVariant\s*&\w+,\s*const\s+QVariantComparisonHelper/ # requires QVariantComparisonHelper
drop_method "", /::operator\s*!=\(const\s+QVariant\s*&\w+,\s*const\s+QVariantComparisonHelper/ # requires QVariantComparisonHelper drop_method "", /::operator\s*!=\(const\s+QVariant\s*&\w+,\s*const\s+QVariantComparisonHelper/ # requires QVariantComparisonHelper
drop_method "QByteArrayMatcher", /QByteArrayMatcher::indexIn\(const\s+QByteArray/ # clashes with const char * variant drop_method "QByteArrayMatcher", /QByteArrayMatcher::indexIn\(const\s+QByteArray/ # clashes with const char * variant
@ -473,6 +547,34 @@ drop_method "QDebug", /QDebug::operator\s*<<\((?!const\s+QString\s*&)/ # don't m
drop_method "", /::operator\s*<<\(QDebug\s*\w*\s*,\s*(?!const\s+QString\s*&)/ # don't map the others right now - too many (TODO: how to map?) drop_method "", /::operator\s*<<\(QDebug\s*\w*\s*,\s*(?!const\s+QString\s*&)/ # don't map the others right now - too many (TODO: how to map?)
drop_method "QNoDebug", /QNoDebug::operator<</ # nothing usable (TODO: how to map?) drop_method "QNoDebug", /QNoDebug::operator<</ # nothing usable (TODO: how to map?)
# No longer supported operator== and operator!= in Qt 6.7/6.8/6.9
add_native_operator_neq(self, "QEasingCurve")
add_native_operator_neq(self, "QTimeZone")
add_native_operator_neq(self, "QDir")
add_native_operator_neq(self, "QFileInfo")
add_native_operator_neq(self, "QItemSelectionRange")
add_native_operator_neq(self, "QJsonArray")
add_native_operator_cmp(self, "QJsonArray::iterator")
add_native_operator_neq(self, "QJsonDocument")
add_native_operator_neq(self, "QJsonObject")
add_native_operator_cmp(self, "QJsonObject::iterator")
add_native_operator_neq(self, "QJsonValue")
add_native_operator_neq(self, "QJsonValueRef")
add_native_operator_neq(self, "QLine")
add_native_operator_neq(self, "QLineF")
add_native_operator_neq(self, "QMimeType")
add_native_operator_neqlt(self, "QModelIndex")
add_native_operator_neqlt(self, "QPersistentModelIndex")
add_native_operator_neq(self, "QProcessEnvironment")
add_native_operator_neq(self, "QRegularExpression")
add_native_operator_neqlt(self, "QUrl")
add_native_operator_neq(self, "QUrlQuery")
add_native_operator_neq(self, "QDomNodeList")
add_native_operator_neq(self, "QXmlStreamAttribute")
add_native_operator_neq(self, "QXmlStreamEntityDeclaration")
add_native_operator_neq(self, "QXmlStreamNamespaceDeclaration")
add_native_operator_neq(self, "QXmlStreamNotationDeclaration")
include "QCoreApplication", [ "<QCoreApplication>", "<QAbstractEventDispatcher>", "<QAbstractNativeEventFilter>", "<QTranslator>" ] include "QCoreApplication", [ "<QCoreApplication>", "<QAbstractEventDispatcher>", "<QAbstractNativeEventFilter>", "<QTranslator>" ]
include "QThread", [ "<QThread>", "<QAbstractEventDispatcher>" ] include "QThread", [ "<QThread>", "<QAbstractEventDispatcher>" ]
@ -551,6 +653,7 @@ no_default_ctor "QModelRoleData"
no_default_ctor "QPartialOrdering" no_default_ctor "QPartialOrdering"
no_default_ctor "QOperatingSystemVersion" no_default_ctor "QOperatingSystemVersion"
no_default_ctor "QStringConverter" no_default_ctor "QStringConverter"
no_default_ctor "QStringConverterBase"
drop_method "QMessageLogger", /QMessageLogger::critical.*\.\.\./ # does not support ... drop_method "QMessageLogger", /QMessageLogger::critical.*\.\.\./ # does not support ...
drop_method "QMessageLogger", /QMessageLogger::debug.*\.\.\./ # does not support ... drop_method "QMessageLogger", /QMessageLogger::debug.*\.\.\./ # does not support ...

View File

@ -592,6 +592,25 @@ _db = Library(
) )
config.add_extension(_db) config.add_extension(_db)
# ------------------------------------------------------------------
# _pex dependency library
_pex_path = os.path.join("src", "pex", "pex")
_pex_sources = set(glob.glob(os.path.join(_pex_path, "*.cc")))
_pex = Library(
config.root + "._pex",
define_macros=config.macros() + [("MAKE_PEX_LIBRARY", 1)],
include_dirs=[_tl_path, _gsi_path, _db_path, _pex_path],
extra_objects=[config.path_of("_tl", _tl_path), config.path_of("_gsi", _gsi_path), config.path_of("_db", _db_path)],
language="c++",
libraries=config.libraries('_pex'),
extra_link_args=config.link_args("_pex"),
extra_compile_args=config.compile_args("_pex"),
sources=list(_pex_sources),
)
config.add_extension(_pex)
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# _lib dependency library # _lib dependency library
@ -869,6 +888,28 @@ db = Extension(
sources=list(db_sources), sources=list(db_sources),
) )
# ------------------------------------------------------------------
# pex extension library
pex_path = os.path.join("src", "pymod", "pex")
pex_sources = set(glob.glob(os.path.join(pex_path, "*.cc")))
pex = Extension(
config.root + ".pexcore",
define_macros=config.macros(),
include_dirs=[_db_path, _tl_path, _gsi_path, _pya_path, _pex_path],
extra_objects=[
config.path_of("_db", _db_path),
config.path_of("_pex", _pex_path),
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_pya", _pya_path),
],
extra_link_args=config.link_args("pexcore"),
extra_compile_args=config.compile_args("pexcore"),
sources=list(pex_sources),
)
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# lib extension library # lib extension library
@ -987,7 +1028,7 @@ if __name__ == "__main__":
setup( setup(
name=config.root, name=config.root,
version=config.version(), version=config.version(),
license="GNU GPLv3", license="GPL-3.0-or-later",
description="KLayout standalone Python package", description="KLayout standalone Python package",
long_description="This package is a standalone distribution of KLayout's Python API.\n\nFor more details see here: https://www.klayout.org/klayout-pypi", long_description="This package is a standalone distribution of KLayout's Python API.\n\nFor more details see here: https://www.klayout.org/klayout-pypi",
author="Matthias Koefferlein", author="Matthias Koefferlein",
@ -996,7 +1037,6 @@ if __name__ == "__main__":
# Recommended classifiers # Recommended classifiers
"Programming Language :: Python :: 2", "Programming Language :: Python :: 2",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: MacOS :: MacOS X", "Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows", "Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux", "Operating System :: POSIX :: Linux",
@ -1011,8 +1051,8 @@ if __name__ == "__main__":
package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]}, package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]},
data_files=[(config.root, ["src/pymod/distutils_src/klayout/py.typed"])], data_files=[(config.root, ["src/pymod/distutils_src/klayout/py.typed"])],
include_package_data=True, include_package_data=True,
ext_modules=[_tl, _gsi, _pya, _rba, _db, _lib, _rdb, _lym, _laybasic, _layview, _ant, _edt, _img] ext_modules=[_tl, _gsi, _pya, _rba, _db, _pex, _lib, _rdb, _lym, _laybasic, _layview, _ant, _edt, _img]
+ db_plugins + db_plugins
+ [tl, db, lib, rdb, lay, pya], + [tl, db, pex, lib, rdb, lay, pya],
cmdclass={'build_ext': klayout_build_ext} cmdclass={'build_ext': klayout_build_ext}
) )

View File

@ -419,6 +419,19 @@ PropertiesPage::description () const
return tl::to_string (tr ("Rulers and Annotations")); return tl::to_string (tr ("Rulers and Annotations"));
} }
void
PropertiesPage::confine_selection (const std::vector<size_t> &remaining_entries)
{
std::vector <ant::Service::obj_iterator> org_selection;
m_selection.swap (org_selection);
for (auto i = remaining_entries.begin (); i != remaining_entries.end (); ++i) {
m_selection.push_back (org_selection [*i]);
}
mp_rulers->set_selection (m_selection);
mp_rulers->clear_highlights ();
}
void void
PropertiesPage::leave () PropertiesPage::leave ()
{ {
@ -517,7 +530,7 @@ PropertiesPage::readonly ()
} }
void void
PropertiesPage::apply () PropertiesPage::apply (bool /*commit*/)
{ {
ant::Object obj; ant::Object obj;
get_object (obj); get_object (obj);

View File

@ -47,10 +47,11 @@ public:
virtual void select_entries (const std::vector<size_t> &entries); virtual void select_entries (const std::vector<size_t> &entries);
virtual std::string description (size_t entry) const; virtual std::string description (size_t entry) const;
virtual std::string description () const; virtual std::string description () const;
virtual void confine_selection (const std::vector<size_t> &remaining_entries);
virtual void update (); virtual void update ();
virtual void leave (); virtual void leave ();
virtual bool readonly (); virtual bool readonly ();
virtual void apply (); virtual void apply (bool commit);
private slots: private slots:
void swap_points_clicked (); void swap_points_clicked ();

View File

@ -1410,8 +1410,8 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
double dmin = std::numeric_limits <double>::max (); double dmin = std::numeric_limits <double>::max ();
const ant::Object *robj_min = 0; const ant::Object *robj_min = 0;
for (std::map<obj_iterator, unsigned int>::const_iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r->first).ptr ()); const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
if (robj) { if (robj) {
double d; double d;
if (is_selected (*robj, p, l, d)) { if (is_selected (*robj, p, l, d)) {
@ -1425,9 +1425,9 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
// further investigate what part to drag // further investigate what part to drag
for (std::map<obj_iterator, unsigned int>::const_iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
obj_iterator ri = r->first; obj_iterator ri = *r;
const ant::Object *robj = dynamic_cast <const ant::Object *> ((*ri).ptr ()); const ant::Object *robj = dynamic_cast <const ant::Object *> ((*ri).ptr ());
if (robj && (! robj_min || robj == robj_min)) { if (robj && (! robj_min || robj == robj_min)) {
@ -1435,7 +1435,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
// found anything: make the moved ruler the selection // found anything: make the moved ruler the selection
clear_selection (); clear_selection ();
m_selected.insert (std::make_pair (ri, 0)); m_selected.insert (ri);
m_current = *robj; m_current = *robj;
m_original = m_current; m_original = m_current;
m_rulers.push_back (new ant::View (this, &m_current, true)); m_rulers.push_back (new ant::View (this, &m_current, true));
@ -1492,7 +1492,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
// found anything: make the moved ruler the selection // found anything: make the moved ruler the selection
clear_selection (); clear_selection ();
m_selected.insert (std::make_pair (mp_view->annotation_shapes ().iterator_from_pointer (&*r), 0)); m_selected.insert (mp_view->annotation_shapes ().iterator_from_pointer (&*r));
m_current = *robj; m_current = *robj;
m_original = m_current; m_original = m_current;
m_rulers.push_back (new ant::View (this, &m_current, true)); m_rulers.push_back (new ant::View (this, &m_current, true));
@ -1667,16 +1667,16 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
if (m_move_mode == MoveSelected) { if (m_move_mode == MoveSelected) {
// replace the rulers that were moved: // replace the rulers that were moved:
for (std::map<obj_iterator, unsigned int>::const_iterator s = m_selected.begin (); s != m_selected.end (); ++s) { for (auto s = m_selected.begin (); s != m_selected.end (); ++s) {
const ant::Object *robj = dynamic_cast<const ant::Object *> (s->first->ptr ()); const ant::Object *robj = dynamic_cast<const ant::Object *> ((*s)->ptr ());
if (robj) { if (robj) {
// compute moved object and replace // compute moved object and replace
ant::Object *rnew = new ant::Object (*robj); ant::Object *rnew = new ant::Object (*robj);
rnew->transform (m_trans); rnew->transform (m_trans);
int new_id = rnew->id (); int new_id = rnew->id ();
mp_view->annotation_shapes ().replace (s->first, db::DUserObject (rnew)); mp_view->annotation_shapes ().replace (*s, db::DUserObject (rnew));
annotation_changed_event (new_id); annotation_changed_event (new_id);
} }
@ -1690,7 +1690,7 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
// replace the ruler that was moved // replace the ruler that was moved
m_current.clean_points (); m_current.clean_points ();
mp_view->annotation_shapes ().replace (m_selected.begin ()->first, db::DUserObject (new ant::Object (m_current))); mp_view->annotation_shapes ().replace (*m_selected.begin (), db::DUserObject (new ant::Object (m_current)));
annotation_changed_event (m_current.id ()); annotation_changed_event (m_current.id ());
// clear the selection (that was artifically created before) // clear the selection (that was artifically created before)
@ -1717,9 +1717,8 @@ Service::selection_to_view ()
} }
m_rulers.clear (); m_rulers.clear ();
m_rulers.reserve (m_selected.size ()); m_rulers.reserve (m_selected.size ());
for (std::map<obj_iterator, unsigned int>::iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
r->second = (unsigned int) m_rulers.size (); const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
const ant::Object *robj = dynamic_cast<const ant::Object *> (r->first->ptr ());
m_rulers.push_back (new ant::View (this, robj, true /*selected*/)); m_rulers.push_back (new ant::View (this, robj, true /*selected*/));
} }
} }
@ -1728,8 +1727,8 @@ db::DBox
Service::selection_bbox () Service::selection_bbox ()
{ {
db::DBox box; db::DBox box;
for (std::map<obj_iterator, unsigned int>::iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> (r->first->ptr ()); const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
if (robj) { if (robj) {
box += robj->box (); box += robj->box ();
} }
@ -1741,16 +1740,16 @@ void
Service::transform (const db::DCplxTrans &trans) Service::transform (const db::DCplxTrans &trans)
{ {
// replace the rulers that were transformed: // replace the rulers that were transformed:
for (std::map<obj_iterator, unsigned int>::const_iterator s = m_selected.begin (); s != m_selected.end (); ++s) { for (auto s = m_selected.begin (); s != m_selected.end (); ++s) {
const ant::Object *robj = dynamic_cast<const ant::Object *> (s->first->ptr ()); const ant::Object *robj = dynamic_cast<const ant::Object *> ((*s)->ptr ());
if (robj) { if (robj) {
// compute transformed object and replace // compute transformed object and replace
int id = robj->id (); int id = robj->id ();
ant::Object *rnew = new ant::Object (*robj); ant::Object *rnew = new ant::Object (*robj);
rnew->transform (trans); rnew->transform (trans);
mp_view->annotation_shapes ().replace (s->first, db::DUserObject (rnew)); mp_view->annotation_shapes ().replace (*s, db::DUserObject (rnew));
annotation_changed_event (id); annotation_changed_event (id);
} }
@ -2173,9 +2172,8 @@ void
Service::copy_selected () Service::copy_selected ()
{ {
// extract all selected rulers and paste in "micron" space // extract all selected rulers and paste in "micron" space
for (std::map<obj_iterator, unsigned int>::iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
r->second = (unsigned int) m_rulers.size (); const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
const ant::Object *robj = dynamic_cast<const ant::Object *> (r->first->ptr ());
if (robj) { if (robj) {
db::Clipboard::instance () += new db::ClipboardValue<ant::Object> (*robj); db::Clipboard::instance () += new db::ClipboardValue<ant::Object> (*robj);
} }
@ -2212,7 +2210,7 @@ Service::paste ()
if (! new_objects.empty ()) { if (! new_objects.empty ()) {
for (auto r = new_objects.begin (); r != new_objects.end (); ++r) { for (auto r = new_objects.begin (); r != new_objects.end (); ++r) {
m_selected.insert (std::make_pair (mp_view->annotation_shapes ().iterator_from_pointer (*r), 0)); m_selected.insert (mp_view->annotation_shapes ().iterator_from_pointer (*r));
} }
selection_to_view (); selection_to_view ();
@ -2240,8 +2238,8 @@ Service::del_selected ()
// positions will hold a set of iterators that are to be erased // positions will hold a set of iterators that are to be erased
std::vector <lay::AnnotationShapes::iterator> positions; std::vector <lay::AnnotationShapes::iterator> positions;
positions.reserve (m_selected.size ()); positions.reserve (m_selected.size ());
for (std::map<obj_iterator, unsigned int>::iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
positions.push_back (r->first); positions.push_back (*r);
} }
// clear selection // clear selection
@ -2276,7 +2274,7 @@ Service::select (obj_iterator obj, lay::Editable::SelectionMode mode)
if (mode == lay::Editable::Replace || mode == lay::Editable::Add) { if (mode == lay::Editable::Replace || mode == lay::Editable::Add) {
// select // select
if (m_selected.find (obj) == m_selected.end ()) { if (m_selected.find (obj) == m_selected.end ()) {
m_selected.insert (std::make_pair (obj, 0)); m_selected.insert (obj);
return true; return true;
} }
} else if (mode == lay::Editable::Reset) { } else if (mode == lay::Editable::Reset) {
@ -2290,7 +2288,7 @@ Service::select (obj_iterator obj, lay::Editable::SelectionMode mode)
if (m_selected.find (obj) != m_selected.end ()) { if (m_selected.find (obj) != m_selected.end ()) {
m_selected.erase (obj); m_selected.erase (obj);
} else { } else {
m_selected.insert (std::make_pair (obj, 0)); m_selected.insert (obj);
} }
return true; return true;
} }
@ -2312,7 +2310,7 @@ Service::click_proximity (const db::DPoint &pos, lay::Editable::SelectionMode mo
// for single-point selections either exclude the current selection or the // for single-point selections either exclude the current selection or the
// accumulated previous selection from the search. // accumulated previous selection from the search.
const std::map<obj_iterator, unsigned int> *exclude = 0; const std::set<obj_iterator> *exclude = 0;
if (mode == lay::Editable::Replace) { if (mode == lay::Editable::Replace) {
exclude = &m_previous_selection; exclude = &m_previous_selection;
} else if (mode == lay::Editable::Add) { } else if (mode == lay::Editable::Add) {
@ -2493,7 +2491,7 @@ Service::transient_to_selection ()
for (lay::AnnotationShapes::iterator r = mp_view->annotation_shapes ().begin (); r != mp_view->annotation_shapes ().end (); ++r) { for (lay::AnnotationShapes::iterator r = mp_view->annotation_shapes ().begin (); r != mp_view->annotation_shapes ().end (); ++r) {
const ant::Object *robj = dynamic_cast <const ant::Object *> (r->ptr ()); const ant::Object *robj = dynamic_cast <const ant::Object *> (r->ptr ());
if (robj == mp_transient_ruler->ruler ()) { if (robj == mp_transient_ruler->ruler ()) {
m_selected.insert (std::make_pair (r, 0)); m_selected.insert (r);
selection_to_view (); selection_to_view ();
return; return;
} }
@ -2523,7 +2521,7 @@ Service::select (const db::DBox &box, lay::Editable::SelectionMode mode)
// for single-point selections either exclude the current selection or the // for single-point selections either exclude the current selection or the
// accumulated previous selection from the search. // accumulated previous selection from the search.
const std::map<obj_iterator, unsigned int> *exclude = 0; const std::set<obj_iterator> *exclude = 0;
if (mode == lay::Editable::Replace) { if (mode == lay::Editable::Replace) {
exclude = &m_previous_selection; exclude = &m_previous_selection;
} else if (mode == lay::Editable::Add) { } else if (mode == lay::Editable::Add) {
@ -2605,7 +2603,7 @@ Service::select (const db::DBox &box, lay::Editable::SelectionMode mode)
// select the one that was found // select the one that was found
if (any_selected) { if (any_selected) {
select (mp_view->annotation_shapes ().iterator_from_pointer (&*rmin), mode); select (mp_view->annotation_shapes ().iterator_from_pointer (&*rmin), mode);
m_previous_selection.insert (std::make_pair (mp_view->annotation_shapes ().iterator_from_pointer (&*rmin), mode)); m_previous_selection.insert (mp_view->annotation_shapes ().iterator_from_pointer (&*rmin));
needs_update = true; needs_update = true;
} }
@ -2667,11 +2665,22 @@ Service::get_selection (std::vector <obj_iterator> &sel) const
sel.reserve (m_selected.size ()); sel.reserve (m_selected.size ());
// positions will hold a set of iterators that are to be erased // positions will hold a set of iterators that are to be erased
for (std::map<obj_iterator, unsigned int>::const_iterator r = m_selected.begin (); r != m_selected.end (); ++r) { for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
sel.push_back (r->first); sel.push_back (*r);
} }
} }
void
Service::set_selection (const std::vector<obj_iterator> &selection)
{
m_selected.clear ();
for (auto i = selection.begin (); i != selection.end (); ++i) {
m_selected.insert (*i);
}
selection_to_view ();
}
void void
Service::delete_ruler (obj_iterator pos) Service::delete_ruler (obj_iterator pos)
{ {

View File

@ -381,14 +381,19 @@ public:
#endif #endif
/** /**
* @brief Get the selection for the properties page * @brief Gets the selection for the properties page
*/ */
void get_selection (std::vector <obj_iterator> &selection) const; void get_selection (std::vector <obj_iterator> &selection) const;
/**
* @brief Sets the selection for the properties page
*/
void set_selection (const std::vector <obj_iterator> &selection);
/** /**
* @brief Direct access to the selection * @brief Direct access to the selection
*/ */
const std::map<obj_iterator, unsigned int> &selection () const const std::set<obj_iterator> &selection () const
{ {
return m_selected; return m_selected;
} }
@ -558,9 +563,9 @@ private:
// and the moved rules in move mode // and the moved rules in move mode
std::vector<ant::View *> m_rulers; std::vector<ant::View *> m_rulers;
// The selection // The selection
std::map<obj_iterator, unsigned int> m_selected; std::set<obj_iterator> m_selected;
// The previous selection // The previous selection
std::map<obj_iterator, unsigned int> m_previous_selection; std::set<obj_iterator> m_previous_selection;
// The reference point in move mode // The reference point in move mode
db::DPoint m_p1; db::DPoint m_p1;
// The transformation in MoveSelection mode // The transformation in MoveSelection mode

View File

@ -1263,7 +1263,7 @@ class AnnotationSelectionIterator
{ {
public: public:
typedef AnnotationRef value_type; typedef AnnotationRef value_type;
typedef std::map<ant::Service::obj_iterator, unsigned int>::const_iterator iterator_type; typedef std::set<ant::Service::obj_iterator>::const_iterator iterator_type;
typedef void pointer; typedef void pointer;
typedef value_type reference; typedef value_type reference;
typedef std::forward_iterator_tag iterator_category; typedef std::forward_iterator_tag iterator_category;
@ -1292,7 +1292,7 @@ public:
reference operator* () const reference operator* () const
{ {
return value_type (*(static_cast<const ant::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ()); return value_type (*(static_cast<const ant::Object *> ((*m_iter)->ptr ())), m_services[m_service]->view ());
} }
private: private:

View File

@ -32,9 +32,9 @@ HEADERS = \
RESOURCES = \ RESOURCES = \
INCLUDEPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC $$LYM_INC INCLUDEPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC $$PEX_INC $$LYM_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC $$LYM_INC DEPENDPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC $$PEX_INC $$LYM_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_lym LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_pex -lklayout_lym
INCLUDEPATH += $$RBA_INC INCLUDEPATH += $$RBA_INC
DEPENDPATH += $$RBA_INC DEPENDPATH += $$RBA_INC

View File

@ -27,6 +27,7 @@
#include "dbReader.h" #include "dbReader.h"
#include "dbWriter.h" #include "dbWriter.h"
#include "tlCommandLineParser.h" #include "tlCommandLineParser.h"
#include "tlTimer.h"
namespace bd namespace bd
{ {
@ -42,8 +43,13 @@ int converter_main (int argc, char *argv[], const std::string &format)
generic_reader_options.add_options (cmd); generic_reader_options.add_options (cmd);
cmd << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)", cmd << tl::arg ("input", &infile, "The input file (any format, may be gzip compressed)",
"You can use '+' or ',' to supply multiple files which will be read after each other into the same layout. " "Multiple files can be combined using '+' or ','. '+' will combine the files in 'blending' mode. "
"This provides some cheap, but risky way of merging files. Beware of cell name conflicts.") "In this mode it is possible to combine identically named cells into one cell for example. This mode "
"needs to be used with care and there some constraints - e.g. the database unit of the involved "
"layouts needs to be the same. When using ',' as a separator, blending is not used, but the layouts "
"are merged by first creating two layouts and then combining them into one. This mode is more robust "
"but does not allow cell merging. '+' combination has higher priority than ',' - i.e. 'a+b,c' is "
"understood as '(a+b),c'.")
<< tl::arg ("output", &outfile, tl::sprintf ("The output file (%s format)", format)) << tl::arg ("output", &outfile, tl::sprintf ("The output file (%s format)", format))
; ;
@ -53,6 +59,8 @@ int converter_main (int argc, char *argv[], const std::string &format)
db::Layout layout; db::Layout layout;
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
{ {
db::LoadLayoutOptions load_options; db::LoadLayoutOptions load_options;
generic_reader_options.configure (load_options); generic_reader_options.configure (load_options);

View File

@ -22,6 +22,8 @@
#include "bdReaderOptions.h" #include "bdReaderOptions.h"
#include "dbLoadLayoutOptions.h" #include "dbLoadLayoutOptions.h"
#include "dbLayerMapping.h"
#include "dbCellMapping.h"
#include "tlCommandLineParser.h" #include "tlCommandLineParser.h"
#include "tlStream.h" #include "tlStream.h"
@ -120,7 +122,9 @@ GenericReaderOptions::GenericReaderOptions ()
m_lefdef_separate_groups = load_options.get_option_by_name ("lefdef_config.separate_groups").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_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_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 (); // Don't take the default, as in practice, it's more common to substitute LEF macros by layouts
// m_lefdef_macro_resolution_mode = load_options.get_option_by_name ("lefdef_config.macro_resolution_mode").to_int ();
m_lefdef_macro_resolution_mode = 2; // "assume FOREIGN always"
} }
void void
@ -829,27 +833,105 @@ static std::string::size_type find_file_sep (const std::string &s, std::string::
} }
} }
static std::vector<std::string> split_file_list (const std::string &infile) static std::vector<std::vector<std::string> > split_file_list (const std::string &infile)
{ {
std::vector<std::string> files; std::vector<std::vector<std::string> > files;
files.push_back (std::vector<std::string> ());
size_t p = 0; size_t p = 0;
for (size_t pp = 0; (pp = find_file_sep (infile, p)) != std::string::npos; p = pp + 1) { while (true) {
files.push_back (std::string (infile, p, pp - p));
size_t sep = find_file_sep (infile, p);
if (sep == std::string::npos) {
files.back ().push_back (std::string (infile, p));
return files;
}
files.back ().push_back (std::string (infile, p, sep - p));
if (infile [sep] == ',') {
files.push_back (std::vector<std::string> ());
}
p = sep + 1;
} }
files.push_back (std::string (infile, p));
return files; return files;
} }
void read_files (db::Layout &layout, const std::string &infile, const db::LoadLayoutOptions &options) void read_files (db::Layout &layout, const std::string &infile, const db::LoadLayoutOptions &options)
{ {
std::vector<std::string> files = split_file_list (infile); // We may do this:
// db::LayoutLocker locker (&layout);
// but there are yet unknown side effects
std::vector<std::vector<std::string> > files = split_file_list (infile);
for (auto ff = files.begin (); ff != files.end (); ++ff) {
// enter a LEF caching context for chaining multiple DEF with the same LEF
db::LoadLayoutOptions local_options (options);
local_options.set_option_by_name ("lefdef_config.lef_context_enabled", true);
db::Layout tmp;
db::Layout *ly = (ff == files.begin () ? &layout : &tmp);
for (auto f = ff->begin (); f != ff->end (); ++f) {
tl::InputStream stream (*f);
db::Reader reader (stream);
if (f != ff->begin ()) {
reader.set_expected_dbu (ly->dbu ());
}
reader.read (*ly, local_options);
}
if (ly != &layout) {
// Move over cells from read layout to destination ("," separated blocks).
// This path does not imply limitations in terms of DBU compatibility etc.
std::vector<db::cell_index_type> cells_target;
std::vector<db::cell_index_type> cells_source;
for (auto c = tmp.begin_top_down (); c != tmp.end_top_cells (); ++c) {
cells_source.push_back (*c);
// as a special rule, join ghost cells if the source top cell fits into
// a ghost cell of the target.
auto cell_target = layout.cell_by_name (tmp.cell_name (*c));
if (cell_target.first && layout.cell (cell_target.second).is_ghost_cell ()) {
cells_target.push_back (cell_target.second);
} else {
cells_target.push_back (layout.add_cell (tmp.cell_name (*c)));
}
}
// ghost cell joining also works the other way around: a top cell of destination
// can match a ghost cell of the source
for (auto c = tmp.end_top_cells (); c != tmp.end_top_down (); ++c) {
const db::Cell &cell_source = tmp.cell (*c);
auto cell_target = layout.cell_by_name (tmp.cell_name (*c));
if (cell_source.is_ghost_cell () && cell_target.first) {
cells_source.push_back (*c);
cells_target.push_back (cell_target.second);
}
}
db::CellMapping cm;
cm.create_multi_mapping_full (layout, cells_target, tmp, cells_source);
db::LayerMapping lm;
lm.create_full (layout, tmp);
layout.move_tree_shapes (tmp, cm, lm);
}
for (std::vector<std::string>::const_iterator f = files.begin (); f != files.end (); ++f) {
tl::InputStream stream (*f);
db::Reader reader (stream);
reader.read (layout, options);
} }
} }

View File

@ -29,6 +29,7 @@
#include "dbSaveLayoutOptions.h" #include "dbSaveLayoutOptions.h"
#include "tlLog.h" #include "tlLog.h"
#include "tlCommandLineParser.h" #include "tlCommandLineParser.h"
#include "tlTimer.h"
struct ClipData struct ClipData
@ -200,6 +201,8 @@ BD_PUBLIC int strmclip (int argc, char *argv[])
cmd.parse (argc, argv); cmd.parse (argc, argv);
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
clip (data); clip (data);
return 0; return 0;

View File

@ -25,6 +25,7 @@
#include "dbLayoutDiff.h" #include "dbLayoutDiff.h"
#include "dbReader.h" #include "dbReader.h"
#include "tlCommandLineParser.h" #include "tlCommandLineParser.h"
#include "tlTimer.h"
BD_PUBLIC int strmcmp (int argc, char *argv[]) BD_PUBLIC int strmcmp (int argc, char *argv[])
{ {
@ -141,6 +142,8 @@ BD_PUBLIC int strmcmp (int argc, char *argv[])
throw tl::Exception ("Both -ta|--top-a and -tb|--top-b top cells must be given"); throw tl::Exception ("Both -ta|--top-a and -tb|--top-b top cells must be given");
} }
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
db::Layout layout_a; db::Layout layout_a;
db::Layout layout_b; db::Layout layout_b;

View File

@ -28,12 +28,14 @@
#include "tlLog.h" #include "tlLog.h"
#include "tlCommandLineParser.h" #include "tlCommandLineParser.h"
#include "tlFileUtils.h" #include "tlFileUtils.h"
#include "tlTimer.h"
#include "rba.h" #include "rba.h"
#include "pya.h" #include "pya.h"
#include "gsi.h" #include "gsi.h"
#include "gsiExpression.h" #include "gsiExpression.h"
#include "libForceLink.h" #include "libForceLink.h"
#include "rdbForceLink.h" #include "rdbForceLink.h"
#include "pexForceLink.h"
#include "lymMacro.h" #include "lymMacro.h"
#include "lymMacroCollection.h" #include "lymMacroCollection.h"
@ -97,5 +99,8 @@ BD_PUBLIC int strmrun (int argc, char *argv[])
lym::Macro macro; lym::Macro macro;
macro.load_from (script); macro.load_from (script);
macro.set_file_path (script); macro.set_file_path (script);
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
return macro.run (); return macro.run ();
} }

View File

@ -32,6 +32,8 @@
#include "gsiExpression.h" #include "gsiExpression.h"
#include "tlCommandLineParser.h" #include "tlCommandLineParser.h"
#include "tlThreads.h" #include "tlThreads.h"
#include "tlThreadedWorkers.h"
#include "tlTimer.h"
namespace { namespace {
@ -319,7 +321,8 @@ struct XORData
dont_summarize_missing_layers (false), silent (false), no_summary (false), dont_summarize_missing_layers (false), silent (false), no_summary (false),
threads (0), threads (0),
tile_size (0.0), heal_results (false), tile_size (0.0), heal_results (false),
output_layout (0), output_cell (0) output_layout (0), output_cell (0),
layers_missing (0)
{ } { }
db::Layout *layout_a, *layout_b; db::Layout *layout_a, *layout_b;
@ -336,6 +339,8 @@ struct XORData
db::cell_index_type output_cell; db::cell_index_type output_cell;
std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc> l2l_map; std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc> l2l_map;
std::map<std::pair<int, db::LayerProperties>, ResultDescriptor> *results; std::map<std::pair<int, db::LayerProperties>, ResultDescriptor> *results;
mutable int layers_missing;
mutable tl::Mutex lock;
}; };
} }
@ -455,6 +460,8 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
} }
} }
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
db::Layout layout_a; db::Layout layout_a;
db::Layout layout_b; db::Layout layout_b;
@ -572,14 +579,22 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
if (! silent && ! no_summary) { if (! silent && ! no_summary) {
if (result) { if (result) {
tl::info << "No differences found"; tl::info << tl::to_string (tr ("No differences found"));
} else { } else {
const char *line_format = " %-10s %-12s %s"; const char *line_format = " %-10s %-12s %s";
const char *sep = " -------------------------------------------------------";
tl::info << "Result summary (layers without differences are not shown):" << tl::endl; std::string headline;
tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep; if (deep) {
headline = tl::sprintf (line_format, tl::to_string (tr ("Layer")), tl::to_string (tr ("Output")), tl::to_string (tr ("Differences (hierarchical shape count)")));
} else {
headline = tl::sprintf (line_format, tl::to_string (tr ("Layer")), tl::to_string (tr ("Output")), tl::to_string (tr ("Differences (shape count)")));
}
const char *sep = " ----------------------------------------------------------------";
tl::info << tl::to_string (tr ("Result summary (layers without differences are not shown):")) << tl::endl;
tl::info << headline << tl::endl << sep;
int ti = -1; int ti = -1;
for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = results.begin (); r != results.end (); ++r) { for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = results.begin (); r != results.end (); ++r) {
@ -587,17 +602,17 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
if (r->first.first != ti) { if (r->first.first != ti) {
ti = r->first.first; ti = r->first.first;
if (tolerances[ti] > db::epsilon) { if (tolerances[ti] > db::epsilon) {
tl::info << tl::endl << "Tolerance " << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl; tl::info << tl::endl << tl::to_string (tr ("Tolerance ")) << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl;
tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep; tl::info << headline << tl::endl << sep;
} }
} }
std::string out ("-"); std::string out ("-");
std::string value; std::string value;
if (r->second.layer_a < 0 && ! dont_summarize_missing_layers) { if (r->second.layer_a < 0 && ! dont_summarize_missing_layers) {
value = "(no such layer in first layout)"; value = tl::to_string (tr ("(no such layer in first layout)"));
} else if (r->second.layer_b < 0 && ! dont_summarize_missing_layers) { } else if (r->second.layer_b < 0 && ! dont_summarize_missing_layers) {
value = "(no such layer in second layout)"; value = tl::to_string (tr ("(no such layer in second layout)"));
} else if (! r->second.is_empty ()) { } else if (! r->second.is_empty ()) {
if (r->second.layer_output >= 0 && r->second.layout) { if (r->second.layer_output >= 0 && r->second.layout) {
out = r->second.layout->get_properties (r->second.layer_output).to_string (); out = r->second.layout->get_properties (r->second.layer_output).to_string ();
@ -758,15 +773,174 @@ bool run_tiled_xor (const XORData &xor_data)
return result; return result;
} }
bool run_deep_xor (const XORData &xor_data)
{
db::DeepShapeStore dss;
dss.set_threads (xor_data.threads);
class XORJob
: public tl::JobBase
{
public:
XORJob (int nworkers)
: tl::JobBase (nworkers)
{
}
virtual tl::Worker *create_worker ();
};
class XORWorker
: public tl::Worker
{
public:
XORWorker (XORJob *job);
void perform_task (tl::Task *task);
db::DeepShapeStore &dss ()
{
return m_dss;
}
private:
XORJob *mp_job;
db::DeepShapeStore m_dss;
};
class XORTask
: public tl::Task
{
public:
XORTask (const XORData *xor_data, const db::LayerProperties &layer_props, int la, int lb, double dbu)
: mp_xor_data (xor_data), m_layer_props (layer_props), m_la (la), m_lb (lb), m_dbu (dbu)
{
// .. nothing yet ..
}
void run (XORWorker *worker) const
{
if ((m_la < 0 || m_lb < 0) && ! mp_xor_data->dont_summarize_missing_layers) {
if (m_la < 0) {
(mp_xor_data->silent ? tl::log : tl::warn) << "Layer " << m_layer_props.to_string () << " is not present in first layout, but in second";
} else {
(mp_xor_data->silent ? tl::log : tl::warn) << "Layer " << m_layer_props.to_string () << " is not present in second layout, but in first";
}
tl::MutexLocker locker (&mp_xor_data->lock);
mp_xor_data->layers_missing += 1;
int tol_index = 0;
for (std::vector<double>::const_iterator t = mp_xor_data->tolerances.begin (); t != mp_xor_data->tolerances.end (); ++t) {
ResultDescriptor &result = mp_xor_data->results->insert (std::make_pair (std::make_pair (tol_index, m_layer_props), ResultDescriptor ())).first->second;
result.layer_a = m_la;
result.layer_b = m_lb;
result.layout = mp_xor_data->output_layout;
result.top_cell = mp_xor_data->output_cell;
++tol_index;
}
} else {
tl::SelfTimer timer (tl::verbosity () >= 11, "XOR on layer " + m_layer_props.to_string ());
db::RecursiveShapeIterator ri_a, ri_b;
if (m_la >= 0) {
ri_a = db::RecursiveShapeIterator (*mp_xor_data->layout_a, mp_xor_data->layout_a->cell (mp_xor_data->cell_a), m_la);
} else {
ri_a = db::RecursiveShapeIterator (*mp_xor_data->layout_a, mp_xor_data->layout_a->cell (mp_xor_data->cell_a), std::vector<unsigned int> ());
}
ri_a.set_for_merged_input (true);
if (m_lb >= 0) {
ri_b = db::RecursiveShapeIterator (*mp_xor_data->layout_b, mp_xor_data->layout_b->cell (mp_xor_data->cell_b), m_lb);
} else {
ri_b = db::RecursiveShapeIterator (*mp_xor_data->layout_b, mp_xor_data->layout_b->cell (mp_xor_data->cell_b), std::vector<unsigned int> ());
}
ri_b.set_for_merged_input (true);
db::Region in_a (ri_a, worker->dss (), db::ICplxTrans (mp_xor_data->layout_a->dbu () / m_dbu));
db::Region in_b (ri_b, worker->dss (), db::ICplxTrans (mp_xor_data->layout_b->dbu () / m_dbu));
db::Region xor_res;
{
tl::SelfTimer timer (tl::verbosity () >= 21, "Basic XOR on layer " + m_layer_props.to_string ());
xor_res = in_a ^ in_b;
}
int tol_index = 0;
for (std::vector<double>::const_iterator t = mp_xor_data->tolerances.begin (); t != mp_xor_data->tolerances.end (); ++t) {
db::LayerProperties lp = m_layer_props;
if (lp.layer >= 0) {
lp.layer += tol_index * mp_xor_data->tolerance_bump;
}
if (*t > db::epsilon) {
tl::SelfTimer timer (tl::verbosity () >= 21, "Tolerance " + tl::to_string (*t) + " on layer " + m_layer_props.to_string ());
xor_res.size (-db::coord_traits<db::Coord>::rounded (0.5 * *t / m_dbu));
xor_res.size (db::coord_traits<db::Coord>::rounded (0.5 * *t / m_dbu));
}
{
tl::MutexLocker locker (&mp_xor_data->lock);
ResultDescriptor &result = mp_xor_data->results->insert (std::make_pair (std::make_pair (tol_index, m_layer_props), ResultDescriptor ())).first->second;
result.layer_a = m_la;
result.layer_b = m_lb;
result.layout = mp_xor_data->output_layout;
result.top_cell = mp_xor_data->output_cell;
if (mp_xor_data->output_layout) {
result.layer_output = result.layout->insert_layer (lp);
xor_res.insert_into (mp_xor_data->output_layout, mp_xor_data->output_cell, result.layer_output);
} else {
result.shape_count = xor_res.hier_count ();
}
}
++tol_index;
}
}
}
private:
const XORData *mp_xor_data;
const db::LayerProperties &m_layer_props;
int m_la;
int m_lb;
double m_dbu;
};
XORWorker::XORWorker (XORJob *job)
: tl::Worker (), mp_job (job)
{
// TODO: this conflicts with the "set_for_merged_input" optimization below. // TODO: this conflicts with the "set_for_merged_input" optimization below.
// It seems not to be very effective then. Why? // It seems not to be very effective then. Why?
dss.set_wants_all_cells (true); // saves time for less cell mapping operations m_dss.set_wants_all_cells (true); // saves time for less cell mapping operations
}
void
XORWorker::perform_task (tl::Task *task)
{
XORTask *xor_task = dynamic_cast <XORTask *> (task);
if (xor_task) {
xor_task->run (this);
}
}
tl::Worker *
XORJob::create_worker ()
{
return new XORWorker (this);
}
bool run_deep_xor (const XORData &xor_data)
{
double dbu = std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ()); double dbu = std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ());
if (tl::verbosity () >= 20) { if (tl::verbosity () >= 20) {
@ -779,98 +953,18 @@ bool run_deep_xor (const XORData &xor_data)
xor_data.output_layout->dbu (dbu); xor_data.output_layout->dbu (dbu);
} }
bool result = true; XORJob job (xor_data.threads);
int index = 1;
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = xor_data.l2l_map.begin (); ll != xor_data.l2l_map.end (); ++ll) { for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = xor_data.l2l_map.begin (); ll != xor_data.l2l_map.end (); ++ll) {
job.schedule (new XORTask (&xor_data, ll->first, ll->second.first, ll->second.second, dbu));
if ((ll->second.first < 0 || ll->second.second < 0) && ! xor_data.dont_summarize_missing_layers) {
if (ll->second.first < 0) {
(xor_data.silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in first layout, but in second";
} else {
(xor_data.silent ? tl::log : tl::warn) << "Layer " << ll->first.to_string () << " is not present in second layout, but in first";
}
result = false;
int tol_index = 0;
for (std::vector<double>::const_iterator t = xor_data.tolerances.begin (); t != xor_data.tolerances.end (); ++t) {
ResultDescriptor &result = xor_data.results->insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
result.layer_a = ll->second.first;
result.layer_b = ll->second.second;
result.layout = xor_data.output_layout;
result.top_cell = xor_data.output_cell;
++tol_index;
}
} else {
tl::SelfTimer timer (tl::verbosity () >= 11, "XOR on layer " + ll->first.to_string ());
db::RecursiveShapeIterator ri_a, ri_b;
if (ll->second.first >= 0) {
ri_a = db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
ri_a.set_for_merged_input (true);
}
if (ll->second.second >= 0) {
ri_b = db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
ri_b.set_for_merged_input (true);
}
db::Region in_a (ri_a, dss, db::ICplxTrans (xor_data.layout_a->dbu () / dbu));
db::Region in_b (ri_b, dss, db::ICplxTrans (xor_data.layout_b->dbu () / dbu));
db::Region xor_res;
{
tl::SelfTimer timer (tl::verbosity () >= 21, "Basic XOR on layer " + ll->first.to_string ());
xor_res = in_a ^ in_b;
}
int tol_index = 0;
for (std::vector<double>::const_iterator t = xor_data.tolerances.begin (); t != xor_data.tolerances.end (); ++t) {
db::LayerProperties lp = ll->first;
if (lp.layer >= 0) {
lp.layer += tol_index * xor_data.tolerance_bump;
}
ResultDescriptor &result = xor_data.results->insert (std::make_pair (std::make_pair (tol_index, ll->first), ResultDescriptor ())).first->second;
result.layer_a = ll->second.first;
result.layer_b = ll->second.second;
result.layout = xor_data.output_layout;
result.top_cell = xor_data.output_cell;
if (*t > db::epsilon) {
tl::SelfTimer timer (tl::verbosity () >= 21, "Tolerance " + tl::to_string (*t) + " on layer " + ll->first.to_string ());
xor_res.size (-db::coord_traits<db::Coord>::rounded (0.5 * *t / dbu));
xor_res.size (db::coord_traits<db::Coord>::rounded (0.5 * *t / dbu));
}
if (xor_data.output_layout) {
result.layer_output = result.layout->insert_layer (lp);
xor_res.insert_into (xor_data.output_layout, xor_data.output_cell, result.layer_output);
} else {
result.shape_count = xor_res.count ();
}
++tol_index;
}
}
++index;
} }
// Determines the output status job.start ();
job.wait ();
// Determine the output status
bool result = (xor_data.layers_missing == 0);
for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = xor_data.results->begin (); r != xor_data.results->end () && result; ++r) { for (std::map<std::pair<int, db::LayerProperties>, ResultDescriptor>::const_iterator r = xor_data.results->begin (); r != xor_data.results->end () && result; ++r) {
result = r->second.is_empty (); result = r->second.is_empty ();
} }

View File

@ -19,7 +19,7 @@ SOURCES = $$PWD/bd/main.cc
INCLUDEPATH += $$BD_INC $$TL_INC $$GSI_INC INCLUDEPATH += $$BD_INC $$TL_INC $$GSI_INC
DEPENDPATH += $$BD_INC $$TL_INC $$GSI_INC DEPENDPATH += $$BD_INC $$TL_INC $$GSI_INC
LIBS += -L$$DESTDIR -lklayout_bd -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_lym LIBS += -L$$DESTDIR -lklayout_bd -lklayout_db -lklayout_pex -lklayout_tl -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_lym
INCLUDEPATH += $$RBA_INC INCLUDEPATH += $$RBA_INC
DEPENDPATH += $$RBA_INC DEPENDPATH += $$RBA_INC

View File

@ -186,3 +186,525 @@ TEST(6)
db::compare_layouts (this, layout, input_au, db::WriteGDS2); db::compare_layouts (this, layout, input_au, db::WriteGDS2);
} }
// Large LEF/DEF to OAS converter test
TEST(10)
{
test_is_long_runner ();
std::string input_dir = tl::testdata_private ();
input_dir += "/lefdef/strm2oas/";
std::string lef_dir = input_dir + "/lef";
std::string def_dir = input_dir + "/def";
std::string gds_dir = input_dir + "/gds";
std::string input_au = input_dir + "/strm2oas_au_2.oas";
std::string output = this->tmp_file ("strm2oas.oas");
std::string map_arg = "--lefdef-map=" + input_dir + "/sky130.map";
const char *lef_files[] = {
"sky130_fd_sc_hd.tlef",
"sky130_fd_sc_hd_merged.lef",
"sky130_fd_sc_hs_merged.lef",
"sky130_ef_sc_hd__decap_20_12.lef",
"sky130_ef_sc_hd__decap_80_12.lef",
"sky130_ef_sc_hd__fill_4.lef",
"sky130_ef_sc_hd__decap_40_12.lef",
"sky130_ef_sc_hd__decap_60_12.lef",
"sky130_ef_io__analog_esd_pad.lef",
"sky130_ef_io__analog_noesd_pad.lef",
"sky130_ef_io__analog_pad.lef",
"sky130_ef_io__bare_pad.lef",
"sky130_ef_io__com_bus_slice_10um.lef",
"sky130_ef_io__com_bus_slice_1um.lef",
"sky130_ef_io__com_bus_slice_20um.lef",
"sky130_ef_io__com_bus_slice_5um.lef",
"sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.lef",
"sky130_ef_io__corner_pad.lef",
"sky130_ef_io__disconnect_vccd_slice_5um.lef",
"sky130_ef_io__disconnect_vdda_slice_5um.lef",
"sky130_ef_io__gpiov2_pad.lef",
"sky130_ef_io__gpiov2_pad_wrapped.lef",
"sky130_ef_io__top_power_hvc.lef",
"sky130_ef_io__vccd_hvc_pad.lef",
"sky130_ef_io__vccd_lvc_clamped2_pad.lef",
"sky130_ef_io__vccd_lvc_clamped3_pad.lef",
"sky130_ef_io__vccd_lvc_clamped_pad.lef",
"sky130_ef_io__vccd_lvc_pad.lef",
"sky130_ef_io__vdda_hvc_clamped_pad.lef",
"sky130_ef_io__vdda_hvc_pad.lef",
"sky130_ef_io__vdda_lvc_pad.lef",
"sky130_ef_io__vddio_hvc_clamped_pad.lef",
"sky130_ef_io__vddio_hvc_pad.lef",
"sky130_ef_io__vddio_lvc_pad.lef",
"sky130_ef_io__vssa_hvc_clamped_pad.lef",
"sky130_ef_io__vssa_hvc_pad.lef",
"sky130_ef_io__vssa_lvc_pad.lef",
"sky130_ef_io__vssd_hvc_pad.lef",
"sky130_ef_io__vssd_lvc_clamped2_pad.lef",
"sky130_ef_io__vssd_lvc_clamped3_pad.lef",
"sky130_ef_io__vssd_lvc_clamped_pad.lef",
"sky130_ef_io__vssd_lvc_pad.lef",
"sky130_ef_io__vssio_hvc_clamped_pad.lef",
"sky130_ef_io__vssio_hvc_pad.lef",
"sky130_ef_io__vssio_lvc_pad.lef",
"sky130_fd_io__signal_5_sym_hv_local_5term.lef",
"sky130_fd_io__top_gpiov2.lef",
"sky130_fd_io__top_power_hvc_wpadv2.lef",
"sky130_fd_sc_hvl__a21o_1.lef",
"sky130_fd_sc_hvl__a21oi_1.lef",
"sky130_fd_sc_hvl__a22o_1.lef",
"sky130_fd_sc_hvl__a22oi_1.lef",
"sky130_fd_sc_hvl__and2_1.lef",
"sky130_fd_sc_hvl__and3_1.lef",
"sky130_fd_sc_hvl__buf_1.lef",
"sky130_fd_sc_hvl__buf_16.lef",
"sky130_fd_sc_hvl__buf_2.lef",
"sky130_fd_sc_hvl__buf_32.lef",
"sky130_fd_sc_hvl__buf_4.lef",
"sky130_fd_sc_hvl__buf_8.lef",
"sky130_fd_sc_hvl__conb_1.lef",
"sky130_fd_sc_hvl__decap_4.lef",
"sky130_fd_sc_hvl__decap_8.lef",
"sky130_fd_sc_hvl__dfrbp_1.lef",
"sky130_fd_sc_hvl__dfrtp_1.lef",
"sky130_fd_sc_hvl__dfsbp_1.lef",
"sky130_fd_sc_hvl__dfstp_1.lef",
"sky130_fd_sc_hvl__dfxbp_1.lef",
"sky130_fd_sc_hvl__dfxtp_1.lef",
"sky130_fd_sc_hvl__diode_2.lef",
"sky130_fd_sc_hvl__dlclkp_1.lef",
"sky130_fd_sc_hvl__dlrtp_1.lef",
"sky130_fd_sc_hvl__dlxtp_1.lef",
"sky130_fd_sc_hvl__einvn_1.lef",
"sky130_fd_sc_hvl__einvp_1.lef",
"sky130_fd_sc_hvl__fill_1.lef",
"sky130_fd_sc_hvl__fill_2.lef",
"sky130_fd_sc_hvl__fill_4.lef",
"sky130_fd_sc_hvl__fill_8.lef",
"sky130_fd_sc_hvl__inv_1.lef",
"sky130_fd_sc_hvl__inv_16.lef",
"sky130_fd_sc_hvl__inv_2.lef",
"sky130_fd_sc_hvl__inv_4.lef",
"sky130_fd_sc_hvl__inv_8.lef",
"sky130_fd_sc_hvl__lsbufhv2hv_hl_1.lef",
"sky130_fd_sc_hvl__lsbufhv2hv_lh_1.lef",
"sky130_fd_sc_hvl__lsbufhv2lv_1.lef",
"sky130_fd_sc_hvl__lsbufhv2lv_simple_1.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_1.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_clkiso_hlkg_3.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_isosrchvaon_1.lef",
"sky130_fd_sc_hvl__lsbuflv2hv_symmetric_1.lef",
"sky130_fd_sc_hvl__mux2_1.lef",
"sky130_fd_sc_hvl__mux4_1.lef",
"sky130_fd_sc_hvl__nand2_1.lef",
"sky130_fd_sc_hvl__nand3_1.lef",
"sky130_fd_sc_hvl__nor2_1.lef",
"sky130_fd_sc_hvl__nor3_1.lef",
"sky130_fd_sc_hvl__o21a_1.lef",
"sky130_fd_sc_hvl__o21ai_1.lef",
"sky130_fd_sc_hvl__o22a_1.lef",
"sky130_fd_sc_hvl__o22ai_1.lef",
"sky130_fd_sc_hvl__or2_1.lef",
"sky130_fd_sc_hvl__or3_1.lef",
"sky130_fd_sc_hvl__probe_p_8.lef",
"sky130_fd_sc_hvl__probec_p_8.lef",
"sky130_fd_sc_hvl__schmittbuf_1.lef",
"sky130_fd_sc_hvl__sdfrbp_1.lef",
"sky130_fd_sc_hvl__sdfrtp_1.lef",
"sky130_fd_sc_hvl__sdfsbp_1.lef",
"sky130_fd_sc_hvl__sdfstp_1.lef",
"sky130_fd_sc_hvl__sdfxbp_1.lef",
"sky130_fd_sc_hvl__sdfxtp_1.lef",
"sky130_fd_sc_hvl__sdlclkp_1.lef",
"sky130_fd_sc_hvl__sdlxtp_1.lef",
"sky130_fd_sc_hvl__xnor2_1.lef",
"sky130_fd_sc_hvl__xor2_1.lef",
"caravel.lef",
"caravel_clocking.lef",
"caravel_core.lef",
"gpio_defaults_block.lef",
"gpio_logic_high.lef",
"housekeeping.lef",
"mgmt_protect_hv.lef",
"mprj2_logic_high.lef",
"mprj_io_buffer.lef",
"mprj_logic_high.lef",
"spare_logic_block.lef",
"user_project_wrapper.lef",
"xres_buf.lef",
"caravel_logo-stub.lef",
"caravel_motto-stub.lef",
"chip_io.lef",
"copyright_block-stub.lef",
"empty_macro.lef",
"manual_power_connections.lef",
"open_source-stub.lef",
"simple_por.lef",
"user_id_programming.lef",
"user_id_textblock-stub.lef",
"RAM128.lef"
};
std::string lefs_arg = "--lefdef-lefs=";
for (size_t i = 0; i < sizeof (lef_files) / sizeof (lef_files[0]); ++i) {
if (i > 0) {
lefs_arg += ",";
}
lefs_arg += lef_dir + "/" + lef_files[i];
}
const char *lefdef_layout_files[] = {
"sky130_fd_sc_hd.gds",
"sky130_fd_sc_hvl__sdlxtp_1.gds",
"sky130_fd_sc_hvl__decap_8.gds",
"sky130_fd_sc_hvl__decap_4.gds",
"sky130_fd_sc_hvl__nand3_1.gds",
"sky130_fd_sc_hvl__sdfxbp_1.gds",
"sky130_fd_sc_hvl__lsbufhv2hv_hl_1.gds",
"sky130_fd_sc_hvl__sdfrbp_1.gds",
"sky130_fd_sc_hvl__a21o_1.gds",
"sky130_fd_sc_hvl__inv_2.gds",
"sky130_fd_sc_hvl__inv_16.gds",
"sky130_fd_sc_hvl__inv_1.gds",
"sky130_fd_sc_hvl__inv_4.gds",
"sky130_fd_sc_hvl__inv_8.gds",
"sky130_fd_sc_hvl__nand2_1.gds",
"sky130_fd_sc_hvl__dfstp_1.gds",
"sky130_fd_sc_hvl__a22o_1.gds",
"sky130_fd_sc_hvl__schmittbuf_1.gds",
"sky130_fd_sc_hvl__a22oi_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_1.gds",
"sky130_fd_sc_hvl__fill_4.gds",
"sky130_fd_sc_hvl__fill_1.gds",
"sky130_fd_sc_hvl__fill_2.gds",
"sky130_fd_sc_hvl__fill_8.gds",
"sky130_fd_sc_hvl__sdfrtp_1.gds",
"sky130_fd_sc_hvl__sdfxtp_1.gds",
"sky130_fd_sc_hvl__o22a_1.gds",
"sky130_fd_sc_hvl__dfsbp_1.gds",
"sky130_fd_sc_hvl__o21a_1.gds",
"sky130_fd_sc_hvl__a21oi_1.gds",
"sky130_fd_sc_hvl__buf_1.gds",
"sky130_fd_sc_hvl__buf_2.gds",
"sky130_fd_sc_hvl__buf_4.gds",
"sky130_fd_sc_hvl__buf_32.gds",
"sky130_fd_sc_hvl__buf_16.gds",
"sky130_fd_sc_hvl__buf_8.gds",
"sky130_fd_sc_hvl__einvp_1.gds",
"sky130_fd_sc_hvl__conb_1.gds",
"sky130_fd_sc_hvl__and3_1.gds",
"sky130_fd_sc_hvl__lsbufhv2lv_1.gds",
"sky130_fd_sc_hvl__and2_1.gds",
"sky130_fd_sc_hvl__nor3_1.gds",
"sky130_fd_sc_hvl__dlclkp_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_symmetric_1.gds",
"sky130_fd_sc_hvl__sdfstp_1.gds",
"sky130_fd_sc_hvl__dfrbp_1.gds",
"sky130_fd_sc_hvl__dfxbp_1.gds",
"sky130_fd_sc_hvl__nor2_1.gds",
"sky130_fd_sc_hvl__diode_2.gds",
"sky130_fd_sc_hvl__dlrtp_1.gds",
"sky130_fd_sc_hvl__dlxtp_1.gds",
"sky130_fd_sc_hvl__lsbufhv2lv_simple_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_clkiso_hlkg_3.gds",
"sky130_fd_sc_hvl__sdlclkp_1.gds",
"sky130_fd_sc_hvl__o22ai_1.gds",
"sky130_fd_sc_hvl__or3_1.gds",
"sky130_fd_sc_hvl__sdfsbp_1.gds",
"sky130_fd_sc_hvl__xor2_1.gds",
"sky130_fd_sc_hvl__mux4_1.gds",
"sky130_fd_sc_hvl__or2_1.gds",
"sky130_fd_sc_hvl__probe_p_8.gds",
"sky130_fd_sc_hvl__dfxtp_1.gds",
"sky130_fd_sc_hvl__mux2_1.gds",
"sky130_fd_sc_hvl__dfrtp_1.gds",
"sky130_fd_sc_hvl__lsbuflv2hv_isosrchvaon_1.gds",
"sky130_fd_sc_hvl__probec_p_8.gds",
"sky130_fd_sc_hvl__xnor2_1.gds",
"sky130_fd_sc_hvl__einvn_1.gds",
"sky130_fd_sc_hvl__o21ai_1.gds",
"sky130_fd_sc_hvl__lsbufhv2hv_lh_1.gds",
"sky130_ef_io__analog.gds",
"sky130_ef_io__bare_pad.gds",
"sky130_ef_io__connect_vcchib_vccd_and_vswitch_vddio_slice_20um.gds",
"sky130_ef_io__disconnect_vccd_slice_5um.gds",
"sky130_ef_io__disconnect_vdda_slice_5um.gds",
"sky130_ef_io__gpiov2_pad_wrapped.gds",
"sky130_ef_sc_hd__decap_12.gds",
"sky130_ef_sc_hd__decap_20_12.gds",
"sky130_ef_sc_hd__decap_40_12.gds",
"sky130_ef_sc_hd__decap_60_12.gds",
"sky130_ef_sc_hd__decap_80_12.gds",
"sky130_ef_sc_hd__fill_12.gds",
"sky130_ef_sc_hd__fill_2.gds",
"sky130_ef_sc_hd__fill_4.gds",
"sky130_ef_sc_hd__fill_8.gds",
"sky130_ef_sc_hvl__fill_8.gds",
"caravel_logo.gds.gz",
"caravel_motto.gds.gz",
"chip_io.gds.gz",
"copyright_block.gds.gz",
"empty_macro.gds.gz",
"manual_power_connections.gds.gz",
"open_source.gds.gz",
"simple_por.gds.gz",
"user_id_programming.gds.gz",
"user_id_textblock.gds.gz",
"RAM128.gds.gz"
};
std::string lefdef_layouts_arg = "--lefdef-lef-layouts=";
for (size_t i = 0; i < sizeof (lefdef_layout_files) / sizeof (lefdef_layout_files[0]); ++i) {
if (i > 0) {
lefdef_layouts_arg += ",";
}
lefdef_layouts_arg += gds_dir + "/" + lefdef_layout_files[i];
}
const char *def_files[] = {
"caravel.def",
"caravel_clocking.def",
"caravel_core.def.gz",
"gpio_defaults_block.def",
"gpio_logic_high.def",
"housekeeping.def",
"mgmt_protect_hv.def",
"mprj2_logic_high.def",
"mprj_io_buffer.def",
"mprj_logic_high.def",
"spare_logic_block.def",
"user_project_wrapper.def",
"xres_buf.def"
};
std::string input;
for (size_t i = 0; i < sizeof (def_files) / sizeof (def_files[0]); ++i) {
if (i > 0) {
input += "+";
}
input += def_dir + "/" + def_files[i];
}
const char *argv[] = { "x",
"--lefdef-no-implicit-lef",
map_arg.c_str (),
lefs_arg.c_str (),
lefdef_layouts_arg.c_str (),
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}
// Merging with +
TEST(11_1)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_1.oas";
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2.oas";
std::string output = this->tmp_file ("strm2oas_1.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}
// Merging with + not allowed on different DBUs
TEST(11_2)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_1.oas";
std::string input = input_dir + "/strm2oas_1.oas+" + input_dir + "/strm2oas_2_10nm.oas";
std::string output = this->tmp_file ("strm2oas_1.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
try {
bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name);
EXPECT_EQ (1, 0);
} catch (tl::Exception &ex) {
EXPECT_EQ (ex.msg (), "Former and present database units are not compatible: 0.001 (former) vs. 0.01 (present)");
}
}
// Merging with + not allowed on different DBUs
TEST(11_3)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_3.oas";
std::string input = input_dir + "/strm2oas_1.oas," + input_dir + "/strm2oas_2_10nm.oas";
std::string output = this->tmp_file ("strm2oas_3.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}
// Merging with + and , under the presence of ghost cells: test+test,top->(test)
TEST(12_1)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_12_1.oas";
std::string input = input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas," + input_dir + "/strm2oas_c.oas";
std::string output = this->tmp_file ("strm2oas_12_1.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}
// Merging with + and , under the presence of ghost cells: top->(test),test+test
TEST(12_2)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_12_2.oas";
std::string input = input_dir + "/strm2oas_c.oas," + input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas";
std::string output = this->tmp_file ("strm2oas_12_2.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}
// Merging with + and , under the presence of ghost cells: test+test,toptop->top->(test)
TEST(12_3)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_12_3.oas";
std::string input = input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas," + input_dir + "/strm2oas_cc.oas";
std::string output = this->tmp_file ("strm2oas_12_3.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}
// Merging with + and , under the presence of ghost cells: toptop->top->(test),test+test
TEST(12_4)
{
std::string input_dir = tl::testdata ();
input_dir += "/bd";
std::string input_au = input_dir + "/strm2oas_au_12_4.oas";
std::string input = input_dir + "/strm2oas_cc.oas," + input_dir + "/strm2oas_a.oas+" + input_dir + "/strm2oas_b.oas";
std::string output = this->tmp_file ("strm2oas_12_4.oas");
const char *argv[] = { "x",
"--blend-mode=0",
input.c_str (),
output.c_str ()
};
EXPECT_EQ (bd::converter_main (sizeof (argv) / sizeof (argv[0]), (char **) argv, bd::GenericWriterOptions::oasis_format_name), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::LoadLayoutOptions options;
db::Reader reader (stream);
reader.read (layout, options);
}
db::compare_layouts (this, layout, input_au, db::WriteOAS);
}

View File

@ -105,7 +105,7 @@ TEST(1A_Flat)
"Result summary (layers without differences are not shown):\n" "Result summary (layers without differences are not shown):\n"
"\n" "\n"
" Layer Output Differences (shape count)\n" " Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n" " ----------------------------------------------------------------\n"
" 3/0 3/0 30\n" " 3/0 3/0 30\n"
" 6/0 6/0 41\n" " 6/0 6/0 41\n"
" 8/1 8/1 1\n" " 8/1 8/1 1\n"
@ -146,8 +146,8 @@ TEST(1A_Deep)
"Layer 10/0 is not present in first layout, but in second\n" "Layer 10/0 is not present in first layout, but in second\n"
"Result summary (layers without differences are not shown):\n" "Result summary (layers without differences are not shown):\n"
"\n" "\n"
" Layer Output Differences (shape count)\n" " Layer Output Differences (hierarchical shape count)\n"
" -------------------------------------------------------\n" " ----------------------------------------------------------------\n"
" 3/0 3/0 3\n" " 3/0 3/0 3\n"
" 6/0 6/0 314\n" " 6/0 6/0 314\n"
" 8/1 8/1 1\n" " 8/1 8/1 1\n"
@ -177,7 +177,7 @@ TEST(1B_Flat)
"Result summary (layers without differences are not shown):\n" "Result summary (layers without differences are not shown):\n"
"\n" "\n"
" Layer Output Differences (shape count)\n" " Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n" " ----------------------------------------------------------------\n"
" 3/0 - 30\n" " 3/0 - 30\n"
" 6/0 - 41\n" " 6/0 - 41\n"
" 8/1 - 1\n" " 8/1 - 1\n"
@ -206,9 +206,9 @@ TEST(1B_Deep)
"Layer 10/0 is not present in first layout, but in second\n" "Layer 10/0 is not present in first layout, but in second\n"
"Result summary (layers without differences are not shown):\n" "Result summary (layers without differences are not shown):\n"
"\n" "\n"
" Layer Output Differences (shape count)\n" " Layer Output Differences (hierarchical shape count)\n"
" -------------------------------------------------------\n" " ----------------------------------------------------------------\n"
" 3/0 - 30\n" " 3/0 - 3\n"
" 6/0 - 314\n" " 6/0 - 314\n"
" 8/1 - 1\n" " 8/1 - 1\n"
" 10/0 - (no such layer in first layout)\n" " 10/0 - (no such layer in first layout)\n"
@ -417,7 +417,7 @@ TEST(3_FlatCount)
"Result summary (layers without differences are not shown):\n" "Result summary (layers without differences are not shown):\n"
"\n" "\n"
" Layer Output Differences (shape count)\n" " Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n" " ----------------------------------------------------------------\n"
" 3/0 - 31\n" " 3/0 - 31\n"
" 6/0 - 217\n" " 6/0 - 217\n"
" 8/1 - 168\n" " 8/1 - 168\n"
@ -483,7 +483,7 @@ TEST(3_FlatCountHeal)
"Result summary (layers without differences are not shown):\n" "Result summary (layers without differences are not shown):\n"
"\n" "\n"
" Layer Output Differences (shape count)\n" " Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n" " ----------------------------------------------------------------\n"
" 3/0 - 30\n" " 3/0 - 30\n"
" 6/0 - 41\n" " 6/0 - 41\n"
" 8/1 - 1\n" " 8/1 - 1\n"
@ -756,3 +756,42 @@ TEST(6_Deep)
"Layer 10/0 is not present in first layout, but in second\n" "Layer 10/0 is not present in first layout, but in second\n"
); );
} }
TEST(7_OptimizeDeep)
{
tl::CaptureChannel cap;
std::string input_a = tl::testdata ();
input_a += "/bd/strmxor_covered1.gds";
std::string input_b = tl::testdata ();
input_b += "/bd/strmxor_covered2.gds";
std::string au = tl::testdata ();
au += "/bd/strmxor_au7d.oas";
std::string output = this->tmp_file ("tmp.oas");
const char *argv[] = { "x", "-u", input_a.c_str (), input_b.c_str (), output.c_str () };
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
EXPECT_EQ (cap.captured_text (),
"Result summary (layers without differences are not shown):\n"
"\n"
" Layer Output Differences (hierarchical shape count)\n"
" ----------------------------------------------------------------\n"
" 2/0 2/0 1\n"
" 3/0 3/0 8\n"
"\n"
);
}

View File

@ -58,6 +58,7 @@ SOURCES = \
dbLog.cc \ dbLog.cc \
dbManager.cc \ dbManager.cc \
dbMatrix.cc \ dbMatrix.cc \
dbMeasureEval.cc \
dbMemStatistics.cc \ dbMemStatistics.cc \
dbMutableEdgePairs.cc \ dbMutableEdgePairs.cc \
dbMutableEdges.cc \ dbMutableEdges.cc \
@ -70,15 +71,21 @@ SOURCES = \
dbNetlistSpiceReaderExpressionParser.cc \ dbNetlistSpiceReaderExpressionParser.cc \
dbObject.cc \ dbObject.cc \
dbObjectWithProperties.cc \ dbObjectWithProperties.cc \
dbPLC.cc \
dbPLCConvexDecomposition.cc \
dbPLCTriangulation.cc \
dbPath.cc \ dbPath.cc \
dbPCellDeclaration.cc \ dbPCellDeclaration.cc \
dbPCellHeader.cc \ dbPCellHeader.cc \
dbPCellVariant.cc \ dbPCellVariant.cc \
dbPoint.cc \ dbPoint.cc \
dbPolygon.cc \ dbPolygon.cc \
dbPolygonNeighborhood.cc \
dbPolygonTools.cc \ dbPolygonTools.cc \
dbPolygonGenerators.cc \ dbPolygonGenerators.cc \
dbPropertiesFilter.cc \
dbPropertiesRepository.cc \ dbPropertiesRepository.cc \
dbQuadTree.cc \
dbReader.cc \ dbReader.cc \
dbRecursiveInstanceIterator.cc \ dbRecursiveInstanceIterator.cc \
dbRecursiveShapeIterator.cc \ dbRecursiveShapeIterator.cc \
@ -102,8 +109,6 @@ SOURCES = \
dbTextWriter.cc \ dbTextWriter.cc \
dbTilingProcessor.cc \ dbTilingProcessor.cc \
dbTrans.cc \ dbTrans.cc \
dbTriangle.cc \
dbTriangles.cc \
dbUserObject.cc \ dbUserObject.cc \
dbUtils.cc \ dbUtils.cc \
dbVector.cc \ dbVector.cc \
@ -136,10 +141,12 @@ SOURCES = \
gsiDeclDbLog.cc \ gsiDeclDbLog.cc \
gsiDeclDbManager.cc \ gsiDeclDbManager.cc \
gsiDeclDbMatrix.cc \ gsiDeclDbMatrix.cc \
gsiDeclDbMeasureHelpers.cc \
gsiDeclDbMetaInfo.cc \ gsiDeclDbMetaInfo.cc \
gsiDeclDbPath.cc \ gsiDeclDbPath.cc \
gsiDeclDbPoint.cc \ gsiDeclDbPoint.cc \
gsiDeclDbPolygon.cc \ gsiDeclDbPolygon.cc \
gsiDeclDbPolygonNeighborhood.cc \
gsiDeclDbReader.cc \ gsiDeclDbReader.cc \
gsiDeclDbRecursiveInstanceIterator.cc \ gsiDeclDbRecursiveInstanceIterator.cc \
gsiDeclDbRecursiveShapeIterator.cc \ gsiDeclDbRecursiveShapeIterator.cc \
@ -292,6 +299,7 @@ HEADERS = \
dbLog.h \ dbLog.h \
dbManager.h \ dbManager.h \
dbMatrix.h \ dbMatrix.h \
dbMeasureEval.h \
dbMemStatistics.h \ dbMemStatistics.h \
dbMetaInfo.h \ dbMetaInfo.h \
dbMutableEdgePairs.h \ dbMutableEdgePairs.h \
@ -306,16 +314,22 @@ HEADERS = \
dbObject.h \ dbObject.h \
dbObjectTag.h \ dbObjectTag.h \
dbObjectWithProperties.h \ dbObjectWithProperties.h \
dbPLC.h \
dbPLCConvexDecomposition.h \
dbPLCTriangulation.h \
dbPath.h \ dbPath.h \
dbPCellDeclaration.h \ dbPCellDeclaration.h \
dbPCellHeader.h \ dbPCellHeader.h \
dbPCellVariant.h \ dbPCellVariant.h \
dbPoint.h \ dbPoint.h \
dbPolygon.h \ dbPolygon.h \
dbPolygonNeighborhood.h \
dbPolygonTools.h \ dbPolygonTools.h \
dbPolygonGenerators.h \ dbPolygonGenerators.h \
dbPropertiesFilter.h \
dbPropertiesRepository.h \ dbPropertiesRepository.h \
dbPropertyConstraint.h \ dbPropertyConstraint.h \
dbQuadTree.h \
dbReader.h \ dbReader.h \
dbRecursiveInstanceIterator.h \ dbRecursiveInstanceIterator.h \
dbRecursiveShapeIterator.h \ dbRecursiveShapeIterator.h \
@ -338,8 +352,6 @@ HEADERS = \
dbTextWriter.h \ dbTextWriter.h \
dbTilingProcessor.h \ dbTilingProcessor.h \
dbTrans.h \ dbTrans.h \
dbTriangle.h \
dbTriangles.h \
dbTypes.h \ dbTypes.h \
dbUserObject.h \ dbUserObject.h \
dbUtils.h \ dbUtils.h \
@ -425,6 +437,7 @@ HEADERS = \
dbNetShape.h \ dbNetShape.h \
dbShapeCollection.h \ dbShapeCollection.h \
dbShapeCollectionUtils.h \ dbShapeCollectionUtils.h \
gsiDeclDbMeasureHelpers.h \
gsiDeclDbPropertiesSupport.h gsiDeclDbPropertiesSupport.h
RESOURCES = \ RESOURCES = \

View File

@ -1571,6 +1571,17 @@ struct array_iterator
} }
} }
/**
* @brief Gets a value indicating whether the iterator is a synthetic one
*
* "is_singular" is true, if the iterator was default-created or with a single
* transformation.
*/
bool is_singular () const
{
return mp_base == 0;
}
private: private:
trans_type m_trans; trans_type m_trans;
basic_array_iterator <Coord> *mp_base; basic_array_iterator <Coord> *mp_base;

View File

@ -81,6 +81,9 @@ AsIfFlatEdgePairs::to_string (size_t nmax) const
} }
first = false; first = false;
os << p->to_string (); os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
} }
if (! p.at_end ()) { if (! p.at_end ()) {
os << "..."; os << "...";
@ -157,13 +160,17 @@ AsIfFlatEdgePairs::processed (const EdgePairProcessorBase &filter) const
{ {
std::unique_ptr<FlatEdgePairs> edge_pairs (new FlatEdgePairs ()); std::unique_ptr<FlatEdgePairs> edge_pairs (new FlatEdgePairs ());
std::vector<db::EdgePair> res_edge_pairs; std::vector<db::EdgePairWithProperties> res_edge_pairs;
for (EdgePairsIterator e = begin (); ! e.at_end (); ++e) { for (EdgePairsIterator e = begin (); ! e.at_end (); ++e) {
res_edge_pairs.clear (); res_edge_pairs.clear ();
filter.process (*e, res_edge_pairs); filter.process (e.wp (), res_edge_pairs);
for (std::vector<db::EdgePair>::const_iterator er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++er) { for (auto er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++er) {
edge_pairs->insert (*er); if (er->properties_id () != 0) {
edge_pairs->insert (*er);
} else {
edge_pairs->insert (er->base ());
}
} }
} }
@ -179,17 +186,16 @@ AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &
region->set_merged_semantics (false); region->set_merged_semantics (false);
} }
std::vector<db::Polygon> res_polygons; std::vector<db::PolygonWithProperties> res_polygons;
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) { for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
res_polygons.clear (); res_polygons.clear ();
filter.process (*e, res_polygons); filter.process (e.wp (), res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
db::properties_id_type prop_id = e.prop_id (); if (pr->properties_id () != 0) {
if (prop_id != 0) {
region->insert (db::PolygonWithProperties (*pr, prop_id));
} else {
region->insert (*pr); region->insert (*pr);
} else {
region->insert (pr->base ());
} }
} }
} }
@ -206,17 +212,16 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter
edges->set_merged_semantics (false); edges->set_merged_semantics (false);
} }
std::vector<db::Edge> res_edges; std::vector<db::EdgeWithProperties> res_edges;
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) { for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
res_edges.clear (); res_edges.clear ();
filter.process (*e, res_edges); filter.process (e.wp (), res_edges);
for (std::vector<db::Edge>::const_iterator pr = res_edges.begin (); pr != res_edges.end (); ++pr) { for (auto pr = res_edges.begin (); pr != res_edges.end (); ++pr) {
db::properties_id_type prop_id = e.prop_id (); if (pr->properties_id () != 0) {
if (prop_id != 0) {
edges->insert (db::EdgeWithProperties (*pr, prop_id));
} else {
edges->insert (*pr); edges->insert (*pr);
} else {
edges->insert (pr->base ());
} }
} }
} }
@ -224,25 +229,44 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter
return edges.release (); return edges.release ();
} }
static void
insert_ep (FlatEdgePairs *dest, const db::EdgePair &ep, db::properties_id_type prop_id)
{
if (prop_id != 0) {
dest->insert (db::EdgePairWithProperties (ep, prop_id));
} else {
dest->insert (ep);
}
}
EdgePairsDelegate * EdgePairsDelegate *
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
{ {
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ()); std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) { for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
db::properties_id_type prop_id = p.prop_id (); insert_ep (new_edge_pairs.get (), *p, p.prop_id ());
if (prop_id != 0) {
new_edge_pairs->insert (db::EdgePairWithProperties (*p, prop_id));
} else {
new_edge_pairs->insert (*p);
}
} }
} }
return new_edge_pairs.release (); return new_edge_pairs.release ();
} }
std::pair <EdgePairsDelegate *, EdgePairsDelegate *>
AsIfFlatEdgePairs::filtered_pair (const EdgePairFilterBase &filter) const
{
std::unique_ptr<FlatEdgePairs> new_edge_pairs_true (new FlatEdgePairs ());
std::unique_ptr<FlatEdgePairs> new_edge_pairs_false (new FlatEdgePairs ());
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
FlatEdgePairs *dest = filter.selected (*p, p.prop_id ()) ? new_edge_pairs_true.get () : new_edge_pairs_false.get ();
insert_ep (dest, *p, p.prop_id ());
}
return std::make_pair (new_edge_pairs_true.release (), new_edge_pairs_false.release ());
}
RegionDelegate * RegionDelegate *
AsIfFlatEdgePairs::pull_interacting (const Region &other) const AsIfFlatEdgePairs::pull_interacting (const Region &other) const
{ {
@ -627,10 +651,6 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*other_flat)); std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*other_flat));
new_edge_pairs->invalidate_cache (); new_edge_pairs->invalidate_cache ();
size_t n = new_edge_pairs->raw_edge_pairs ().size () + count ();
new_edge_pairs->reserve (n);
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) { for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
db::properties_id_type prop_id = p.prop_id (); db::properties_id_type prop_id = p.prop_id ();
if (prop_id) { if (prop_id) {
@ -646,10 +666,6 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ()); std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
size_t n = count () + other.count ();
new_edge_pairs->reserve (n);
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) { for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
db::properties_id_type prop_id = p.prop_id (); db::properties_id_type prop_id = p.prop_id ();
if (prop_id) { if (prop_id) {

View File

@ -53,6 +53,7 @@ public:
} }
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const; virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const;
virtual std::pair<EdgePairsDelegate *, EdgePairsDelegate *> filtered_pair (const EdgePairFilterBase &filter) const;
virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &proc) virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &proc)
{ {

View File

@ -89,6 +89,9 @@ AsIfFlatEdges::to_string (size_t nmax) const
} }
first = false; first = false;
os << p->to_string (); os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
} }
if (! p.at_end ()) { if (! p.at_end ()) {
os << "..."; os << "...";
@ -645,13 +648,17 @@ AsIfFlatEdges::processed (const EdgeProcessorBase &filter) const
edges->set_merged_semantics (false); edges->set_merged_semantics (false);
} }
std::vector<db::Edge> res_edges; std::vector<db::EdgeWithProperties> res_edges;
for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) { for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) {
res_edges.clear (); res_edges.clear ();
filter.process (*e, res_edges); filter.process (e.wp (), res_edges);
for (std::vector<db::Edge>::const_iterator er = res_edges.begin (); er != res_edges.end (); ++er) { for (auto er = res_edges.begin (); er != res_edges.end (); ++er) {
edges->insert (*er); if (er->properties_id () != 0) {
edges->insert (*er);
} else {
edges->insert (er->base ());
}
} }
} }
@ -667,13 +674,17 @@ AsIfFlatEdges::processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filte
edge_pairs->set_merged_semantics (false); edge_pairs->set_merged_semantics (false);
} }
std::vector<db::EdgePair> res_edge_pairs; std::vector<db::EdgePairWithProperties> res_edge_pairs;
for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) { for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) {
res_edge_pairs.clear (); res_edge_pairs.clear ();
filter.process (*e, res_edge_pairs); filter.process (e.wp (), res_edge_pairs);
for (std::vector<db::EdgePair>::const_iterator epr = res_edge_pairs.begin (); epr != res_edge_pairs.end (); ++epr) { for (auto epr = res_edge_pairs.begin (); epr != res_edge_pairs.end (); ++epr) {
edge_pairs->insert (*epr); if (epr->properties_id () != 0) {
edge_pairs->insert (*epr);
} else {
edge_pairs->insert (epr->base ());
}
} }
} }
@ -689,13 +700,17 @@ AsIfFlatEdges::processed_to_polygons (const EdgeToPolygonProcessorBase &filter)
region->set_merged_semantics (false); region->set_merged_semantics (false);
} }
std::vector<db::Polygon> res_polygons; std::vector<db::PolygonWithProperties> res_polygons;
for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) { for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) {
res_polygons.clear (); res_polygons.clear ();
filter.process (*e, res_polygons); filter.process (e.wp (), res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
region->insert (*pr); if (pr->properties_id () != 0) {
region->insert (*pr);
} else {
region->insert (pr->base ());
}
} }
} }
@ -708,14 +723,43 @@ AsIfFlatEdges::filtered (const EdgeFilterBase &filter) const
std::unique_ptr<FlatEdges> new_region (new FlatEdges ()); std::unique_ptr<FlatEdges> new_region (new FlatEdges ());
for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) { for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
new_region->insert (*p); if (p.prop_id () != 0) {
new_region->insert (db::EdgeWithProperties (*p, p.prop_id ()));
} else {
new_region->insert (*p);
}
} }
} }
return new_region.release (); return new_region.release ();
} }
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::filtered_pair (const EdgeFilterBase &filter) const
{
std::unique_ptr<FlatEdges> new_region_true (new FlatEdges ());
std::unique_ptr<FlatEdges> new_region_false (new FlatEdges ());
for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) {
new_region_true->insert (db::EdgeWithProperties (*p, p.prop_id ()));
} else {
new_region_true->insert (*p);
}
} else {
if (p.prop_id () != 0) {
new_region_false->insert (db::EdgeWithProperties (*p, p.prop_id ()));
} else {
new_region_false->insert (*p);
}
}
}
return std::make_pair (new_region_true.release (), new_region_false.release ());
}
EdgePairsDelegate * EdgePairsDelegate *
AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const
{ {
@ -1009,12 +1053,12 @@ AsIfFlatEdges::add (const Edges &other) const
new_edges->set_is_merged (false); new_edges->set_is_merged (false);
new_edges->invalidate_cache (); new_edges->invalidate_cache ();
size_t n = new_edges->raw_edges ().size () + count ();
new_edges->reserve (n);
for (EdgesIterator p (begin ()); ! p.at_end (); ++p) { for (EdgesIterator p (begin ()); ! p.at_end (); ++p) {
new_edges->raw_edges ().insert (*p); if (p.prop_id () == 0) {
new_edges->raw_edges ().insert (*p);
} else {
new_edges->raw_edges ().insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
} }
return new_edges.release (); return new_edges.release ();
@ -1023,15 +1067,19 @@ AsIfFlatEdges::add (const Edges &other) const
std::unique_ptr<FlatEdges> new_edges (new FlatEdges (false /*not merged*/)); std::unique_ptr<FlatEdges> new_edges (new FlatEdges (false /*not merged*/));
size_t n = count () + other.count ();
new_edges->reserve (n);
for (EdgesIterator p (begin ()); ! p.at_end (); ++p) { for (EdgesIterator p (begin ()); ! p.at_end (); ++p) {
new_edges->raw_edges ().insert (*p); if (p.prop_id () == 0) {
new_edges->raw_edges ().insert (*p);
} else {
new_edges->raw_edges ().insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
} }
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) { for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
new_edges->raw_edges ().insert (*p); if (p.prop_id () == 0) {
new_edges->raw_edges ().insert (*p);
} else {
new_edges->raw_edges ().insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
} }
return new_edges.release (); return new_edges.release ();

View File

@ -101,6 +101,7 @@ public:
} }
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const; virtual EdgesDelegate *filtered (const EdgeFilterBase &) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> filtered_pair (const EdgeFilterBase &filter) const;
virtual EdgesDelegate *merged_in_place () virtual EdgesDelegate *merged_in_place ()
{ {

View File

@ -53,7 +53,7 @@ struct ResultCountingInserter
{ {
typedef db::Polygon value_type; typedef db::Polygon value_type;
ResultCountingInserter (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > &result) ResultCountingInserter (std::unordered_map<const db::Polygon *, size_t, tl::ptr_hash_from_value<db::Polygon> > &result)
: mp_result (&result) : mp_result (&result)
{ {
// .. nothing yet .. // .. nothing yet ..
@ -70,7 +70,7 @@ struct ResultCountingInserter
} }
private: private:
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > *mp_result; std::unordered_map<const db::Polygon *, size_t, tl::ptr_hash_from_value<db::Polygon> > *mp_result;
}; };
} }
@ -134,6 +134,9 @@ AsIfFlatRegion::to_string (size_t nmax) const
} }
first = false; first = false;
os << p->to_string (); os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
} }
if (! p.at_end ()) { if (! p.at_end ()) {
os << "..."; os << "...";
@ -152,31 +155,31 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcesso
} }
result->reserve (n); result->reserve (n);
std::vector<db::Edge> heap; std::vector<db::EdgeWithProperties> heap;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
db::properties_id_type prop_id = p.prop_id ();
if (proc) { if (proc) {
heap.clear (); heap.clear ();
proc->process (*p, heap); proc->process (p.wp (), heap);
for (auto e = heap.begin (); e != heap.end (); ++e) { for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected (*e)) { if (! filter || filter->selected (*e, e->properties_id ())) {
if (prop_id != 0) { if (e->properties_id () != 0) {
result->insert (db::EdgeWithProperties (*e, prop_id));
} else {
result->insert (*e); result->insert (*e);
} else {
result->insert (e->base ());
} }
} }
} }
} else { } else {
auto prop_id = p.prop_id ();
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected (*e)) { if (! filter || filter->selected (*e, prop_id)) {
if (prop_id != 0) { if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, prop_id)); result->insert (db::EdgeWithProperties (*e, prop_id));
} else { } else {
@ -322,7 +325,7 @@ struct ComparePolygonsWithProperties
} }
void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc) const void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const
{ {
db::EdgeProcessor ep (report_progress (), progress_desc ()); db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ()); ep.set_base_verbosity (base_verbosity ());
@ -330,16 +333,101 @@ void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence,
// count edges and reserve memory // count edges and reserve memory
size_t n = 0; size_t n = 0;
db::properties_id_type prop_id = 0; db::properties_id_type prop_id = 0;
bool need_split_props = false; bool multiple_properties = false;
for (RegionIterator s (begin ()); ! s.at_end (); ++s, ++n) { for (RegionIterator s (begin ()); ! s.at_end (); ++s, ++n) {
if (n == 0) { if (n == 0) {
prop_id = s.prop_id (); prop_id = s.prop_id ();
} else if (! need_split_props && prop_id != s.prop_id ()) { } else if (! multiple_properties && prop_id != s.prop_id ()) {
need_split_props = true; multiple_properties = true;
} }
} }
if (need_split_props) { if (multiple_properties && join_properties_on_merge) {
// this merge variant requires a two-step approach: we first and then join original properties IDs
// in a separate interaction step
std::vector<db::properties_id_type> org_prop_ids;
org_prop_ids.reserve (n);
n = 0;
for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
n += p->vertices ();
}
ep.reserve (n);
size_t org_poly_id = 0;
for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++org_poly_id) {
org_prop_ids.push_back (p.prop_id ());
ep.insert (*p, org_poly_id);
}
// and run the merge step
db::MergeOp op (min_wc);
db::PolygonContainer pc;
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence);
ep.process (pg, op);
// reserve space for new (merged) polygons
for (auto p = pc.polygons ().begin (); p != pc.polygons ().end (); ++p) {
n += p->vertices ();
}
ep.reserve (n);
size_t merged_poly_id = org_poly_id;
for (auto p = pc.polygons ().begin (); p != pc.polygons ().end (); ++p, ++merged_poly_id) {
ep.insert (*p, merged_poly_id);
}
// compute interactions between merged and original polygons
db::InteractionDetector id;
id.set_include_touching (false);
db::EdgeSink es;
ep.process (es, id);
id.finish ();
// collect original property IDs per merged polygon
std::vector<std::set<db::properties_id_type> > prop_ids_per_merged_polygon;
prop_ids_per_merged_polygon.resize (merged_poly_id - org_poly_id);
for (auto ii = id.begin (); ii != id.end (); ++ii) {
auto first = std::min (ii->first, ii->second);
auto second = std::max (ii->first, ii->second);
if (first < org_poly_id && second >= org_poly_id) {
prop_ids_per_merged_polygon [second - org_poly_id].insert (org_prop_ids [first]);
}
}
// Form new polygons with joined properties
for (auto p = pc.polygons ().begin (); p != pc.polygons ().end (); ++p) {
const std::set<db::properties_id_type> &prop_ids = prop_ids_per_merged_polygon [p - pc.polygons ().begin ()];
db::properties_id_type prop_id = 0;
if (prop_ids.size () == 1) {
prop_id = *prop_ids.begin ();
} else if (prop_ids.size () > 1) {
db::PropertiesSet ps;
for (auto p = prop_ids.begin (); p != prop_ids.end (); ++p) {
// merge in "larger one wins" mode - the advantage of this mode is that
// it is independent on the order of the attribute sets (which in fact are pointers)
ps.join_max (db::properties (*p));
}
prop_id = db::properties_id (ps);
}
if (prop_id != 0) {
output.insert (db::PolygonWithProperties (*p, prop_id));
} else {
output.insert (*p);
}
}
} else if (multiple_properties) {
db::Shapes result (output.is_editable ()); db::Shapes result (output.is_editable ());
@ -417,8 +505,12 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const
std::unique_ptr<FlatRegion> new_region (new FlatRegion ()); std::unique_ptr<FlatRegion> new_region (new FlatRegion ());
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
new_region->insert (*p); if (p.prop_id () != 0) {
new_region->insert (db::PolygonWithProperties (*p, p.prop_id ()));
} else {
new_region->insert (*p);
}
} }
} }
@ -426,6 +518,33 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const
return new_region.release (); return new_region.release ();
} }
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::filtered_pair (const PolygonFilterBase &filter) const
{
std::unique_ptr<FlatRegion> new_region_true (new FlatRegion ());
std::unique_ptr<FlatRegion> new_region_false (new FlatRegion ());
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) {
new_region_true->insert (db::PolygonWithProperties (*p, p.prop_id ()));
} else {
new_region_true->insert (*p);
}
} else {
if (p.prop_id () != 0) {
new_region_false->insert (db::PolygonWithProperties (*p, p.prop_id ()));
} else {
new_region_false->insert (*p);
}
}
}
new_region_true->set_is_merged (true);
new_region_false->set_is_merged (true);
return std::make_pair (new_region_true.release (), new_region_false.release ());
}
RegionDelegate * RegionDelegate *
AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const
{ {
@ -434,17 +553,17 @@ AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const
new_region->set_merged_semantics (false); new_region->set_merged_semantics (false);
} }
std::vector<db::Polygon> poly_res; std::vector<db::PolygonWithProperties> poly_res;
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
poly_res.clear (); poly_res.clear ();
filter.process (*p, poly_res); filter.process (p.wp (), poly_res);
for (std::vector<db::Polygon>::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) { for (auto pr = poly_res.begin (); pr != poly_res.end (); ++pr) {
if (p.prop_id () != 0) { if (pr->properties_id () != 0) {
new_region->insert (db::PolygonWithProperties (*pr, p.prop_id ()));
} else {
new_region->insert (*pr); new_region->insert (*pr);
} else {
new_region->insert (pr->base ());
} }
} }
@ -461,17 +580,17 @@ AsIfFlatRegion::processed_to_edges (const PolygonToEdgeProcessorBase &filter) co
new_edges->set_merged_semantics (false); new_edges->set_merged_semantics (false);
} }
std::vector<db::Edge> edge_res; std::vector<db::EdgeWithProperties> edge_res;
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
edge_res.clear (); edge_res.clear ();
filter.process (*p, edge_res); filter.process (p.wp (), edge_res);
for (std::vector<db::Edge>::const_iterator er = edge_res.begin (); er != edge_res.end (); ++er) { for (auto er = edge_res.begin (); er != edge_res.end (); ++er) {
if (p.prop_id () != 0) { if (er->properties_id () != 0) {
new_edges->insert (db::EdgeWithProperties (*er, p.prop_id ()));
} else {
new_edges->insert (*er); new_edges->insert (*er);
} else {
new_edges->insert (er->base ());
} }
} }
@ -488,17 +607,17 @@ AsIfFlatRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &f
new_edge_pairs->set_merged_semantics (false); new_edge_pairs->set_merged_semantics (false);
} }
std::vector<db::EdgePair> edge_pair_res; std::vector<db::EdgePairWithProperties> edge_pair_res;
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
edge_pair_res.clear (); edge_pair_res.clear ();
filter.process (*p, edge_pair_res); filter.process (p.wp (), edge_pair_res);
for (std::vector<db::EdgePair>::const_iterator epr = edge_pair_res.begin (); epr != edge_pair_res.end (); ++epr) { for (auto epr = edge_pair_res.begin (); epr != edge_pair_res.end (); ++epr) {
if (p.prop_id () != 0) { if (epr->properties_id () != 0) {
new_edge_pairs->insert (db::EdgePairWithProperties (*epr, p.prop_id ()));
} else {
new_edge_pairs->insert (*epr); new_edge_pairs->insert (*epr);
} else {
new_edge_pairs->insert (epr->base ());
} }
} }
@ -1215,7 +1334,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
} }
RegionDelegate * RegionDelegate *
AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const
{ {
if (empty ()) { if (empty ()) {
@ -1233,7 +1352,7 @@ AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const
} else { } else {
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true)); std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
merge_polygons_to (new_region->raw_polygons (), min_coherence, min_wc); merge_polygons_to (new_region->raw_polygons (), min_coherence, min_wc, join_properties_on_merge);
return new_region.release (); return new_region.release ();
@ -1818,12 +1937,12 @@ AsIfFlatRegion::add (const Region &other) const
new_region->set_is_merged (false); new_region->set_is_merged (false);
new_region->invalidate_cache (); new_region->invalidate_cache ();
size_t n = new_region->raw_polygons ().size () + count ();
new_region->reserve (n);
for (RegionIterator p (begin ()); ! p.at_end (); ++p) { for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
new_region->raw_polygons ().insert (*p); if (p.prop_id () == 0) {
new_region->raw_polygons ().insert (*p);
} else {
new_region->raw_polygons ().insert (db::PolygonWithProperties (*p, p.prop_id ()));
}
} }
return new_region.release (); return new_region.release ();
@ -1832,15 +1951,19 @@ AsIfFlatRegion::add (const Region &other) const
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false /*not merged*/)); std::unique_ptr<FlatRegion> new_region (new FlatRegion (false /*not merged*/));
size_t n = count () + other.count ();
new_region->reserve (n);
for (RegionIterator p (begin ()); ! p.at_end (); ++p) { for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
new_region->raw_polygons ().insert (*p); if (p.prop_id () == 0) {
new_region->raw_polygons ().insert (*p);
} else {
new_region->raw_polygons ().insert (db::PolygonWithProperties (*p, p.prop_id ()));
}
} }
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
new_region->raw_polygons ().insert (*p); if (p.prop_id () == 0) {
new_region->raw_polygons ().insert (*p);
} else {
new_region->raw_polygons ().insert (db::PolygonWithProperties (*p, p.prop_id ()));
}
} }
return new_region.release (); return new_region.release ();
@ -1849,7 +1972,7 @@ AsIfFlatRegion::add (const Region &other) const
} }
static void static void
deliver_shapes_of_nets_recursive (db::Shapes &out, const db::Circuit *circuit, const LayoutToNetlist *l2n, const db::Region *of_layer, NetPropertyMode prop_mode, const tl::Variant &net_prop_name, const db::ICplxTrans &tr, const std::set<const db::Net *> *net_filter) deliver_shapes_of_nets_recursive (db::Shapes &out, const db::Circuit *circuit, const LayoutToNetlist *l2n, unsigned int lid, NetPropertyMode prop_mode, const tl::Variant &net_prop_name, const db::ICplxTrans &tr, const std::set<const db::Net *> *net_filter)
{ {
db::CplxTrans dbu_trans (l2n->internal_layout ()->dbu ()); db::CplxTrans dbu_trans (l2n->internal_layout ()->dbu ());
auto dbu_trans_inv = dbu_trans.inverted (); auto dbu_trans_inv = dbu_trans.inverted ();
@ -1858,14 +1981,14 @@ deliver_shapes_of_nets_recursive (db::Shapes &out, const db::Circuit *circuit, c
if (! net_filter || net_filter->find (n.operator-> ()) != net_filter->end ()) { if (! net_filter || net_filter->find (n.operator-> ()) != net_filter->end ()) {
db::properties_id_type prop_id = db::NetBuilder::make_netname_propid (prop_mode, net_prop_name, *n); db::properties_id_type prop_id = db::NetBuilder::make_netname_propid (prop_mode, net_prop_name, *n);
l2n->shapes_of_net (*n, *of_layer, true, out, prop_id, tr); l2n->shapes_of_net (*n, lid, true, out, prop_id, tr);
} }
// dive into subcircuits // dive into subcircuits
for (auto sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) { for (auto sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) {
const db::Circuit *circuit_ref = sc->circuit_ref (); const db::Circuit *circuit_ref = sc->circuit_ref ();
db::ICplxTrans tr_ref = tr * (dbu_trans_inv * sc->trans () * dbu_trans); db::ICplxTrans tr_ref = tr * (dbu_trans_inv * sc->trans () * dbu_trans);
deliver_shapes_of_nets_recursive (out, circuit_ref, l2n, of_layer, prop_mode, net_prop_name, tr_ref, net_filter); deliver_shapes_of_nets_recursive (out, circuit_ref, l2n, lid, prop_mode, net_prop_name, tr_ref, net_filter);
} }
} }
@ -1879,9 +2002,9 @@ AsIfFlatRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl:
} }
std::unique_ptr<db::FlatRegion> result (new db::FlatRegion ()); std::unique_ptr<db::FlatRegion> result (new db::FlatRegion ());
std::unique_ptr<db::Region> region_for_layer (l2n->layer_by_original (this)); tl::optional<unsigned int> li = l2n->layer_by_original (this);
if (! region_for_layer) { if (! li.has_value ()) {
throw tl::Exception (tl::to_string (tr ("The given layer is not an original layer used in netlist extraction"))); throw tl::Exception (tl::to_string (tr ("The given layer is not an original layer used in netlist extraction")));
} }
@ -1897,7 +2020,7 @@ AsIfFlatRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl:
net_filter_set.insert (net_filter->begin (), net_filter->end ()); net_filter_set.insert (net_filter->begin (), net_filter->end ());
} }
deliver_shapes_of_nets_recursive (result->raw_polygons (), top_circuit, l2n, region_for_layer.get (), prop_mode, net_prop_name, db::ICplxTrans (), net_filter ? &net_filter_set : 0); deliver_shapes_of_nets_recursive (result->raw_polygons (), top_circuit, l2n, li.value (), prop_mode, net_prop_name, db::ICplxTrans (), net_filter ? &net_filter_set : 0);
return result.release (); return result.release ();
} }

View File

@ -101,23 +101,24 @@ public:
} }
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const; virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> filtered_pair (const PolygonFilterBase &filter) const;
virtual RegionDelegate *merged_in_place () virtual RegionDelegate *merged_in_place ()
{ {
return merged (); return merged ();
} }
virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc) virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge)
{ {
return merged (min_coherence, min_wc); return merged (min_coherence, min_wc, join_properties_on_merge);
} }
virtual RegionDelegate *merged () const virtual RegionDelegate *merged () const
{ {
return merged (min_coherence (), 0); return merged (min_coherence (), 0, join_properties_on_merge ());
} }
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const; virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const;
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
@ -287,7 +288,7 @@ public:
protected: protected:
void update_bbox (const db::Box &box); void update_bbox (const db::Box &box);
void invalidate_bbox (); void invalidate_bbox ();
void merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc) const; void merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const;
RegionDelegate *and_or_not_with (bool is_and, const Region &other, PropertyConstraint property_constraint) const; RegionDelegate *and_or_not_with (bool is_and, const Region &other, PropertyConstraint property_constraint) const;
virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const; virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const;

View File

@ -79,6 +79,9 @@ AsIfFlatTexts::to_string (size_t nmax) const
} }
first = false; first = false;
os << p->to_string (); os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
} }
if (! p.at_end ()) { if (! p.at_end ()) {
os << "..."; os << "...";
@ -156,26 +159,59 @@ AsIfFlatTexts::filtered (const TextFilterBase &filter) const
std::unique_ptr<FlatTexts> new_texts (new FlatTexts ()); std::unique_ptr<FlatTexts> new_texts (new FlatTexts ());
for (TextsIterator p (begin ()); ! p.at_end (); ++p) { for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
new_texts->insert (*p); if (p.prop_id () != 0) {
new_texts->insert (db::TextWithProperties (*p, p.prop_id ()));
} else {
new_texts->insert (*p);
}
} }
} }
return new_texts.release (); return new_texts.release ();
} }
std::pair<TextsDelegate *, TextsDelegate *>
AsIfFlatTexts::filtered_pair (const TextFilterBase &filter) const
{
std::unique_ptr<FlatTexts> new_texts_true (new FlatTexts ());
std::unique_ptr<FlatTexts> new_texts_false (new FlatTexts ());
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) {
new_texts_true->insert (db::TextWithProperties (*p, p.prop_id ()));
} else {
new_texts_true->insert (*p);
}
} else {
if (p.prop_id () != 0) {
new_texts_false->insert (db::TextWithProperties (*p, p.prop_id ()));
} else {
new_texts_false->insert (*p);
}
}
}
return std::make_pair (new_texts_true.release (), new_texts_false.release ());
}
TextsDelegate * TextsDelegate *
AsIfFlatTexts::processed (const TextProcessorBase &filter) const AsIfFlatTexts::processed (const TextProcessorBase &filter) const
{ {
std::unique_ptr<FlatTexts> texts (new FlatTexts ()); std::unique_ptr<FlatTexts> texts (new FlatTexts ());
std::vector<db::Text> res_texts; std::vector<db::TextWithProperties> res_texts;
for (TextsIterator e = begin (); ! e.at_end (); ++e) { for (TextsIterator e = begin (); ! e.at_end (); ++e) {
res_texts.clear (); res_texts.clear ();
filter.process (*e, res_texts); filter.process (e.wp (), res_texts);
for (std::vector<db::Text>::const_iterator er = res_texts.begin (); er != res_texts.end (); ++er) { for (auto er = res_texts.begin (); er != res_texts.end (); ++er) {
texts->insert (*er); if (er->properties_id () != 0) {
texts->insert (*er);
} else {
texts->insert (er->base ());
}
} }
} }
@ -191,16 +227,16 @@ AsIfFlatTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter)
region->set_merged_semantics (false); region->set_merged_semantics (false);
} }
std::vector<db::Polygon> res_polygons; std::vector<db::PolygonWithProperties> res_polygons;
for (TextsIterator e (begin ()); ! e.at_end (); ++e) { for (TextsIterator e (begin ()); ! e.at_end (); ++e) {
res_polygons.clear (); res_polygons.clear ();
filter.process (*e, res_polygons); filter.process (e.wp (), res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
if (e.prop_id () != 0) { if (pr->properties_id () != 0) {
region->insert (db::PolygonWithProperties (*pr, e.prop_id ()));
} else {
region->insert (*pr); region->insert (*pr);
} else {
region->insert (pr->base ());
} }
} }
} }
@ -209,14 +245,32 @@ AsIfFlatTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter)
} }
RegionDelegate * RegionDelegate *
AsIfFlatTexts::polygons (db::Coord e) const AsIfFlatTexts::polygons (db::Coord e, const tl::Variant &text_prop) const
{ {
db::property_names_id_type key_id = 0;
if (! text_prop.is_nil ()) {
key_id = db::property_names_id (text_prop);
}
std::map<std::string, db::properties_id_type> value_ids;
std::unique_ptr<FlatRegion> output (new FlatRegion ()); std::unique_ptr<FlatRegion> output (new FlatRegion ());
for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) { for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) {
db::Box box = tp->box (); db::Box box = tp->box ();
box.enlarge (db::Vector (e, e)); box.enlarge (db::Vector (e, e));
output->insert (db::Polygon (box)); if (key_id == 0) {
output->insert (db::Polygon (box));
} else {
std::string value (tp->string ());
auto v = value_ids.find (value);
if (v == value_ids.end ()) {
db::PropertiesSet ps;
ps.insert_by_id (key_id, db::property_values_id (value));
v = value_ids.insert (std::make_pair (value, db::properties_id (ps))).first;
}
output->insert (db::PolygonWithProperties (db::Polygon (box), v->second));
}
} }
return output.release (); return output.release ();
@ -244,12 +298,12 @@ AsIfFlatTexts::add (const Texts &other) const
std::unique_ptr<FlatTexts> new_texts (new FlatTexts (*other_flat)); std::unique_ptr<FlatTexts> new_texts (new FlatTexts (*other_flat));
new_texts->invalidate_cache (); new_texts->invalidate_cache ();
size_t n = new_texts->raw_texts ().size () + count ();
new_texts->reserve (n);
for (TextsIterator p (begin ()); ! p.at_end (); ++p) { for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
new_texts->raw_texts ().insert (*p); if (p.prop_id () == 0) {
new_texts->raw_texts ().insert (*p);
} else {
new_texts->raw_texts ().insert (TextWithProperties (*p, p.prop_id ()));
}
} }
return new_texts.release (); return new_texts.release ();
@ -258,15 +312,19 @@ AsIfFlatTexts::add (const Texts &other) const
std::unique_ptr<FlatTexts> new_texts (new FlatTexts ()); std::unique_ptr<FlatTexts> new_texts (new FlatTexts ());
size_t n = count () + other.count ();
new_texts->reserve (n);
for (TextsIterator p (begin ()); ! p.at_end (); ++p) { for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
new_texts->raw_texts ().insert (*p); if (p.prop_id () == 0) {
new_texts->raw_texts ().insert (*p);
} else {
new_texts->raw_texts ().insert (db::TextWithProperties (*p, p.prop_id ()));
}
} }
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
new_texts->raw_texts ().insert (*p); if (p.prop_id () == 0) {
new_texts->raw_texts ().insert (*p);
} else {
new_texts->raw_texts ().insert (db::TextWithProperties (*p, p.prop_id ()));
}
} }
return new_texts.release (); return new_texts.release ();

View File

@ -54,6 +54,7 @@ public:
} }
virtual TextsDelegate *filtered (const TextFilterBase &) const; virtual TextsDelegate *filtered (const TextFilterBase &) const;
virtual std::pair<TextsDelegate *, TextsDelegate *> filtered_pair (const TextFilterBase &filter) const;
virtual TextsDelegate *process_in_place (const TextProcessorBase &proc) virtual TextsDelegate *process_in_place (const TextProcessorBase &proc)
{ {
@ -70,7 +71,7 @@ public:
virtual TextsDelegate *add (const Texts &other) const; virtual TextsDelegate *add (const Texts &other) const;
virtual RegionDelegate *polygons (db::Coord e) const; virtual RegionDelegate *polygons (db::Coord e, const tl::Variant &text_prop) const;
virtual EdgesDelegate *edges () const; virtual EdgesDelegate *edges () const;
virtual TextsDelegate *in (const Texts &, bool) const; virtual TextsDelegate *in (const Texts &, bool) const;

View File

@ -36,12 +36,7 @@ DB_PUBLIC db::Box cellinst_box_convert_impl (const db::CellInst &inst, const db:
} else if (allow_empty) { } else if (allow_empty) {
return inst.bbox (*layout); return inst.bbox (*layout);
} else { } else {
db::Box box = inst.bbox (*layout); return inst.bbox_with_empty (*layout);
if (box.empty ()) {
return db::Box (db::Point (0, 0), db::Point (0, 0));
} else {
return box;
}
} }
} }
@ -52,11 +47,7 @@ DB_PUBLIC db::Box cell_box_convert_impl (const db::Cell &c, int layer, bool allo
} else if (allow_empty) { } else if (allow_empty) {
return c.bbox (); return c.bbox ();
} else { } else {
if (c.bbox ().empty ()) { return c.bbox_with_empty ();
return db::Box (db::Point (0, 0), db::Point (0, 0));
} else {
return c.bbox ();
}
} }
} }

View File

@ -96,7 +96,7 @@ Cell::Cell (cell_index_type ci, db::Layout &l)
m_bbox_needs_update (false), m_locked (false), m_ghost_cell (false), m_bbox_needs_update (false), m_locked (false), m_ghost_cell (false),
mp_last (0), mp_next (0) mp_last (0), mp_next (0)
{ {
// .. nothing yet m_bbox_with_empty = box_type (box_type::point_type (), box_type::point_type ());
} }
Cell::Cell (const Cell &d) Cell::Cell (const Cell &d)
@ -128,6 +128,7 @@ Cell::operator= (const Cell &d)
m_locked = d.m_locked; m_locked = d.m_locked;
m_instances = d.m_instances; m_instances = d.m_instances;
m_bbox = d.m_bbox; m_bbox = d.m_bbox;
m_bbox_with_empty = d.m_bbox_with_empty;
m_bboxes = d.m_bboxes; m_bboxes = d.m_bboxes;
m_hier_levels = d.m_hier_levels; m_hier_levels = d.m_hier_levels;
m_prop_id = d.m_prop_id; m_prop_id = d.m_prop_id;
@ -282,6 +283,10 @@ Cell::update_bbox (unsigned int layers)
box_type org_bbox = m_bbox; box_type org_bbox = m_bbox;
m_bbox = box_type (); m_bbox = box_type ();
// determine the bounding box with empty cells
box_type org_bbox_with_empty = m_bbox_with_empty;
m_bbox_with_empty = box_type ();
// save the original boxes for simple compare // save the original boxes for simple compare
box_map org_bboxes; box_map org_bboxes;
org_bboxes.swap (m_bboxes); org_bboxes.swap (m_bboxes);
@ -313,16 +318,21 @@ Cell::update_bbox (unsigned int layers)
m_bbox += lbox; m_bbox += lbox;
box_map::iterator b = m_bboxes.find (l); box_map::iterator b = m_bboxes.find (l);
if (b == m_bboxes.end ()) { if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (l, lbox)); m_bboxes.insert (std::make_pair (l, lbox));
} else { } else {
b->second += lbox; b->second += lbox;
} }
} }
} }
db::box_convert <cell_inst_type, false> bc_we (*mp_layout);
m_bbox_with_empty += o1_inst->bbox_from_raw_bbox (raw_box, bc_we);
} }
box_type sbox_all;
// update the bboxes of the shapes lists // update the bboxes of the shapes lists
for (shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) { for (shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
@ -331,7 +341,7 @@ Cell::update_bbox (unsigned int layers)
box_type sbox (s->second.bbox ()); box_type sbox (s->second.bbox ());
if (! sbox.empty ()) { if (! sbox.empty ()) {
m_bbox += sbox; sbox_all += sbox;
box_map::iterator b = m_bboxes.find (s->first); box_map::iterator b = m_bboxes.find (s->first);
if (b == m_bboxes.end ()) { if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (s->first, sbox)); m_bboxes.insert (std::make_pair (s->first, sbox));
@ -342,12 +352,20 @@ Cell::update_bbox (unsigned int layers)
} }
// combine shapes in all-layer boxes
m_bbox += sbox_all;
m_bbox_with_empty += sbox_all;
// no empty box
if (m_bbox_with_empty.empty ()) {
m_bbox_with_empty = box_type (box_type::point_type (), box_type::point_type ());
}
// reset "dirty child instances" flag // reset "dirty child instances" flag
m_bbox_needs_update = false; m_bbox_needs_update = false;
// return true, if anything has changed with the box // return true, if anything has changed with the box
return (org_bbox != m_bbox || org_bboxes != m_bboxes); return (org_bbox != m_bbox || org_bbox_with_empty != m_bbox_with_empty || org_bboxes != m_bboxes);
} }
void void
@ -442,6 +460,13 @@ Cell::prop_id (db::properties_id_type id)
} }
} }
const Cell::box_type &
Cell::bbox_with_empty () const
{
mp_layout->update ();
return m_bbox_with_empty;
}
const Cell::box_type & const Cell::box_type &
Cell::bbox () const Cell::bbox () const
{ {

View File

@ -536,6 +536,17 @@ public:
*/ */
const box_type &bbox () const; const box_type &bbox () const;
/**
* @brief Retrieve the bounding box of the cell, including empty cells
*
* This method behaves like "bbox", but includes empty cells as single-point
* boxes (0,0;0,0). This bounding box is used for drawing and allows
* including empty cells.
*
* @return The bounding box that was computed by update_bbox
*/
const box_type &bbox_with_empty () const;
/** /**
* @brief Retrieve the per-layer bounding box of the cell * @brief Retrieve the per-layer bounding box of the cell
* *
@ -1098,7 +1109,7 @@ private:
mutable db::Layout *mp_layout; mutable db::Layout *mp_layout;
shapes_map m_shapes_map; shapes_map m_shapes_map;
instances_type m_instances; instances_type m_instances;
box_type m_bbox; box_type m_bbox, m_bbox_with_empty;
box_map m_bboxes; box_map m_bboxes;
db::properties_id_type m_prop_id; db::properties_id_type m_prop_id;

View File

@ -33,6 +33,12 @@ CellInst::bbox (const db::Layout &g) const
return g.cell (m_cell_index).bbox (); return g.cell (m_cell_index).bbox ();
} }
CellInst::box_type
CellInst::bbox_with_empty (const db::Layout &g) const
{
return g.cell (m_cell_index).bbox_with_empty ();
}
CellInst::box_type CellInst::box_type
CellInst::bbox (const db::Layout &g, unsigned int l) const CellInst::bbox (const db::Layout &g, unsigned int l) const
{ {

View File

@ -90,6 +90,15 @@ public:
*/ */
box_type bbox (const Layout &g) const; box_type bbox (const Layout &g) const;
/**
* @brief Compute the bounding box, including empty cells
*
* This method computes the bbox of the cell instance.
* As a requirement, the cell's bounding box must have been
* computed before.
*/
box_type bbox_with_empty (const Layout &g) const;
/** /**
* @brief Compute the bounding box * @brief Compute the bounding box
* *

View File

@ -284,8 +284,17 @@ std::vector<db::cell_index_type> CellMapping::source_cells () const
return s; return s;
} }
std::vector<db::cell_index_type> CellMapping::target_cells () const
{
std::vector<db::cell_index_type> s;
s.reserve (m_b2a_mapping.size ());
for (iterator m = begin (); m != end (); ++m) {
s.push_back (m->second);
}
return s;
}
void void
CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_index_type cell_index_a, const db::Layout & /*layout_b*/, db::cell_index_type cell_index_b) CellMapping::create_single_mapping (const db::Layout & /*layout_a*/, db::cell_index_type cell_index_a, const db::Layout & /*layout_b*/, db::cell_index_type cell_index_b)
{ {
clear (); clear ();
@ -345,6 +354,13 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &
std::vector<db::cell_index_type> &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int); std::vector<db::cell_index_type> &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int);
std::vector<db::cell_index_type> new_cells_b; std::vector<db::cell_index_type> new_cells_b;
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > all_a2b;
for (std::vector<db::cell_index_type>::const_iterator b = cell_index_b.begin (); b != cell_index_b.end (); ++b) {
auto m = m_b2a_mapping.find (*b);
tl_assert (m != m_b2a_mapping.end ());
all_a2b.push_back (std::make_pair (m->second, *b));
}
std::set<db::cell_index_type> called_b; std::set<db::cell_index_type> called_b;
for (std::vector<db::cell_index_type>::const_iterator i = cell_index_b.begin (); i != cell_index_b.end (); ++i) { for (std::vector<db::cell_index_type>::const_iterator i = cell_index_b.begin (); i != cell_index_b.end (); ++i) {
layout_b.cell (*i).collect_called_cells (called_b); layout_b.cell (*i).collect_called_cells (called_b);
@ -359,6 +375,7 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &
db::cell_index_type new_cell = layout_a.add_cell (layout_b, *b); db::cell_index_type new_cell = layout_a.add_cell (layout_b, *b);
new_cells.push_back (new_cell); new_cells.push_back (new_cell);
new_cells_b.push_back (*b); new_cells_b.push_back (*b);
all_a2b.push_back (std::make_pair (new_cell, *b));
if (mapped_pairs) { if (mapped_pairs) {
mapped_pairs->push_back (std::make_pair (*b, new_cell)); mapped_pairs->push_back (std::make_pair (*b, new_cell));
@ -369,43 +386,40 @@ CellMapping::do_create_missing_mapping (db::Layout &layout_a, const db::Layout &
} }
} }
if (! new_cells.empty ()) { if (all_a2b.empty ()) {
return;
}
// Note: this avoids frequent cell index table rebuilds if source and target layout are identical // Note: this avoids frequent cell index table rebuilds if source and target layout are identical
layout_a.start_changes (); db::LayoutLocker locker (&layout_a);
// Create instances for the new cells in layout A according to their instantiation in layout B // Create instances for the new cells in layout A according to their instantiation in layout B
double mag = layout_b.dbu () / layout_a.dbu (); double mag = layout_b.dbu () / layout_a.dbu ();
for (size_t i = 0; i < new_cells.size (); ++i) { for (auto i = all_a2b.begin (); i != all_a2b.end (); ++i) {
const db::Cell &b = layout_b.cell (new_cells_b [i]); const db::Cell &b = layout_b.cell (i->second);
for (db::Cell::parent_inst_iterator pb = b.begin_parent_insts (); ! pb.at_end (); ++pb) { for (db::Cell::parent_inst_iterator pb = b.begin_parent_insts (); ! pb.at_end (); ++pb) {
if (called_b.find (pb->parent_cell_index ()) != called_b.end ()) { if (called_b.find (pb->parent_cell_index ()) != called_b.end ()) {
db::Cell &pa = layout_a.cell (m_b2a_mapping [pb->parent_cell_index ()]); db::Cell &pa = layout_a.cell (m_b2a_mapping [pb->parent_cell_index ()]);
db::Instance bi = pb->child_inst (); db::Instance bi = pb->child_inst ();
db::CellInstArray bci = bi.cell_inst (); db::CellInstArray bci = bi.cell_inst ();
bci.object ().cell_index (new_cells [i]); bci.object ().cell_index (i->first);
bci.transform_into (db::ICplxTrans (mag), &layout_a.array_repository ()); bci.transform_into (db::ICplxTrans (mag), &layout_a.array_repository ());
if (bi.has_prop_id ()) {
pa.insert (db::CellInstArrayWithProperties (bci, bi.prop_id ()));
} else {
pa.insert (bci);
}
if (bi.has_prop_id ()) {
pa.insert (db::CellInstArrayWithProperties (bci, bi.prop_id ()));
} else {
pa.insert (bci);
} }
} }
} }
// Note: must be there because of start_changes
layout_a.end_changes ();
} }
} }

View File

@ -206,6 +206,11 @@ public:
*/ */
std::vector<db::cell_index_type> source_cells () const; std::vector<db::cell_index_type> source_cells () const;
/**
* @brief Gets the target cells
*/
std::vector<db::cell_index_type> target_cells () const;
/** /**
* @brief Access to the mapping table * @brief Access to the mapping table
*/ */

View File

@ -712,6 +712,28 @@ VariantsCollectorBase::create_var_instances_tl_invariant (db::Cell &in_cell, std
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
TransformationReducer *
make_reducer (ReducerType type)
{
switch (type) {
case Orientation:
return new OrientationReducer ();
case Orthogonal:
return new OrthogonalTransformationReducer ();
case Magnification:
return new MagnificationReducer ();
case XYAnisotropyAndMagnification:
return new XYAnisotropyAndMagnificationReducer ();
case MagnificationAndOrientation:
return new MagnificationAndOrientationReducer ();
default:
return 0;
}
}
// ------------------------------------------------------------------------------------------
VariantStatistics::VariantStatistics () VariantStatistics::VariantStatistics ()
: mp_red () : mp_red ()
{ {

View File

@ -166,6 +166,51 @@ private:
int64_t m_grid; int64_t m_grid;
}; };
/**
* @brief An enum describing a reducer type
*
* This enum is used to create a generic reducer (parameterless) from the code.
*/
enum ReducerType
{
/**
* @brief No specific reducer
*/
NoReducer = 0,
/**
* @brief Rotation/mirror variants
*/
Orientation = 1,
/**
* @brief Orthogonal transformations (rotations of multiple of 90 degree) variants
*/
Orthogonal = 2,
/**
* @brief Scaling variants
*/
Magnification = 3,
/**
* @brief Scaling and x/y assymmetry variants (i.e. anisotropic size)
*/
XYAnisotropyAndMagnification = 4,
/**
* @brief Scaling and orientation variants
*/
MagnificationAndOrientation = 5
};
/**
* @brief Creates a TransformationReducer from the type enum
*
* This function returns 0 if the type is NoReducer or invalid.
*/
DB_PUBLIC TransformationReducer *make_reducer (ReducerType type);
/** /**
* @brief A class computing variants for cells according to a given criterion * @brief A class computing variants for cells according to a given criterion
* *

View File

@ -146,8 +146,6 @@ CommonReaderBase::name_for_id (size_t id) const
void void
CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string &cn) CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string &cn)
{ {
m_name_for_id.insert (std::make_pair (id, cn));
std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id); std::map<size_t, std::pair<std::string, db::cell_index_type> >::iterator iid = m_id_map.find (id);
std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn); std::map<std::string, std::pair<size_t, db::cell_index_type> >::iterator iname = m_name_map.find (cn);
@ -156,9 +154,22 @@ CommonReaderBase::rename_cell (db::Layout &layout, size_t id, const std::string
} }
if (iname != m_name_map.end () && iname->second.first != null_id && iname->second.first != id) { if (iname != m_name_map.end () && iname->second.first != null_id && iname->second.first != id) {
common_reader_error (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld")), cn, id, iname->second.first));
// picking a different name on name clash (issue #2088)
std::string cn_new = cn + "_id$" + tl::to_string (id);
for (size_t i = 0; m_name_map.find (cn_new) != m_name_map.end (); ++i) {
cn_new = cn + "_id$" + tl::to_string (id) + "$" + tl::to_string (i);
}
common_reader_warn (tl::sprintf (tl::to_string (tr ("Same cell name %s, but different IDs: %ld and %ld, renaming first to %s")), cn, id, iname->second.first, cn_new));
rename_cell (layout, id, cn_new);
return;
} }
m_name_for_id.insert (std::make_pair (id, cn));
if (iid != m_id_map.end () && iname != m_name_map.end ()) { if (iid != m_id_map.end () && iname != m_name_map.end ()) {
if (iname->second.second != iid->second.second) { if (iname->second.second != iid->second.second) {
@ -240,7 +251,7 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn)
} }
void void
CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances) const CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances)
{ {
const db::Cell &src_cell = layout.cell (src_cell_index); const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index); db::Cell &target_cell = layout.cell (target_cell_index);
@ -284,7 +295,7 @@ CommonReaderBase::merge_cell (db::Layout &layout, db::cell_index_type target_cel
} }
void void
CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta)
{ {
const db::Cell &src_cell = layout.cell (src_cell_index); const db::Cell &src_cell = layout.cell (src_cell_index);
db::Cell &target_cell = layout.cell (target_cell_index); db::Cell &target_cell = layout.cell (target_cell_index);
@ -297,25 +308,31 @@ CommonReaderBase::merge_cell_without_instances (db::Layout &layout, db::cell_ind
} }
// replace all instances of the new cell with the original one // replace all instances of the new cell with the original one
layout.replace_instances_of (src_cell.cell_index (), target_cell.cell_index ()); layout.replace_instances_of (src_cell_index, target_cell_index);
// merge meta info // merge meta info
if (with_meta) { if (with_meta) {
auto ib = layout.begin_meta (src_cell.cell_index ()); auto ib = layout.begin_meta (src_cell_index);
auto ie = layout.end_meta (src_cell.cell_index ()); auto ie = layout.end_meta (src_cell_index);
for (auto i = ib; i != ie; ++i) { for (auto i = ib; i != ie; ++i) {
layout.add_meta_info (target_cell.cell_index (), i->first, i->second); layout.add_meta_info (target_cell_index, i->first, i->second);
} }
} }
layout.clear_meta (src_cell.cell_index ()); layout.clear_meta (src_cell_index);
// finally delete the new cell // finally delete the new cell
layout.delete_cell (src_cell.cell_index ()); m_temp_cells.erase (src_cell_index);
layout.delete_cell (src_cell_index);
} }
void void
CommonReaderBase::init () CommonReaderBase::start ()
{ {
m_id_map.clear ();
m_name_map.clear ();
m_temp_cells.clear ();
m_name_for_id.clear ();
m_layer_map_out.clear (); m_layer_map_out.clear ();
m_multi_mapping_placeholders.clear (); m_multi_mapping_placeholders.clear ();
m_layer_cache.clear (); m_layer_cache.clear ();
@ -621,7 +638,7 @@ void
CommonReader::init (const LoadLayoutOptions &options) CommonReader::init (const LoadLayoutOptions &options)
{ {
ReaderBase::init (options); ReaderBase::init (options);
CommonReaderBase::init (); CommonReaderBase::start ();
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> (); db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
set_conflict_resolution_mode (common_options.cell_conflict_resolution); set_conflict_resolution_mode (common_options.cell_conflict_resolution);

View File

@ -207,7 +207,7 @@ public:
/** /**
* @brief Re-initialize: clears the tables and caches * @brief Re-initialize: clears the tables and caches
*/ */
void init (); void start ();
/** /**
* @brief Sets a value indicating whether to create layers * @brief Sets a value indicating whether to create layers
@ -242,12 +242,12 @@ protected:
/** /**
* @brief Merge (and delete) the src_cell into target_cell * @brief Merge (and delete) the src_cell into target_cell
*/ */
void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances) const; void merge_cell (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta, bool no_duplicate_instances);
/** /**
* @brief Merge (and delete) the src_cell into target_cell without instances * @brief Merge (and delete) the src_cell into target_cell without instances
*/ */
void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta) const; void merge_cell_without_instances (db::Layout &layout, db::cell_index_type target_cell_index, db::cell_index_type src_cell_index, bool with_meta);
/** /**
* @brief Gets the layer name map * @brief Gets the layer name map

View File

@ -302,13 +302,16 @@ CompoundTransformationReducer::is_translation_invariant () const
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode (const std::vector<CompoundRegionOperationNode *> &children) CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode (const std::vector<CompoundRegionOperationNode *> &children, bool no_init)
{ {
for (std::vector<CompoundRegionOperationNode *>::const_iterator c = children.begin (); c != children.end (); ++c) { for (std::vector<CompoundRegionOperationNode *>::const_iterator c = children.begin (); c != children.end (); ++c) {
(*c)->keep (); (*c)->keep ();
m_children.push_back (*c); m_children.push_back (*c);
} }
init ();
if (! no_init) {
init ();
}
} }
CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode () CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode ()
@ -362,6 +365,11 @@ CompoundRegionMultiInputOperationNode::init ()
for (tl::shared_collection<CompoundRegionOperationNode>::iterator i = m_children.begin (); i != m_children.end (); ++i) { for (tl::shared_collection<CompoundRegionOperationNode>::iterator i = m_children.begin (); i != m_children.end (); ++i) {
m_vars.add (i->vars ()); m_vars.add (i->vars ());
} }
// add the local variant reducer
if (local_vars ()) {
m_vars.add (local_vars ());
}
} }
CompoundRegionMultiInputOperationNode::~CompoundRegionMultiInputOperationNode () CompoundRegionMultiInputOperationNode::~CompoundRegionMultiInputOperationNode ()
@ -1260,7 +1268,13 @@ CompoundRegionEdgePairFilterOperationNode::do_compute_local (CompoundRegionOpera
bool bool
CompoundRegionEdgePairFilterOperationNode::is_selected (const db::EdgePair &p) const CompoundRegionEdgePairFilterOperationNode::is_selected (const db::EdgePair &p) const
{ {
return mp_filter->selected (p); return mp_filter->selected (p, db::properties_id_type (0));
}
bool
CompoundRegionEdgePairFilterOperationNode::is_selected (const db::EdgePairWithProperties &p) const
{
return mp_filter->selected (p, p.properties_id ());
} }
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------

View File

@ -453,7 +453,7 @@ class DB_PUBLIC CompoundRegionMultiInputOperationNode
: public CompoundRegionOperationNode : public CompoundRegionOperationNode
{ {
public: public:
CompoundRegionMultiInputOperationNode (const std::vector<CompoundRegionOperationNode *> &children); CompoundRegionMultiInputOperationNode (const std::vector<CompoundRegionOperationNode *> &children, bool no_init = false);
CompoundRegionMultiInputOperationNode (); CompoundRegionMultiInputOperationNode ();
CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *child); CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *child);
CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b); CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b);
@ -521,14 +521,16 @@ protected:
CompoundRegionOperationNode *child (unsigned int index); CompoundRegionOperationNode *child (unsigned int index);
const CompoundRegionOperationNode *child (unsigned int index) const; const CompoundRegionOperationNode *child (unsigned int index) const;
virtual const TransformationReducer *local_vars () const { return 0; }
void init ();
private: private:
tl::shared_collection<CompoundRegionOperationNode> m_children; tl::shared_collection<CompoundRegionOperationNode> m_children;
// maps child#,layer# to layer# of child: // maps child#,layer# to layer# of child:
std::map<std::pair<unsigned int, unsigned int>, unsigned int> m_map_layer_to_child; std::map<std::pair<unsigned int, unsigned int>, unsigned int> m_map_layer_to_child;
std::vector<db::Region *> m_inputs; std::vector<db::Region *> m_inputs;
CompoundTransformationReducer m_vars; CompoundTransformationReducer m_vars;
void init ();
}; };
@ -1015,14 +1017,12 @@ private:
child (0)->compute_local (cache, layout, cell, interactions, one, proc); child (0)->compute_local (cache, layout, cell, interactions, one, proc);
if (m_sum_of_set) { if (m_sum_of_set) {
std::unordered_set<T> wo_props; if (mp_filter->selected_set (one.front ())) {
wo_props.insert (one.front ().begin (), one.front ().end ());
if (mp_filter->selected_set (wo_props)) {
results.front ().insert (one.front ().begin (), one.front ().end ()); results.front ().insert (one.front ().begin (), one.front ().end ());
} }
} else { } else {
for (typename std::unordered_set<db::object_with_properties<T> >::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) { for (typename std::unordered_set<db::object_with_properties<T> >::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) {
if (mp_filter->selected (*p)) { if (mp_filter->selected (*p, p->properties_id ())) {
results.front ().insert (*p); results.front ().insert (*p);
} }
} }
@ -1066,14 +1066,12 @@ private:
child (0)->compute_local (cache, layout, cell, interactions, one, proc); child (0)->compute_local (cache, layout, cell, interactions, one, proc);
if (m_sum_of) { if (m_sum_of) {
std::unordered_set<db::Edge> wo_props; if (mp_filter->selected_set (one.front ())) {
wo_props.insert (one.front ().begin (), one.front ().end ());
if (mp_filter->selected (wo_props)) {
results.front ().insert (one.front ().begin (), one.front ().end ()); results.front ().insert (one.front ().begin (), one.front ().end ());
} }
} else { } else {
for (typename std::unordered_set<db::EdgeWithProperties>::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) { for (typename std::unordered_set<db::EdgeWithProperties>::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) {
if (mp_filter->selected (*p)) { if (mp_filter->selected (*p, p->properties_id ())) {
results.front ().insert (*p); results.front ().insert (*p);
} }
} }
@ -1108,6 +1106,7 @@ private:
bool m_owns_filter; bool m_owns_filter;
bool is_selected (const db::EdgePair &p) const; bool is_selected (const db::EdgePair &p) const;
bool is_selected (const db::EdgePairWithProperties &p) const;
template <class T, class TR> template <class T, class TR>
void implement_compute_local (db::CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions<T, T> &interactions, std::vector<std::unordered_set<TR> > &results, const db::LocalProcessorBase *proc) const void implement_compute_local (db::CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions<T, T> &interactions, std::vector<std::unordered_set<TR> > &results, const db::LocalProcessorBase *proc) const

View File

@ -161,12 +161,16 @@ EdgePairsDelegate *DeepEdgePairs::clone () const
return new DeepEdgePairs (*this); return new DeepEdgePairs (*this);
} }
void DeepEdgePairs::do_insert (const db::EdgePair &edge_pair) void DeepEdgePairs::do_insert (const db::EdgePair &edge_pair, db::properties_id_type prop_id)
{ {
db::Layout &layout = deep_layer ().layout (); db::Layout &layout = deep_layer ().layout ();
if (layout.begin_top_down () != layout.end_top_down ()) { if (layout.begin_top_down () != layout.end_top_down ()) {
db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
top_cell.shapes (deep_layer ().layer ()).insert (edge_pair); if (prop_id == 0) {
top_cell.shapes (deep_layer ().layer ()).insert (edge_pair);
} else {
top_cell.shapes (deep_layer ().layer ()).insert (db::EdgePairWithProperties (edge_pair, prop_id));
}
} }
invalidate_bbox (); invalidate_bbox ();
@ -307,6 +311,11 @@ const db::EdgePair *DeepEdgePairs::nth (size_t) const
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat edge pair collections"))); throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat edge pair collections")));
} }
db::properties_id_type DeepEdgePairs::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to edge pairs is available only for flat edge pair collections")));
}
bool DeepEdgePairs::has_valid_edge_pairs () const bool DeepEdgePairs::has_valid_edge_pairs () const
{ {
return false; return false;
@ -340,9 +349,12 @@ DeepEdgePairs::add_in_place (const EdgePairs &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ()); db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
for (db::EdgePairs::const_iterator p = other.begin (); ! p.at_end (); ++p) { for (db::EdgePairs::const_iterator p = other.begin (); ! p.at_end (); ++p) {
shapes.insert (*p); if (p.prop_id () == 0) {
shapes.insert (*p);
} else {
shapes.insert (db::EdgePairWithProperties (*p, p.prop_id ()));
}
} }
} }
return this; return this;
@ -365,18 +377,24 @@ EdgePairsDelegate *
DeepEdgePairs::filter_in_place (const EdgePairFilterBase &filter) DeepEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
{ {
// TODO: implement to be really in-place // TODO: implement to be really in-place
*this = *apply_filter (filter); *this = *apply_filter (filter, true, false).first;
return this; return this;
} }
EdgePairsDelegate * EdgePairsDelegate *
DeepEdgePairs::filtered (const EdgePairFilterBase &filter) const DeepEdgePairs::filtered (const EdgePairFilterBase &filter) const
{ {
return apply_filter (filter); return apply_filter (filter, true, false).first;
} }
DeepEdgePairs * std::pair<EdgePairsDelegate *, EdgePairsDelegate *>
DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const DeepEdgePairs::filtered_pair (const EdgePairFilterBase &filter) const
{
return apply_filter (filter, true, true);
}
std::pair<DeepEdgePairs *, DeepEdgePairs *>
DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter, bool with_true, bool with_false) const
{ {
const db::DeepLayer &edge_pairs = deep_layer (); const db::DeepLayer &edge_pairs = deep_layer ();
db::Layout &layout = const_cast<db::Layout &> (edge_pairs.layout ()); db::Layout &layout = const_cast<db::Layout &> (edge_pairs.layout ());
@ -394,9 +412,10 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const
} }
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit; std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit_true, to_commit_false;
std::unique_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (edge_pairs.derived ())); std::unique_ptr<db::DeepEdgePairs> res_true (with_true ? new db::DeepEdgePairs (edge_pairs.derived ()) : 0);
std::unique_ptr<db::DeepEdgePairs> res_false (with_false ? new db::DeepEdgePairs (edge_pairs.derived ()) : 0);
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (edge_pairs.layer ()); const db::Shapes &s = c->shapes (edge_pairs.layer ());
@ -406,18 +425,34 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const
const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ()); const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ());
for (auto v = vv.begin (); v != vv.end (); ++v) { for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st; db::Shapes *st_true = 0, *st_false = 0;
if (vv.size () == 1) { if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ()); if (with_true) {
st_true = & c->shapes (res_true->deep_layer ().layer ());
}
if (with_false) {
st_false = & c->shapes (res_false->deep_layer ().layer ());
}
} else { } else {
st = & to_commit [c->cell_index ()] [*v]; if (with_true) {
st_true = & to_commit_true [c->cell_index ()] [*v];
}
if (with_false) {
st_false = & to_commit_false [c->cell_index ()] [*v];
}
} }
const db::ICplxTrans &tr = *v; const db::ICplxTrans &tr = *v;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) {
if (filter.selected (si->edge_pair ().transformed (tr))) { if (filter.selected (si->edge_pair ().transformed (tr), si->prop_id ())) {
st->insert (*si); if (st_true) {
st_true->insert (*si);
}
} else {
if (st_false) {
st_false->insert (*si);
}
} }
} }
@ -425,11 +460,18 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const
} else { } else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::Shapes *st_true = with_true ? &c->shapes (res_true->deep_layer ().layer ()) : 0;
db::Shapes *st_false = with_false ? &c->shapes (res_false->deep_layer ().layer ()) : 0;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) {
if (filter.selected (si->edge_pair ())) { if (filter.selected (si->edge_pair (), si->prop_id ())) {
st.insert (*si); if (with_true) {
st_true->insert (*si);
}
} else {
if (with_false) {
st_false->insert (*si);
}
} }
} }
@ -437,11 +479,16 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const
} }
if (! to_commit.empty () && vars.get ()) { if (! to_commit_true.empty () && vars.get ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit); tl_assert (res_true.get () != 0);
vars->commit_shapes (res_true->deep_layer ().layer (), to_commit_true);
}
if (! to_commit_false.empty () && vars.get ()) {
tl_assert (res_false.get () != 0);
vars->commit_shapes (res_false->deep_layer ().layer (), to_commit_false);
} }
return res.release (); return std::make_pair (res_true.release (), res_false.release ());
} }
EdgePairsDelegate *DeepEdgePairs::process_in_place (const EdgePairProcessorBase &filter) EdgePairsDelegate *DeepEdgePairs::process_in_place (const EdgePairProcessorBase &filter)

View File

@ -50,7 +50,7 @@ public:
EdgePairsDelegate *clone () const; EdgePairsDelegate *clone () const;
virtual void do_insert (const db::EdgePair &edge_pair); virtual void do_insert (const db::EdgePair &edge_pair, db::properties_id_type prop_id);
virtual void do_transform (const db::Trans &t); virtual void do_transform (const db::Trans &t);
virtual void do_transform (const db::ICplxTrans &t); virtual void do_transform (const db::ICplxTrans &t);
@ -70,12 +70,14 @@ public:
virtual Box bbox () const; virtual Box bbox () const;
virtual bool empty () const; virtual bool empty () const;
virtual const db::EdgePair *nth (size_t n) const; virtual const db::EdgePair *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edge_pairs () const; virtual bool has_valid_edge_pairs () const;
virtual const db::RecursiveShapeIterator *iter () const; virtual const db::RecursiveShapeIterator *iter () const;
virtual void apply_property_translator (const db::PropertiesTranslator &pt); virtual void apply_property_translator (const db::PropertiesTranslator &pt);
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter); virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter);
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const; virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const;
virtual std::pair<EdgePairsDelegate *, EdgePairsDelegate *> filtered_pair (const EdgePairFilterBase &filter) const;
virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &); virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &);
virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &) const; virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &) const;
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const; virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
@ -115,7 +117,7 @@ private:
void init (); void init ();
EdgesDelegate *generic_edges (bool first, bool second) const; EdgesDelegate *generic_edges (bool first, bool second) const;
DeepEdgePairs *apply_filter (const EdgePairFilterBase &filter) const; std::pair<DeepEdgePairs *, DeepEdgePairs *> apply_filter (const EdgePairFilterBase &filter, bool with_true, bool with_false) const;
}; };
} }

View File

@ -438,6 +438,12 @@ DeepEdges::nth (size_t /*n*/) const
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat edge collections"))); throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat edge collections")));
} }
db::properties_id_type
DeepEdges::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat collections")));
}
bool bool
DeepEdges::has_valid_edges () const DeepEdges::has_valid_edges () const
{ {
@ -799,18 +805,24 @@ EdgesDelegate *
DeepEdges::filter_in_place (const EdgeFilterBase &filter) DeepEdges::filter_in_place (const EdgeFilterBase &filter)
{ {
// TODO: implement to be really in-place // TODO: implement to be really in-place
*this = *apply_filter (filter); *this = *apply_filter (filter, true, false).first;
return this; return this;
} }
EdgesDelegate * EdgesDelegate *
DeepEdges::filtered (const EdgeFilterBase &filter) const DeepEdges::filtered (const EdgeFilterBase &filter) const
{ {
return apply_filter (filter); return apply_filter (filter, true, false).first;
} }
DeepEdges * std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::apply_filter (const EdgeFilterBase &filter) const DeepEdges::filtered_pair (const EdgeFilterBase &filter) const
{
return apply_filter (filter, true, true);
}
std::pair<DeepEdges *, DeepEdges *>
DeepEdges::apply_filter (const EdgeFilterBase &filter, bool with_true, bool with_false) const
{ {
const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer (); const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
db::Layout &layout = const_cast<db::Layout &> (edges.layout ()); db::Layout &layout = const_cast<db::Layout &> (edges.layout ());
@ -828,9 +840,10 @@ DeepEdges::apply_filter (const EdgeFilterBase &filter) const
} }
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit; std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit_true, to_commit_false;
std::unique_ptr<db::DeepEdges> res (new db::DeepEdges (edges.derived ())); std::unique_ptr<db::DeepEdges> res_true (with_true ? new db::DeepEdges (edges.derived ()) : 0);
std::unique_ptr<db::DeepEdges> res_false (with_false ? new db::DeepEdges (edges.derived ()) : 0);
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (edges.layer ()); const db::Shapes &s = c->shapes (edges.layer ());
@ -840,16 +853,34 @@ DeepEdges::apply_filter (const EdgeFilterBase &filter) const
const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ()); const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ());
for (auto v = vv.begin (); v != vv.end (); ++v) { for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st; db::Shapes *st_true = 0, *st_false = 0;
if (vv.size () == 1) { if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ()); if (with_true) {
st_true = & c->shapes (res_true->deep_layer ().layer ());
}
if (with_false) {
st_false = & c->shapes (res_false->deep_layer ().layer ());
}
} else { } else {
st = & to_commit [c->cell_index ()] [*v]; if (with_true) {
st_true = & to_commit_true [c->cell_index ()] [*v];
}
if (with_false) {
st_false = & to_commit_false [c->cell_index ()] [*v];
}
} }
const db::ICplxTrans &tr = *v;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
if (filter.selected (si->edge ().transformed (*v))) { if (filter.selected (si->edge ().transformed (tr), si->prop_id ())) {
st->insert (*si); if (st_true) {
st_true->insert (*si);
}
} else {
if (st_false) {
st_false->insert (*si);
}
} }
} }
@ -857,11 +888,18 @@ DeepEdges::apply_filter (const EdgeFilterBase &filter) const
} else { } else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::Shapes *st_true = with_true ? &c->shapes (res_true->deep_layer ().layer ()) : 0;
db::Shapes *st_false = with_false ? &c->shapes (res_false->deep_layer ().layer ()) : 0;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
if (filter.selected (si->edge ())) { if (filter.selected (si->edge (), si->prop_id ())) {
st.insert (*si); if (with_true) {
st_true->insert (*si);
}
} else {
if (with_false) {
st_false->insert (*si);
}
} }
} }
@ -869,14 +907,25 @@ DeepEdges::apply_filter (const EdgeFilterBase &filter) const
} }
if (! to_commit.empty () && vars.get ()) { if (! to_commit_true.empty () && vars.get ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit); tl_assert (res_true.get () != 0);
vars->commit_shapes (res_true->deep_layer ().layer (), to_commit_true);
}
if (! to_commit_false.empty () && vars.get ()) {
tl_assert (res_false.get () != 0);
vars->commit_shapes (res_false->deep_layer ().layer (), to_commit_false);
} }
if (! filter.requires_raw_input ()) { if (! filter.requires_raw_input ()) {
res->set_is_merged (true); if (res_true.get ()) {
res_true->set_is_merged (true);
}
if (res_false.get ()) {
res_false->set_is_merged (true);
}
} }
return res.release ();
return std::make_pair (res_true.release (), res_false.release ());
} }
EdgesDelegate *DeepEdges::merged_in_place () EdgesDelegate *DeepEdges::merged_in_place ()
@ -1236,7 +1285,11 @@ DeepEdges::add_in_place (const Edges &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ()); db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
for (db::Edges::const_iterator p = other.begin (); ! p.at_end (); ++p) { for (db::Edges::const_iterator p = other.begin (); ! p.at_end (); ++p) {
shapes.insert (*p); if (p.prop_id () == 0) {
shapes.insert (*p);
} else {
shapes.insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
} }
} }

View File

@ -76,6 +76,7 @@ public:
virtual bool is_merged () const; virtual bool is_merged () const;
virtual const db::Edge *nth (size_t n) const; virtual const db::Edge *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edges () const; virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const; virtual bool has_valid_merged_edges () const;
@ -125,6 +126,7 @@ public:
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter); virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter);
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const; virtual EdgesDelegate *filtered (const EdgeFilterBase &) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> filtered_pair (const EdgeFilterBase &filter) const;
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &); virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &);
virtual EdgesDelegate *processed (const EdgeProcessorBase &) const; virtual EdgesDelegate *processed (const EdgeProcessorBase &) const;
virtual EdgePairsDelegate *processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filter) const; virtual EdgePairsDelegate *processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filter) const;
@ -197,7 +199,7 @@ private:
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode, size_t min_count, size_t max_count) const; virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
EdgesDelegate *selected_interacting_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const; EdgesDelegate *selected_interacting_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, size_t min_count, size_t max_count) const; std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
DeepEdges *apply_filter (const EdgeFilterBase &filter) const; std::pair<DeepEdges *, DeepEdges *> apply_filter (const EdgeFilterBase &filter, bool with_true, bool with_false) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const; template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
}; };

View File

@ -231,6 +231,11 @@ void DeepRegion::min_coherence_changed ()
set_is_merged (false); set_is_merged (false);
} }
void DeepRegion::join_properties_on_merge_changed ()
{
set_is_merged (false);
}
void DeepRegion::do_insert (const db::Polygon &polygon, db::properties_id_type prop_id) void DeepRegion::do_insert (const db::Polygon &polygon, db::properties_id_type prop_id)
{ {
db::Layout &layout = deep_layer ().layout (); db::Layout &layout = deep_layer ().layout ();
@ -520,7 +525,7 @@ class ClusterMerger
{ {
public: public:
ClusterMerger (unsigned int layer, db::Layout &layout, const db::hier_clusters<db::PolygonRef> &hc, bool min_coherence, bool report_progress, const std::string &progress_desc) ClusterMerger (unsigned int layer, db::Layout &layout, const db::hier_clusters<db::PolygonRef> &hc, bool min_coherence, bool report_progress, const std::string &progress_desc)
: m_layer (layer), mp_layout (&layout), mp_hc (&hc), m_min_coherence (min_coherence), m_ep (report_progress, progress_desc) : m_layer (layer), mp_layout (&layout), mp_hc (&hc), m_min_coherence (min_coherence), m_text_name_id (0), m_ep (report_progress, progress_desc)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -530,6 +535,19 @@ public:
m_ep.set_base_verbosity (vb); m_ep.set_base_verbosity (vb);
} }
/**
* @brief Specifies the label property name ID for pseudo-label polygons
* If set to 0, the merge does not skip pseudo-labels.
*/
void set_text_name (const tl::Variant &n)
{
if (n.is_nil ()) {
m_text_name_id = 0;
} else {
m_text_name_id = db::property_names_id (n);
}
}
db::Shapes &merged (size_t cid, db::cell_index_type ci, unsigned int min_wc = 0) db::Shapes &merged (size_t cid, db::cell_index_type ci, unsigned int min_wc = 0)
{ {
return compute_merged (cid, ci, true, min_wc); return compute_merged (cid, ci, true, min_wc);
@ -548,8 +566,19 @@ private:
db::Layout *mp_layout; db::Layout *mp_layout;
const db::hier_clusters<db::PolygonRef> *mp_hc; const db::hier_clusters<db::PolygonRef> *mp_hc;
bool m_min_coherence; bool m_min_coherence;
db::property_names_id_type m_text_name_id;
db::EdgeProcessor m_ep; db::EdgeProcessor m_ep;
bool skip_pseudo_label (db::properties_id_type prop_id)
{
if (prop_id == 0 || m_text_name_id == 0) {
return false;
} else {
const db::PropertiesSet &ps = db::properties (prop_id);
return (ps.size () == 1 && ps.begin ()->first == m_text_name_id);
}
}
db::properties_id_type property_id (size_t cid, db::cell_index_type ci, bool initial) db::properties_id_type property_id (size_t cid, db::cell_index_type ci, bool initial)
{ {
std::map<std::pair<size_t, db::cell_index_type>, db::properties_id_type>::iterator s = m_property_id_per_cluster.find (std::make_pair (cid, ci)); std::map<std::pair<size_t, db::cell_index_type>, db::properties_id_type>::iterator s = m_property_id_per_cluster.find (std::make_pair (cid, ci));
@ -563,21 +592,40 @@ private:
return s->second; return s->second;
} }
s = m_property_id_per_cluster.insert (std::make_pair (std::make_pair (cid, ci), db::properties_id_type (0))).first;
const db::connected_clusters<db::PolygonRef> &cc = mp_hc->clusters_per_cell (ci); const db::connected_clusters<db::PolygonRef> &cc = mp_hc->clusters_per_cell (ci);
const db::local_cluster<db::PolygonRef> &c = cc.cluster_by_id (cid); const db::local_cluster<db::PolygonRef> &c = cc.cluster_by_id (cid);
if (c.begin_attr () != c.end_attr ()) { // collect attributes (aka properties) of the root and the child clusters and join them
s->second = *c.begin_attr (); s = m_property_id_per_cluster.insert (std::make_pair (std::make_pair (cid, ci), db::properties_id_type (0))).first;
} else { std::set<db::properties_id_type> attrs (c.begin_attr (), c.end_attr ());
const db::connected_clusters<db::PolygonRef>::connections_type &conn = cc.connections_for_cluster (cid); const db::connected_clusters<db::PolygonRef>::connections_type &conn = cc.connections_for_cluster (cid);
for (db::connected_clusters<db::PolygonRef>::connections_type::const_iterator i = conn.begin (); i != conn.end () && s->second == db::properties_id_type (0); ++i) { for (db::connected_clusters<db::PolygonRef>::connections_type::const_iterator i = conn.begin (); i != conn.end (); ++i) {
s->second = property_id (i->id (), i->inst_cell_index (), false); auto prop_id = property_id (i->id (), i->inst_cell_index (), false);
if (prop_id != 0) {
attrs.insert (prop_id);
} }
}
if (attrs.size () > 1) {
// join the properties
db::PropertiesSet ps;
for (auto a = attrs.begin (); a != attrs.end (); ++a) {
if (! skip_pseudo_label (*a)) {
// merge in "larger one wins" mode - the advantage of this mode is that
// it is independent on the order of the attribute sets (which in fact are pointers)
ps.join_max (db::properties (*a));
}
}
s->second = db::properties_id (ps);
} else if (! attrs.empty () && ! skip_pseudo_label (*attrs.begin ())) {
s->second = *attrs.begin ();
} }
@ -702,7 +750,7 @@ DeepRegion::ensure_merged_polygons_valid () const
db::Connectivity conn; db::Connectivity conn;
conn.connect (deep_layer ()); conn.connect (deep_layer ());
hc.set_base_verbosity (base_verbosity () + 10); hc.set_base_verbosity (base_verbosity () + 10);
hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells (), true /*separate_attributes*/); hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells (), ! join_properties_on_merge ());
// collect the clusters and merge them into big polygons // collect the clusters and merge them into big polygons
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
@ -711,6 +759,14 @@ DeepRegion::ensure_merged_polygons_valid () const
ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence (), report_progress (), progress_desc ()); ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence (), report_progress (), progress_desc ());
cm.set_base_verbosity (base_verbosity () + 10); cm.set_base_verbosity (base_verbosity () + 10);
// Specify the property name ID for the pseudo-labels, so we can filter out those properties
// (for backward compatibility only if join_properties_on_merge is true - if we don't with
// join_properties_on_merge, the pseudo-label properties may get attached to other shapes which
// will be taken as texts then)
if (join_properties_on_merge ()) {
cm.set_text_name (deep_layer ().store ()->text_property_name ());
}
// TODO: iterate only over the called cells? // TODO: iterate only over the called cells?
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::connected_clusters<db::PolygonRef> &cc = hc.clusters_per_cell (c->cell_index ()); const db::connected_clusters<db::PolygonRef> &cc = hc.clusters_per_cell (c->cell_index ());
@ -757,13 +813,13 @@ DeepRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Var
DeepLayer result = deep_layer ().derived (); DeepLayer result = deep_layer ().derived ();
std::unique_ptr<db::Region> region_for_layer (l2n->layer_by_original (this)); tl::optional<unsigned int> li = l2n->layer_by_original (this);
if (! region_for_layer) { if (! li.has_value ()) {
throw tl::Exception (tl::to_string (tr ("The given layer is not an original layer used in netlist extraction"))); throw tl::Exception (tl::to_string (tr ("The given layer is not an original layer used in netlist extraction")));
} }
std::map<unsigned int, const db::Region *> lmap; std::map<unsigned int, unsigned int> lmap;
lmap.insert (std::make_pair (result.layer (), region_for_layer.get ())); lmap.insert (std::make_pair (result.layer (), li.value ()));
net_builder.build_nets (nets, lmap, prop_mode, net_prop_name); net_builder.build_nets (nets, lmap, prop_mode, net_prop_name);
@ -1054,12 +1110,7 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
{ {
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ()); const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
if (empty ()) { if (other.empty ()) {
// Nothing to do
return other.delegate ()->clone ();
} else if (other.empty ()) {
// Nothing to do // Nothing to do
return clone (); return clone ();
@ -1068,6 +1119,18 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
return AsIfFlatRegion::xor_with (other, property_constraint); return AsIfFlatRegion::xor_with (other, property_constraint);
} else if (empty ()) {
// Nothing to do, but to maintain the normal behavior, we have to map the other
// input to our layout if neccessary
if (&other_deep->deep_layer ().layout () == &deep_layer ().layout ()) {
return other.delegate ()->clone ();
} else {
std::unique_ptr<DeepRegion> other_deep_mapped (dynamic_cast<DeepRegion *> (clone ()));
other_deep_mapped->deep_layer ().add_from (other_deep->deep_layer ());
return other_deep_mapped.release ();
}
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) { } else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
return new DeepRegion (deep_layer ().derived ()); return new DeepRegion (deep_layer ().derived ());
@ -1125,6 +1188,7 @@ DeepRegion::add_in_place (const Region &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ()); db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
db::PolygonRefToShapesGenerator pr (const_cast<db::Layout *> (& deep_layer ().layout ()), &shapes); db::PolygonRefToShapesGenerator pr (const_cast<db::Layout *> (& deep_layer ().layout ()), &shapes);
for (db::Region::const_iterator p = other.begin (); ! p.at_end (); ++p) { for (db::Region::const_iterator p = other.begin (); ! p.at_end (); ++p) {
pr.set_prop_id (p.prop_id ());
pr.put (*p); pr.put (*p);
} }
@ -1497,12 +1561,13 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas
const db::Shapes &s = c->shapes (polygons.layer ()); const db::Shapes &s = c->shapes (polygons.layer ());
db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::Shapes &st = c->shapes (res->deep_layer ().layer ());
std::vector<db::Edge> heap; std::vector<db::EdgeWithProperties> heap;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly; db::PolygonWithProperties poly;
si->polygon (poly); si->polygon (poly);
poly.properties_id (si->prop_id ());
if (proc) { if (proc) {
@ -1510,16 +1575,16 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas
proc->process (poly, heap); proc->process (poly, heap);
for (auto e = heap.begin (); e != heap.end (); ++e) { for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) { if (! filter || filter->selected ((*e).transformed (tr), e->properties_id ())) {
st.insert (db::EdgeWithProperties (*e, si->prop_id ())); st.insert (*e);
} }
} }
} else { } else {
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) { if (! filter || filter->selected ((*e).transformed (tr), poly.properties_id ())) {
st.insert (db::EdgeWithProperties (*e, si->prop_id ())); st.insert (db::EdgeWithProperties (*e, poly.properties_id ()));
} }
} }
@ -1585,7 +1650,7 @@ DeepRegion::filter_in_place (const PolygonFilterBase &filter)
} }
// TODO: implement to be really in-place // TODO: implement to be really in-place
*this = *apply_filter (filter); *this = *apply_filter (filter, true, false).first;
return this; return this;
} }
@ -1596,11 +1661,17 @@ DeepRegion::filtered (const PolygonFilterBase &filter) const
return clone (); return clone ();
} }
return apply_filter (filter); return apply_filter (filter, true, false).first;
} }
DeepRegion * std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::apply_filter (const PolygonFilterBase &filter) const DeepRegion::filtered_pair (const PolygonFilterBase &filter) const
{
return apply_filter (filter, true, true);
}
std::pair<DeepRegion *, DeepRegion *>
DeepRegion::apply_filter (const PolygonFilterBase &filter, bool with_true, bool with_false) const
{ {
const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer (); const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
db::Layout &layout = const_cast<db::Layout &> (polygons.layout ()); db::Layout &layout = const_cast<db::Layout &> (polygons.layout ());
@ -1618,9 +1689,10 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const
} }
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit; std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit_true, to_commit_false;
std::unique_ptr<db::DeepRegion> res (new db::DeepRegion (polygons.derived ())); std::unique_ptr<db::DeepRegion> res_true (with_true ? new db::DeepRegion (polygons.derived ()) : 0);
std::unique_ptr<db::DeepRegion> res_false (with_false ? new db::DeepRegion (polygons.derived ()) : 0);
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (polygons.layer ()); const db::Shapes &s = c->shapes (polygons.layer ());
@ -1630,18 +1702,36 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const
const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ()); const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ());
for (auto v = vv.begin (); v != vv.end (); ++v) { for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st; db::Shapes *st_true = 0, *st_false = 0;
if (vv.size () == 1) { if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ()); if (with_true) {
st_true = & c->shapes (res_true->deep_layer ().layer ());
}
if (with_false) {
st_false = & c->shapes (res_false->deep_layer ().layer ());
}
} else { } else {
st = & to_commit [c->cell_index ()] [*v]; if (with_true) {
st_true = & to_commit_true [c->cell_index ()] [*v];
}
if (with_false) {
st_false = & to_commit_false [c->cell_index ()] [*v];
}
} }
const db::ICplxTrans &tr = *v;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly; db::Polygon poly;
si->polygon (poly); si->polygon (poly);
if (filter.selected (poly.transformed (*v))) { if (filter.selected (poly.transformed (tr), si->prop_id ())) {
st->insert (*si); if (st_true) {
st_true->insert (*si);
}
} else {
if (st_false) {
st_false->insert (*si);
}
} }
} }
@ -1649,13 +1739,20 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const
} else { } else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::Shapes *st_true = with_true ? &c->shapes (res_true->deep_layer ().layer ()) : 0;
db::Shapes *st_false = with_false ? &c->shapes (res_false->deep_layer ().layer ()) : 0;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly; db::Polygon poly;
si->polygon (poly); si->polygon (poly);
if (filter.selected (poly)) { if (filter.selected (poly, si->prop_id ())) {
st.insert (*si); if (with_true) {
st_true->insert (*si);
}
} else {
if (with_false) {
st_false->insert (*si);
}
} }
} }
@ -1663,14 +1760,25 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const
} }
if (! to_commit.empty () && vars.get ()) { if (! to_commit_true.empty () && vars.get ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit); tl_assert (res_true.get () != 0);
vars->commit_shapes (res_true->deep_layer ().layer (), to_commit_true);
}
if (! to_commit_false.empty () && vars.get ()) {
tl_assert (res_false.get () != 0);
vars->commit_shapes (res_false->deep_layer ().layer (), to_commit_false);
} }
if (! filter.requires_raw_input ()) { if (! filter.requires_raw_input ()) {
res->set_is_merged (true); if (res_true.get ()) {
res_true->set_is_merged (true);
}
if (res_false.get ()) {
res_false->set_is_merged (true);
}
} }
return res.release ();
return std::make_pair (res_true.release (), res_false.release ());
} }
RegionDelegate * RegionDelegate *
@ -1690,10 +1798,10 @@ DeepRegion::merged_in_place ()
} }
RegionDelegate * RegionDelegate *
DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc) DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge)
{ {
// TODO: implement to be really in-place // TODO: implement to be really in-place
return merged (min_coherence, min_wc); return merged (min_coherence, min_wc, join_properties_on_merge);
} }
RegionDelegate * RegionDelegate *
@ -1719,7 +1827,7 @@ DeepRegion::merged () const
} }
RegionDelegate * RegionDelegate *
DeepRegion::merged (bool min_coherence, unsigned int min_wc) const DeepRegion::merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const
{ {
if (empty ()) { if (empty ()) {
return clone (); return clone ();
@ -1733,7 +1841,7 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
db::Connectivity conn; db::Connectivity conn;
conn.connect (deep_layer ()); conn.connect (deep_layer ());
hc.set_base_verbosity (base_verbosity () + 10); hc.set_base_verbosity (base_verbosity () + 10);
hc.build (layout, deep_layer ().initial_cell (), conn); hc.build (layout, deep_layer ().initial_cell (), conn, 0, 0, ! join_properties_on_merge);
// collect the clusters and merge them into big polygons // collect the clusters and merge them into big polygons
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
@ -1744,6 +1852,14 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence, report_progress (), progress_desc ()); ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence, report_progress (), progress_desc ());
cm.set_base_verbosity (base_verbosity () + 10); cm.set_base_verbosity (base_verbosity () + 10);
// Specify the property name ID for the pseudo-labels, so we can filter out those properties
// (for backward compatibility only if join_properties_on_merge is true - if we don't with
// join_properties_on_merge, the pseudo-label properties may get attached to other shapes which
// will be taken as texts then)
if (join_properties_on_merge) {
cm.set_text_name (deep_layer ().store ()->text_property_name ());
}
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::connected_clusters<db::PolygonRef> &cc = hc.clusters_per_cell (c->cell_index ()); const db::connected_clusters<db::PolygonRef> &cc = hc.clusters_per_cell (c->cell_index ());
for (db::connected_clusters<db::PolygonRef>::all_iterator cl = cc.begin_all (); ! cl.at_end (); ++cl) { for (db::connected_clusters<db::PolygonRef>::all_iterator cl = cc.begin_all (); ! cl.at_end (); ++cl) {

View File

@ -125,12 +125,13 @@ public:
virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &filter) const; virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &filter) const;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter); virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter);
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const; virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> filtered_pair (const PolygonFilterBase &filter) const;
virtual RegionDelegate *merged_in_place (); virtual RegionDelegate *merged_in_place ();
virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge);
virtual RegionDelegate *merged () const; virtual RegionDelegate *merged () const;
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const; virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const;
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
@ -154,6 +155,7 @@ public:
protected: protected:
virtual void merged_semantics_changed (); virtual void merged_semantics_changed ();
virtual void min_coherence_changed (); virtual void min_coherence_changed ();
virtual void join_properties_on_merge_changed ();
virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const; virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const;
virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const; virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const;
@ -181,8 +183,7 @@ private:
DeepLayer not_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const; DeepLayer not_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const;
DeepLayer and_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const; DeepLayer and_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const;
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const; std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const;
DeepRegion *apply_filter (const PolygonFilterBase &filter) const; std::pair<DeepRegion *, DeepRegion *> apply_filter (const PolygonFilterBase &filter, bool with_true, bool with_false) const;
template <class Proc> template <class Proc>
void configure_proc (Proc &proc) const void configure_proc (Proc &proc) const
{ {

View File

@ -1166,62 +1166,67 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
DeliveryMappingCacheKey key (layout_index, tl::id_of (into_layout), into_cell); DeliveryMappingCacheKey key (layout_index, tl::id_of (into_layout), into_cell);
std::map<DeliveryMappingCacheKey, CellMappingWithGenerationIds>::iterator cm = m_delivery_mapping_cache.find (key); std::map<DeliveryMappingCacheKey, CellMappingWithGenerationIds>::iterator cm = m_delivery_mapping_cache.find (key);
if (cm == m_delivery_mapping_cache.end () || ! cm->second.is_valid (*into_layout, *source_layout)) { if (cm != m_delivery_mapping_cache.end () && cm->second.is_valid (*into_layout, *source_layout)) {
return cm->second;
}
cm = m_delivery_mapping_cache.insert (std::make_pair (key, CellMappingWithGenerationIds ())).first; cm = m_delivery_mapping_cache.insert (std::make_pair (key, CellMappingWithGenerationIds ())).first;
cm->second.clear (); cm->second.clear ();
// collects the cell mappings we skip because they are variants (variant building or box variants) // Not found in cache - compute a fresh mapping
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) { // collects the cell mappings we skip because they are variants (variant building or box variants)
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
// This is the case of mapping back to the original. In this case we can use the information if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) {
// provided inside the original hierarchy builders. They list the source cells and the target cells
// create from them. We need to consider however, that the hierarchy builder is allowed to create
// variants which we cannot map.
for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ) { // This is the case of mapping back to the original. In this case we can use the information
// provided inside the original hierarchy builders. They list the source cells and the target cells
// create from them. We need to consider however, that the hierarchy builder is allowed to create
// variants which we cannot map.
HierarchyBuilder::cell_map_type::const_iterator mm = m; for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ) {
HierarchyBuilder::cell_map_type::const_iterator mm = m;
++mm;
bool skip = original_builder.is_variant (m->second); // skip variant cells
while (mm != original_builder.end_cell_map () && mm->first.original_cell == m->first.original_cell) {
// we have cell (box) variants and cannot simply map
++mm; ++mm;
bool skip = original_builder.is_variant (m->second); // skip variant cells skip = true;
while (mm != original_builder.end_cell_map () && mm->first.original_cell == m->first.original_cell) {
// we have cell (box) variants and cannot simply map
++mm;
skip = true;
}
if (! skip) {
cm->second.map (m->second, m->first.original_cell);
} else {
for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) {
tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ());
cm_skipped_variants [n->second] = n->first;
}
}
m = mm;
} }
} else if (into_layout->cells () == 1) { if (! skip) {
cm->second.map (m->second, m->first.original_cell);
} else {
for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) {
tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ());
cm_skipped_variants [n->second] = n->first;
}
}
// Another simple case is mapping into an empty (or single-top-cell-only) layout, where we can use "create_from_single_full". m = mm;
cm->second.create_single_mapping (*into_layout, into_cell, *source_layout, source_top);
} else {
cm->second.create_from_geometry (*into_layout, into_cell, *source_layout, source_top);
} }
// Add new cells for the variants and (possible) devices which are cells added during the device } else if (into_layout->cells () == 1) {
// extraction process
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > new_pairs = cm->second.create_missing_mapping2 (*into_layout, *source_layout, source_top, excluded_cells, included_cells);
// the variant's originals we are going to delete // Another simple case is mapping into an empty (or single-top-cell-only) layout, where we can use "create_from_single_full".
std::set<db::cell_index_type> cells_to_delete; cm->second.create_single_mapping (*into_layout, into_cell, *source_layout, source_top);
} else {
cm->second.create_from_geometry (*into_layout, into_cell, *source_layout, source_top);
}
// Add new cells for the variants and (possible) devices which are cells added during the device
// extraction process
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > new_pairs = cm->second.create_missing_mapping2 (*into_layout, *source_layout, source_top, excluded_cells, included_cells);
if (! new_pairs.empty ()) {
std::vector<std::pair <db::cell_index_type, db::cell_index_type> > new_variants;
// We now need to fix the cell map from the hierarchy builder, so we can import back from the modified layout. // We now need to fix the cell map from the hierarchy builder, so we can import back from the modified layout.
// This is in particular important if we created new cells for known variants. // This is in particular important if we created new cells for known variants.
@ -1232,9 +1237,9 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey>::const_iterator icm = cm_skipped_variants.find (var_org); std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey>::const_iterator icm = cm_skipped_variants.find (var_org);
if (icm != cm_skipped_variants.end ()) { if (icm != cm_skipped_variants.end ()) {
// create the variant clone in the original layout too and delete this cell // create the variant clone in the original layout too
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.original_cell); VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.original_cell);
cells_to_delete.insert (icm->second.original_cell); new_variants.push_back (std::make_pair (np->second, icm->second.original_cell));
// forget the original cell (now separated into variants) and map the variants back into the // forget the original cell (now separated into variants) and map the variants back into the
// DSS layout // DSS layout
@ -1253,15 +1258,105 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
} }
// delete the variant's original cell if (! new_variants.empty ()) {
if (! cells_to_delete.empty ()) {
into_layout->delete_cells (cells_to_delete);
}
cm->second.set_generation_ids (*into_layout, *source_layout); // copy cell instances for the new variants
std::map<db::cell_index_type, db::cell_index_type> variant_to_org;
for (auto vv = new_variants.begin (); vv != new_variants.end (); ++vv) {
variant_to_org.insert (std::make_pair (vv->first, vv->second));
}
// Copy the variant instances - but only those for cells which are not handled by the cell mapping object.
for (auto vv = new_variants.begin (); vv != new_variants.end (); ++vv) {
const db::Cell &from = into_layout->cell (vv->second); // original
db::Cell &to = into_layout->cell (vv->first); // variant
// Collect and copy the cells which are not mapped already.
// Skip variant original cells if their variants are included.
std::set<db::cell_index_type> dont_copy;
for (auto c = to.begin_child_cells (); ! c.at_end (); ++c) {
auto v2o = variant_to_org.find (*c);
if (v2o != variant_to_org.end ()) {
dont_copy.insert (v2o->second);
} else {
dont_copy.insert (*c);
}
}
for (db::Cell::const_iterator i = from.begin (); ! i.at_end (); ++i) {
if (dont_copy.find (i->cell_index ()) == dont_copy.end ()) {
to.insert (*i);
}
}
}
// clean up instances of variant original cells
std::map<db::cell_index_type, std::set<db::cell_index_type> > delete_instances_of;
into_layout->force_update ();
for (auto vv = new_variants.begin (); vv != new_variants.end (); ++vv) {
const db::Cell &to = into_layout->cell (vv->first);
for (auto p = to.begin_parent_cells (); p != to.end_parent_cells (); ++p) {
delete_instances_of [*p].insert (vv->second);
}
}
std::vector<db::Instance> insts_to_delete;
for (auto di = delete_instances_of.begin (); di != delete_instances_of.end (); ++di) {
db::Cell &in = into_layout->cell (di->first);
insts_to_delete.clear ();
for (auto i = in.begin (); ! i.at_end (); ++i) {
if (di->second.find (i->cell_index ()) != di->second.end ()) {
insts_to_delete.push_back (*i);
}
}
in.erase_insts (insts_to_delete);
}
// remove variant original cells unless they are still used
into_layout->force_update ();
std::set<db::cell_index_type> vars;
for (auto vv = new_variants.begin (); vv != new_variants.end (); ++vv) {
vars.insert (vv->second);
}
std::set<db::cell_index_type> cells_to_delete;
bool more = true;
while (more) {
more = false;
for (auto v = vars.begin (); v != vars.end (); ++v) {
if (cells_to_delete.find (*v) == cells_to_delete.end ()) {
const db::Cell &vc = into_layout->cell (*v);
bool used = false;
for (auto p = vc.begin_parent_cells (); p != vc.end_parent_cells () && ! used; ++p) {
used = (cells_to_delete.find (*p) == cells_to_delete.end ());
}
if (! used) {
cells_to_delete.insert (*v);
more = true;
}
}
}
}
if (! cells_to_delete.empty ()) {
into_layout->delete_cells (cells_to_delete);
}
}
} }
cm->second.set_generation_ids (*into_layout, *source_layout);
return cm->second; return cm->second;
} }

View File

@ -178,12 +178,16 @@ TextsDelegate *DeepTexts::clone () const
return new DeepTexts (*this); return new DeepTexts (*this);
} }
void DeepTexts::do_insert (const db::Text &text) void DeepTexts::do_insert (const db::Text &text, db::properties_id_type prop_id)
{ {
db::Layout &layout = deep_layer ().layout (); db::Layout &layout = deep_layer ().layout ();
if (layout.begin_top_down () != layout.end_top_down ()) { if (layout.begin_top_down () != layout.end_top_down ()) {
db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
top_cell.shapes (deep_layer ().layer ()).insert (db::TextRef (text, layout.shape_repository ())); if (prop_id == 0) {
top_cell.shapes (deep_layer ().layer ()).insert (db::TextRef (text, layout.shape_repository ()));
} else {
top_cell.shapes (deep_layer ().layer ()).insert (db::TextRefWithProperties (db::TextRef (text, layout.shape_repository ()), prop_id));
}
} }
invalidate_bbox (); invalidate_bbox ();
@ -328,6 +332,12 @@ const db::Text *DeepTexts::nth (size_t) const
throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat text collections"))); throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat text collections")));
} }
db::properties_id_type
DeepTexts::nth_prop_id (size_t) const
{
throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat collections")));
}
bool DeepTexts::has_valid_texts () const bool DeepTexts::has_valid_texts () const
{ {
return false; return false;
@ -361,7 +371,11 @@ DeepTexts::add_in_place (const Texts &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ()); db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
for (db::Texts::const_iterator p = other.begin (); ! p.at_end (); ++p) { for (db::Texts::const_iterator p = other.begin (); ! p.at_end (); ++p) {
shapes.insert (*p); if (p.prop_id () == 0) {
shapes.insert (*p);
} else {
shapes.insert (db::TextWithProperties (*p, p.prop_id ()));
}
} }
} }
@ -385,16 +399,23 @@ TextsDelegate *DeepTexts::add (const Texts &other) const
TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter) TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter)
{ {
// TODO: implement as really in place // TODO: implement as really in place
*this = *apply_filter (filter); *this = *apply_filter (filter, true, false).first;
return this; return this;
} }
TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const
{ {
return apply_filter (filter); return apply_filter (filter, true, false).first;
} }
DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const std::pair<TextsDelegate *, TextsDelegate *>
DeepTexts::filtered_pair (const TextFilterBase &filter) const
{
return apply_filter (filter, true, true);
}
std::pair<DeepTexts *, DeepTexts *>
DeepTexts::apply_filter (const TextFilterBase &filter, bool with_true, bool with_false) const
{ {
const db::DeepLayer &texts = deep_layer (); const db::DeepLayer &texts = deep_layer ();
db::Layout &layout = const_cast<db::Layout &> (texts.layout ()); db::Layout &layout = const_cast<db::Layout &> (texts.layout ());
@ -412,9 +433,10 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
} }
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit; std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit_true, to_commit_false;
std::unique_ptr<db::DeepTexts> res (new db::DeepTexts (texts.derived ())); std::unique_ptr<db::DeepTexts> res_true (with_true ? new db::DeepTexts (texts.derived ()) : 0);
std::unique_ptr<db::DeepTexts> res_false (with_false ? new db::DeepTexts (texts.derived ()) : 0);
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (texts.layer ()); const db::Shapes &s = c->shapes (texts.layer ());
@ -424,18 +446,36 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ()); const std::set<db::ICplxTrans> &vv = vars->variants (c->cell_index ());
for (auto v = vv.begin (); v != vv.end (); ++v) { for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st; db::Shapes *st_true = 0, *st_false = 0;
if (vv.size () == 1) { if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ()); if (with_true) {
st_true = & c->shapes (res_true->deep_layer ().layer ());
}
if (with_false) {
st_false = & c->shapes (res_false->deep_layer ().layer ());
}
} else { } else {
st = & to_commit [c->cell_index ()] [*v]; if (with_true) {
st_true = & to_commit_true [c->cell_index ()] [*v];
}
if (with_false) {
st_false = & to_commit_false [c->cell_index ()] [*v];
}
} }
const db::ICplxTrans &tr = *v;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
db::Text text; db::Text text;
si->text (text); si->text (text);
if (filter.selected (text.transformed (*v))) { if (filter.selected (text.transformed (tr), si->prop_id ())) {
st->insert (*si); if (st_true) {
st_true->insert (*si);
}
} else {
if (st_false) {
st_false->insert (*si);
}
} }
} }
@ -443,13 +483,20 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
} else { } else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ()); db::Shapes *st_true = with_true ? &c->shapes (res_true->deep_layer ().layer ()) : 0;
db::Shapes *st_false = with_false ? &c->shapes (res_false->deep_layer ().layer ()) : 0;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
db::Text text; db::Text text;
si->text (text); si->text (text);
if (filter.selected (text)) { if (filter.selected (text, si->prop_id ())) {
st.insert (*si); if (with_true) {
st_true->insert (*si);
}
} else {
if (with_false) {
st_false->insert (*si);
}
} }
} }
@ -457,11 +504,16 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
} }
if (! to_commit.empty () && vars.get ()) { if (! to_commit_true.empty () && vars.get ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit); tl_assert (res_true.get () != 0);
vars->commit_shapes (res_true->deep_layer ().layer (), to_commit_true);
}
if (! to_commit_false.empty () && vars.get ()) {
tl_assert (res_false.get () != 0);
vars->commit_shapes (res_false->deep_layer ().layer (), to_commit_false);
} }
return res.release (); return std::make_pair (res_true.release (), res_false.release ());
} }
TextsDelegate *DeepTexts::process_in_place (const TextProcessorBase &filter) TextsDelegate *DeepTexts::process_in_place (const TextProcessorBase &filter)
@ -482,8 +534,15 @@ DeepTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter) cons
return shape_collection_processed_impl<db::Text, db::Polygon, db::DeepRegion> (deep_layer (), filter); return shape_collection_processed_impl<db::Text, db::Polygon, db::DeepRegion> (deep_layer (), filter);
} }
RegionDelegate *DeepTexts::polygons (db::Coord e) const RegionDelegate *DeepTexts::polygons (db::Coord e, const tl::Variant &text_prop) const
{ {
db::property_names_id_type key_id = 0;
if (! text_prop.is_nil ()) {
key_id = db::property_names_id (text_prop);
}
std::map<std::string, db::properties_id_type> value_ids;
db::DeepLayer new_layer = deep_layer ().derived (); db::DeepLayer new_layer = deep_layer ().derived ();
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ()); db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
@ -493,7 +552,18 @@ RegionDelegate *DeepTexts::polygons (db::Coord e) const
db::Box box = s->bbox (); db::Box box = s->bbox ();
box.enlarge (db::Vector (e, e)); box.enlarge (db::Vector (e, e));
db::Polygon poly (box); db::Polygon poly (box);
output.insert (db::PolygonRef (poly, layout.shape_repository ())); if (key_id == 0) {
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
} else {
std::string value (s->text_string ());
auto v = value_ids.find (value);
if (v == value_ids.end ()) {
db::PropertiesSet ps;
ps.insert_by_id (key_id, db::property_values_id (value));
v = value_ids.insert (std::make_pair (value, db::properties_id (ps))).first;
}
output.insert (db::PolygonRefWithProperties (db::PolygonRef (poly, layout.shape_repository ()), v->second));
}
} }
} }

View File

@ -51,7 +51,7 @@ public:
TextsDelegate *clone () const; TextsDelegate *clone () const;
virtual void do_insert (const db::Text &text); virtual void do_insert (const db::Text &text, properties_id_type prop_id);
virtual void do_transform (const db::Trans &t); virtual void do_transform (const db::Trans &t);
virtual void do_transform (const db::ICplxTrans &t); virtual void do_transform (const db::ICplxTrans &t);
@ -71,12 +71,14 @@ public:
virtual Box bbox () const; virtual Box bbox () const;
virtual bool empty () const; virtual bool empty () const;
virtual const db::Text *nth (size_t n) const; virtual const db::Text *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_texts () const; virtual bool has_valid_texts () const;
virtual const db::RecursiveShapeIterator *iter () const; virtual const db::RecursiveShapeIterator *iter () const;
virtual void apply_property_translator (const db::PropertiesTranslator &pt); virtual void apply_property_translator (const db::PropertiesTranslator &pt);
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter); virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
virtual TextsDelegate *filtered (const TextFilterBase &) const; virtual TextsDelegate *filtered (const TextFilterBase &) const;
virtual std::pair<TextsDelegate *, TextsDelegate *> filtered_pair (const TextFilterBase &filter) const;
virtual TextsDelegate *process_in_place (const TextProcessorBase &); virtual TextsDelegate *process_in_place (const TextProcessorBase &);
virtual TextsDelegate *processed (const TextProcessorBase &) const; virtual TextsDelegate *processed (const TextProcessorBase &) const;
@ -85,7 +87,7 @@ public:
virtual TextsDelegate *add_in_place (const Texts &other); virtual TextsDelegate *add_in_place (const Texts &other);
virtual TextsDelegate *add (const Texts &other) const; virtual TextsDelegate *add (const Texts &other) const;
virtual RegionDelegate *polygons (db::Coord e) const; virtual RegionDelegate *polygons (db::Coord e, const tl::Variant &text_prop) const;
virtual EdgesDelegate *edges () const; virtual EdgesDelegate *edges () const;
virtual TextsDelegate *in (const Texts &, bool) const; virtual TextsDelegate *in (const Texts &, bool) const;
@ -105,7 +107,7 @@ private:
DeepTexts &operator= (const DeepTexts &other); DeepTexts &operator= (const DeepTexts &other);
void init (); void init ();
DeepTexts *apply_filter (const TextFilterBase &filter) const; std::pair<DeepTexts *, DeepTexts *> apply_filter (const TextFilterBase &filter, bool with_true, bool with_false) const;
virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const; virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const;
virtual RegionDelegate *pull_generic (const Region &other) const; virtual RegionDelegate *pull_generic (const Region &other) const;

View File

@ -133,6 +133,17 @@ const Net *Device::net_for_terminal (size_t terminal_id) const
return 0; return 0;
} }
const NetTerminalRef *Device::terminal_ref_for_terminal (size_t terminal_id) const
{
if (terminal_id < m_terminal_refs.size ()) {
Net::terminal_iterator p = m_terminal_refs [terminal_id];
if (! tl::is_null_iterator (p)) {
return p.operator-> ();
}
}
return 0;
}
void Device::connect_terminal (size_t terminal_id, Net *net) void Device::connect_terminal (size_t terminal_id, Net *net)
{ {
if (net_for_terminal (terminal_id) == net) { if (net_for_terminal (terminal_id) == net) {

View File

@ -254,6 +254,22 @@ public:
return const_cast<Net *> (((const Device *) this)->net_for_terminal (terminal_id)); return const_cast<Net *> (((const Device *) this)->net_for_terminal (terminal_id));
} }
/**
* @brief Gets the terminal reference for the given terminal on a device
* Returns 0 if no net is attached or the device is not embedded into a netlist.
* A terminal ref is the connector between a net and a device. It is useful for example
* to get the shapes of a terminal.
*/
const NetTerminalRef *terminal_ref_for_terminal (size_t terminal_id) const;
/**
* @brief Gets the terminal reference for the given terminal on a device (non-const version)
*/
NetTerminalRef *terminal_ref_for_terminal (size_t terminal_id)
{
return const_cast<NetTerminalRef *> (((const Device *) this)->terminal_ref_for_terminal (terminal_id));
}
/** /**
* @brief Connects the given terminal to the given net * @brief Connects the given terminal to the given net
* If the net is 0 the terminal is disconnected. * If the net is 0 the terminal is disconnected.

View File

@ -158,7 +158,7 @@ class DB_PUBLIC EdgeNeighborhoodCompoundOperationNode
: public CompoundRegionMultiInputOperationNode : public CompoundRegionMultiInputOperationNode
{ {
public: public:
EdgeNeighborhoodCompoundOperationNode (const std::vector<CompoundRegionOperationNode *> &children, EdgeNeighborhoodVisitor *visitor, const db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout); EdgeNeighborhoodCompoundOperationNode (const std::vector<CompoundRegionOperationNode *> &children, EdgeNeighborhoodVisitor *visitor, db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout);
virtual ResultType result_type () const virtual ResultType result_type () const
{ {

View File

@ -43,12 +43,12 @@ EdgeFilterBasedEdgePairFilter::~EdgeFilterBasedEdgePairFilter ()
// .. nothing yet .. // .. nothing yet ..
} }
bool EdgeFilterBasedEdgePairFilter::selected (const db::EdgePair &edge_pair) const bool EdgeFilterBasedEdgePairFilter::selected (const db::EdgePair &edge_pair, db::properties_id_type prop_id) const
{ {
if (m_one_must_match) { if (m_one_must_match) {
return mp_edge_filter->selected (edge_pair.first ()) || mp_edge_filter->selected (edge_pair.second ()); return mp_edge_filter->selected (edge_pair.first (), prop_id) || mp_edge_filter->selected (edge_pair.second (), prop_id);
} else { } else {
return mp_edge_filter->selected (edge_pair.first ()) && mp_edge_filter->selected (edge_pair.second ()); return mp_edge_filter->selected (edge_pair.first (), prop_id) && mp_edge_filter->selected (edge_pair.second (), prop_id);
} }
} }
@ -71,7 +71,7 @@ EdgePairFilterByDistance::EdgePairFilterByDistance (distance_type min_distance,
// .. nothing yet .. // .. nothing yet ..
} }
bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair) const bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair, db::properties_id_type) const
{ {
distance_type dist = edge_pair.distance (); distance_type dist = edge_pair.distance ();
bool sel = (dist >= m_min_distance && dist < m_max_distance); bool sel = (dist >= m_min_distance && dist < m_max_distance);
@ -87,7 +87,7 @@ EdgePairFilterByArea::EdgePairFilterByArea (area_type min_area, area_type max_ar
// .. nothing yet .. // .. nothing yet ..
} }
bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair) const bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair, db::properties_id_type) const
{ {
area_type dist = edge_pair.to_simple_polygon (0).area (); area_type dist = edge_pair.to_simple_polygon (0).area ();
bool sel = (dist >= m_min_area && dist < m_max_area); bool sel = (dist >= m_min_area && dist < m_max_area);
@ -110,7 +110,7 @@ InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool incl
} }
bool bool
InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair) const InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair, db::properties_id_type) const
{ {
db::Vector d1 = edge_pair.first ().d (); db::Vector d1 = edge_pair.first ().d ();
db::Vector d2 = edge_pair.second ().d (); db::Vector d2 = edge_pair.second ().d ();

View File

@ -47,7 +47,7 @@ public:
EdgeFilterBasedEdgePairFilter (EdgeFilterBase *edge_filter, bool one_must_match); EdgeFilterBasedEdgePairFilter (EdgeFilterBase *edge_filter, bool one_must_match);
virtual ~EdgeFilterBasedEdgePairFilter (); virtual ~EdgeFilterBasedEdgePairFilter ();
virtual bool selected (const db::EdgePair &edge_pair) const; virtual bool selected (const db::EdgePair &edge_pair, properties_id_type prop_id) const;
virtual const TransformationReducer *vars () const; virtual const TransformationReducer *vars () const;
virtual bool wants_variants () const; virtual bool wants_variants () const;
@ -69,7 +69,7 @@ public:
EdgePairFilterByDistance (distance_type min_distance, distance_type max_distance, bool inverted); EdgePairFilterByDistance (distance_type min_distance, distance_type max_distance, bool inverted);
virtual bool selected (const db::EdgePair &edge_pair) const; virtual bool selected (const db::EdgePair &edge_pair, properties_id_type) const;
virtual const TransformationReducer *vars () const { return &m_vars; } virtual const TransformationReducer *vars () const { return &m_vars; }
virtual bool wants_variants () const { return true; } virtual bool wants_variants () const { return true; }
@ -92,7 +92,7 @@ public:
EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted); EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted);
virtual bool selected (const db::EdgePair &edge_pair) const; virtual bool selected (const db::EdgePair &edge_pair, properties_id_type) const;
virtual const TransformationReducer *vars () const { return &m_vars; } virtual const TransformationReducer *vars () const { return &m_vars; }
virtual bool wants_variants () const { return true; } virtual bool wants_variants () const { return true; }
@ -114,7 +114,7 @@ public:
InternalAngleEdgePairFilter (double a, bool inverted); InternalAngleEdgePairFilter (double a, bool inverted);
InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted); InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted);
virtual bool selected (const db::EdgePair &edge_pair) const; virtual bool selected (const db::EdgePair &edge_pair, properties_id_type) const;
virtual const TransformationReducer *vars () const { return 0; } virtual const TransformationReducer *vars () const { return 0; }
virtual bool wants_variants () const { return false; } virtual bool wants_variants () const { return false; }

View File

@ -96,6 +96,13 @@ EdgePairs::EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
mp_delegate = new DeepEdgePairs (si, dss, trans); mp_delegate = new DeepEdgePairs (si, dss, trans);
} }
EdgePairs::EdgePairs (DeepShapeStore &dss)
{
tl_assert (dss.is_singular ());
unsigned int layout_index = 0; // singular layout index
mp_delegate = new DeepEdgePairs (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
}
void void
EdgePairs::write (const std::string &fn) const EdgePairs::write (const std::string &fn) const
{ {
@ -120,6 +127,7 @@ void EdgePairs::insert (const Sh &shape)
} }
template DB_PUBLIC void EdgePairs::insert (const db::EdgePair &); template DB_PUBLIC void EdgePairs::insert (const db::EdgePair &);
template DB_PUBLIC void EdgePairs::insert (const db::EdgePairWithProperties &);
void EdgePairs::insert (const db::Shape &shape) void EdgePairs::insert (const db::Shape &shape)
{ {

View File

@ -55,10 +55,12 @@ class EdgePairs;
class DB_PUBLIC EdgePairFilterBase class DB_PUBLIC EdgePairFilterBase
{ {
public: public:
typedef db::EdgePair shape_type;
EdgePairFilterBase () { } EdgePairFilterBase () { }
virtual ~EdgePairFilterBase () { } virtual ~EdgePairFilterBase () { }
virtual bool selected (const db::EdgePair &edge_pair) const = 0; virtual bool selected (const db::EdgePair &edge_pair, db::properties_id_type prop_id) const = 0;
virtual const TransformationReducer *vars () const = 0; virtual const TransformationReducer *vars () const = 0;
virtual bool wants_variants () const = 0; virtual bool wants_variants () const = 0;
}; };
@ -128,6 +130,17 @@ public:
insert (s); insert (s);
} }
/**
* @brief Constructor from an object with properties
*
* Creates an edge pair set representing a single instance of that object
*/
explicit EdgePairs (const db::EdgePairWithProperties &s)
: mp_delegate (0)
{
insert (s);
}
/** /**
* @brief Constructor from an object * @brief Constructor from an object
* *
@ -185,6 +198,12 @@ public:
*/ */
explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
/**
* @brief Creates a new empty layer inside the dss
* This method requires the DSS to be singular.
*/
explicit EdgePairs (DeepShapeStore &dss);
/** /**
* @brief Writes the edge pair collection to a file * @brief Writes the edge pair collection to a file
* *
@ -346,6 +365,18 @@ public:
return EdgePairs (mp_delegate->filtered (filter)); return EdgePairs (mp_delegate->filtered (filter));
} }
/**
* @brief Returns the filtered edge pairs and the others
*
* This method will return a new edge pair collection with only those edge pairs which
* conform to the filter criterion and another for those which don't.
*/
std::pair<EdgePairs, EdgePairs> split_filter (const EdgePairFilterBase &filter) const
{
std::pair<db::EdgePairsDelegate *, db::EdgePairsDelegate *> p = mp_delegate->filtered_pair (filter);
return std::make_pair (EdgePairs (p.first), EdgePairs (p.second));
}
/** /**
* @brief Processes the edge pairs in-place * @brief Processes the edge pairs in-place
* *
@ -649,7 +680,7 @@ public:
/** /**
* @brief Returns the nth edge pair * @brief Returns the nth edge pair
* *
* This operation is available only for flat regions - i.e. such for which * This operation is available only for flat edge pair collections - i.e. such for which
* "has_valid_edge_pairs" is true. * "has_valid_edge_pairs" is true.
*/ */
const db::EdgePair *nth (size_t n) const const db::EdgePair *nth (size_t n) const
@ -657,6 +688,17 @@ public:
return mp_delegate->nth (n); return mp_delegate->nth (n);
} }
/**
* @brief Returns the nth edge pair's property ID
*
* This operation is available only for flat edge pair collections - i.e. such for which
* "has_valid_edge_pairs" is true.
*/
db::properties_id_type nth_prop_id (size_t n) const
{
return mp_delegate->nth_prop_id (n);
}
/** /**
* @brief Forces flattening of the edge pair collection * @brief Forces flattening of the edge pair collection
* *

View File

@ -52,14 +52,6 @@ public:
: m_e (e) : m_e (e)
{ } { }
void process(const EdgePair &ep, std::vector<db::Polygon> &res) const
{
db::Polygon poly = ep.normalized ().to_polygon (m_e);
if (poly.vertices () >= 3) {
res.push_back (poly);
}
}
void process(const EdgePairWithProperties &ep, std::vector<db::PolygonWithProperties> &res) const void process(const EdgePairWithProperties &ep, std::vector<db::PolygonWithProperties> &res) const
{ {
db::Polygon poly = ep.normalized ().to_polygon (m_e); db::Polygon poly = ep.normalized ().to_polygon (m_e);
@ -80,12 +72,6 @@ public:
EdgePairToEdgesProcessor () EdgePairToEdgesProcessor ()
{ } { }
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
res.push_back (ep.first ());
res.push_back (ep.second ());
}
void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const
{ {
res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ())); res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ()));
@ -101,14 +87,6 @@ public:
EdgePairToFirstEdgesProcessor () EdgePairToFirstEdgesProcessor ()
{ } { }
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
res.push_back (ep.first ());
if (ep.is_symmetric ()) {
res.push_back (ep.second ());
}
}
void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const
{ {
res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ())); res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ()));
@ -126,13 +104,6 @@ public:
EdgePairToSecondEdgesProcessor () EdgePairToSecondEdgesProcessor ()
{ } { }
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
if (! ep.is_symmetric ()) {
res.push_back (ep.second ());
}
}
void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const
{ {
if (! ep.is_symmetric ()) { if (! ep.is_symmetric ()) {
@ -149,11 +120,6 @@ public:
EdgePairToLesserEdgesProcessor () EdgePairToLesserEdgesProcessor ()
{ } { }
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
res.push_back (ep.lesser ());
}
void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const
{ {
res.push_back (db::EdgeWithProperties (ep.lesser (), ep.properties_id ())); res.push_back (db::EdgeWithProperties (ep.lesser (), ep.properties_id ()));
@ -168,11 +134,6 @@ public:
EdgePairToGreaterEdgesProcessor () EdgePairToGreaterEdgesProcessor ()
{ } { }
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
res.push_back (ep.greater ());
}
void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const void process(const EdgePairWithProperties &ep, std::vector<db::EdgeWithProperties> &res) const
{ {
res.push_back (db::EdgeWithProperties (ep.greater (), ep.properties_id ())); res.push_back (db::EdgeWithProperties (ep.greater (), ep.properties_id ()));
@ -240,6 +201,7 @@ public:
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter) = 0; virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter) = 0;
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &filter) const = 0; virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &filter) const = 0;
virtual std::pair<EdgePairsDelegate *, EdgePairsDelegate *> filtered_pair (const EdgePairFilterBase &filter) const = 0;
virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &proc) = 0; virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &proc) = 0;
virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &proc) const = 0; virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &proc) const = 0;
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &proc) const = 0; virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &proc) const = 0;
@ -272,6 +234,7 @@ public:
virtual EdgePairsDelegate *in (const EdgePairs &other, bool invert) const = 0; virtual EdgePairsDelegate *in (const EdgePairs &other, bool invert) const = 0;
virtual const db::EdgePair *nth (size_t n) const = 0; virtual const db::EdgePair *nth (size_t n) const = 0;
virtual db::properties_id_type nth_prop_id (size_t n) const = 0;
virtual bool has_valid_edge_pairs () const = 0; virtual bool has_valid_edge_pairs () const = 0;
virtual const db::RecursiveShapeIterator *iter () const = 0; virtual const db::RecursiveShapeIterator *iter () const = 0;

View File

@ -1321,7 +1321,7 @@ struct edge_xmin_at_yinterval_double_compare
{ {
if (edge_xmax (a) < edge_xmin (b)) { if (edge_xmax (a) < edge_xmin (b)) {
return true; return true;
} else if (edge_xmin (a) >= edge_xmax (b)) { } else if (edge_xmin (a) > edge_xmax (b)) {
return false; return false;
} else { } else {
C xa = edge_xmin_at_yinterval_double (a, m_y1, m_y2); C xa = edge_xmin_at_yinterval_double (a, m_y1, m_y2);

View File

@ -107,6 +107,13 @@ Edges::Edges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::I
mp_delegate = new DeepEdges (si, dss, trans, as_edges, merged_semantics); mp_delegate = new DeepEdges (si, dss, trans, as_edges, merged_semantics);
} }
Edges::Edges (DeepShapeStore &dss)
{
tl_assert (dss.is_singular ());
unsigned int layout_index = 0; // singular layout index
mp_delegate = new DeepEdges (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
}
const db::RecursiveShapeIterator & const db::RecursiveShapeIterator &
Edges::iter () const Edges::iter () const
{ {

View File

@ -112,6 +112,17 @@ public:
insert (s); insert (s);
} }
/**
* @brief Constructor from a box with properties
*
* Creates an edge set representing the contour of the box
*/
explicit Edges (const db::BoxWithProperties &s)
: mp_delegate (0)
{
insert (s);
}
/** /**
* @brief Constructor from a simple polygon * @brief Constructor from a simple polygon
* *
@ -123,6 +134,17 @@ public:
insert (s); insert (s);
} }
/**
* @brief Constructor from a simple polygon with properties
*
* Creates an edge set representing the contour of the polygon
*/
explicit Edges (const db::SimplePolygonWithProperties &s)
: mp_delegate (0)
{
insert (s);
}
/** /**
* @brief Constructor from a polygon * @brief Constructor from a polygon
* *
@ -134,6 +156,17 @@ public:
insert (s); insert (s);
} }
/**
* @brief Constructor from a polygon with properties
*
* Creates an edge set representing the contour of the polygon
*/
explicit Edges (const db::PolygonWithProperties &s)
: mp_delegate (0)
{
insert (s);
}
/** /**
* @brief Constructor from a path * @brief Constructor from a path
* *
@ -145,6 +178,17 @@ public:
insert (s); insert (s);
} }
/**
* @brief Constructor from a path with properties
*
* Creates an edge set representing the contour of the path
*/
explicit Edges (const db::PathWithProperties &s)
: mp_delegate (0)
{
insert (s);
}
/** /**
* @brief Constructor from an edge * @brief Constructor from an edge
* *
@ -156,6 +200,17 @@ public:
insert (s); insert (s);
} }
/**
* @brief Constructor from an edge with properties
*
* Creates an edge set representing the single edge
*/
explicit Edges (const db::EdgeWithProperties &s)
: mp_delegate (0)
{
insert (s);
}
/** /**
* @brief Sequence constructor * @brief Sequence constructor
* *
@ -203,6 +258,12 @@ public:
*/ */
explicit Edges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges = true, bool merged_semantics = true); explicit Edges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges = true, bool merged_semantics = true);
/**
* @brief Creates a new empty layer inside the dss
* This method requires the DSS to be singular.
*/
explicit Edges (DeepShapeStore &dss);
/** /**
* @brief Implementation of the ShapeCollection interface * @brief Implementation of the ShapeCollection interface
*/ */
@ -468,6 +529,18 @@ public:
return Edges (mp_delegate->filtered (filter)); return Edges (mp_delegate->filtered (filter));
} }
/**
* @brief Returns the filtered edges and the others
*
* This method will return a new edge collection with only those edges which
* conform to the filter criterion and another for those which don't.
*/
std::pair<Edges, Edges> split_filter (const EdgeFilterBase &filter) const
{
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->filtered_pair (filter);
return std::make_pair (Edges (p.first), Edges (p.second));
}
/** /**
* @brief Processes the (merged) edges * @brief Processes the (merged) edges
* *
@ -1367,13 +1440,24 @@ public:
/** /**
* @brief Returns the nth edge * @brief Returns the nth edge
* *
* This operation is available only for flat regions - i.e. such for which "has_valid_edges" is true. * This operation is available only for flat edge collections - i.e. such for which "has_valid_edges" is true.
*/ */
const db::Edge *nth (size_t n) const const db::Edge *nth (size_t n) const
{ {
return mp_delegate->nth (n); return mp_delegate->nth (n);
} }
/**
* @brief Returns the nth edge's property ID
*
* This operation is available only for flat edge collections - i.e. such for which
* "has_valid_edges" is true.
*/
db::properties_id_type nth_prop_id (size_t n) const
{
return mp_delegate->nth_prop_id (n);
}
/** /**
* @brief Forces flattening of the edge collection * @brief Forces flattening of the edge collection
* *

View File

@ -45,6 +45,8 @@ namespace db {
class DB_PUBLIC EdgeFilterBase class DB_PUBLIC EdgeFilterBase
{ {
public: public:
typedef db::Edge shape_type;
/** /**
* @brief Constructor * @brief Constructor
*/ */
@ -56,13 +58,13 @@ public:
* @brief Filters the edge * @brief Filters the edge
* If this method returns true, the edge is kept. Otherwise it's discarded. * If this method returns true, the edge is kept. Otherwise it's discarded.
*/ */
virtual bool selected (const db::Edge &edge) const = 0; virtual bool selected (const db::Edge &edge, db::properties_id_type prop_id) const = 0;
/** /**
* @brief Filters the edge set * @brief Filters the edge set
* If this method returns true, the edges are kept. Otherwise they are discarded. * If this method returns true, the edges are kept. Otherwise they are discarded.
*/ */
virtual bool selected (const std::unordered_set<db::Edge> &edge) const = 0; virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edge) const = 0;
/** /**
* @brief Returns the transformation reducer for building cell variants * @brief Returns the transformation reducer for building cell variants
@ -228,6 +230,7 @@ public:
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter) = 0; virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter) = 0;
virtual EdgesDelegate *filtered (const EdgeFilterBase &filter) const = 0; virtual EdgesDelegate *filtered (const EdgeFilterBase &filter) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> filtered_pair (const EdgeFilterBase &filter) const = 0;
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &filter) = 0; virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &filter) = 0;
virtual EdgesDelegate *processed (const EdgeProcessorBase &filter) const = 0; virtual EdgesDelegate *processed (const EdgeProcessorBase &filter) const = 0;
virtual EdgePairsDelegate *processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filter) const = 0; virtual EdgePairsDelegate *processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filter) const = 0;
@ -279,6 +282,7 @@ public:
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const = 0; virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const = 0;
virtual const db::Edge *nth (size_t n) const = 0; virtual const db::Edge *nth (size_t n) const = 0;
virtual db::properties_id_type nth_prop_id (size_t n) const = 0;
virtual bool has_valid_edges () const = 0; virtual bool has_valid_edges () const = 0;
virtual bool has_valid_merged_edges () const = 0; virtual bool has_valid_merged_edges () const = 0;

View File

@ -184,34 +184,6 @@ EdgeSegmentSelector::EdgeSegmentSelector (int mode, Edge::distance_type length,
EdgeSegmentSelector::~EdgeSegmentSelector () EdgeSegmentSelector::~EdgeSegmentSelector ()
{ } { }
void
EdgeSegmentSelector::process (const db::Edge &edge, std::vector<db::Edge> &res) const
{
double l = std::max (edge.double_length () * m_fraction, double (m_length));
db::DVector ds;
if (! edge.is_degenerate ()) {
ds = db::DVector (edge.d ()) * (l / edge.double_length ());
}
if (m_mode < 0) {
res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + ds)));
} else if (m_mode > 0) {
res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - ds), edge.p2 ()));
} else {
db::DVector dl = ds * 0.5;
db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5;
res.push_back (db::Edge (db::Point (center - dl), db::Point (center + dl)));
}
}
void void
EdgeSegmentSelector::process (const db::EdgeWithProperties &edge, std::vector<db::EdgeWithProperties> &res) const EdgeSegmentSelector::process (const db::EdgeWithProperties &edge, std::vector<db::EdgeWithProperties> &res) const
{ {
@ -250,8 +222,8 @@ EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start
include_angle_start = true; include_angle_start = true;
} }
m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ()); m_t_start = db::ICplxTrans (1.0, angle_start, false, db::Vector ());
m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ()); m_t_end = db::ICplxTrans (1.0, angle_end, false, db::Vector ());
m_include_start = include_angle_start; m_include_start = include_angle_start;
m_include_end = include_angle_end; m_include_end = include_angle_end;
@ -266,10 +238,10 @@ EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start
bool bool
EdgeAngleChecker::check (const db::Vector &a, const db::Vector &b) const EdgeAngleChecker::check (const db::Vector &a, const db::Vector &b) const
{ {
db::DVector vout (b); db::Vector vout (b);
db::DVector v1 = m_t_start * a; db::Vector v1 = m_t_start * a;
db::DVector v2 = m_t_end * a; db::Vector v2 = m_t_end * a;
int vps1 = db::vprod_sign (v1, vout); int vps1 = db::vprod_sign (v1, vout);
int vps2 = db::vprod_sign (v2, vout); int vps2 = db::vprod_sign (v2, vout);
@ -304,14 +276,16 @@ EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse, bool absol
} }
bool bool
EdgeOrientationFilter::selected (const db::Edge &edge) const EdgeOrientationFilter::selected (const db::Edge &edge, db::properties_id_type) const
{ {
db::Vector en = db::Vector (std::max (edge.dx_abs (), edge.dy_abs ()), 0);
// NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded). // NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded).
// A horizontal edge has 0 degree, a vertical one has 90 degree. // A horizontal edge has 0 degree, a vertical one has 90 degree.
if (edge.dx () < 0 || (edge.dx () == 0 && edge.dy () < 0)) { if (edge.dx () < 0 || (edge.dx () == 0 && edge.dy () < 0)) {
return m_checker (db::Vector (edge.ortho_length (), 0), -edge.d ()); return m_checker (en, -edge.d ());
} else { } else {
return m_checker (db::Vector (edge.ortho_length (), 0), edge.d ()); return m_checker (en, edge.d ());
} }
} }
@ -342,7 +316,7 @@ static EdgeAngleChecker s_orthodiagonal_checkers [] = {
}; };
bool bool
SpecialEdgeOrientationFilter::selected (const db::Edge &edge) const SpecialEdgeOrientationFilter::selected (const db::Edge &edge, properties_id_type) const
{ {
const EdgeAngleChecker *eb, *ee; const EdgeAngleChecker *eb, *ee;
@ -363,7 +337,7 @@ SpecialEdgeOrientationFilter::selected (const db::Edge &edge) const
} }
db::Vector en, ev; db::Vector en, ev;
en = db::Vector (edge.ortho_length (), 0); en = db::Vector (std::max (edge.dx_abs (), edge.dy_abs ()), 0);
// NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded). // NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded).
// A horizontal edge has 0 degree, a vertical one has 90 degree. // A horizontal edge has 0 degree, a vertical one has 90 degree.

View File

@ -71,7 +71,7 @@ struct DB_PUBLIC EdgeLengthFilter
/** /**
* @brief Returns true if the edge length matches the criterion * @brief Returns true if the edge length matches the criterion
*/ */
virtual bool selected (const db::Edge &edge) const virtual bool selected (const db::Edge &edge, db::properties_id_type) const
{ {
return check (edge.length ()); return check (edge.length ());
} }
@ -79,10 +79,10 @@ struct DB_PUBLIC EdgeLengthFilter
/** /**
* @brief Returns true if the total edge length matches the criterion * @brief Returns true if the total edge length matches the criterion
*/ */
bool selected (const std::unordered_set<db::Edge> &edges) const bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
{ {
length_type l = 0; length_type l = 0;
for (std::unordered_set<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) { for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
l += e->length (); l += e->length ();
} }
return check (l); return check (l);
@ -155,7 +155,7 @@ public:
} }
private: private:
db::CplxTrans m_t_start, m_t_end; db::ICplxTrans m_t_start, m_t_end;
bool m_include_start, m_include_end; bool m_include_start, m_include_end;
bool m_big_angle, m_all; bool m_big_angle, m_all;
bool m_inverse, m_absolute; bool m_inverse, m_absolute;
@ -204,15 +204,15 @@ struct DB_PUBLIC EdgeOrientationFilter
/** /**
* @brief Returns true if the edge orientation matches the criterion * @brief Returns true if the edge orientation matches the criterion
*/ */
virtual bool selected (const db::Edge &edge) const; virtual bool selected (const db::Edge &edge, properties_id_type) const;
/** /**
* @brief Returns true if all edge orientations match the criterion * @brief Returns true if all edge orientations match the criterion
*/ */
virtual bool selected (const std::unordered_set<db::Edge> &edges) const virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
{ {
for (std::unordered_set<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) { for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
if (! selected (*e)) { if (! selected (*e, e->properties_id ())) {
return false; return false;
} }
} }
@ -274,15 +274,15 @@ struct DB_PUBLIC SpecialEdgeOrientationFilter
/** /**
* @brief Returns true if the edge orientation matches the criterion * @brief Returns true if the edge orientation matches the criterion
*/ */
virtual bool selected (const db::Edge &edge) const; virtual bool selected (const db::Edge &edge, db::properties_id_type) const;
/** /**
* @brief Returns true if all edge orientations match the criterion * @brief Returns true if all edge orientations match the criterion
*/ */
virtual bool selected (const std::unordered_set<db::Edge> &edges) const virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
{ {
for (std::unordered_set<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) { for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
if (! selected (*e)) { if (! selected (*e, e->properties_id ())) {
return false; return false;
} }
} }
@ -319,6 +319,29 @@ private:
db::OrthogonalTransformationReducer m_vars; db::OrthogonalTransformationReducer m_vars;
}; };
/**
* @brief A filter implementation which implements the set filters through "all must match"
*/
struct DB_PUBLIC AllEdgesMustMatchFilter
: public EdgeFilterBase
{
/**
* @brief Constructor
*/
AllEdgesMustMatchFilter () { }
virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
{
for (std::unordered_set<db::EdgeWithProperties>::const_iterator p = edges.begin (); p != edges.end (); ++p) {
if (! selected (*p, p->properties_id ())) {
return false;
}
}
return true;
}
};
/** /**
* @brief A predicate defining edge a interacts with b * @brief A predicate defining edge a interacts with b
*/ */
@ -621,11 +644,6 @@ public:
: m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i) : m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i)
{ } { }
virtual void process (const Edge &edge, std::vector<db::Polygon> &res) const
{
res.push_back (extended_edge (edge, m_ext_b, m_ext_e, m_ext_o, m_ext_i));
}
virtual void process (const EdgeWithProperties &edge, std::vector<db::PolygonWithProperties> &res) const virtual void process (const EdgeWithProperties &edge, std::vector<db::PolygonWithProperties> &res) const
{ {
res.push_back (db::PolygonWithProperties (extended_edge (edge, m_ext_b, m_ext_e, m_ext_o, m_ext_i), edge.properties_id ())); res.push_back (db::PolygonWithProperties (extended_edge (edge, m_ext_b, m_ext_e, m_ext_o, m_ext_i), edge.properties_id ()));
@ -645,7 +663,6 @@ public:
EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction); EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction);
~EdgeSegmentSelector (); ~EdgeSegmentSelector ();
virtual void process (const db::Edge &edge, std::vector<db::Edge> &res) const;
virtual void process (const db::EdgeWithProperties &edge, std::vector<db::EdgeWithProperties> &res) const; virtual void process (const db::EdgeWithProperties &edge, std::vector<db::EdgeWithProperties> &res) const;
virtual const TransformationReducer *vars () const { return &m_vars; } virtual const TransformationReducer *vars () const { return &m_vars; }

View File

@ -56,6 +56,7 @@ public:
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &) { return this; } virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &) { return this; }
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const { return new EmptyEdgePairs (); } virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const { return new EmptyEdgePairs (); }
virtual std::pair<EdgePairsDelegate *, EdgePairsDelegate *> filtered_pair (const EdgePairFilterBase &) const { return std::make_pair (new EmptyEdgePairs (), new EmptyEdgePairs ()); }
virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &) { return this; } virtual EdgePairsDelegate *process_in_place (const EdgePairProcessorBase &) { return this; }
virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &) const { return new EmptyEdgePairs (); } virtual EdgePairsDelegate *processed (const EdgePairProcessorBase &) const { return new EmptyEdgePairs (); }
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const; virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
@ -88,6 +89,7 @@ public:
virtual EdgePairsDelegate *in (const EdgePairs &, bool) const { return new EmptyEdgePairs (); } virtual EdgePairsDelegate *in (const EdgePairs &, bool) const { return new EmptyEdgePairs (); }
virtual const db::EdgePair *nth (size_t) const { tl_assert (false); } virtual const db::EdgePair *nth (size_t) const { tl_assert (false); }
virtual db::properties_id_type nth_prop_id (size_t) const { tl_assert (false); }
virtual bool has_valid_edge_pairs () const { return true; } virtual bool has_valid_edge_pairs () const { return true; }
virtual const db::RecursiveShapeIterator *iter () const { return 0; } virtual const db::RecursiveShapeIterator *iter () const { return 0; }

View File

@ -66,6 +66,7 @@ public:
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &) { return this; } virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &) { return this; }
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const { return new EmptyEdges (); } virtual EdgesDelegate *filtered (const EdgeFilterBase &) const { return new EmptyEdges (); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> filtered_pair (const EdgeFilterBase &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &) { return this; } virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &) { return this; }
virtual EdgesDelegate *processed (const EdgeProcessorBase &) const { return new EmptyEdges (); } virtual EdgesDelegate *processed (const EdgeProcessorBase &) const { return new EmptyEdges (); }
virtual EdgePairsDelegate *processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &) const; virtual EdgePairsDelegate *processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &) const;
@ -118,6 +119,7 @@ public:
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); } virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual const db::Edge *nth (size_t) const { tl_assert (false); } virtual const db::Edge *nth (size_t) const { tl_assert (false); }
virtual db::properties_id_type nth_prop_id (size_t) const { tl_assert (false); }
virtual bool has_valid_edges () const { return true; } virtual bool has_valid_edges () const { return true; }
virtual bool has_valid_merged_edges () const { return true; } virtual bool has_valid_merged_edges () const { return true; }

View File

@ -85,15 +85,16 @@ public:
virtual EdgesDelegate *edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const; virtual EdgesDelegate *edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; } virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); } virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> filtered_pair (const PolygonFilterBase &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; } virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; }
virtual RegionDelegate *processed (const PolygonProcessorBase &) const { return new EmptyRegion (); } virtual RegionDelegate *processed (const PolygonProcessorBase &) const { return new EmptyRegion (); }
virtual EdgesDelegate *processed_to_edges (const PolygonToEdgeProcessorBase &) const; virtual EdgesDelegate *processed_to_edges (const PolygonToEdgeProcessorBase &) const;
virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &) const; virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &) const;
virtual RegionDelegate *merged_in_place () { return this; } virtual RegionDelegate *merged_in_place () { return this; }
virtual RegionDelegate *merged_in_place (bool, unsigned int) { return this; } virtual RegionDelegate *merged_in_place (bool, unsigned int, bool) { return this; }
virtual RegionDelegate *merged () const { return new EmptyRegion (); } virtual RegionDelegate *merged () const { return new EmptyRegion (); }
virtual RegionDelegate *merged (bool, unsigned int) const { return new EmptyRegion (); } virtual RegionDelegate *merged (bool, unsigned int, bool) const { return new EmptyRegion (); }
virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); } virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); }
virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); } virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); }

View File

@ -49,7 +49,7 @@ EmptyTexts::clone () const
} }
RegionDelegate * RegionDelegate *
EmptyTexts::polygons (db::Coord) const EmptyTexts::polygons (db::Coord, const tl::Variant &) const
{ {
return new EmptyRegion (); return new EmptyRegion ();
} }

View File

@ -56,12 +56,13 @@ public:
virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; } virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; }
virtual TextsDelegate *filtered (const TextFilterBase &) const { return new EmptyTexts (); } virtual TextsDelegate *filtered (const TextFilterBase &) const { return new EmptyTexts (); }
virtual std::pair<TextsDelegate *, TextsDelegate *> filtered_pair (const TextFilterBase &) const { return std::make_pair (new EmptyTexts (), new EmptyTexts ()); }
virtual TextsDelegate *process_in_place (const TextProcessorBase &) { return this; } virtual TextsDelegate *process_in_place (const TextProcessorBase &) { return this; }
virtual TextsDelegate *processed (const TextProcessorBase &) const { return new EmptyTexts (); } virtual TextsDelegate *processed (const TextProcessorBase &) const { return new EmptyTexts (); }
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &) const; virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &) const;
virtual RegionDelegate *polygons (db::Coord e) const; virtual RegionDelegate *polygons (db::Coord e, const tl::Variant &text_prop) const;
virtual EdgesDelegate *edges () const; virtual EdgesDelegate *edges () const;
virtual TextsDelegate *add_in_place (const Texts &other); virtual TextsDelegate *add_in_place (const Texts &other);
@ -70,6 +71,7 @@ public:
virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); } virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); }
virtual const db::Text *nth (size_t) const { tl_assert (false); } virtual const db::Text *nth (size_t) const { tl_assert (false); }
virtual db::properties_id_type nth_prop_id (size_t) const { tl_assert (false); }
virtual bool has_valid_texts () const { return true; } virtual bool has_valid_texts () const { return true; }
virtual const db::RecursiveShapeIterator *iter () const { return 0; } virtual const db::RecursiveShapeIterator *iter () const { return 0; }

View File

@ -77,14 +77,16 @@ public:
} }
// because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps // because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps
// with an integer until the effective rasterizer pitch get big enough. // with an integer until the effective rasterizer pitch gets big enough.
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1; m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1; m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
db::Box fp_bbox = fp.box (); db::Box fp_bbox = fp.box ();
// compensate for distortion by sheared kernel // compensate for distortion by sheared kernel
fp_bbox.enlarge (db::Vector (db::coord_traits<db::Coord>::rounded (double (fp_bbox.height ()) * std::abs (m_column_step.x ()) / dy), db::coord_traits<db::Coord>::rounded (double (fp_bbox.width ()) * std::abs (m_row_step.y ()) / dx))); db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
fp_bbox.enlarge (db::Vector (ex, ey));
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy; int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx; int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
@ -167,6 +169,11 @@ public:
return m_area_maps [i]; return m_area_maps [i];
} }
db::AreaMap &area_map (unsigned int i)
{
return m_area_maps [i];
}
private: private:
std::vector<db::AreaMap> m_area_maps; std::vector<db::AreaMap> m_area_maps;
db::Vector m_row_step, m_column_step; db::Vector m_row_step, m_column_step;
@ -246,7 +253,7 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
for (unsigned int i = 0; i < am.area_maps (); ++i) { for (unsigned int i = 0; i < am.area_maps (); ++i) {
const db::AreaMap &am1 = am.area_map (i); db::AreaMap &am1 = am.area_map (i);
size_t nx = am1.nx (); size_t nx = am1.nx ();
size_t ny = am1.ny (); size_t ny = am1.ny ();
@ -263,31 +270,54 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
++jj; ++jj;
} }
ninsts += (jj - j);
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin; db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ()); p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
db::CellInstArray array; db::CellInstArray array;
if (jj > j + 1) { // try to expand the array in x direction
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (), (unsigned long) (jj - j), 1); size_t ii = i + 1;
for ( ; ii < nx; ++ii) {
bool all = true;
for (size_t k = j; k < jj && all; ++k) {
all = am1.get (ii, k) == am1.pixel_area ();
}
if (all) {
for (size_t k = j; k < jj; ++k) {
// disable pixel, so we do not see it again in the following columns
am1.get (ii, k) = 0;
}
} else {
break;
}
}
ninsts += (jj - j) * (ii - i);
if (jj > j + 1 || ii > i + 1) {
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
} else { } else {
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0)); array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
} }
{ {
// In case we run this from a tiling processor we need to lock against multithread races // In case we run this from a tiling processor we need to lock against multithread races
tl::MutexLocker locker (&db::TilingProcessor::output_lock ()); tl_assert (cell->layout () != 0);
tl::MutexLocker locker (&cell->layout ()->lock ());
cell->insert (array); cell->insert (array);
} }
if (remaining_parts) { if (remaining_parts) {
if (am1.d ().y () == am1.p ().y ()) { if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point (am1.p ().x (), am1.p ().y () * db::Coord (jj - j))).moved (kernel_origin + p0))); db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
filled_regions.push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
} else { } else {
db::Box fill_box (db::Point (), db::Point () + am1.p ());
fill_box.enlarge (fill_margin);
for (size_t k = 0; k < jj - j; ++k) { for (size_t k = 0; k < jj - j; ++k) {
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point () + am1.p ()).moved (kernel_origin + p0 + db::Vector (0, am1.d ().y () * db::Coord (k))))); for (size_t l = 0; l < ii - i; ++l) {
filled_regions.push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
}
} }
} }
} }
@ -314,19 +344,9 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
if (any_fill) { if (any_fill) {
if (remaining_parts) { if (remaining_parts) {
std::vector <db::Polygon> fp1; std::vector <db::Polygon> fp1;
if (fill_margin != db::Vector ()) {
ep.size (filled_regions, fill_margin.x (), fill_margin.y (), fp1, 3 /*mode*/, false /*=don't resolve holes*/);
filled_regions.swap (fp1);
fp1.clear ();
}
fp1.push_back (fp0); fp1.push_back (fp0);
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/); ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
} }
return true; return true;

View File

@ -103,7 +103,7 @@ FlatEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
edge_pair_iterator_type pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (); edge_pair_iterator_type pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin ();
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) { for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
if (pw == ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ()) { if (pw == ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ()) {
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().insert (*p); ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().insert (*p);
pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end (); pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().end ();
@ -173,7 +173,46 @@ EdgePairsDelegate *FlatEdgePairs::add_in_place (const EdgePairs &other)
const db::EdgePair *FlatEdgePairs::nth (size_t n) const const db::EdgePair *FlatEdgePairs::nth (size_t n) const
{ {
return n < mp_edge_pairs->size () ? &mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ().begin () [n] : 0; // NOTE: this assumes that we iterate over non-property edge pairs first and then over edges with properties
if (n >= mp_edge_pairs->size ()) {
return 0;
}
const db::layer<db::EdgePair, db::unstable_layer_tag> &l = mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ();
if (n < l.size ()) {
return &l.begin () [n];
}
n -= l.size ();
const db::layer<db::EdgePairWithProperties, db::unstable_layer_tag> &lp = mp_edge_pairs->get_layer<db::EdgePairWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return &lp.begin () [n];
}
return 0;
}
db::properties_id_type FlatEdgePairs::nth_prop_id (size_t n) const
{
// NOTE: this assumes that we iterate over non-property edge pairs first and then over edges with properties
if (n >= mp_edge_pairs->size ()) {
return 0;
}
const db::layer<db::EdgePair, db::unstable_layer_tag> &l = mp_edge_pairs->get_layer<db::EdgePair, db::unstable_layer_tag> ();
if (n < l.size ()) {
return 0;
}
n -= l.size ();
const db::layer<db::EdgePairWithProperties, db::unstable_layer_tag> &lp = mp_edge_pairs->get_layer<db::EdgePairWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return lp.begin () [n].properties_id ();
}
return 0;
} }
bool FlatEdgePairs::has_valid_edge_pairs () const bool FlatEdgePairs::has_valid_edge_pairs () const
@ -221,9 +260,13 @@ FlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsig
} }
void void
FlatEdgePairs::do_insert (const db::EdgePair &ep) FlatEdgePairs::do_insert (const db::EdgePair &ep, db::properties_id_type prop_id)
{ {
mp_edge_pairs->insert (ep); if (prop_id != 0) {
mp_edge_pairs->insert (db::EdgePairWithProperties (ep, prop_id));
} else {
mp_edge_pairs->insert (ep);
}
invalidate_cache (); invalidate_cache ();
} }

View File

@ -75,6 +75,7 @@ public:
virtual EdgePairsDelegate *add (const EdgePairs &other) const; virtual EdgePairsDelegate *add (const EdgePairs &other) const;
virtual const db::EdgePair *nth (size_t n) const; virtual const db::EdgePair *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edge_pairs () const; virtual bool has_valid_edge_pairs () const;
virtual const db::RecursiveShapeIterator *iter () const; virtual const db::RecursiveShapeIterator *iter () const;
@ -83,7 +84,7 @@ public:
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
virtual void do_insert (const db::EdgePair &edge_pair); virtual void do_insert (const db::EdgePair &edge_pair, db::properties_id_type prop_id);
virtual void do_transform (const db::Trans &t) virtual void do_transform (const db::Trans &t)
{ {

View File

@ -127,7 +127,7 @@ FlatEdges::ensure_merged_edges_valid () const
if (! need_split_props) { if (! need_split_props) {
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr); EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr, prop_id);
scanner.reserve (mp_edges->size ()); scanner.reserve (mp_edges->size ());
@ -226,7 +226,7 @@ Box FlatEdges::compute_bbox () const
EdgesDelegate * EdgesDelegate *
FlatEdges::processed_in_place (const EdgeProcessorBase &filter) FlatEdges::processed_in_place (const EdgeProcessorBase &filter)
{ {
std::vector<db::Edge> edge_res; std::vector<db::EdgeWithProperties> edge_res;
db::Shapes &e = *mp_edges; db::Shapes &e = *mp_edges;
@ -236,22 +236,22 @@ FlatEdges::processed_in_place (const EdgeProcessorBase &filter)
for (EdgesIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { for (EdgesIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
edge_res.clear (); edge_res.clear ();
filter.process (*p, edge_res); filter.process (p.wp (), edge_res);
for (std::vector<db::Edge>::const_iterator pr = edge_res.begin (); pr != edge_res.end (); ++pr) { for (auto pr = edge_res.begin (); pr != edge_res.end (); ++pr) {
if (p.prop_id () != 0) { if (pr->properties_id () != 0) {
if (pw_wp == e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ()) { if (pw_wp == e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ()) {
e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().insert (db::EdgeWithProperties (*pr, p.prop_id ())); e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().insert (*pr);
pw_wp = e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end (); pw_wp = e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ();
} else { } else {
e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().replace (pw_wp++, db::EdgeWithProperties (*pr, p.prop_id ())); e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().replace (pw_wp++, *pr);
} }
} else { } else {
if (pw == e.get_layer<db::Edge, db::unstable_layer_tag> ().end ()) { if (pw == e.get_layer<db::Edge, db::unstable_layer_tag> ().end ()) {
e.get_layer<db::Edge, db::unstable_layer_tag> ().insert (*pr); e.get_layer<db::Edge, db::unstable_layer_tag> ().insert (pr->base ());
pw = e.get_layer<db::Edge, db::unstable_layer_tag> ().end (); pw = e.get_layer<db::Edge, db::unstable_layer_tag> ().end ();
} else { } else {
e.get_layer<db::Edge, db::unstable_layer_tag> ().replace (pw++, *pr); e.get_layer<db::Edge, db::unstable_layer_tag> ().replace (pw++, pr->base ());
} }
} }
} }
@ -276,7 +276,7 @@ FlatEdges::filter_in_place (const EdgeFilterBase &filter)
edge_iterator_wp_type pw_wp = e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().begin (); edge_iterator_wp_type pw_wp = e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().begin ();
for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) { for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) { if (p.prop_id () != 0) {
if (pw_wp == e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ()) { if (pw_wp == e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ()) {
e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().insert (db::EdgeWithProperties (*p, p.prop_id ())); e.get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().insert (db::EdgeWithProperties (*p, p.prop_id ()));
@ -314,18 +314,16 @@ EdgesDelegate *FlatEdges::add (const Edges &other) const
if (other_flat) { if (other_flat) {
new_region->raw_edges ().insert (other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().end ()); new_region->raw_edges ().insert (other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().end ());
new_region->raw_edges ().insert (other_flat->raw_edges ().get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ());
} else { } else {
size_t n = new_region->raw_edges ().size ();
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) { for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
++n; if (p.prop_id () == 0) {
} new_region->raw_edges ().insert (*p);
} else {
new_region->raw_edges ().reserve (db::Edge::tag (), n); new_region->raw_edges ().insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
new_region->raw_edges ().insert (*p);
} }
} }
@ -344,18 +342,16 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other)
if (other_flat) { if (other_flat) {
e.insert (other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().end ()); e.insert (other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().end ());
e.insert (other_flat->raw_edges ().get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ());
} else { } else {
size_t n = e.size ();
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) { for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
++n; if (p.prop_id () == 0) {
} e.insert (*p);
} else {
e.reserve (db::Edge::tag (), n); e.insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
e.insert (*p);
} }
} }
@ -365,7 +361,46 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other)
const db::Edge *FlatEdges::nth (size_t n) const const db::Edge *FlatEdges::nth (size_t n) const
{ {
return n < mp_edges->size () ? &mp_edges->get_layer<db::Edge, db::unstable_layer_tag> ().begin () [n] : 0; // NOTE: this assumes that we iterate over non-property edges first and then over edges with properties
if (n >= mp_edges->size ()) {
return 0;
}
const db::layer<db::Edge, db::unstable_layer_tag> &l = mp_edges->get_layer<db::Edge, db::unstable_layer_tag> ();
if (n < l.size ()) {
return &l.begin () [n];
}
n -= l.size ();
const db::layer<db::EdgeWithProperties, db::unstable_layer_tag> &lp = mp_edges->get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return &lp.begin () [n];
}
return 0;
}
db::properties_id_type FlatEdges::nth_prop_id (size_t n) const
{
// NOTE: this assumes that we iterate over non-property polygons first and then over polygons with properties
if (n >= mp_edges->size ()) {
return 0;
}
const db::layer<db::Edge, db::unstable_layer_tag> &l = mp_edges->get_layer<db::Edge, db::unstable_layer_tag> ();
if (n < l.size ()) {
return 0;
}
n -= l.size ();
const db::layer<db::EdgeWithProperties, db::unstable_layer_tag> &lp = mp_edges->get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ();
if (n < lp.size ()) {
return lp.begin () [n].properties_id ();
}
return 0;
} }
bool FlatEdges::has_valid_edges () const bool FlatEdges::has_valid_edges () const

View File

@ -89,6 +89,7 @@ public:
virtual EdgesDelegate *add (const Edges &other) const; virtual EdgesDelegate *add (const Edges &other) const;
virtual const db::Edge *nth (size_t n) const; virtual const db::Edge *nth (size_t n) const;
virtual db::properties_id_type nth_prop_id (size_t n) const;
virtual bool has_valid_edges () const; virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const; virtual bool has_valid_merged_edges () const;

View File

@ -99,6 +99,12 @@ void FlatRegion::merged_semantics_changed ()
m_merged_polygons_valid = false; m_merged_polygons_valid = false;
} }
void FlatRegion::join_properties_on_merge_changed ()
{
mp_merged_polygons->clear ();
m_merged_polygons_valid = false;
}
void FlatRegion::min_coherence_changed () void FlatRegion::min_coherence_changed ()
{ {
m_is_merged = false; m_is_merged = false;
@ -115,7 +121,7 @@ void
FlatRegion::ensure_merged_polygons_valid () const FlatRegion::ensure_merged_polygons_valid () const
{ {
if (! m_merged_polygons_valid) { if (! m_merged_polygons_valid) {
merge_polygons_to (*mp_merged_polygons, min_coherence (), 0); merge_polygons_to (*mp_merged_polygons, min_coherence (), 0, join_properties_on_merge ());
m_merged_polygons_valid = true; m_merged_polygons_valid = true;
} }
} }
@ -184,7 +190,7 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter)
polygon_iterator_wp_type pw_wp = poly_layer_wp.begin (); polygon_iterator_wp_type pw_wp = poly_layer_wp.begin ();
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) { if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) { if (p.prop_id () != 0) {
if (pw_wp == poly_layer_wp.end ()) { if (pw_wp == poly_layer_wp.end ()) {
poly_layer_wp.insert (db::PolygonWithProperties (*p, p.prop_id ())); poly_layer_wp.insert (db::PolygonWithProperties (*p, p.prop_id ()));
@ -220,16 +226,16 @@ RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter
db::layer<db::PolygonWithProperties, db::unstable_layer_tag> &poly_layer_wp = mp_polygons->get_layer<db::PolygonWithProperties, db::unstable_layer_tag> (); db::layer<db::PolygonWithProperties, db::unstable_layer_tag> &poly_layer_wp = mp_polygons->get_layer<db::PolygonWithProperties, db::unstable_layer_tag> ();
db::layer<db::PolygonWithProperties, db::unstable_layer_tag> out_wp; db::layer<db::PolygonWithProperties, db::unstable_layer_tag> out_wp;
std::vector<db::Polygon> poly_res; std::vector<db::PolygonWithProperties> poly_res;
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
poly_res.clear (); poly_res.clear ();
filter.process (*p, poly_res); filter.process (p.wp (), poly_res);
if (p.prop_id () != 0) { for (auto r = poly_res.begin (); r != poly_res.end (); ++r) {
for (auto r = poly_res.begin (); r != poly_res.end (); ++r) { if (r->properties_id () != 0) {
out_wp.insert (db::PolygonWithProperties (*r, p.prop_id ())); out_wp.insert (*r);
} else {
out_wp.insert (r->base ());
} }
} else {
out.insert (poly_res.begin (), poly_res.end ());
} }
} }
@ -260,7 +266,7 @@ RegionDelegate *FlatRegion::merged_in_place ()
return this; return this;
} else { } else {
return merged_in_place (min_coherence (), 0); return merged_in_place (min_coherence (), 0, join_properties_on_merge ());
} }
} else { } else {
@ -268,7 +274,7 @@ RegionDelegate *FlatRegion::merged_in_place ()
} }
} }
RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc) RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge)
{ {
if (empty ()) { if (empty ()) {
@ -285,7 +291,7 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi
} else { } else {
invalidate_cache (); invalidate_cache ();
merge_polygons_to (*mp_polygons, min_coherence, min_wc); merge_polygons_to (*mp_polygons, min_coherence, min_wc, join_properties_on_merge);
m_is_merged = true; m_is_merged = true;
@ -301,7 +307,7 @@ RegionDelegate *FlatRegion::merged () const
if (m_merged_polygons_valid) { if (m_merged_polygons_valid) {
return new FlatRegion (*mp_merged_polygons, true); return new FlatRegion (*mp_merged_polygons, true);
} else { } else {
return AsIfFlatRegion::merged (min_coherence (), 0); return AsIfFlatRegion::merged (min_coherence (), 0, join_properties_on_merge ());
} }
} else { } else {
@ -323,15 +329,12 @@ RegionDelegate *FlatRegion::add (const Region &other) const
} else { } else {
size_t n = new_region->raw_polygons ().size ();
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
++n; if (p.prop_id () == 0) {
} new_region->raw_polygons ().insert (*p);
} else {
new_region->raw_polygons ().reserve (db::Polygon::tag (), n); new_region->raw_polygons ().insert (db::PolygonWithProperties (*p, p.prop_id ()));
}
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
new_region->raw_polygons ().insert (*p);
} }
} }
@ -354,15 +357,12 @@ RegionDelegate *FlatRegion::add_in_place (const Region &other)
} else { } else {
size_t n = polygons.size ();
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
++n; if (p.prop_id () == 0) {
} polygons.insert (*p);
} else {
polygons.reserve (db::Polygon::tag (), n); polygons.insert (db::PolygonWithProperties (*p, p.prop_id ()));
}
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
polygons.insert (*p);
} }
} }

View File

@ -81,11 +81,11 @@ public:
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
virtual RegionDelegate *merged_in_place (); virtual RegionDelegate *merged_in_place ();
virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge);
virtual RegionDelegate *merged () const; virtual RegionDelegate *merged () const;
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const
{ {
return db::AsIfFlatRegion::merged (min_coherence, min_wc); return db::AsIfFlatRegion::merged (min_coherence, min_wc, join_properties_on_merge);
} }
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter); virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
@ -131,6 +131,7 @@ public:
protected: protected:
virtual void merged_semantics_changed (); virtual void merged_semantics_changed ();
virtual void join_properties_on_merge_changed ();
virtual void min_coherence_changed (); virtual void min_coherence_changed ();
virtual Box compute_bbox () const; virtual Box compute_bbox () const;
void invalidate_cache (); void invalidate_cache ();

Some files were not shown because too many files have changed in this diff Show More