mirror of https://github.com/KLayout/klayout.git
Merge branch 'devel' into vias-development
This commit is contained in:
commit
8c53fb934e
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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
163
Changelog
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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 ..
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
#========================================================================================
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
#--------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.cibuildwheel]
|
||||
build-verbosity = "3"
|
||||
test-command = [
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ...
|
||||
|
|
|
|||
48
setup.py
48
setup.py
|
|
@ -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}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (); }
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ EmptyTexts::clone () const
|
|||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyTexts::polygons (db::Coord) const
|
||||
EmptyTexts::polygons (db::Coord, const tl::Variant &) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue