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:
- os: "macos-13" # intel runner
cibuild: "*macosx*"
cibw_arch: "macos_x86_64"
macos-arch: "x86_64"
- os: "macos-14" # M1 runner
cibuild: "*macosx*"
cibw_arch: "macos_arm64"
macos-arch: "arm64"
- os: "ubuntu-latest"
cibuild: "*manylinux*"
cibw_arch: "manylinux"
- os: "ubuntu-latest"
cibuild: "*musllinux*"
cibw_arch: "musllinux"
- os: "ubuntu-24.04-arm" # aarch64 manylinux on ARM runner
cibuild: "*manylinux*"
cibw_arch: "aarch64"
steps:
- name: Free Disk Space (Ubuntu)
if: matrix.os == 'ubuntu-latest'
@ -44,29 +51,44 @@ jobs:
uses: styfle/cancel-workflow-action@0.12.1
- uses: actions/checkout@v4
- name: ccache
if: matrix.os != 'ubuntu-24.04-arm'
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.cibuild }} # Make cache specific to OS
max-size: "5G"
- name: Install dependencies
if: matrix.os != 'ubuntu-24.04-arm'
run: |
env
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH
HOST_CCACHE_DIR="$(ccache -k cache_dir)"
mkdir -p $HOST_CCACHE_DIR
- name: Build wheels # check https://cibuildwheel.readthedocs.io/en/stable/setup/#github-actions
uses: pypa/cibuildwheel@v2.22.0
# to supply options, put them in 'env', like:
# env:
# CIBW_SOME_OPTION: value
- name: Build wheels (ARM)
if: matrix.os == 'ubuntu-24.04-arm'
uses: pypa/cibuildwheel@v3.1.3
env:
# 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:
CIBW_BUILD: ${{ matrix.cibuild }}
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
CIBW_DEPENDENCY_VERSIONS_MACOS: cibw_constraints.txt
- 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
run: |
env
@ -76,8 +98,9 @@ jobs:
mv ./wheelhouse/.ccache $HOST_CCACHE_DIR
ls -la $HOST_CCACHE_DIR
ccache -s
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: artifact-${{ matrix.os }}-${{ matrix.cibw_arch }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
# The following was taken from https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/
@ -90,20 +113,21 @@ jobs:
- name: Build SDist
run: pipx run build --sdist
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: artifact-sdist
path: dist/*.tar.gz
upload_to_test_pypy:
needs: [build, make_sdist]
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: artifact
merge-multiple: true
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
with:
user: __token__
@ -115,12 +139,12 @@ jobs:
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: artifact
merge-multiple: true
path: dist
- uses: pypa/gh-action-pypi-publish@v1.12.3
- uses: pypa/gh-action-pypi-publish@v1.12.4
with:
user: __token__
password: ${{ secrets.pypi_password }}

View File

@ -1,12 +1,11 @@
klayout is packaged by Peter C.S. Scholtens <peter.scholtens@xs4all.nl>
and Matthias Köfferlein <matthias@koefferlein.de>
klayout is packaged by Matthias Köfferlein <matthias@koefferlein.de>
and was obtained from https://www.klayout.org/downloads/source/klayout-%VERSION%.tar.gz
Authors:
Matthias Köfferlein
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
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):
* 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

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
* 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/rdb/rdb *.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/pymod *.pyi
recursive-include src/plugins/*/db_plugin *.cc *.h

View File

@ -92,7 +92,8 @@ jobs:
displayName: 'Download and Extract KLayout bits'
- 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'
- script: |

View File

@ -11,16 +11,18 @@ if [[ -f "/etc/centos-release" ]]; then
[ $s -eq 0 ] || exit $s
if [[ -d "/usr/lib64/ccache" ]]; then
ln -s /usr/bin/ccache /usr/lib64/ccache/c++
ln -s /usr/bin/ccache /usr/lib64/ccache/cc
ln -s /usr/bin/ccache /usr/lib64/ccache/gcc
ln -s /usr/bin/ccache /usr/lib64/ccache/g++
for comp in c++ cc gcc g++; do
if ! [ -e /usr/lib64/ccache/$comp ]; then
ln -s /usr/bin/ccache /usr/lib64/ccache/$comp
fi
done
export PATH="/usr/lib64/ccache:$PATH"
elif [[ -d "/usr/lib/ccache" ]]; then
ln -s /usr/bin/ccache /usr/lib/ccache/c++
ln -s /usr/bin/ccache /usr/lib/ccache/cc
ln -s /usr/bin/ccache /usr/lib/ccache/gcc
ln -s /usr/bin/ccache /usr/lib/ccache/g++
for comp in c++ cc gcc g++; do
if ! [ -e /usr/lib/ccache/$comp ]; then
ln -s /usr/bin/ccache /usr/lib/ccache/$comp
fi
done
export PATH="/usr/lib/ccache:$PATH"
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>
Last modified: 2025-01-19<br>
Last modified: 2025-05-30<br>
# 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:
* Sonoma (14.x) : the primary development environment
* Ventura (13.x) : experimental
* Sequoia (15.x) : -- ditto --
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:
* Sequoia (15.x) : the primary development environment
* Sonoma (14.x) : experimental
* Ventura (13.x) : -- ditto --
Building KLayout for the previous operating systems listed below has been discontinued.<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)
* 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>
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/
```
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>
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' >>
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
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value
@ -123,7 +123,7 @@ $ [python] ./build4mac.py
```
# 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.
### 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`.
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
$ ./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
```
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.
* "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.
@ -185,7 +185,7 @@ $ ./build4mac.py -q qt5macports -r mp33 -p mp312
$ ./build4mac.py -q qt5macports -r mp33 -p mp312 -Y
```
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.
* "qt5MP" means that Qt5 from MacPorts is used.
* "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
```
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.
* "qt6Brew" means that Qt6 from Homebrew is used.
* "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
```
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.
* "qt6Brew" means that Qt6 from Homebrew is used.
* "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
```
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.
* "qt5MP" means that Qt5 from MacPorts is used.
* "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.
### 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 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
```
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.
* "qt5Ana3" means that Qt5 from Anaconda3 is used.
* "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,
```
$ 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>
* **`LW-klayout-0.29.11-macOS-Sonoma-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`** ---(1) the main DMG file
* **`LW-klayout-0.30.2-macOS-Sequoia-1-qt5MP-Rmp33Pmp312.dmg.md5`** ---(2) MD5-value text file
# 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>

View File

@ -5,7 +5,7 @@
# File: "macbuild/build4mac.py"
#
# 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 os
@ -45,7 +45,7 @@ def GenerateUsage(platform):
usage = "\n"
usage += "-----------------------------------------------------------------------------------------------------------\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 += "$ [python] ./build4mac.py\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"
cmd4_args = " -m setup clean --all \\\n"
#--------------------------------------------------------------------
#-----------------------------------------------------------------------------------
# [4] Make the consolidated command lines
#--------------------------------------------------------------------
# "caffeinate" makes the CPU run at full speed even when the screen is locked.
#-----------------------------------------------------------------------------------
command1 = "time"
command1 += " \\\n %s \\\n" % parameters['python']
command1 += " \\\n caffeinate -i %s \\\n" % parameters['python']
command1 += cmd1_args
command1 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command1 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
command2 = "time"
command2 += " \\\n %s \\\n" % parameters['python']
command2 += " \\\n caffeinate -i %s \\\n" % parameters['python']
command2 += cmd2_args
command2 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command2 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
command3 = "time"
command3 += " \\\n %s \\\n" % deloc_cmd
command3 += " \\\n caffeinate -i %s \\\n" % deloc_cmd
command3 += cmd3_args
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
command3 += " test ${PIPESTATUS[0]} -eq 0" # tee always exits with 0
command4 = "time"
command4 += " \\\n %s \\\n" % parameters['python']
command4 += " \\\n caffeinate -i %s \\\n" % parameters['python']
command4 += cmd4_args
command4 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
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
# 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:
command3 = "time"
command3 += " \\\n %s \\\n" % deloc_cmd
command3 += " \\\n caffeinate -i %s \\\n" % deloc_cmd
command3 += " %s \\\n" % cmd3_args[0]
command3 += " 2>&1 | tee -a %s; \\\n" % parameters['logfile']
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
# 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
# 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":
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:
print( "", file=sys.stderr )
print( "-------------------------------------------------------------", file=sys.stderr )
@ -1114,11 +1115,12 @@ def Run_Build_Command(config, parameters):
else:
cmd_args += " \\\n -nopython"
#-----------------------------------------------------
#-----------------------------------------------------------------------------------
# [4] Make the consolidated command line
#-----------------------------------------------------
# "caffeinate" makes the CPU run at full speed even when the screen is locked.
#-----------------------------------------------------------------------------------
command = "time"
command += " \\\n %s" % parameters['build_cmd']
command += " \\\n caffeinate -i %s" % parameters['build_cmd']
command += cmd_args
command += " 2>&1 | tee %s; \\\n" % parameters['logfile']
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
# To use Python3.1 from Homebrew on Sonoma...
# To use Python3.11 from Homebrew on Sequoia...
# in "/usr/local/opt/python@3.11/lib/"
# Python.framework -> ../Frameworks/Python.framework/ <=== this symbolic was needed
# pkgconfig/
#
# 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
# Sonoma{kazzz-s} lib (2)% ll
# Sequoia{kazzz-s} lib (2)% ll
# total 0
# drwxr-xr-x 4 kazzz-s admin 128 9 21 23:03 .
# 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/
# 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
# Sonoma{kazzz-s} Versions (4)% ll
# Sequoia{kazzz-s} Versions (4)% ll
# total 0
# 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 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/
#
# Sonoma{kazzz-s} Python.framework (5)% pwd
# Sequoia{kazzz-s} Python.framework (5)% pwd
# /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
# drwxr-xr-x 6 kazzz-s admin 192 9 21 23:03 .
# drwxr-xr-x 3 kazzz-s admin 96 9 7 10:03 ..

View File

@ -6,7 +6,7 @@
#
# Here are dictionaries of ...
# 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.
#===============================================================================
@ -192,7 +192,7 @@ RubySequoia = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions
# install with 'sudo port install ruby33'
# [Key Type Name] = 'MP33'
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'
}

View File

@ -6,7 +6,7 @@
#
# Here are utility functions and classes ...
# 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.
#========================================================================================

View File

@ -5,7 +5,7 @@
# File: "macbuild/macQAT.py"
#
# 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.
#
# This script must be copied to a "*.macQAT/" directory to run.

View File

@ -4,7 +4,7 @@
# File: "macbuild/macQAT.sh"
#
# 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.
#
# This script must be copied to a "*.macQAT/" directory to run.

View File

@ -4,7 +4,7 @@
# File: "macbuild/macQAT2.sh"
#
# 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.
#
# 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 += "<< 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 += "$ [python] ./makeDMG4mac.py\n"
Usage += " option & argument : descriptions | default value\n"
Usage += " ----------------------------------------------------------------------------------+-----------------\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 += " <-m|--make> : make a compressed DMG file | disabled\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
#
# The package directory name should look like:
# * ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312 --- (1)
# * LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312
# * HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311
# * ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312 --- (1)
# * LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312
# * HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311
#
# * ST-qt6MP.pkg.macos-Sonoma-release-RsysPsys
# * LW-qt6MP.pkg.macos-Sonoma-release-Rmp33Pmp312
# * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
#
# 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;
# on failure, -1
@ -268,15 +268,15 @@ def CheckPkgDirectory():
#-----------------------------------------------------------------------------------------------
# [2] Identify (Qt, Ruby, Python) from PkgDir
# * ST-qt5MP.pkg.macos-Sonoma-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Sonoma-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Sonoma-release-Rhb34Phb312
# * LW-qt5MP.pkg.macos-Sonoma-release-Rmp33Pmp312
# * HW-qt6Brew.pkg.macos-Sonoma-release-RsysPhb311
# * EX-qt5MP.pkg.macos-Sonoma-release-Rhb34Pmp312
# * ST-qt5MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt5Ana3.pkg.macos-Sequoia-release-Rana3Pana3
# * LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb312
# * LW-qt5MP.pkg.macos-Sequoia-release-Rmp33Pmp312
# * HW-qt6Brew.pkg.macos-Sequoia-release-RsysPhb311
# * EX-qt5MP.pkg.macos-Sequoia-release-Rhb34Pmp312
#
# * ST-qt6MP.pkg.macos-Sonoma-release-RsysPsys
# * LW-qt6MP.pkg.macos-Sonoma-release-Rmp33Pmp312
# * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
# * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
#-----------------------------------------------------------------------------------------------
# 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]+)'
@ -424,7 +424,7 @@ def CheckPkgDirectory():
#------------------------------------------------------
# [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] )
#------------------------------------------------------
@ -671,14 +671,14 @@ def MakeTargetDMGFile(msg=""):
imageDest = "%s/.background" % MountDir
if not os.path.isdir(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)
#--------------------------------------------------------
# (6) Create 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)
#--------------------------------------------------------
@ -702,7 +702,7 @@ def MakeTargetDMGFile(msg=""):
print( ">>> (8) Copying the volume icon..." )
iconsSrc = "macbuild/Resources/%s" % VolumeIcons
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
os.system(command1)
sleep(2)
@ -713,7 +713,7 @@ def MakeTargetDMGFile(msg=""):
# (9) Change the permission
#--------------------------------------------------------
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)
#--------------------------------------------------------

View File

@ -339,7 +339,7 @@ def Parse_CommandLine_Arguments():
Usage += " (3) $ ./nightlyBuild.py --test |\n"
Usage += " (4) $ ./nightlyBuild.py --check (confirm the QA Test results) |\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 += "-----------------------------------------------------------------------------+----------------------------\n"

View File

@ -18,7 +18,7 @@ qtVer,target,bdType
5,0,r
5,1,r
6,2,r
6,13,r
5,13,r
5,4,r
#6,0,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 += " option & argument : descriptions | default value\n"
Usage += " -------------------------------------------------------------------+---------------\n"
Usage += " <-v|--version <number>>: in ['3.8', '3.9', '3.10', '3.11', '3.12', | ''\n"
Usage += " '3.13'] |\n"
Usage += " <-v|--version <number>>: in ['3.11', '3.12','3.13'] | ''\n"
Usage += " [-u|-unlink] : unlink only | disabled\n"
Usage += " [-?|--?] : print this usage and exit | disabled\n"
Usage += "----------------------------------------------------------------------+-----------------\n"
@ -50,7 +49,7 @@ def Parse_CLI_Args():
p.add_option( '-v', '--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',
action='store_true',
@ -75,7 +74,7 @@ def Parse_CLI_Args():
Version = opt.version
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(Usage)
sys.exit(0)

View File

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

View File

@ -57,6 +57,9 @@ $python $inst/stubgen.py tl >$pyi_srcdir/tlcore.pyi
echo "Generating stubs for db .."
$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 .."
$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"))
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
@ -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::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 "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 "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 "QThread", [ "<QThread>", "<QAbstractEventDispatcher>" ]
@ -551,6 +653,7 @@ no_default_ctor "QModelRoleData"
no_default_ctor "QPartialOrdering"
no_default_ctor "QOperatingSystemVersion"
no_default_ctor "QStringConverter"
no_default_ctor "QStringConverterBase"
drop_method "QMessageLogger", /QMessageLogger::critical.*\.\.\./ # does not support ...
drop_method "QMessageLogger", /QMessageLogger::debug.*\.\.\./ # does not support ...

View File

@ -592,6 +592,25 @@ _db = Library(
)
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
@ -869,6 +888,28 @@ db = Extension(
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
@ -987,7 +1028,7 @@ if __name__ == "__main__":
setup(
name=config.root,
version=config.version(),
license="GNU GPLv3",
license="GPL-3.0-or-later",
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",
author="Matthias Koefferlein",
@ -996,7 +1037,6 @@ if __name__ == "__main__":
# Recommended classifiers
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
@ -1011,8 +1051,8 @@ if __name__ == "__main__":
package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]},
data_files=[(config.root, ["src/pymod/distutils_src/klayout/py.typed"])],
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
+ [tl, db, lib, rdb, lay, pya],
+ [tl, db, pex, lib, rdb, lay, pya],
cmdclass={'build_ext': klayout_build_ext}
)

View File

@ -419,6 +419,19 @@ PropertiesPage::description () const
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
PropertiesPage::leave ()
{
@ -517,7 +530,7 @@ PropertiesPage::readonly ()
}
void
PropertiesPage::apply ()
PropertiesPage::apply (bool /*commit*/)
{
ant::Object obj;
get_object (obj);

View File

@ -47,10 +47,11 @@ public:
virtual void select_entries (const std::vector<size_t> &entries);
virtual std::string description (size_t entry) const;
virtual std::string description () const;
virtual void confine_selection (const std::vector<size_t> &remaining_entries);
virtual void update ();
virtual void leave ();
virtual bool readonly ();
virtual void apply ();
virtual void apply (bool commit);
private slots:
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 ();
const ant::Object *robj_min = 0;
for (std::map<obj_iterator, unsigned int>::const_iterator r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r->first).ptr ());
for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
if (robj) {
double 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
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 ());
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
clear_selection ();
m_selected.insert (std::make_pair (ri, 0));
m_selected.insert (ri);
m_current = *robj;
m_original = m_current;
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
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_original = m_current;
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) {
// 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) {
// compute moved object and replace
ant::Object *rnew = new ant::Object (*robj);
rnew->transform (m_trans);
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);
}
@ -1690,7 +1690,7 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
// replace the ruler that was moved
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 ());
// clear the selection (that was artifically created before)
@ -1717,9 +1717,8 @@ Service::selection_to_view ()
}
m_rulers.clear ();
m_rulers.reserve (m_selected.size ());
for (std::map<obj_iterator, unsigned int>::iterator 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->first->ptr ());
for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
m_rulers.push_back (new ant::View (this, robj, true /*selected*/));
}
}
@ -1728,8 +1727,8 @@ db::DBox
Service::selection_bbox ()
{
db::DBox box;
for (std::map<obj_iterator, unsigned int>::iterator r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> (r->first->ptr ());
for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
if (robj) {
box += robj->box ();
}
@ -1741,16 +1740,16 @@ void
Service::transform (const db::DCplxTrans &trans)
{
// 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) {
// compute transformed object and replace
int id = robj->id ();
ant::Object *rnew = new ant::Object (*robj);
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);
}
@ -2173,9 +2172,8 @@ void
Service::copy_selected ()
{
// 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) {
r->second = (unsigned int) m_rulers.size ();
const ant::Object *robj = dynamic_cast<const ant::Object *> (r->first->ptr ());
for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
const ant::Object *robj = dynamic_cast<const ant::Object *> ((*r)->ptr ());
if (robj) {
db::Clipboard::instance () += new db::ClipboardValue<ant::Object> (*robj);
}
@ -2212,7 +2210,7 @@ Service::paste ()
if (! new_objects.empty ()) {
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 ();
@ -2240,8 +2238,8 @@ Service::del_selected ()
// positions will hold a set of iterators that are to be erased
std::vector <lay::AnnotationShapes::iterator> positions;
positions.reserve (m_selected.size ());
for (std::map<obj_iterator, unsigned int>::iterator r = m_selected.begin (); r != m_selected.end (); ++r) {
positions.push_back (r->first);
for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
positions.push_back (*r);
}
// clear selection
@ -2276,7 +2274,7 @@ Service::select (obj_iterator obj, lay::Editable::SelectionMode mode)
if (mode == lay::Editable::Replace || mode == lay::Editable::Add) {
// select
if (m_selected.find (obj) == m_selected.end ()) {
m_selected.insert (std::make_pair (obj, 0));
m_selected.insert (obj);
return true;
}
} 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 ()) {
m_selected.erase (obj);
} else {
m_selected.insert (std::make_pair (obj, 0));
m_selected.insert (obj);
}
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
// 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) {
exclude = &m_previous_selection;
} 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) {
const ant::Object *robj = dynamic_cast <const ant::Object *> (r->ptr ());
if (robj == mp_transient_ruler->ruler ()) {
m_selected.insert (std::make_pair (r, 0));
m_selected.insert (r);
selection_to_view ();
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
// 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) {
exclude = &m_previous_selection;
} 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
if (any_selected) {
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;
}
@ -2667,11 +2665,22 @@ Service::get_selection (std::vector <obj_iterator> &sel) const
sel.reserve (m_selected.size ());
// 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) {
sel.push_back (r->first);
for (auto r = m_selected.begin (); r != m_selected.end (); ++r) {
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
Service::delete_ruler (obj_iterator pos)
{

View File

@ -381,14 +381,19 @@ public:
#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;
/**
* @brief Sets the selection for the properties page
*/
void set_selection (const std::vector <obj_iterator> &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;
}
@ -558,9 +563,9 @@ private:
// and the moved rules in move mode
std::vector<ant::View *> m_rulers;
// The selection
std::map<obj_iterator, unsigned int> m_selected;
std::set<obj_iterator> m_selected;
// 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
db::DPoint m_p1;
// The transformation in MoveSelection mode

View File

@ -1263,7 +1263,7 @@ class AnnotationSelectionIterator
{
public:
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 value_type reference;
typedef std::forward_iterator_tag iterator_category;
@ -1292,7 +1292,7 @@ public:
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:

View File

@ -32,9 +32,9 @@ HEADERS = \
RESOURCES = \
INCLUDEPATH += $$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 $$LYM_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_lym
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 $$PEX_INC $$LYM_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_pex -lklayout_lym
INCLUDEPATH += $$RBA_INC
DEPENDPATH += $$RBA_INC

View File

@ -27,6 +27,7 @@
#include "dbReader.h"
#include "dbWriter.h"
#include "tlCommandLineParser.h"
#include "tlTimer.h"
namespace bd
{
@ -42,8 +43,13 @@ int converter_main (int argc, char *argv[], const std::string &format)
generic_reader_options.add_options (cmd);
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. "
"This provides some cheap, but risky way of merging files. Beware of cell name conflicts.")
"Multiple files can be combined using '+' or ','. '+' will combine the files in 'blending' mode. "
"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))
;
@ -53,6 +59,8 @@ int converter_main (int argc, char *argv[], const std::string &format)
db::Layout layout;
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
{
db::LoadLayoutOptions load_options;
generic_reader_options.configure (load_options);

View File

@ -22,6 +22,8 @@
#include "bdReaderOptions.h"
#include "dbLoadLayoutOptions.h"
#include "dbLayerMapping.h"
#include "dbCellMapping.h"
#include "tlCommandLineParser.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_joined_paths = load_options.get_option_by_name ("lefdef_config.joined_paths").to_bool ();
m_lefdef_map_file = load_options.get_option_by_name ("lefdef_config.map_file").to_string ();
m_lefdef_macro_resolution_mode = load_options.get_option_by_name ("lefdef_config.macro_resolution_mode").to_int ();
// 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
@ -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;
for (size_t pp = 0; (pp = find_file_sep (infile, p)) != std::string::npos; p = pp + 1) {
files.push_back (std::string (infile, p, pp - p));
while (true) {
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;
}
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 "tlLog.h"
#include "tlCommandLineParser.h"
#include "tlTimer.h"
struct ClipData
@ -200,6 +201,8 @@ BD_PUBLIC int strmclip (int argc, char *argv[])
cmd.parse (argc, argv);
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
clip (data);
return 0;

View File

@ -25,6 +25,7 @@
#include "dbLayoutDiff.h"
#include "dbReader.h"
#include "tlCommandLineParser.h"
#include "tlTimer.h"
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");
}
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Total")));
db::Layout layout_a;
db::Layout layout_b;

View File

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

View File

@ -32,6 +32,8 @@
#include "gsiExpression.h"
#include "tlCommandLineParser.h"
#include "tlThreads.h"
#include "tlThreadedWorkers.h"
#include "tlTimer.h"
namespace {
@ -319,7 +321,8 @@ struct XORData
dont_summarize_missing_layers (false), silent (false), no_summary (false),
threads (0),
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;
@ -336,6 +339,8 @@ struct XORData
db::cell_index_type output_cell;
std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc> l2l_map;
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_b;
@ -572,14 +579,22 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
if (! silent && ! no_summary) {
if (result) {
tl::info << "No differences found";
tl::info << tl::to_string (tr ("No differences found"));
} else {
const char *line_format = " %-10s %-12s %s";
const char *sep = " -------------------------------------------------------";
tl::info << "Result summary (layers without differences are not shown):" << tl::endl;
tl::info << tl::sprintf (line_format, "Layer", "Output", "Differences (shape count)") << tl::endl << sep;
std::string headline;
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;
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) {
ti = r->first.first;
if (tolerances[ti] > db::epsilon) {
tl::info << tl::endl << "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 << tl::endl << tl::to_string (tr ("Tolerance ")) << tl::micron_to_string (tolerances[ti]) << ":" << tl::endl;
tl::info << headline << tl::endl << sep;
}
}
std::string out ("-");
std::string value;
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) {
value = "(no such layer in second layout)";
value = tl::to_string (tr ("(no such layer in second layout)"));
} else if (! r->second.is_empty ()) {
if (r->second.layer_output >= 0 && r->second.layout) {
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;
}
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.
// 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 ());
if (tl::verbosity () >= 20) {
@ -779,98 +953,18 @@ bool run_deep_xor (const XORData &xor_data)
xor_data.output_layout->dbu (dbu);
}
bool result = true;
int index = 1;
XORJob job (xor_data.threads);
for (std::map<db::LayerProperties, std::pair<int, int> >::const_iterator ll = xor_data.l2l_map.begin (); ll != xor_data.l2l_map.end (); ++ll) {
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;
job.schedule (new XORTask (&xor_data, ll->first, ll->second.first, ll->second.second, dbu));
}
// 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) {
result = r->second.is_empty ();
}

View File

@ -19,7 +19,7 @@ SOURCES = $$PWD/bd/main.cc
INCLUDEPATH += $$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
DEPENDPATH += $$RBA_INC

View File

@ -186,3 +186,525 @@ TEST(6)
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"
"\n"
" Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n"
" ----------------------------------------------------------------\n"
" 3/0 3/0 30\n"
" 6/0 6/0 41\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"
"Result summary (layers without differences are not shown):\n"
"\n"
" Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n"
" Layer Output Differences (hierarchical shape count)\n"
" ----------------------------------------------------------------\n"
" 3/0 3/0 3\n"
" 6/0 6/0 314\n"
" 8/1 8/1 1\n"
@ -177,7 +177,7 @@ TEST(1B_Flat)
"Result summary (layers without differences are not shown):\n"
"\n"
" Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n"
" ----------------------------------------------------------------\n"
" 3/0 - 30\n"
" 6/0 - 41\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"
"Result summary (layers without differences are not shown):\n"
"\n"
" Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n"
" 3/0 - 30\n"
" Layer Output Differences (hierarchical shape count)\n"
" ----------------------------------------------------------------\n"
" 3/0 - 3\n"
" 6/0 - 314\n"
" 8/1 - 1\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"
"\n"
" Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n"
" ----------------------------------------------------------------\n"
" 3/0 - 31\n"
" 6/0 - 217\n"
" 8/1 - 168\n"
@ -483,7 +483,7 @@ TEST(3_FlatCountHeal)
"Result summary (layers without differences are not shown):\n"
"\n"
" Layer Output Differences (shape count)\n"
" -------------------------------------------------------\n"
" ----------------------------------------------------------------\n"
" 3/0 - 30\n"
" 6/0 - 41\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"
);
}
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 \
dbManager.cc \
dbMatrix.cc \
dbMeasureEval.cc \
dbMemStatistics.cc \
dbMutableEdgePairs.cc \
dbMutableEdges.cc \
@ -70,15 +71,21 @@ SOURCES = \
dbNetlistSpiceReaderExpressionParser.cc \
dbObject.cc \
dbObjectWithProperties.cc \
dbPLC.cc \
dbPLCConvexDecomposition.cc \
dbPLCTriangulation.cc \
dbPath.cc \
dbPCellDeclaration.cc \
dbPCellHeader.cc \
dbPCellVariant.cc \
dbPoint.cc \
dbPolygon.cc \
dbPolygonNeighborhood.cc \
dbPolygonTools.cc \
dbPolygonGenerators.cc \
dbPropertiesFilter.cc \
dbPropertiesRepository.cc \
dbQuadTree.cc \
dbReader.cc \
dbRecursiveInstanceIterator.cc \
dbRecursiveShapeIterator.cc \
@ -102,8 +109,6 @@ SOURCES = \
dbTextWriter.cc \
dbTilingProcessor.cc \
dbTrans.cc \
dbTriangle.cc \
dbTriangles.cc \
dbUserObject.cc \
dbUtils.cc \
dbVector.cc \
@ -136,10 +141,12 @@ SOURCES = \
gsiDeclDbLog.cc \
gsiDeclDbManager.cc \
gsiDeclDbMatrix.cc \
gsiDeclDbMeasureHelpers.cc \
gsiDeclDbMetaInfo.cc \
gsiDeclDbPath.cc \
gsiDeclDbPoint.cc \
gsiDeclDbPolygon.cc \
gsiDeclDbPolygonNeighborhood.cc \
gsiDeclDbReader.cc \
gsiDeclDbRecursiveInstanceIterator.cc \
gsiDeclDbRecursiveShapeIterator.cc \
@ -292,6 +299,7 @@ HEADERS = \
dbLog.h \
dbManager.h \
dbMatrix.h \
dbMeasureEval.h \
dbMemStatistics.h \
dbMetaInfo.h \
dbMutableEdgePairs.h \
@ -306,16 +314,22 @@ HEADERS = \
dbObject.h \
dbObjectTag.h \
dbObjectWithProperties.h \
dbPLC.h \
dbPLCConvexDecomposition.h \
dbPLCTriangulation.h \
dbPath.h \
dbPCellDeclaration.h \
dbPCellHeader.h \
dbPCellVariant.h \
dbPoint.h \
dbPolygon.h \
dbPolygonNeighborhood.h \
dbPolygonTools.h \
dbPolygonGenerators.h \
dbPropertiesFilter.h \
dbPropertiesRepository.h \
dbPropertyConstraint.h \
dbQuadTree.h \
dbReader.h \
dbRecursiveInstanceIterator.h \
dbRecursiveShapeIterator.h \
@ -338,8 +352,6 @@ HEADERS = \
dbTextWriter.h \
dbTilingProcessor.h \
dbTrans.h \
dbTriangle.h \
dbTriangles.h \
dbTypes.h \
dbUserObject.h \
dbUtils.h \
@ -425,6 +437,7 @@ HEADERS = \
dbNetShape.h \
dbShapeCollection.h \
dbShapeCollectionUtils.h \
gsiDeclDbMeasureHelpers.h \
gsiDeclDbPropertiesSupport.h
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:
trans_type m_trans;
basic_array_iterator <Coord> *mp_base;

View File

@ -81,6 +81,9 @@ AsIfFlatEdgePairs::to_string (size_t nmax) const
}
first = false;
os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
}
if (! p.at_end ()) {
os << "...";
@ -157,13 +160,17 @@ AsIfFlatEdgePairs::processed (const EdgePairProcessorBase &filter) const
{
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) {
res_edge_pairs.clear ();
filter.process (*e, res_edge_pairs);
for (std::vector<db::EdgePair>::const_iterator er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++er) {
edge_pairs->insert (*er);
filter.process (e.wp (), res_edge_pairs);
for (auto er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++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);
}
std::vector<db::Polygon> res_polygons;
std::vector<db::PolygonWithProperties> res_polygons;
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
res_polygons.clear ();
filter.process (*e, res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
db::properties_id_type prop_id = e.prop_id ();
if (prop_id != 0) {
region->insert (db::PolygonWithProperties (*pr, prop_id));
} else {
filter.process (e.wp (), res_polygons);
for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
if (pr->properties_id () != 0) {
region->insert (*pr);
} else {
region->insert (pr->base ());
}
}
}
@ -206,17 +212,16 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter
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) {
res_edges.clear ();
filter.process (*e, res_edges);
for (std::vector<db::Edge>::const_iterator pr = res_edges.begin (); pr != res_edges.end (); ++pr) {
db::properties_id_type prop_id = e.prop_id ();
if (prop_id != 0) {
edges->insert (db::EdgeWithProperties (*pr, prop_id));
} else {
filter.process (e.wp (), res_edges);
for (auto pr = res_edges.begin (); pr != res_edges.end (); ++pr) {
if (pr->properties_id () != 0) {
edges->insert (*pr);
} else {
edges->insert (pr->base ());
}
}
}
@ -224,25 +229,44 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter
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 *
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
{
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) {
db::properties_id_type prop_id = p.prop_id ();
if (prop_id != 0) {
new_edge_pairs->insert (db::EdgePairWithProperties (*p, prop_id));
} else {
new_edge_pairs->insert (*p);
}
if (filter.selected (*p, p.prop_id ())) {
insert_ep (new_edge_pairs.get (), *p, p.prop_id ());
}
}
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 *
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));
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) {
db::properties_id_type prop_id = p.prop_id ();
if (prop_id) {
@ -646,10 +666,6 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
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) {
db::properties_id_type prop_id = p.prop_id ();
if (prop_id) {

View File

@ -53,6 +53,7 @@ public:
}
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)
{

View File

@ -89,6 +89,9 @@ AsIfFlatEdges::to_string (size_t nmax) const
}
first = false;
os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
}
if (! p.at_end ()) {
os << "...";
@ -645,13 +648,17 @@ AsIfFlatEdges::processed (const EdgeProcessorBase &filter) const
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) {
res_edges.clear ();
filter.process (*e, res_edges);
for (std::vector<db::Edge>::const_iterator er = res_edges.begin (); er != res_edges.end (); ++er) {
edges->insert (*er);
filter.process (e.wp (), res_edges);
for (auto er = res_edges.begin (); er != res_edges.end (); ++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);
}
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) {
res_edge_pairs.clear ();
filter.process (*e, res_edge_pairs);
for (std::vector<db::EdgePair>::const_iterator epr = res_edge_pairs.begin (); epr != res_edge_pairs.end (); ++epr) {
edge_pairs->insert (*epr);
filter.process (e.wp (), res_edge_pairs);
for (auto epr = res_edge_pairs.begin (); epr != res_edge_pairs.end (); ++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);
}
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) {
res_polygons.clear ();
filter.process (*e, res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
region->insert (*pr);
filter.process (e.wp (), res_polygons);
for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++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 ());
for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) {
new_region->insert (*p);
if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) {
new_region->insert (db::EdgeWithProperties (*p, p.prop_id ()));
} else {
new_region->insert (*p);
}
}
}
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 *
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->invalidate_cache ();
size_t n = new_edges->raw_edges ().size () + count ();
new_edges->reserve (n);
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 ();
@ -1023,15 +1067,19 @@ AsIfFlatEdges::add (const Edges &other) const
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) {
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) {
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 ();

View File

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

View File

@ -53,7 +53,7 @@ struct ResultCountingInserter
{
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)
{
// .. nothing yet ..
@ -70,7 +70,7 @@ struct ResultCountingInserter
}
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;
os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
}
if (! p.at_end ()) {
os << "...";
@ -152,31 +155,31 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcesso
}
result->reserve (n);
std::vector<db::Edge> heap;
std::vector<db::EdgeWithProperties> heap;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
db::properties_id_type prop_id = p.prop_id ();
if (proc) {
heap.clear ();
proc->process (*p, heap);
proc->process (p.wp (), heap);
for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, prop_id));
} else {
if (! filter || filter->selected (*e, e->properties_id ())) {
if (e->properties_id () != 0) {
result->insert (*e);
} else {
result->insert (e->base ());
}
}
}
} else {
auto prop_id = p.prop_id ();
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) {
result->insert (db::EdgeWithProperties (*e, prop_id));
} 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 ());
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
size_t n = 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) {
if (n == 0) {
prop_id = s.prop_id ();
} else if (! need_split_props && prop_id != s.prop_id ()) {
need_split_props = true;
} else if (! multiple_properties && prop_id != s.prop_id ()) {
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 ());
@ -417,8 +505,12 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const
std::unique_ptr<FlatRegion> new_region (new FlatRegion ());
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) {
new_region->insert (*p);
if (filter.selected (*p, p.prop_id ())) {
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 ();
}
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 *
AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const
{
@ -434,17 +553,17 @@ AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const
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) {
poly_res.clear ();
filter.process (*p, poly_res);
for (std::vector<db::Polygon>::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) {
if (p.prop_id () != 0) {
new_region->insert (db::PolygonWithProperties (*pr, p.prop_id ()));
} else {
filter.process (p.wp (), poly_res);
for (auto pr = poly_res.begin (); pr != poly_res.end (); ++pr) {
if (pr->properties_id () != 0) {
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);
}
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) {
edge_res.clear ();
filter.process (*p, edge_res);
for (std::vector<db::Edge>::const_iterator er = edge_res.begin (); er != edge_res.end (); ++er) {
if (p.prop_id () != 0) {
new_edges->insert (db::EdgeWithProperties (*er, p.prop_id ()));
} else {
filter.process (p.wp (), edge_res);
for (auto er = edge_res.begin (); er != edge_res.end (); ++er) {
if (er->properties_id () != 0) {
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);
}
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) {
edge_pair_res.clear ();
filter.process (*p, edge_pair_res);
for (std::vector<db::EdgePair>::const_iterator epr = edge_pair_res.begin (); epr != edge_pair_res.end (); ++epr) {
if (p.prop_id () != 0) {
new_edge_pairs->insert (db::EdgePairWithProperties (*epr, p.prop_id ()));
} else {
filter.process (p.wp (), edge_pair_res);
for (auto epr = edge_pair_res.begin (); epr != edge_pair_res.end (); ++epr) {
if (epr->properties_id () != 0) {
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 *
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 ()) {
@ -1233,7 +1352,7 @@ AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const
} else {
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 ();
@ -1818,12 +1937,12 @@ AsIfFlatRegion::add (const Region &other) const
new_region->set_is_merged (false);
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) {
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 ();
@ -1832,15 +1951,19 @@ AsIfFlatRegion::add (const Region &other) const
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) {
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) {
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 ();
@ -1849,7 +1972,7 @@ AsIfFlatRegion::add (const Region &other) const
}
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 ());
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 ()) {
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
for (auto sc = circuit->begin_subcircuits (); sc != circuit->end_subcircuits (); ++sc) {
const db::Circuit *circuit_ref = sc->circuit_ref ();
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::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")));
}
@ -1897,7 +2020,7 @@ AsIfFlatRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl:
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 ();
}

View File

@ -101,23 +101,24 @@ public:
}
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> filtered_pair (const PolygonFilterBase &filter) const;
virtual RegionDelegate *merged_in_place ()
{
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
{
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 dx, coord_type dy, unsigned int mode) const;
@ -287,7 +288,7 @@ public:
protected:
void update_bbox (const db::Box &box);
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;
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;
os << p->to_string ();
if (p.prop_id () != 0) {
os << db::properties (p.prop_id ()).to_dict_var ().to_string ();
}
}
if (! p.at_end ()) {
os << "...";
@ -156,26 +159,59 @@ AsIfFlatTexts::filtered (const TextFilterBase &filter) const
std::unique_ptr<FlatTexts> new_texts (new FlatTexts ());
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) {
new_texts->insert (*p);
if (filter.selected (*p, p.prop_id ())) {
if (p.prop_id () != 0) {
new_texts->insert (db::TextWithProperties (*p, p.prop_id ()));
} else {
new_texts->insert (*p);
}
}
}
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 *
AsIfFlatTexts::processed (const TextProcessorBase &filter) const
{
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) {
res_texts.clear ();
filter.process (*e, res_texts);
for (std::vector<db::Text>::const_iterator er = res_texts.begin (); er != res_texts.end (); ++er) {
texts->insert (*er);
filter.process (e.wp (), res_texts);
for (auto er = res_texts.begin (); er != res_texts.end (); ++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);
}
std::vector<db::Polygon> res_polygons;
std::vector<db::PolygonWithProperties> res_polygons;
for (TextsIterator e (begin ()); ! e.at_end (); ++e) {
res_polygons.clear ();
filter.process (*e, res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
if (e.prop_id () != 0) {
region->insert (db::PolygonWithProperties (*pr, e.prop_id ()));
} else {
filter.process (e.wp (), res_polygons);
for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
if (pr->properties_id () != 0) {
region->insert (*pr);
} else {
region->insert (pr->base ());
}
}
}
@ -209,14 +245,32 @@ AsIfFlatTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter)
}
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 ());
for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) {
db::Box box = tp->box ();
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 ();
@ -244,12 +298,12 @@ AsIfFlatTexts::add (const Texts &other) const
std::unique_ptr<FlatTexts> new_texts (new FlatTexts (*other_flat));
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) {
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 ();
@ -258,15 +312,19 @@ AsIfFlatTexts::add (const Texts &other) const
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) {
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) {
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 ();

View File

@ -54,6 +54,7 @@ public:
}
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)
{
@ -70,7 +71,7 @@ public:
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 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) {
return inst.bbox (*layout);
} else {
db::Box box = inst.bbox (*layout);
if (box.empty ()) {
return db::Box (db::Point (0, 0), db::Point (0, 0));
} else {
return box;
}
return inst.bbox_with_empty (*layout);
}
}
@ -52,11 +47,7 @@ DB_PUBLIC db::Box cell_box_convert_impl (const db::Cell &c, int layer, bool allo
} else if (allow_empty) {
return c.bbox ();
} else {
if (c.bbox ().empty ()) {
return db::Box (db::Point (0, 0), db::Point (0, 0));
} else {
return c.bbox ();
}
return c.bbox_with_empty ();
}
}

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),
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)
@ -128,6 +128,7 @@ Cell::operator= (const Cell &d)
m_locked = d.m_locked;
m_instances = d.m_instances;
m_bbox = d.m_bbox;
m_bbox_with_empty = d.m_bbox_with_empty;
m_bboxes = d.m_bboxes;
m_hier_levels = d.m_hier_levels;
m_prop_id = d.m_prop_id;
@ -282,6 +283,10 @@ Cell::update_bbox (unsigned int layers)
box_type org_bbox = m_bbox;
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
box_map org_bboxes;
org_bboxes.swap (m_bboxes);
@ -313,16 +318,21 @@ Cell::update_bbox (unsigned int layers)
m_bbox += lbox;
box_map::iterator b = m_bboxes.find (l);
if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (l, lbox));
m_bboxes.insert (std::make_pair (l, lbox));
} 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
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 ());
if (! sbox.empty ()) {
m_bbox += sbox;
sbox_all += sbox;
box_map::iterator b = m_bboxes.find (s->first);
if (b == m_bboxes.end ()) {
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
m_bbox_needs_update = false;
// 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
@ -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 &
Cell::bbox () const
{

View File

@ -536,6 +536,17 @@ public:
*/
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
*
@ -1098,7 +1109,7 @@ private:
mutable db::Layout *mp_layout;
shapes_map m_shapes_map;
instances_type m_instances;
box_type m_bbox;
box_type m_bbox, m_bbox_with_empty;
box_map m_bboxes;
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 ();
}
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::bbox (const db::Layout &g, unsigned int l) const
{

View File

@ -90,6 +90,15 @@ public:
*/
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
*

View File

@ -284,8 +284,17 @@ std::vector<db::cell_index_type> CellMapping::source_cells () const
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)
{
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_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;
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);
@ -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);
new_cells.push_back (new_cell);
new_cells_b.push_back (*b);
all_a2b.push_back (std::make_pair (new_cell, *b));
if (mapped_pairs) {
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
layout_a.start_changes ();
// Note: this avoids frequent cell index table rebuilds if source and target layout are identical
db::LayoutLocker locker (&layout_a);
// Create instances for the new cells in layout A according to their instantiation in layout B
double mag = layout_b.dbu () / layout_a.dbu ();
for (size_t i = 0; i < new_cells.size (); ++i) {
// Create instances for the new cells in layout A according to their instantiation in layout B
double mag = layout_b.dbu () / layout_a.dbu ();
for (auto i = all_a2b.begin (); i != all_a2b.end (); ++i) {
const db::Cell &b = layout_b.cell (new_cells_b [i]);
for (db::Cell::parent_inst_iterator pb = b.begin_parent_insts (); ! pb.at_end (); ++pb) {
const db::Cell &b = layout_b.cell (i->second);
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 ();
bci.object ().cell_index (new_cells [i]);
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);
}
db::CellInstArray bci = bi.cell_inst ();
bci.object ().cell_index (i->first);
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);
}
}
}
// 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;
/**
* @brief Gets the target cells
*/
std::vector<db::cell_index_type> target_cells () const;
/**
* @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 ()
: mp_red ()
{

View File

@ -166,6 +166,51 @@ private:
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
*

View File

@ -146,8 +146,6 @@ CommonReaderBase::name_for_id (size_t id) const
void
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<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) {
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 (iname->second.second != iid->second.second) {
@ -240,7 +251,7 @@ CommonReaderBase::cell_for_instance (db::Layout &layout, const std::string &cn)
}
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);
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
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);
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
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
if (with_meta) {
auto ib = layout.begin_meta (src_cell.cell_index ());
auto ie = layout.end_meta (src_cell.cell_index ());
auto ib = layout.begin_meta (src_cell_index);
auto ie = layout.end_meta (src_cell_index);
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
layout.delete_cell (src_cell.cell_index ());
m_temp_cells.erase (src_cell_index);
layout.delete_cell (src_cell_index);
}
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_multi_mapping_placeholders.clear ();
m_layer_cache.clear ();
@ -621,7 +638,7 @@ void
CommonReader::init (const LoadLayoutOptions &options)
{
ReaderBase::init (options);
CommonReaderBase::init ();
CommonReaderBase::start ();
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
set_conflict_resolution_mode (common_options.cell_conflict_resolution);

View File

@ -207,7 +207,7 @@ public:
/**
* @brief Re-initialize: clears the tables and caches
*/
void init ();
void start ();
/**
* @brief Sets a value indicating whether to create layers
@ -242,12 +242,12 @@ protected:
/**
* @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
*/
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

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) {
(*c)->keep ();
m_children.push_back (*c);
}
init ();
if (! no_init) {
init ();
}
}
CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode ()
@ -362,6 +365,11 @@ CompoundRegionMultiInputOperationNode::init ()
for (tl::shared_collection<CompoundRegionOperationNode>::iterator i = m_children.begin (); i != m_children.end (); ++i) {
m_vars.add (i->vars ());
}
// add the local variant reducer
if (local_vars ()) {
m_vars.add (local_vars ());
}
}
CompoundRegionMultiInputOperationNode::~CompoundRegionMultiInputOperationNode ()
@ -1260,7 +1268,13 @@ CompoundRegionEdgePairFilterOperationNode::do_compute_local (CompoundRegionOpera
bool
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:
CompoundRegionMultiInputOperationNode (const std::vector<CompoundRegionOperationNode *> &children);
CompoundRegionMultiInputOperationNode (const std::vector<CompoundRegionOperationNode *> &children, bool no_init = false);
CompoundRegionMultiInputOperationNode ();
CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *child);
CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b);
@ -521,14 +521,16 @@ protected:
CompoundRegionOperationNode *child (unsigned int index);
const CompoundRegionOperationNode *child (unsigned int index) const;
virtual const TransformationReducer *local_vars () const { return 0; }
void init ();
private:
tl::shared_collection<CompoundRegionOperationNode> m_children;
// maps child#,layer# to layer# of child:
std::map<std::pair<unsigned int, unsigned int>, unsigned int> m_map_layer_to_child;
std::vector<db::Region *> m_inputs;
CompoundTransformationReducer m_vars;
void init ();
};
@ -1015,14 +1017,12 @@ private:
child (0)->compute_local (cache, layout, cell, interactions, one, proc);
if (m_sum_of_set) {
std::unordered_set<T> wo_props;
wo_props.insert (one.front ().begin (), one.front ().end ());
if (mp_filter->selected_set (wo_props)) {
if (mp_filter->selected_set (one.front ())) {
results.front ().insert (one.front ().begin (), one.front ().end ());
}
} else {
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);
}
}
@ -1066,14 +1066,12 @@ private:
child (0)->compute_local (cache, layout, cell, interactions, one, proc);
if (m_sum_of) {
std::unordered_set<db::Edge> wo_props;
wo_props.insert (one.front ().begin (), one.front ().end ());
if (mp_filter->selected (wo_props)) {
if (mp_filter->selected_set (one.front ())) {
results.front ().insert (one.front ().begin (), one.front ().end ());
}
} else {
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);
}
}
@ -1108,6 +1106,7 @@ private:
bool m_owns_filter;
bool is_selected (const db::EdgePair &p) const;
bool is_selected (const db::EdgePairWithProperties &p) const;
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

View File

@ -161,12 +161,16 @@ EdgePairsDelegate *DeepEdgePairs::clone () const
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 ();
if (layout.begin_top_down () != layout.end_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 ();
@ -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")));
}
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
{
return false;
@ -340,9 +349,12 @@ DeepEdgePairs::add_in_place (const EdgePairs &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
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;
@ -365,18 +377,24 @@ EdgePairsDelegate *
DeepEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
{
// TODO: implement to be really in-place
*this = *apply_filter (filter);
*this = *apply_filter (filter, true, false).first;
return this;
}
EdgePairsDelegate *
DeepEdgePairs::filtered (const EdgePairFilterBase &filter) const
{
return apply_filter (filter);
return apply_filter (filter, true, false).first;
}
DeepEdgePairs *
DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const
std::pair<EdgePairsDelegate *, EdgePairsDelegate *>
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 ();
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) {
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 ());
for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
db::Shapes *st_true = 0, *st_false = 0;
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 {
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::EdgePairs); ! si.at_end (); ++si) {
if (filter.selected (si->edge_pair ().transformed (tr))) {
st->insert (*si);
if (filter.selected (si->edge_pair ().transformed (tr), si->prop_id ())) {
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 {
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) {
if (filter.selected (si->edge_pair ())) {
st.insert (*si);
if (filter.selected (si->edge_pair (), si->prop_id ())) {
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 ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit);
if (! to_commit_true.empty () && vars.get ()) {
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)

View File

@ -50,7 +50,7 @@ public:
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::ICplxTrans &t);
@ -70,12 +70,14 @@ public:
virtual Box bbox () const;
virtual bool empty () 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 const db::RecursiveShapeIterator *iter () const;
virtual void apply_property_translator (const db::PropertiesTranslator &pt);
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter);
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 *processed (const EdgePairProcessorBase &) const;
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
@ -115,7 +117,7 @@ private:
void init ();
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")));
}
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
DeepEdges::has_valid_edges () const
{
@ -799,18 +805,24 @@ EdgesDelegate *
DeepEdges::filter_in_place (const EdgeFilterBase &filter)
{
// TODO: implement to be really in-place
*this = *apply_filter (filter);
*this = *apply_filter (filter, true, false).first;
return this;
}
EdgesDelegate *
DeepEdges::filtered (const EdgeFilterBase &filter) const
{
return apply_filter (filter);
return apply_filter (filter, true, false).first;
}
DeepEdges *
DeepEdges::apply_filter (const EdgeFilterBase &filter) const
std::pair<EdgesDelegate *, EdgesDelegate *>
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 ();
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) {
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 ());
for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
db::Shapes *st_true = 0, *st_false = 0;
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 {
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) {
if (filter.selected (si->edge ().transformed (*v))) {
st->insert (*si);
if (filter.selected (si->edge ().transformed (tr), si->prop_id ())) {
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 {
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) {
if (filter.selected (si->edge ())) {
st.insert (*si);
if (filter.selected (si->edge (), si->prop_id ())) {
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 ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit);
if (! to_commit_true.empty () && vars.get ()) {
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 ()) {
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 ()
@ -1236,7 +1285,11 @@ DeepEdges::add_in_place (const Edges &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
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 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_merged_edges () const;
@ -125,6 +126,7 @@ public:
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter);
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 *processed (const EdgeProcessorBase &) 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;
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;
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;
};

View File

@ -231,6 +231,11 @@ void DeepRegion::min_coherence_changed ()
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)
{
db::Layout &layout = deep_layer ().layout ();
@ -520,7 +525,7 @@ class ClusterMerger
{
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)
: 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 ..
}
@ -530,6 +535,19 @@ public:
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)
{
return compute_merged (cid, ci, true, min_wc);
@ -548,8 +566,19 @@ private:
db::Layout *mp_layout;
const db::hier_clusters<db::PolygonRef> *mp_hc;
bool m_min_coherence;
db::property_names_id_type m_text_name_id;
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)
{
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;
}
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::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);
for (db::connected_clusters<db::PolygonRef>::connections_type::const_iterator i = conn.begin (); i != conn.end () && s->second == db::properties_id_type (0); ++i) {
s->second = property_id (i->id (), i->inst_cell_index (), false);
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 (); ++i) {
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;
conn.connect (deep_layer ());
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
// 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 ());
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?
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 ());
@ -757,13 +813,13 @@ DeepRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Var
DeepLayer result = deep_layer ().derived ();
std::unique_ptr<db::Region> region_for_layer (l2n->layer_by_original (this));
if (! region_for_layer) {
tl::optional<unsigned int> li = l2n->layer_by_original (this);
if (! li.has_value ()) {
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;
lmap.insert (std::make_pair (result.layer (), region_for_layer.get ()));
std::map<unsigned int, unsigned int> lmap;
lmap.insert (std::make_pair (result.layer (), li.value ()));
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 ());
if (empty ()) {
// Nothing to do
return other.delegate ()->clone ();
} else if (other.empty ()) {
if (other.empty ()) {
// Nothing to do
return clone ();
@ -1068,6 +1119,18 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
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)) {
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::PolygonRefToShapesGenerator pr (const_cast<db::Layout *> (& deep_layer ().layout ()), &shapes);
for (db::Region::const_iterator p = other.begin (); ! p.at_end (); ++p) {
pr.set_prop_id (p.prop_id ());
pr.put (*p);
}
@ -1497,12 +1561,13 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas
const db::Shapes &s = c->shapes (polygons.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) {
db::Polygon poly;
db::PolygonWithProperties poly;
si->polygon (poly);
poly.properties_id (si->prop_id ());
if (proc) {
@ -1510,16 +1575,16 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas
proc->process (poly, heap);
for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, si->prop_id ()));
if (! filter || filter->selected ((*e).transformed (tr), e->properties_id ())) {
st.insert (*e);
}
}
} else {
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, si->prop_id ()));
if (! filter || filter->selected ((*e).transformed (tr), poly.properties_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
*this = *apply_filter (filter);
*this = *apply_filter (filter, true, false).first;
return this;
}
@ -1596,11 +1661,17 @@ DeepRegion::filtered (const PolygonFilterBase &filter) const
return clone ();
}
return apply_filter (filter);
return apply_filter (filter, true, false).first;
}
DeepRegion *
DeepRegion::apply_filter (const PolygonFilterBase &filter) const
std::pair<RegionDelegate *, RegionDelegate *>
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 ();
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) {
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 ());
for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
db::Shapes *st_true = 0, *st_false = 0;
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 {
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) {
db::Polygon poly;
si->polygon (poly);
if (filter.selected (poly.transformed (*v))) {
st->insert (*si);
if (filter.selected (poly.transformed (tr), si->prop_id ())) {
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 {
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) {
db::Polygon poly;
si->polygon (poly);
if (filter.selected (poly)) {
st.insert (*si);
if (filter.selected (poly, si->prop_id ())) {
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 ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit);
if (! to_commit_true.empty () && vars.get ()) {
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 ()) {
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 *
@ -1690,10 +1798,10 @@ DeepRegion::merged_in_place ()
}
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
return merged (min_coherence, min_wc);
return merged (min_coherence, min_wc, join_properties_on_merge);
}
RegionDelegate *
@ -1719,7 +1827,7 @@ DeepRegion::merged () const
}
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 ()) {
return clone ();
@ -1733,7 +1841,7 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
db::Connectivity conn;
conn.connect (deep_layer ());
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
// 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 ());
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) {
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) {

View File

@ -125,12 +125,13 @@ public:
virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &filter) const;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter);
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 (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 (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 dx, coord_type dy, unsigned int mode) const;
@ -154,6 +155,7 @@ public:
protected:
virtual void merged_semantics_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_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 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;
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>
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);
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->second.clear ();
cm = m_delivery_mapping_cache.insert (std::make_pair (key, CellMappingWithGenerationIds ())).first;
cm->second.clear ();
// 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;
// Not found in cache - compute a fresh mapping
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
// 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.
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) {
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;
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;
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;
skip = true;
}
} 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".
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);
m = mm;
}
// 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);
} else if (into_layout->cells () == 1) {
// the variant's originals we are going to delete
std::set<db::cell_index_type> cells_to_delete;
// Another simple case is mapping into an empty (or single-top-cell-only) layout, where we can use "create_from_single_full".
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.
// 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);
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);
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
// DSS layout
@ -1253,15 +1258,105 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
}
// delete the variant's original cell
if (! cells_to_delete.empty ()) {
into_layout->delete_cells (cells_to_delete);
}
if (! new_variants.empty ()) {
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;
}

View File

@ -178,12 +178,16 @@ TextsDelegate *DeepTexts::clone () const
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 ();
if (layout.begin_top_down () != layout.end_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 ();
@ -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")));
}
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
{
return false;
@ -361,7 +371,11 @@ DeepTexts::add_in_place (const Texts &other)
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
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)
{
// TODO: implement as really in place
*this = *apply_filter (filter);
*this = *apply_filter (filter, true, false).first;
return this;
}
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 ();
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) {
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 ());
for (auto v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
db::Shapes *st_true = 0, *st_false = 0;
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 {
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) {
db::Text text;
si->text (text);
if (filter.selected (text.transformed (*v))) {
st->insert (*si);
if (filter.selected (text.transformed (tr), si->prop_id ())) {
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 {
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) {
db::Text text;
si->text (text);
if (filter.selected (text)) {
st.insert (*si);
if (filter.selected (text, si->prop_id ())) {
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 ()) {
vars->commit_shapes (res->deep_layer ().layer (), to_commit);
if (! to_commit_true.empty () && vars.get ()) {
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)
@ -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);
}
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::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 ();
box.enlarge (db::Vector (e, e));
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;
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::ICplxTrans &t);
@ -71,12 +71,14 @@ public:
virtual Box bbox () const;
virtual bool empty () 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 const db::RecursiveShapeIterator *iter () const;
virtual void apply_property_translator (const db::PropertiesTranslator &pt);
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
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 *processed (const TextProcessorBase &) const;
@ -85,7 +87,7 @@ public:
virtual TextsDelegate *add_in_place (const Texts &other);
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 TextsDelegate *in (const Texts &, bool) const;
@ -105,7 +107,7 @@ private:
DeepTexts &operator= (const DeepTexts &other);
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 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;
}
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)
{
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));
}
/**
* @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
* If the net is 0 the terminal is disconnected.

View File

@ -158,7 +158,7 @@ class DB_PUBLIC EdgeNeighborhoodCompoundOperationNode
: public CompoundRegionMultiInputOperationNode
{
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
{

View File

@ -43,12 +43,12 @@ EdgeFilterBasedEdgePairFilter::~EdgeFilterBasedEdgePairFilter ()
// .. 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) {
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 {
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 ..
}
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 ();
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 ..
}
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 ();
bool sel = (dist >= m_min_area && dist < m_max_area);
@ -110,7 +110,7 @@ InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool incl
}
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 d2 = edge_pair.second ().d ();

View File

@ -47,7 +47,7 @@ public:
EdgeFilterBasedEdgePairFilter (EdgeFilterBase *edge_filter, bool one_must_match);
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 bool wants_variants () const;
@ -69,7 +69,7 @@ public:
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 bool wants_variants () const { return true; }
@ -92,7 +92,7 @@ public:
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 bool wants_variants () const { return true; }
@ -114,7 +114,7 @@ public:
InternalAngleEdgePairFilter (double a, 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 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);
}
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
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::EdgePairWithProperties &);
void EdgePairs::insert (const db::Shape &shape)
{

View File

@ -55,10 +55,12 @@ class EdgePairs;
class DB_PUBLIC EdgePairFilterBase
{
public:
typedef db::EdgePair shape_type;
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 bool wants_variants () const = 0;
};
@ -128,6 +130,17 @@ public:
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
*
@ -185,6 +198,12 @@ public:
*/
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
*
@ -346,6 +365,18 @@ public:
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
*
@ -649,7 +680,7 @@ public:
/**
* @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.
*/
const db::EdgePair *nth (size_t n) const
@ -657,6 +688,17 @@ public:
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
*

View File

@ -52,14 +52,6 @@ public:
: 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
{
db::Polygon poly = ep.normalized ().to_polygon (m_e);
@ -80,12 +72,6 @@ public:
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
{
res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ()));
@ -101,14 +87,6 @@ public:
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
{
res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ()));
@ -126,13 +104,6 @@ public:
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
{
if (! ep.is_symmetric ()) {
@ -149,11 +120,6 @@ public:
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
{
res.push_back (db::EdgeWithProperties (ep.lesser (), ep.properties_id ()));
@ -168,11 +134,6 @@ public:
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
{
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 *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 *processed (const EdgePairProcessorBase &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 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 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)) {
return true;
} else if (edge_xmin (a) >= edge_xmax (b)) {
} else if (edge_xmin (a) > edge_xmax (b)) {
return false;
} else {
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);
}
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 &
Edges::iter () const
{

View File

@ -112,6 +112,17 @@ public:
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
*
@ -123,6 +134,17 @@ public:
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
*
@ -134,6 +156,17 @@ public:
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
*
@ -145,6 +178,17 @@ public:
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
*
@ -156,6 +200,17 @@ public:
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
*
@ -203,6 +258,12 @@ public:
*/
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
*/
@ -468,6 +529,18 @@ public:
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
*
@ -1367,13 +1440,24 @@ public:
/**
* @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
{
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
*

View File

@ -45,6 +45,8 @@ namespace db {
class DB_PUBLIC EdgeFilterBase
{
public:
typedef db::Edge shape_type;
/**
* @brief Constructor
*/
@ -56,13 +58,13 @@ public:
* @brief Filters the edge
* 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
* 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
@ -228,6 +230,7 @@ public:
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter) = 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 *processed (const EdgeProcessorBase &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 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_merged_edges () const = 0;

View File

@ -184,34 +184,6 @@ EdgeSegmentSelector::EdgeSegmentSelector (int mode, Edge::distance_type length,
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
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;
}
m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ());
m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ());
m_t_start = db::ICplxTrans (1.0, angle_start, false, db::Vector ());
m_t_end = db::ICplxTrans (1.0, angle_end, false, db::Vector ());
m_include_start = include_angle_start;
m_include_end = include_angle_end;
@ -266,10 +238,10 @@ EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start
bool
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::DVector v2 = m_t_end * a;
db::Vector v1 = m_t_start * a;
db::Vector v2 = m_t_end * a;
int vps1 = db::vprod_sign (v1, vout);
int vps2 = db::vprod_sign (v2, vout);
@ -304,14 +276,16 @@ EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse, bool absol
}
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).
// A horizontal edge has 0 degree, a vertical one has 90 degree.
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 {
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
SpecialEdgeOrientationFilter::selected (const db::Edge &edge) const
SpecialEdgeOrientationFilter::selected (const db::Edge &edge, properties_id_type) const
{
const EdgeAngleChecker *eb, *ee;
@ -363,7 +337,7 @@ SpecialEdgeOrientationFilter::selected (const db::Edge &edge) const
}
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).
// 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
*/
virtual bool selected (const db::Edge &edge) const
virtual bool selected (const db::Edge &edge, db::properties_id_type) const
{
return check (edge.length ());
}
@ -79,10 +79,10 @@ struct DB_PUBLIC EdgeLengthFilter
/**
* @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;
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 ();
}
return check (l);
@ -155,7 +155,7 @@ public:
}
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_big_angle, m_all;
bool m_inverse, m_absolute;
@ -204,15 +204,15 @@ struct DB_PUBLIC EdgeOrientationFilter
/**
* @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
*/
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) {
if (! selected (*e)) {
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
if (! selected (*e, e->properties_id ())) {
return false;
}
}
@ -274,15 +274,15 @@ struct DB_PUBLIC SpecialEdgeOrientationFilter
/**
* @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
*/
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) {
if (! selected (*e)) {
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
if (! selected (*e, e->properties_id ())) {
return false;
}
}
@ -319,6 +319,29 @@ private:
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
*/
@ -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)
{ }
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
{
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 ();
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 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 *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 *processed (const EdgePairProcessorBase &) const { return new EmptyEdgePairs (); }
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 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 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 *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 *processed (const EdgeProcessorBase &) const { return new EmptyEdges (); }
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 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_merged_edges () const { return true; }

View File

@ -85,15 +85,16 @@ public:
virtual EdgesDelegate *edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
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 *processed (const PolygonProcessorBase &) const { return new EmptyRegion (); }
virtual EdgesDelegate *processed_to_edges (const PolygonToEdgeProcessorBase &) const;
virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &) const;
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 (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, coord_type, unsigned int) const { return new EmptyRegion (); }

View File

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

View File

@ -56,12 +56,13 @@ public:
virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; }
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 *processed (const TextProcessorBase &) const { return new EmptyTexts (); }
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 TextsDelegate *add_in_place (const Texts &other);
@ -70,6 +71,7 @@ public:
virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); }
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 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
// 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_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
db::Box fp_bbox = fp.box ();
// 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 rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
@ -167,6 +169,11 @@ public:
return m_area_maps [i];
}
db::AreaMap &area_map (unsigned int i)
{
return m_area_maps [i];
}
private:
std::vector<db::AreaMap> m_area_maps;
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) {
const db::AreaMap &am1 = am.area_map (i);
db::AreaMap &am1 = am.area_map (i);
size_t nx = am1.nx ();
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;
}
ninsts += (jj - j);
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
db::CellInstArray array;
if (jj > j + 1) {
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (), (unsigned long) (jj - j), 1);
// try to expand the array in x direction
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 {
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
tl::MutexLocker locker (&db::TilingProcessor::output_lock ());
tl_assert (cell->layout () != 0);
tl::MutexLocker locker (&cell->layout ()->lock ());
cell->insert (array);
}
if (remaining_parts) {
if (am1.d ().y () == am1.p ().y ()) {
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)));
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
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 {
db::Box fill_box (db::Point (), db::Point () + am1.p ());
fill_box.enlarge (fill_margin);
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 (remaining_parts) {
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);
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
}
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 ();
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 ()) {
ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().insert (*p);
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
{
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
@ -221,9 +260,13 @@ FlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsig
}
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 ();
}

View File

@ -75,6 +75,7 @@ public:
virtual EdgePairsDelegate *add (const EdgePairs &other) 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 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_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)
{

View File

@ -127,7 +127,7 @@ FlatEdges::ensure_merged_edges_valid () const
if (! need_split_props) {
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr);
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr, prop_id);
scanner.reserve (mp_edges->size ());
@ -226,7 +226,7 @@ Box FlatEdges::compute_bbox () const
EdgesDelegate *
FlatEdges::processed_in_place (const EdgeProcessorBase &filter)
{
std::vector<db::Edge> edge_res;
std::vector<db::EdgeWithProperties> edge_res;
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) {
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) {
if (p.prop_id () != 0) {
for (auto pr = edge_res.begin (); pr != edge_res.end (); ++pr) {
if (pr->properties_id () != 0) {
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 ();
} 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 {
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 ();
} 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 ();
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 (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 ()));
@ -314,18 +314,16 @@ EdgesDelegate *FlatEdges::add (const Edges &other) const
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::EdgeWithProperties, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ());
} else {
size_t n = new_region->raw_edges ().size ();
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
++n;
}
new_region->raw_edges ().reserve (db::Edge::tag (), n);
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
new_region->raw_edges ().insert (*p);
if (p.prop_id () == 0) {
new_region->raw_edges ().insert (*p);
} else {
new_region->raw_edges ().insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
}
}
@ -344,18 +342,16 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other)
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::EdgeWithProperties, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::EdgeWithProperties, db::unstable_layer_tag> ().end ());
} else {
size_t n = e.size ();
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
++n;
}
e.reserve (db::Edge::tag (), n);
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
e.insert (*p);
if (p.prop_id () == 0) {
e.insert (*p);
} else {
e.insert (db::EdgeWithProperties (*p, p.prop_id ()));
}
}
}
@ -365,7 +361,46 @@ EdgesDelegate *FlatEdges::add_in_place (const Edges &other)
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

View File

@ -89,6 +89,7 @@ public:
virtual EdgesDelegate *add (const Edges &other) 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_merged_edges () const;

View File

@ -99,6 +99,12 @@ void FlatRegion::merged_semantics_changed ()
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 ()
{
m_is_merged = false;
@ -115,7 +121,7 @@ void
FlatRegion::ensure_merged_polygons_valid () const
{
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;
}
}
@ -184,7 +190,7 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter)
polygon_iterator_wp_type pw_wp = poly_layer_wp.begin ();
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 (pw_wp == poly_layer_wp.end ()) {
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> 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) {
poly_res.clear ();
filter.process (*p, poly_res);
if (p.prop_id () != 0) {
for (auto r = poly_res.begin (); r != poly_res.end (); ++r) {
out_wp.insert (db::PolygonWithProperties (*r, p.prop_id ()));
filter.process (p.wp (), poly_res);
for (auto r = poly_res.begin (); r != poly_res.end (); ++r) {
if (r->properties_id () != 0) {
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;
} else {
return merged_in_place (min_coherence (), 0);
return merged_in_place (min_coherence (), 0, join_properties_on_merge ());
}
} 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 ()) {
@ -285,7 +291,7 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi
} else {
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;
@ -301,7 +307,7 @@ RegionDelegate *FlatRegion::merged () const
if (m_merged_polygons_valid) {
return new FlatRegion (*mp_merged_polygons, true);
} else {
return AsIfFlatRegion::merged (min_coherence (), 0);
return AsIfFlatRegion::merged (min_coherence (), 0, join_properties_on_merge ());
}
} else {
@ -323,15 +329,12 @@ RegionDelegate *FlatRegion::add (const Region &other) const
} else {
size_t n = new_region->raw_polygons ().size ();
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
++n;
}
new_region->raw_polygons ().reserve (db::Polygon::tag (), n);
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 ()));
}
}
}
@ -354,15 +357,12 @@ RegionDelegate *FlatRegion::add_in_place (const Region &other)
} else {
size_t n = polygons.size ();
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
++n;
}
polygons.reserve (db::Polygon::tag (), n);
for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) {
polygons.insert (*p);
if (p.prop_id () == 0) {
polygons.insert (*p);
} else {
polygons.insert (db::PolygonWithProperties (*p, p.prop_id ()));
}
}
}

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 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 (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);
@ -131,6 +131,7 @@ public:
protected:
virtual void merged_semantics_changed ();
virtual void join_properties_on_merge_changed ();
virtual void min_coherence_changed ();
virtual Box compute_bbox () const;
void invalidate_cache ();

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