Merge remote-tracking branch 'origin/master' into HEAD
|
|
@ -12,8 +12,39 @@ on:
|
|||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Check for source changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
code: ${{ steps.filter.outputs.code == 'true' || github.event_name == 'release' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dorny/paths-filter@v4
|
||||
id: filter
|
||||
if: github.event_name != 'release'
|
||||
with:
|
||||
filters: |
|
||||
code:
|
||||
- '!**/*.md'
|
||||
- '!docs/**'
|
||||
- '!samples/**'
|
||||
- '!Jenkinsfile*'
|
||||
- '!.travis.yml'
|
||||
- '!dropbox-deployment.yml'
|
||||
- '!.gitignore'
|
||||
- '!LICENSE'
|
||||
- '!COPYRIGHT'
|
||||
- '!CONTRIB'
|
||||
- '!Changelog*'
|
||||
|
||||
build:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -47,9 +78,7 @@ jobs:
|
|||
haskell: true
|
||||
large-packages: true
|
||||
- uses: hmarr/debug-action@v3
|
||||
- name: Cancel Workflow Action
|
||||
uses: styfle/cancel-workflow-action@0.13.0
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- name: ccache
|
||||
if: matrix.os != 'ubuntu-24.04-arm'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
|
@ -66,7 +95,7 @@ jobs:
|
|||
mkdir -p $HOST_CCACHE_DIR
|
||||
- name: Build wheels (ARM)
|
||||
if: matrix.os == 'ubuntu-24.04-arm'
|
||||
uses: pypa/cibuildwheel@v3.3.1
|
||||
uses: pypa/cibuildwheel@v4.1.1
|
||||
env:
|
||||
# override the default CentOS “yum install … ccache” and drop ccache
|
||||
CIBW_BEFORE_ALL_LINUX: |
|
||||
|
|
@ -81,7 +110,7 @@ jobs:
|
|||
|
||||
- name: Build wheels (all other platforms)
|
||||
if: matrix.os != 'ubuntu-24.04-arm'
|
||||
uses: pypa/cibuildwheel@v3.3.1
|
||||
uses: pypa/cibuildwheel@v4.1.1
|
||||
env:
|
||||
CIBW_BUILD: ${{ matrix.cibuild }}
|
||||
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
||||
|
|
@ -98,7 +127,7 @@ jobs:
|
|||
mv ./wheelhouse/.ccache $HOST_CCACHE_DIR
|
||||
ls -la $HOST_CCACHE_DIR
|
||||
ccache -s
|
||||
- uses: actions/upload-artifact@v6
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: artifact-${{ matrix.os }}-${{ matrix.cibw_arch }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
|
@ -106,14 +135,16 @@ jobs:
|
|||
# The following was taken from https://cibuildwheel.readthedocs.io/en/stable/deliver-to-pypi/
|
||||
make_sdist:
|
||||
name: Make SDist
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Build SDist
|
||||
run: pipx run build --sdist
|
||||
|
||||
- uses: actions/upload-artifact@v6
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: artifact-sdist
|
||||
path: dist/*.tar.gz
|
||||
|
|
@ -122,12 +153,12 @@ jobs:
|
|||
needs: [build, make_sdist]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: dist
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@v1.13.0
|
||||
- uses: pypa/gh-action-pypi-publish@v1.14.2
|
||||
continue-on-error: true # might fail if we don't bump the version
|
||||
with:
|
||||
user: __token__
|
||||
|
|
@ -139,12 +170,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: dist
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@v1.13.0
|
||||
- uses: pypa/gh-action-pypi-publish@v1.14.2
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.pypi_password }}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
|
|
|
|||
582
.travis.yml
|
|
@ -1,582 +0,0 @@
|
|||
branches:
|
||||
only:
|
||||
- /v\d+\.\d+(\.\d+)?(\S*)?$/ # tag format: *v0.25(.8)(dev14)
|
||||
- staging
|
||||
- master
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# python manylinux packages
|
||||
- name: "cp39-cp39m-manylinux2014_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '3.9'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
- PY_VERSION="cp39-cp39"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp38-cp38m-manylinux2014_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '3.8'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
- PY_VERSION="cp38-cp38"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp37-cp37m-manylinux2014_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '3.7-dev'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
- PY_VERSION="cp37-cp37m"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp36-cp36m-manylinux2014_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '3.6'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
- PY_VERSION="cp36-cp36m"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp35-cp35m-manylinux2014_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '3.5'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
- PY_VERSION="cp35-cp35m"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=true
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
- name: "cp27-cp27m-manylinux2014_x86_64.whl"
|
||||
os: linux
|
||||
sudo: true
|
||||
language: python
|
||||
python: '2.7'
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- DOCKER_IMAGE="quay.io/pypa/manylinux2014_x86_64"
|
||||
- PY_VERSION="cp27-cp27m"
|
||||
- DOCKER_BUILD=true
|
||||
- TEST_IN_HOST=false # travis's python 2.7 uses ucs4 (mu), so this test fails.
|
||||
- MATRIX_EVAL=""
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
|
||||
# python 3 osx
|
||||
|
||||
# MacOS 10.15
|
||||
|
||||
# MacOS 10.15, Python 3.9
|
||||
- name: "cp39-cp39m-macosx_10_15_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode12 # macOS 10.15
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.9
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.9/bin/python3'; alias pip='/usr/local/opt/python@3.9/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.15, Python 3.8
|
||||
- name: "cp38-cp38m-macosx_10_15_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode12 # macOS 10.15
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.8
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.8/bin/python3'; alias pip='/usr/local/opt/python@3.8/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.15, Python 3.7
|
||||
- name: "cp37-cp37m-macosx_10_15_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode12 # macOS 10.15
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.7
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.7/bin/python3'; alias pip='/usr/local/opt/python@3.7/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.14
|
||||
|
||||
# MacOS 10.14, Python 3.9
|
||||
- name: "cp39-cp39m-macosx_10_14_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode11 # macOS 10.14
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.9
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.9/bin/python3'; alias pip='/usr/local/opt/python@3.9/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.14, Python 3.8
|
||||
- name: "cp38-cp38m-macosx_10_14_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode11 # macOS 10.14
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.8
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.8/bin/python3'; alias pip='/usr/local/opt/python@3.8/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.14, Python 3.7
|
||||
- name: "cp37-cp37m-macosx_10_14_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode11 # macOS 10.14
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.7
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.7/bin/python3'; alias pip='/usr/local/opt/python@3.7/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.13
|
||||
|
||||
# MacOS 10.13, Python 3.9
|
||||
- name: "cp39-cp39m-macosx_10_13_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode10.1 # macOS 10.13
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.9
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.9/bin/python3'; alias pip='/usr/local/opt/python@3.9/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.13, Python 3.8
|
||||
- name: "cp38-cp38m-macosx_10_13_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode10.1 # macOS 10.13
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.8
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.8/bin/python3'; alias pip='/usr/local/opt/python@3.8/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.13, Python 3.7
|
||||
- name: "cp37-cp37m-macosx_10_13_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode10.1 # macOS 10.13
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python@3.7
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='/usr/local/opt/python@3.7/bin/python3'; alias pip='/usr/local/opt/python@3.7/bin/pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# MacOS 10.12, Python 3.7
|
||||
|
||||
# - name: "klayout python3 osx10.12"
|
||||
- name: "cp37-cp37m-macosx_10_12_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode9.2 # macOS 10.12
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python3
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="shopt -s expand_aliases; alias python='python3'; alias pip='pip3';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
exclude:
|
||||
|
||||
# No XCode 8.2.1 for Mac OS 10.11
|
||||
|
||||
# - name: "klayout python3 osx10.11"
|
||||
- name: "cp37-cp37m-macosx_10_11_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode8 # macOS 10.11
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="brew update; brew config; brew upgrade python; brew postinstall python; ls -l /usr/local/opt/python/libexec/bin/; shopt -s expand_aliases; alias python='/usr/local/opt/python/libexec/bin/python'; alias pip='/usr/local/opt/python/libexec/bin/pip';"
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# Python 2 is EOL
|
||||
|
||||
# python 2 osx
|
||||
|
||||
# - name: "klayout python2 osx10.13"
|
||||
- name: "cp27-cp27m-macosx_10_13_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode9.4 # macOS 10.13
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL=""
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# - name: "klayout python2 osx10.12"
|
||||
- name: "cp27-cp27m-macosx_10_12_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode8.3 # macOS 10.12
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="brew install python2 || brew link --overwrite python@2" # deficient python2 in travis's xcode8.3 (no ssl)
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# - name: "klayout python2 osx10.11"
|
||||
- name: "cp27-cp27m-macosx_10_11_x86_64.whl"
|
||||
os: osx
|
||||
osx_image: xcode8 # macOS 10.11
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL=""
|
||||
- ARCHFLAGS="-std=c++11"
|
||||
- PIP_UPDATE="1"
|
||||
- PYTHON_BUILD=true
|
||||
|
||||
# KLayout builds not enabled for now on MacOS
|
||||
|
||||
# KLayout builds for mac
|
||||
# Python 3
|
||||
- name: "KLayout macOS 10.13 with py3.7"
|
||||
os: osx
|
||||
osx_image: xcode9.4 # macOS 10.13
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python3
|
||||
- qt
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL=""
|
||||
- PYTHON_VERSION=B37
|
||||
- MACOS_VERSION=HighSierra
|
||||
- KLAYOUT_BUILD=true
|
||||
|
||||
- name: "KLayout macOS 10.12 with py3.7"
|
||||
os: osx
|
||||
osx_image: xcode8.3 # macOS 10.12
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python3
|
||||
- qt
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL=""
|
||||
- PYTHON_VERSION=B37
|
||||
- MACOS_VERSION=Sierra
|
||||
- KLAYOUT_BUILD=true
|
||||
|
||||
- name: "KLayout macOS 10.11 with py3.7"
|
||||
os: osx
|
||||
osx_image: xcode8 # macOS 10.11
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- python3
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="brew update; brew config; brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/56c500b569c724b049be7ab9e12d9693f85522f9/Formula/qt.rb" # Qt 5.11.2
|
||||
- PYTHON_VERSION=B37
|
||||
- MACOS_VERSION=ElCapitan
|
||||
- KLAYOUT_BUILD=true
|
||||
|
||||
# Python 2
|
||||
- name: "KLayout macOS 10.13 with py2.7"
|
||||
os: osx
|
||||
osx_image: xcode9.4 # macOS 10.13
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL=""
|
||||
- PYTHON_VERSION=Sys
|
||||
- MACOS_VERSION=HighSierra
|
||||
- KLAYOUT_BUILD=true
|
||||
|
||||
- name: "KLayout macOS 10.12 with py2.7"
|
||||
os: osx
|
||||
osx_image: xcode8.3 # macOS 10.12
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL=""
|
||||
- PYTHON_VERSION=Sys
|
||||
- MACOS_VERSION=Sierra
|
||||
- KLAYOUT_BUILD=true
|
||||
|
||||
- name: "KLayout macOS 10.11 with py2.7"
|
||||
os: osx
|
||||
osx_image: xcode8 # macOS 10.11
|
||||
cache:
|
||||
directories:
|
||||
- ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
update: true
|
||||
env:
|
||||
- MATRIX_EVAL="brew update; brew config; brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/56c500b569c724b049be7ab9e12d9693f85522f9/Formula/qt.rb" # Qt 5.11.2
|
||||
- PYTHON_VERSION=Sys
|
||||
- MACOS_VERSION=ElCapitan
|
||||
- KLAYOUT_BUILD=true
|
||||
|
||||
before_install:
|
||||
- env
|
||||
- gem install dropbox-deployment
|
||||
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
export PATH="/usr/local/opt/ccache/libexec:$PATH";
|
||||
mkdir -p ccache;
|
||||
export CCACHE_DIR="`pwd`/ccache";
|
||||
ccache -s;
|
||||
fi
|
||||
- eval "${MATRIX_EVAL}"
|
||||
- if [ "${PIP_UPDATE}" == "1" ]; then
|
||||
pip --version;
|
||||
pip install --upgrade pip || sudo pip install --upgrade pip;
|
||||
pip --version;
|
||||
pip install --upgrade setuptools wheel || sudo pip install --upgrade setuptools wheel;
|
||||
fi
|
||||
- python -c "import distutils.sysconfig as sysconfig; print(sysconfig.__file__)"
|
||||
|
||||
install:
|
||||
- if [ "$DOCKER_BUILD" = true ]; then
|
||||
docker pull $DOCKER_IMAGE;
|
||||
fi
|
||||
|
||||
script:
|
||||
- if [ "$DOCKER_BUILD" = true ]; then
|
||||
mkdir -p ccache;
|
||||
mkdir -p wheelhouse;
|
||||
docker run --rm -e DOCKER_IMAGE -e PY_VERSION -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD "/io/ci-scripts/docker/docker_build.sh";
|
||||
klayout_version=$(python -c 'import setup; print(setup.Config().version())');
|
||||
mkdir -p deploy/dist-pymod/$klayout_version;
|
||||
cp -a wheelhouse/{klayout-*manylinux2014*.whl,*.zip} deploy/dist-pymod/$klayout_version;
|
||||
if [ "$TEST_IN_HOST" = true ]; then
|
||||
pip install klayout --no-index -f ./wheelhouse;
|
||||
python testdata/pymod/import_db.py;
|
||||
python testdata/pymod/import_rdb.py;
|
||||
python testdata/pymod/import_tl.py;
|
||||
python testdata/pymod/import_lib.py;
|
||||
python testdata/pymod/pya_tests.py;
|
||||
fi
|
||||
fi
|
||||
- if [ "$PYTHON_BUILD" = true ]; then
|
||||
python setup.py build;
|
||||
python setup.py bdist_wheel;
|
||||
python setup.py install;
|
||||
python setup.py sdist --formats=zip;
|
||||
python testdata/pymod/import_db.py;
|
||||
python testdata/pymod/import_rdb.py;
|
||||
python testdata/pymod/import_tl.py;
|
||||
python testdata/pymod/import_lib.py;
|
||||
python testdata/pymod/pya_tests.py;
|
||||
klayout_version=$(python -c 'import setup; print(setup.Config().version())');
|
||||
mkdir -p deploy/dist-pymod/$klayout_version;
|
||||
cp -a dist/{*.whl,*.zip} deploy/dist-pymod/$klayout_version;
|
||||
python -c 'import klayout.db as db; print(dir(db))';
|
||||
python -c 'import klayout.rdb as rdb; print(dir(rdb))';
|
||||
python -c 'import klayout.tl as tl; print(dir(tl))';
|
||||
fi
|
||||
- if [ "$KLAYOUT_BUILD" = true ]; then
|
||||
./travis-build.sh;
|
||||
fi
|
||||
|
||||
before_cache:
|
||||
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
ccache -s;
|
||||
fi
|
||||
|
||||
after_success:
|
||||
# upload to dropbox
|
||||
# need DROPBOX_OAUTH_BEARER environment variable
|
||||
- dropbox-deployment
|
||||
|
||||
# uploading to pypi using twine
|
||||
# need TWINE_USERNAME, TWINE_PASSWORD and TWINE_REPOSITORY_URL env variable
|
||||
- if [ ! -z "$TRAVIS_TAG" ] && [ ! -z "$TWINE_PASSWORD" ] && [[ "$PYTHON_BUILD" = true || "$DOCKER_BUILD" = true ]]; then
|
||||
pip install -U twine || sudo pip install -U twine;
|
||||
twine upload --skip-existing deploy/dist-pymod/$klayout_version/*;
|
||||
fi
|
||||
144
Changelog
|
|
@ -1,3 +1,147 @@
|
|||
0.30.10 (2026-07-25):
|
||||
* Bugfix: %GITHUB%/issues/2384 Deep DRC failure with scaled instances
|
||||
* Enhancement: %GITHUB%/issues/2391 Grid Features: switching between coarser and finier grids with keyboard shortcut
|
||||
* Bugfix: %GITHUB%/issues/2392 Wrong PCell instantiations when switching technologies
|
||||
* Bugfix: %GITHUB%/issues/2396 Python objects did nott support weak refs
|
||||
* Bugfix: Region#edges was not working properly when used on Regions with properties
|
||||
enabled. Now, with properties enabled, the regions are consistently formed from polygons with
|
||||
identical properties before generating the edges.
|
||||
* Enhancement: %GITHUB%/issues/2398 Clarify 'move to' (and others) scope in window caption
|
||||
* Enhancement: DRC two-layer checks now do not necessarily require merging for the
|
||||
first input. This in general speeds up the operation in certain cases.
|
||||
As a side effect, the error markers may be split according to partial input
|
||||
polygons, as is the case for plain "space" check already.
|
||||
* Enhancement: Use multiple drawing workers for image_with_options rendering
|
||||
* Bugfix: Update layer names in layer list (when used in addition to layer/datatypes) on reload
|
||||
As a side effect, the layer properties nodes will update the "real source" according to
|
||||
the actual name if the name is used in addition to layer/datatypes. Also, the layout readers
|
||||
will update layer names in the layer properties of the Layout object.
|
||||
* Bugfix: Marek's bug: move interactive/copy interactive did not do anything when the mouse wasn't moved
|
||||
* Bugfix: Entering '16:17' (or other nonsense) into 'new layout' layer list made KLayout hang
|
||||
* Bugfix: API: removing a pin from a Circuit does not crash if the pin was not disconnected before.
|
||||
Now it's disconnected automatically
|
||||
* Enhancement: Improved the image pixel value display: favors selected image, and follows mouse instantly
|
||||
* Bugfix: When images are selected and images are turned off, the selection no longer persists
|
||||
* Bugfix: Using PCell parameter name 'name' won't break PCell's cell_name_impl default implementation
|
||||
* Enhancement: New API functions
|
||||
* Create a Layout as a deep copy of a cell (Layout#new)
|
||||
* PixelBuffer#to_bytes and PixelBuffer#from_bytes for zero-overhead RGBA pixel access
|
||||
|
||||
0.30.9 (2026-05-25):
|
||||
* Bugfix: %GITHUB%/issues/2331 Screen size error (Assertion tlPixelBuffer.cc:260 n < m_height was not true)
|
||||
* Enhancement: %GITHUB%/issues/2335 Editor Options (F3) behaviour has changed
|
||||
* Enhancement: %GITHUB%/issues/2337 [Feature Request] Add to_bytes and from_bytes to shape classes
|
||||
* Bugfix: %GITHUB%/issues/2339 Ruby ReportDatabase merging can lead to internal error
|
||||
* Bugfix: %GITHUB%/issues/2343 copy_tree implicitly drops collinear points
|
||||
* Bugfix: %GITHUB%/issues/2344 Instance properties inside a PCell are not preserved in KLayout
|
||||
* Bugfix: %GITHUB%/issues/2345 Substrate sequestration
|
||||
Although this ticket was more a discussion, this enhancement fixes the behavior of
|
||||
empty layers in deep mode, which allows placing device terminals on them.
|
||||
This eliminates the need for the workaround mentioned in the ticket.
|
||||
* Bugfix: %GITHUB%/issues/2350 strm2oas klayout/testdata/gds/issue_1835.gds a.oas, a.oas is empty
|
||||
With this fix, it is possible to save and load layouts that use a single library references
|
||||
or PCell variants as top cell. This is not strictly a supported use model, but may be
|
||||
useful in some cases. The "strm2xxx" tools now allow translating such files from OASIS
|
||||
to GDS and back.
|
||||
* Bugfix: %GITHUB%/issues/2356 Edit options always shown, even for klayout -ne
|
||||
* Enhancement: because of issue #2356 and #2335, the "Editor Options" dock was overhauled
|
||||
* It is called "Tool Options" now as it hosts not just shape editor options
|
||||
* The Ruler tool got its own page as the original page was not functional and
|
||||
rulers have other options. This replicates some settings from the "Ruler
|
||||
and annotations setup" page.
|
||||
* The dock widget's visibility can be controlled in the same way than the other
|
||||
docks. The "Edit/Editor Options" entry moved to "View/Tool Options". It turns
|
||||
on or off the tool options dock, which is populated with pages depending on the tool.
|
||||
The default key binding (F3) will now show or hide this dock.
|
||||
* Enhancement: %GITHUB%/issues/2360 Sort ports by name in "make_top_level_pins"
|
||||
* Enhancement: A feature to compute a density map. It is found inside Tools/Density Map.
|
||||
The density map can be computed from one or multiple layers, the region can be
|
||||
specified in terms of visible region, rulers or bounding boxes of certain layers
|
||||
or the whole cell. The tool will generate an image overlay over the layout
|
||||
holding the density data.
|
||||
* Bugfix: using "xkill" on a KLayout instance ended in a crash
|
||||
* Enhancement: settings of search features are persisted (see discussion 2868)
|
||||
* Enhancement: when moving rulers with "snap to objects", all points of the
|
||||
rulers snap to edges or vertexes now.
|
||||
* Bugfix: false color maps in images where incorrectly interpolated in some
|
||||
cases.
|
||||
* Bugfix: small bugfix in L2N/LVSDB reader - default values of parameters were
|
||||
treated as int.
|
||||
* Bugfix: properties on objects with properties (such as BoxWithProperties) where
|
||||
not properly serialized. Specifically their representation did not include the
|
||||
type. Hence it was not possible to retrieve properties on deserialization with
|
||||
"from_s". The fix is to annotate the property values with type information.
|
||||
NOTE: this is a change that is not backward-compatible.
|
||||
* Bugfix: snapping rulers to edges parallel to the allowed ruler direction resulted
|
||||
in skew rulers.
|
||||
* Enhancement: renamed ruler option for more clarity - changed
|
||||
'snap to objects (unless disabled in template)' to 'never snap to object' (inverted)
|
||||
* Enhancement: enhancements in the script API
|
||||
* Cell#is_cold_proxy?: indicates if a cell is a "defunc" library reference
|
||||
* Cell#library_cell_name: gets the library cell name for a "defunc" reference
|
||||
* Cell#library_name: gets the library name for a "defunc" reference
|
||||
* Cell#pcell_name: gets the pcell name for a "defunct" reference
|
||||
* Layout#delete_cells: now available with a list of cell object
|
||||
* Layout#delete_cell_rec: now available with a cell object
|
||||
* Layout#prune_cell: now available with a cell object
|
||||
* Layout#prune_cells: for pruning multiple cells in one call
|
||||
* Layout#prune_subcells: now with a cell object
|
||||
* Layout#prune_subcells: now with multiple root cells
|
||||
* Layout#flatten: now with a cell object
|
||||
* Layout#flatten_into: now with cell objects
|
||||
* Layout#delete_cell: now with a cell object
|
||||
* Default value "all" for "levels" argument in "prune_subcells" and "prune_cell"
|
||||
* Default value "all" for "levels" and "true" for "prune" argument in "flatten"
|
||||
* Default value "all" for "levels" and "unity" for "trans" argument in "flatten_into"
|
||||
|
||||
0.30.8 (2026-04-14):
|
||||
* Enhancement: %GITHUB%/issues/2248 Switch layouts but without losing the handle
|
||||
* Bugfix: %GITHUB%/issues/2299 gf180mcu DRC performance regression.
|
||||
This patch contains some other enhancements which improve performance of DRC,
|
||||
although in certain cases only.
|
||||
* Enhancement: %GITHUB%/issues/2300 More options to set layout format, specifically on LEF/DEF
|
||||
* Bugfix: %GITHUB%/2301 UI freezes permanently with open Macro Development window and event listening plugin
|
||||
* Bugfix: %GITHUB%/issues/2305 Library reloading problems
|
||||
* Enhancement: %GITHUB%/2306 Feature Request: API-access to a setter for the selected entry in the Netlist Database Browser
|
||||
* Bugfix: %GITHUB%/2311 Tip window is shown although running in non-GUI modebug
|
||||
* Bugfix: %GITHUB%/2315 Edit/Layout/Scale causes confusing
|
||||
* Enhancement: %GITHUB%/2316 Edit/Selection/Make Array: support both pitch and spacing
|
||||
* Bugfix: %GITHUB%/2320 Failure to read OASIS files with large property strings
|
||||
* Enhancement: %GITHUB%/2322 Options(text): split text scaling and rotation into two separate options
|
||||
* Enhancement: %GITHUB%/2326 Fit shouldn't take bbox of "empty" struct into account
|
||||
* Bugfix: %GITHUB%/2331 Screen size error (Assertion tlPixelBuffer.cc:260 n < m_height was not true)
|
||||
* Enhancement: "strmrun" now can run DRC and LVS scripts
|
||||
* Enhancement: "Library#library_by_name" now can be used with "*" for technology
|
||||
* Bugfix: PCell "coerce_parameters" and "callback" was called with the client layout
|
||||
instead of definition layout, hence the DBU was incorrect if both layouts have different DBU.
|
||||
* Enhancement: new config option: disable generation of new layers
|
||||
The name of the config option is "auto-create-new-layers".
|
||||
With this option set to true (default), new layers are automatically added to the layer list on
|
||||
"paste" or placing instances.
|
||||
* Enhancement: hovering over a pixel of an image with display the pixel's value in
|
||||
the status bar.
|
||||
* Enhancement: experimental support for library declaration files to install static
|
||||
libraries from other places than the "library" folder and with additional metadata.
|
||||
|
||||
0.30.7 (2026-03-07):
|
||||
* Enhancement: %GITHUB%/issues/2248 Switch layouts but without losing the handle
|
||||
* Bugfix: %GITHUB%/issues/2273 Potential use-after-free bug due to Ruby GC
|
||||
* Bugfix: %GITHUB%/issues/2277 Poor netlister performance in some cases
|
||||
* Enhancement: %GITHUB%/issues/2278 Option to hide markers frames
|
||||
* Bugfix: %GITHUB%/issues/2284 klayoutrc parse issue silently replaces config file
|
||||
* Bugfix: %GITHUB%/issues/2286 CLI arguments, '--help' / '--version' should be implemented
|
||||
* Bugfix: %GITHUB%/issues/2293 Layers window: changing the layer order with the arrow buttons deselects the layer to be moved
|
||||
* Enhancement: ReportDatabase#merge - a method to merge two report databases
|
||||
* Bugfix: double clicking an edge in partial mode opened the properties dialog, not setting a point
|
||||
* Bugfix: Python did not support downcasting of PolygonWithProperties to Polygon on Shapes#polygon for example
|
||||
* Bugfix: OASIS reader was not able to read S_GDS_PROPERTY from file level or under forward reference conditions
|
||||
* Enhancement: Adding an option '-of|--format' to strmxor and strmclip to specify the output format instead of taking it from the suffix
|
||||
* Bugfix: 'oasis_read_all_options' as always on in buddy tools
|
||||
* Bugfix: avoid a crash on application exit when using objects for user property values or names
|
||||
* Bugfix: Fixing a small glitch: drawing into a ghost cell is possible, but did not turn off the ghost cell flag
|
||||
* Bugfix: Fixing a potential segfault during layout painting due to a race condition (rare but happened)
|
||||
* Enhancement: Performance improvement for hierarchical processor - better parallelization in some cases
|
||||
|
||||
0.30.6 (2026-02-07):
|
||||
* Bugfix: %GITHUB%/issues/2210 LayoutView::create_measure_ruler() creates incorrect rulers
|
||||
* Enhancement: %GITHUB%/issues/2214 Take selection modifer into account on release rather than on click
|
||||
|
|
|
|||
|
|
@ -1,3 +1,31 @@
|
|||
klayout (0.30.10-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Sat, 25 Jul 2026 09:48:16 +0200
|
||||
|
||||
klayout (0.30.9-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Mon, 25 May 2026 19:46:05 +0200
|
||||
|
||||
klayout (0.30.8-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Tue, 14 Apr 2026 19:16:26 +0200
|
||||
|
||||
klayout (0.30.7-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
- See changelog
|
||||
|
||||
-- Matthias Köfferlein <matthias@koefferlein.de> Sat, 07 Mar 2026 13:30:05 +0100
|
||||
|
||||
klayout (0.30.6-1) unstable; urgency=low
|
||||
|
||||
* New features and bugfixes
|
||||
|
|
|
|||
|
|
@ -7,6 +7,44 @@ trigger:
|
|||
tags:
|
||||
include:
|
||||
- 'v*'
|
||||
paths:
|
||||
exclude:
|
||||
- '*.md'
|
||||
- docs/*
|
||||
- samples/*
|
||||
- etc/*
|
||||
- macbuild/*
|
||||
- ci-scripts/*
|
||||
- scripts/*
|
||||
- .travis.yml
|
||||
- Jenkinsfile*
|
||||
- .gitignore
|
||||
- LICENSE
|
||||
- COPYRIGHT
|
||||
- CONTRIB
|
||||
- Changelog*
|
||||
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- staging
|
||||
paths:
|
||||
exclude:
|
||||
- '*.md'
|
||||
- docs/*
|
||||
- samples/*
|
||||
- etc/*
|
||||
- macbuild/*
|
||||
- ci-scripts/*
|
||||
- scripts/*
|
||||
- .travis.yml
|
||||
- Jenkinsfile*
|
||||
- .gitignore
|
||||
- LICENSE
|
||||
- COPYRIGHT
|
||||
- CONTRIB
|
||||
- Changelog*
|
||||
|
||||
jobs:
|
||||
- job: Build
|
||||
|
|
@ -14,18 +52,6 @@ jobs:
|
|||
vmImage: 'windows-2022' # other options: 'macOS-10.13', 'ubuntu-16.04'
|
||||
strategy:
|
||||
matrix:
|
||||
cp36-cp36m-win_amd64.whl:
|
||||
python.version: '3.6'
|
||||
python.architecture: 'x64'
|
||||
cp37-cp37m-win_amd64.whl:
|
||||
python.version: '3.7'
|
||||
python.architecture: 'x64'
|
||||
cp38-cp38-win_amd64.whl:
|
||||
python.version: '3.8'
|
||||
python.architecture: 'x64'
|
||||
cp39-cp39-win_amd64.whl:
|
||||
python.version: '3.9'
|
||||
python.architecture: 'x64'
|
||||
cp310-cp310-win_amd64.whl:
|
||||
python.version: '3.10'
|
||||
python.architecture: 'x64'
|
||||
|
|
@ -41,18 +67,6 @@ jobs:
|
|||
cp314-cp314-win_amd64.whl:
|
||||
python.version: '3.14'
|
||||
python.architecture: 'x64'
|
||||
cp36-cp36m-win32.whl:
|
||||
python.version: '3.6'
|
||||
python.architecture: 'x86'
|
||||
cp37-cp37m-win32.whl:
|
||||
python.version: '3.7'
|
||||
python.architecture: 'x86'
|
||||
cp38-cp38-win32.whl:
|
||||
python.version: '3.8'
|
||||
python.architecture: 'x86'
|
||||
cp39-cp39-win32.whl:
|
||||
python.version: '3.9'
|
||||
python.architecture: 'x86'
|
||||
cp310-cp310-win32.whl:
|
||||
python.version: '3.10'
|
||||
python.architecture: 'x86'
|
||||
|
|
@ -76,6 +90,13 @@ jobs:
|
|||
versionSpec: '$(python.version)'
|
||||
architecture: '$(python.architecture)'
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: 'microbits | "4.0"'
|
||||
path: $(Build.SourcesDirectory)/klayout-microbits
|
||||
cacheHitVar: MICROBITS_CACHED
|
||||
displayName: 'Cache KLayout microbits'
|
||||
|
||||
# Add additional tasks to run using each Python version in the matrix above
|
||||
|
||||
# PowerShell
|
||||
|
|
@ -86,9 +107,13 @@ jobs:
|
|||
#arguments: # Optional
|
||||
script: | # Required when targetType == Inline
|
||||
pwd
|
||||
Invoke-WebRequest -Uri "https://www.klayout.org/downloads/klayout-microbits-4.0.zip" -OutFile klayout-microbits-4.0.zip
|
||||
dir
|
||||
Expand-Archive klayout-microbits-4.0.zip -DestinationPath klayout-microbits
|
||||
if ("$(MICROBITS_CACHED)" -ne "true") {
|
||||
Write-Host "Cache miss: downloading and extracting KLayout microbits..."
|
||||
Invoke-WebRequest -Uri "https://www.klayout.org/downloads/klayout-microbits-4.0.zip" -OutFile klayout-microbits-4.0.zip
|
||||
Expand-Archive klayout-microbits-4.0.zip -DestinationPath klayout-microbits
|
||||
} else {
|
||||
Write-Host "Cache hit: restored KLayout microbits from cache."
|
||||
}
|
||||
dir klayout-microbits
|
||||
#errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
|
||||
#failOnStderr: false # Optional
|
||||
|
|
@ -174,26 +199,6 @@ jobs:
|
|||
inputs:
|
||||
artifactName: 'wheel-3.10.x64'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.9.x64'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.9.x64'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.8.x64'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.8.x64'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.7.x64'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.7.x64'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.6.x64'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.6.x64'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.14.x86'
|
||||
inputs:
|
||||
|
|
@ -219,26 +224,6 @@ jobs:
|
|||
inputs:
|
||||
artifactName: 'wheel-3.10.x86'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.9.x86'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.9.x86'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.8.x86'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.8.x86'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.7.x86'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.7.x86'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: 'Download Build Artifacts wheel-3.6.x86'
|
||||
inputs:
|
||||
artifactName: 'wheel-3.6.x86'
|
||||
downloadPath: '$(System.DefaultWorkingDirectory)'
|
||||
- task: CopyFiles@2
|
||||
condition: always()
|
||||
inputs:
|
||||
|
|
|
|||
6
build.sh
|
|
@ -41,6 +41,7 @@ HAVE_CURL=0
|
|||
HAVE_EXPAT=0
|
||||
HAVE_GIT2=1
|
||||
HAVE_LSTREAM=1
|
||||
HAVE_CPP20=0
|
||||
|
||||
RUBYINCLUDE=""
|
||||
RUBYINCLUDE2=""
|
||||
|
|
@ -217,6 +218,9 @@ while [ "$*" != "" ]; do
|
|||
-nolstream)
|
||||
HAVE_LSTREAM=0
|
||||
;;
|
||||
-cpp20)
|
||||
HAVE_CPP20=1
|
||||
;;
|
||||
-qt5)
|
||||
echo "*** WARNING: -qt5 option is ignored - Qt version is auto-detected now."
|
||||
;;
|
||||
|
|
@ -275,6 +279,7 @@ while [ "$*" != "" ]; do
|
|||
echo " -libpng Use libpng instead of Qt for PNG generation"
|
||||
echo " -nolibgit2 Do not include libgit2 for Git package support"
|
||||
echo " -nolstream Do not include the LStream plugin"
|
||||
echo " -cpp20 Uses some C++20 features (e.g. atomics)"
|
||||
echo ""
|
||||
echo "Environment Variables:"
|
||||
echo ""
|
||||
|
|
@ -670,6 +675,7 @@ qmake_options=(
|
|||
HAVE_PNG="$HAVE_PNG"
|
||||
HAVE_GIT2="$HAVE_GIT2"
|
||||
HAVE_LSTREAM="$HAVE_LSTREAM"
|
||||
HAVE_CPP20="$HAVE_CPP20"
|
||||
PREFIX="$BIN"
|
||||
RPATH="$RPATH"
|
||||
KLAYOUT_VERSION="$KLAYOUT_VERSION"
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
deploy:
|
||||
dropbox_path: /Builds/klayout # The path to the folder on Dropbox where the files will go
|
||||
artifacts_path: deploy # can be a single file, or a path
|
||||
debug: true # if you want to see more logs
|
||||
|
|
@ -1,16 +1,17 @@
|
|||
Relevant KLayout version: 0.30.5<br>
|
||||
Relevant KLayout version: 0.30.9<br>
|
||||
Author: Kazzz-S<br>
|
||||
Last modified: 2025-11-10<br>
|
||||
Last modified: 2026-07-26<br>
|
||||
|
||||
# 1. Introduction
|
||||
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.30.5 or later for different 64-bit macOS, including:
|
||||
This directory **`macbuild`** contains various files required for building KLayout (http://www.klayout.de/) version 0.30.9 or later for different 64-bit macOS, including:
|
||||
* Golden Gate (27.x) : really experimental (on M4 Mac Mini)
|
||||
* Tahoe (26.x) : really experimental (on M4 Mac Mini)
|
||||
* Sequoia (15.x) : the primary development environment
|
||||
* Sonoma (14.x) : experimental
|
||||
|
||||
Building KLayout for the previous operating systems listed below has been discontinued.<br>
|
||||
Pre-built DMG packages are also not provided.<br>
|
||||
As of today (November 2025), Homebrew classifies macOS Catalina 10.15 - Ventura 13 as Tier 3.
|
||||
As of November 2025, Homebrew classifies macOS Catalina 10.15 - Ventura 13 as Tier 3.
|
||||
* Ventura (13.7.8; the build would still be possible)
|
||||
* Monterey (12.7.6; the build would still be possible)
|
||||
* Big Sur (11.7.10)
|
||||
|
|
@ -47,7 +48,7 @@ Then, follow the instructions in Section 6F.
|
|||
|
||||
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.13.x" (earlier, Python 3.12.x) in this version.
|
||||
I have also tried migrating to "Python 3.14.x" (earlier, Python 3.13.x) in this version.
|
||||
|
||||
# 3. Script language support: Ruby and Python
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ The operating system type is detected automatically.
|
|||
```
|
||||
-----------------------------------------------------------------------------------------------------------
|
||||
<< Usage of 'build4mac.py' >>
|
||||
for building KLayout 0.30.5 or later on different Apple macOS platforms.
|
||||
for building KLayout 0.30.9 or later on different Apple macOS platforms.
|
||||
|
||||
$ [python] ./build4mac.py
|
||||
option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details) | default value
|
||||
|
|
@ -88,27 +89,27 @@ $ [python] ./build4mac.py
|
|||
: (*) migration to Qt6 is ongoing |
|
||||
[-r|--ruby <type>] : case-insensitive type=['nil', 'Sys', 'MP34', 'HB34', 'Ana3'] | sys
|
||||
: nil: don't bind Ruby |
|
||||
: Sys: use [Tahoe|Sequoia|Sonoma]-bundled Ruby 2.6 |
|
||||
: Sys: use [GoldenGate|Tahoe|Sequoia|Sonoma]-bundled Ruby 2.6 |
|
||||
: MP34: use Ruby 3.4 from MacPorts |
|
||||
: HB34: use Ruby 3.4 from Homebrew |
|
||||
: Ana3: use Ruby 3.4 from Anaconda3 |
|
||||
[-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP313', 'HB313', 'Ana3', | sys
|
||||
: 'MP312', 'MP312', |
|
||||
: 'MP311', 'HB311', 'HBAuto'] |
|
||||
[-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP314', 'HB314', 'Ana3', | sys
|
||||
: 'MP314', 'HB314', |
|
||||
: 'HB311', 'HBAuto'] |
|
||||
: nil: don't bind Python |
|
||||
: Sys: use [Tahoe|Sequoia|Sonoma]-bundled Python 3.9 |
|
||||
: MP313: use Python 3.13 from MacPorts |
|
||||
: HB313: use Python 3.13 from Homebrew |
|
||||
: Ana3: use Python 3.13 from Anaconda3 |
|
||||
: MP312: use Python 3.12 from MacPorts |
|
||||
: HB312: use Python 3.12 from Homebrew |
|
||||
: MP311: use Python 3.11 from MacPorts |
|
||||
: Sys: use [GoldenGate|Tahoe|Sequoia|Sonoma]-bundled Python 3.9 |
|
||||
: MP314: use Python 3.14 from MacPorts |
|
||||
: HB314: use Python 3.14 from Homebrew |
|
||||
: Ana3: use Python 3.14 from Anaconda3 |
|
||||
: MP314: use Python 3.14 from MacPorts |
|
||||
: HB314: use Python 3.14 from Homebrew |
|
||||
: HB311: use Python 3.11 from Homebrew (+) |
|
||||
: (+) required to provide the legacy pip in HW-*.dmg |
|
||||
: HBAuto: use the latest Python 3.x auto-detected from Homebrew |
|
||||
[-P|--buildPymod] : build and deploy Pymod (*.whl) for LW-*.dmg | disabled
|
||||
[-n|--noqtbinding] : don't create Qt bindings for ruby scripts | disabled
|
||||
[-u|--noqtuitools] : don't include uitools in Qt binding | disabled
|
||||
[-s|--no32bitcoord] : don't use short (32bit) coordinates; use long (64bit) instead | disabled
|
||||
[-g|--nolibgit2] : don't include libgit2 for Git package support | disabled
|
||||
[-m|--make <option>] : option passed to 'make' | '--jobs=4'
|
||||
[-d|--debug] : enable debug mode build; AddressSanitizer (ASAN) is linked | disabled
|
||||
|
|
@ -160,27 +161,28 @@ $ ./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-Sequoia-release-RsysPsys`** directory, where
|
||||
**`ST-qt5MP.pkg.macos-Sequoia-C32-release-RsysPsys`** directory, where
|
||||
* "ST-" means this is a standard package.
|
||||
* "qt5MP" means that Qt5 from MacPorts is used.
|
||||
* "C32" means that the coordinate representation is a 32-bit integer (C64, for 64-bit).
|
||||
* "RsysPsys" means that Ruby is 2.6 provided by OS; Python is 3.9 provided by OS.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
|
||||
### 6B. Fully MacPorts-flavored build with MacPorts Ruby 3.4 and MacPorts Python 3.13
|
||||
0. Install MacPorts, then install Qt5, Ruby 3.4, Python 3.13, and libgit2 by
|
||||
### 6B. Fully MacPorts-flavored build with MacPorts Ruby 3.4 and MacPorts Python 3.14
|
||||
0. Install MacPorts, then install Qt5, Ruby 3.4, Python 3.14, and libgit2 by
|
||||
```
|
||||
$ sudo port install coreutils
|
||||
$ sudo port install findutils
|
||||
$ sudo port install qt5
|
||||
$ sudo port install ruby34
|
||||
$ sudo port install python313
|
||||
$ sudo port install py313-pip
|
||||
$ sudo port install python314
|
||||
$ sudo port install py314-pip
|
||||
$ sudo port install libgit2
|
||||
```
|
||||
1. Invoke **`build4mac.py`** with the following options:
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt5macports -r mp34 -p mp313
|
||||
$ ./build4mac.py -q qt5macports -r mp34 -p mp314
|
||||
```
|
||||
2. Confirm successful build (it will take about one hour, depending on your machine spec).
|
||||
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
|
|
@ -188,50 +190,52 @@ $ ./build4mac.py -q qt5macports -r mp34 -p mp313
|
|||
If you use `--buildPymod` option in Step-1 and Step-3, the KLayout Standalone Python Package (\*.whl) will be built and deployed under **klayout.app/Contents/pymod-dist/**.
|
||||
|
||||
```
|
||||
$ ./build4mac.py -q qt5macports -r mp34 -p mp313 -Y
|
||||
$ ./build4mac.py -q qt5macports -r mp34 -p mp314 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt5MP.pkg.macos-Sequoia-release-Rmp34Pmp313`** directory, where
|
||||
**`LW-qt5MP.pkg.macos-Sequoia-C32-release-Rmp34Pmp314`** directory, where
|
||||
* "LW-" means this is a lightweight package.
|
||||
* "qt5MP" means that Qt5 from MacPorts is used.
|
||||
* "Rmp34Pmp313" means that Ruby is 3.4 from MacPorts; Python is 3.13 from MacPorts.
|
||||
* "C32" means that the coordinate representation is a 32-bit integer (C64, for 64-bit).
|
||||
* "Rmp34Pmp314" means that Ruby is 3.4 from MacPorts; Python is 3.14 from MacPorts.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
|
||||
### 6C. Fully Homebrew-flavored build with Homebrew Ruby 3.4 and Homebrew Python 3.13
|
||||
### 6C. Fully Homebrew-flavored build with Homebrew Ruby 3.4 and Homebrew Python 3.14
|
||||
> [!IMPORTANT]
|
||||
> To build KLayout >= 0.29.0, you need "Qt6" >= 6.7.0 to address [the compilation issue](https://github.com/KLayout/klayout/issues/1599).<br>
|
||||
|
||||
0. Install Homebrew, then install Qt6, Ruby 3.4, Python 3.13, and libgit2 by
|
||||
0. Install Homebrew, then install Qt6, Ruby 3.4, Python 3.14, and libgit2 by
|
||||
```
|
||||
$ brew install qt@6
|
||||
$ brew install ruby@3.4
|
||||
$ brew install python@3.13
|
||||
$ brew install python@3.14
|
||||
$ brew install libgit2
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ cd macbuild
|
||||
$ ./python3HB.py -v 3.13
|
||||
$ ./python3HB.py -v 3.14
|
||||
```
|
||||
1. Invoke **`build4mac.py`** with the following options:
|
||||
```
|
||||
$ cd /where/'build.sh'/exists
|
||||
$ ./build4mac.py -q qt6brew -r hb34 -p hb313
|
||||
$ ./build4mac.py -q qt6brew -r hb34 -p hb314
|
||||
```
|
||||
2. Confirm successful build (it will take about one hour, depending on your machine spec).
|
||||
3. Rerun **`build4mac.py`** with the same options used in 1. PLUS "-Y" to deploy executables and libraries under **`klayout.app`** bundle.<br>
|
||||
The buddy command-line tools (strm*) will also be deployed under **klayout.app/Contents/Buddy/** in this step.<br>
|
||||
|
||||
```
|
||||
$ ./build4mac.py -q qt6brew -r hb34 -p hb313 -Y
|
||||
$ ./build4mac.py -q qt6brew -r hb34 -p hb314 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt6Brew.pkg.macos-Sequoia-release-Rhb34Phb313`** directory, where
|
||||
**`LW-qt6Brew.pkg.macos-Sequoia-C32-release-Rhb34Phb314`** directory, where
|
||||
* "LW-" means this is a lightweight package.
|
||||
* "qt6Brew" means that Qt6 from Homebrew is used.
|
||||
* "Rhb34Phb313" means that Ruby is 3.4 from Homebrew; Python is 3.13 from Homebrew.
|
||||
* "C32" means that the coordinate representation is a 32-bit integer (C64, for 64-bit).
|
||||
* "Rhb34Phb314" means that Ruby is 3.4 from Homebrew; Python is 3.14 from Homebrew.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
|
||||
> [!WARNING]
|
||||
> We can no longer use the legacy **pip** command with Homebew Python@3.13, and we will get,
|
||||
> We can no longer use the legacy **pip** command with Homebew Python@3.12-, and we will get,
|
||||
> ```
|
||||
> error: externally-managed-environment
|
||||
> ```
|
||||
|
|
@ -264,9 +268,10 @@ $ ./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-Sequoia-release-RsysPhb311`** directory, where
|
||||
**`HW-qt6Brew.pkg.macos-Sequoia-C32-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.
|
||||
* "C32" means that the coordinate representation is a 32-bit integer (C64, for 64-bit).
|
||||
* "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.
|
||||
> [!IMPORTANT]
|
||||
|
|
@ -306,9 +311,10 @@ $ ./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-Sequoia-release-RsysPhb311`** directory, where
|
||||
**`HW-qt5MP.pkg.macos-Sequoia-C32-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.
|
||||
* "C32" means that the coordinate representation is a 32-bit integer (C64, for 64-bit).
|
||||
* "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.
|
||||
|
||||
|
|
@ -355,9 +361,10 @@ $ ./build4mac.py -q qt6ana3 -r ana3 -p ana3
|
|||
$ ./build4mac.py -q qt6ana3 -r ana3 -p ana3 -Y
|
||||
```
|
||||
The application bundle **`klayout.app`** is located under:<br>
|
||||
**`LW-qt6Ana3.pkg.macos-Sequoia-release-Rana3Pana3`** directory, where
|
||||
**`LW-qt6Ana3.pkg.macos-Sequoia-C32-release-Rana3Pana3`** directory, where
|
||||
* "LW-" means this is a lightweight package.
|
||||
* "qt6Ana3" means that Qt6 from Anaconda3 is used.
|
||||
* "C32" means that the coordinate representation is a 32-bit integer (C64, for 64-bit).
|
||||
* "Rana3Pana3" means that Ruby (3.4) is from Anaconda3; Python (3.13) is from Anaconda3.
|
||||
4. Copy/move the generated application bundle **`klayout.app`** to your **`/Applications`** directory for installation.
|
||||
5. Now, you need to create an Automator wrapper app (Launcher) to start the application.
|
||||
|
|
@ -420,11 +427,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-Sequoia-release-Rmp34Pmp313 -m
|
||||
$ ./makeDMG4mac.py -p LW-qt5MP.pkg.macos-Sequoia-C32-release-Rmp34Pmp314 -m
|
||||
```
|
||||
This command will generate the two files below:<br>
|
||||
* **`LW-klayout-0.30.5-macOS-Sequoia-1-qt5MP-Rmp34Pmp313.dmg`** ---(1) the main DMG file
|
||||
* **`LW-klayout-0.30.5-macOS-Sequoia-1-qt5MP-Rmp34Pmp313.dmg.md5`** ---(2) MD5-value text file
|
||||
* **`LW-klayout-0.30.9-macOS-Sequoia-C32-1-qt5MP-Rmp34Pmp314.dmg`** ---(1) the main DMG file
|
||||
* **`LW-klayout-0.30.9-macOS-Sequoia-C32-1-qt5MP-Rmp34Pmp314.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>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 212 KiB |
|
|
@ -5,7 +5,7 @@
|
|||
# File: "macbuild/build4mac.py"
|
||||
#
|
||||
# The top Python script for building KLayout (http://www.klayout.de/index.php).
|
||||
# version 0.30.5 or later on different Apple Mac OSX platforms.
|
||||
# version 0.30.9 or later on different Apple Mac OSX platforms.
|
||||
#===============================================================================
|
||||
import sys
|
||||
import os
|
||||
|
|
@ -36,7 +36,7 @@ from bundle_qtconf import generate_qtconf, QtConfError
|
|||
# @return (usage, moduleset)-tuple
|
||||
#-------------------------------------------------------------------------------
|
||||
def GenerateUsage(platform):
|
||||
if platform.upper() in [ "TAHOE", "SEQUOIA", "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ]
|
||||
if platform.upper() in [ "GOLDENGATE", "TAHOE", "SEQUOIA", "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ]
|
||||
myQt56 = "qt5macports"
|
||||
myRuby = "sys"
|
||||
myPython = "sys"
|
||||
|
|
@ -47,7 +47,7 @@ def GenerateUsage(platform):
|
|||
usage = "\n"
|
||||
usage += "-----------------------------------------------------------------------------------------------------------\n"
|
||||
usage += "<< Usage of 'build4mac.py' >>\n"
|
||||
usage += " for building KLayout 0.30.5 or later on different Apple macOS platforms.\n"
|
||||
usage += " for building KLayout 0.30.9 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"
|
||||
|
|
@ -63,27 +63,27 @@ def GenerateUsage(platform):
|
|||
usage += " : (*) migration to Qt6 is ongoing |\n"
|
||||
usage += " [-r|--ruby <type>] : case-insensitive type=['nil', 'Sys', 'MP34', 'HB34', 'Ana3'] | %s\n" % myRuby
|
||||
usage += " : nil: don't bind Ruby |\n"
|
||||
usage += " : Sys: use [Tahoe|Sequoia|Sonoma]-bundled Ruby 2.6 |\n"
|
||||
usage += " : Sys: use [GoldenGate|Tahoe|Sequoia|Sonoma]-bundled Ruby 2.6 |\n"
|
||||
usage += " : MP34: use Ruby 3.4 from MacPorts |\n"
|
||||
usage += " : HB34: use Ruby 3.4 from Homebrew |\n"
|
||||
usage += " : Ana3: use Ruby 3.4 from Anaconda3 |\n"
|
||||
usage += " [-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP313', 'HB313', 'Ana3', | %s\n" % myPython
|
||||
usage += " : 'MP312', 'MP312', |\n"
|
||||
usage += " : 'MP311', 'HB311', 'HBAuto'] |\n"
|
||||
usage += " [-p|--python <type>] : case-insensitive type=['nil', 'Sys', 'MP314', 'HB314', 'Ana3', | %s\n" % myPython
|
||||
usage += " : 'MP313', 'HB313', |\n"
|
||||
usage += " : 'HB311', 'HBAuto'] |\n"
|
||||
usage += " : nil: don't bind Python |\n"
|
||||
usage += " : Sys: use [Tahoe|Sequoia|Sonoma]-bundled Python 3.9 |\n"
|
||||
usage += " : Sys: use [GoldenGate|Tahoe|Sequoia|Sonoma]-bundled Python 3.9 |\n"
|
||||
usage += " : MP314: use Python 3.14 from MacPorts |\n"
|
||||
usage += " : HB314: use Python 3.14 from Homebrew |\n"
|
||||
usage += " : Ana3: use Python 3.13 from Anaconda3 |\n"
|
||||
usage += " : MP313: use Python 3.13 from MacPorts |\n"
|
||||
usage += " : HB313: use Python 3.13 from Homebrew |\n"
|
||||
usage += " : Ana3: use Python 3.13 from Anaconda3 |\n"
|
||||
usage += " : MP312: use Python 3.12 from MacPorts |\n"
|
||||
usage += " : HB312: use Python 3.12 from Homebrew |\n"
|
||||
usage += " : MP311: use Python 3.11 from MacPorts |\n"
|
||||
usage += " : HB311: use Python 3.11 from Homebrew (+) |\n"
|
||||
usage += " : (+) required to provide the legacy pip in HW-*.dmg |\n"
|
||||
usage += " : HBAuto: use the latest Python 3.x auto-detected from Homebrew |\n"
|
||||
usage += " [-P|--buildPymod] : build and deploy Pymod (*.whl) for LW-*.dmg | disabled\n"
|
||||
usage += " [-n|--noqtbinding] : don't create Qt bindings for ruby scripts | disabled\n"
|
||||
usage += " [-u|--noqtuitools] : don't include uitools in Qt binding | disabled\n"
|
||||
usage += " [-s|--no32bitcoord] : don't use short (32bit) coordinates; use long (64bit) instead | disabled\n"
|
||||
usage += " [-g|--nolibgit2] : don't include libgit2 for Git package support | disabled\n"
|
||||
usage += " [-m|--make <option>] : option passed to 'make' | '--jobs=4'\n"
|
||||
usage += " [-d|--debug] : enable debug mode build; AddressSanitizer (ASAN) is linked | disabled\n"
|
||||
|
|
@ -123,7 +123,9 @@ def Get_Default_Config():
|
|||
# Dropped [ElCapitan - BigSur] (2023-10-24).
|
||||
# See 415b5aa2efca04928f1148a69e77efd5d76f8c1d for the previous states.
|
||||
#----------------------------------------------------------------------------
|
||||
if release == 25:
|
||||
if release == 27:
|
||||
Platform = "GoldenGate"
|
||||
elif release == 25:
|
||||
Platform = "Tahoe"
|
||||
elif release == 24:
|
||||
Platform = "Sequoia"
|
||||
|
|
@ -142,7 +144,7 @@ def Get_Default_Config():
|
|||
|
||||
if not Machine == "x86_64":
|
||||
# with an Apple Silicon Chip?
|
||||
if Machine == "arm64" and Platform in ["Tahoe", "Sequoia", "Sonoma", "Ventura", "Monterey"]:
|
||||
if Machine == "arm64" and Platform in ["GoldenGate", "Tahoe", "Sequoia", "Sonoma", "Ventura", "Monterey"]:
|
||||
print("")
|
||||
print( "### Your Mac equips an Apple Silicon Chip ###" )
|
||||
print( " Setting QMAKE_APPLE_DEVICE_ARCHS=arm64\n")
|
||||
|
|
@ -160,7 +162,11 @@ def Get_Default_Config():
|
|||
ToolDebug = list()
|
||||
|
||||
# Set the default modules
|
||||
if Platform == "Tahoe":
|
||||
if Platform == "GoldenGate":
|
||||
ModuleQt = "Qt5MacPorts"
|
||||
ModuleRuby = "Sys"
|
||||
ModulePython = "Sys"
|
||||
elif Platform == "Tahoe":
|
||||
ModuleQt = "Qt5MacPorts"
|
||||
ModuleRuby = "Sys"
|
||||
ModulePython = "Sys"
|
||||
|
|
@ -189,6 +195,7 @@ def Get_Default_Config():
|
|||
NonOSStdLang = False
|
||||
NoQtBindings = False
|
||||
NoQtUiTools = False
|
||||
No32bitCoord = False
|
||||
NoLibGit2 = False
|
||||
MakeOptions = "--jobs=4"
|
||||
DebugMode = False
|
||||
|
|
@ -214,6 +221,7 @@ def Get_Default_Config():
|
|||
config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen
|
||||
config['NoQtBindings'] = NoQtBindings # True if not creating Qt bindings for Ruby scripts
|
||||
config['NoQtUiTools'] = NoQtUiTools # True if not to include QtUiTools in Qt binding
|
||||
config['No32bitCoord'] = No32bitCoord # True if not use the short (32bit) coordinate
|
||||
config['NoLibGit2'] = NoLibGit2 # True if not to include libgit2 for Git package support
|
||||
config['MakeOptions'] = MakeOptions # options passed to `make`
|
||||
config['DebugMode'] = DebugMode # True if debug mode build
|
||||
|
|
@ -259,6 +267,7 @@ def Parse_CLI_Args(config):
|
|||
NonOSStdLang = config['NonOSStdLang']
|
||||
NoQtBindings = config['NoQtBindings']
|
||||
NoQtUiTools = config['NoQtUiTools']
|
||||
No32bitCoord = config['No32bitCoord']
|
||||
NoLibGit2 = config['NoLibGit2']
|
||||
MakeOptions = config['MakeOptions']
|
||||
DebugMode = config['DebugMode']
|
||||
|
|
@ -287,7 +296,7 @@ def Parse_CLI_Args(config):
|
|||
|
||||
p.add_option( '-p', '--python',
|
||||
dest='type_python',
|
||||
help="Python type=['nil', 'Sys', 'MP313', 'HB313', 'Ana3', 'MP312', 'HB312', 'MP311', 'HB311', 'HBAuto']" )
|
||||
help="Python type=['nil', 'Sys', 'MP314', 'HB314', 'Ana3', 'MP313', 'HB313', 'HB311', 'HBAuto']" )
|
||||
|
||||
p.add_option( '-P', '--buildPymod',
|
||||
action='store_true',
|
||||
|
|
@ -307,6 +316,12 @@ def Parse_CLI_Args(config):
|
|||
default=False,
|
||||
help="don't include uitools in Qt binding" )
|
||||
|
||||
p.add_option( '-s', '--no32bitcoord',
|
||||
action='store_true',
|
||||
dest='no_32_bitcoord',
|
||||
default=False,
|
||||
help="don't use short (32bit) coordinates; use long (64bit) instead " )
|
||||
|
||||
p.add_option( '-g', '--nolibgit2',
|
||||
action='store_true',
|
||||
dest='no_libgit2',
|
||||
|
|
@ -356,13 +371,14 @@ def Parse_CLI_Args(config):
|
|||
default=False,
|
||||
help='check usage' )
|
||||
|
||||
if Platform.upper() in [ "TAHOE", "SEQUOIA", "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ]
|
||||
if Platform.upper() in [ "GOLDENGATE", "TAHOE", "SEQUOIA", "SONOMA", "VENTURA", "MONTEREY" ]: # with Xcode [13.1 .. ]
|
||||
p.set_defaults( type_qt = "qt5macports",
|
||||
type_ruby = "sys",
|
||||
type_python = "sys",
|
||||
build_pymod_whl = False,
|
||||
no_qt_binding = False,
|
||||
no_qt_uitools = False,
|
||||
no_32_bitcoord = False,
|
||||
no_libgit2 = False,
|
||||
make_option = "--jobs=4",
|
||||
debug_build = False,
|
||||
|
|
@ -432,7 +448,9 @@ def Parse_CLI_Args(config):
|
|||
if choiceRuby == "nil":
|
||||
ModuleRuby = 'nil'
|
||||
elif choiceRuby == "Sys":
|
||||
if Platform == "Tahoe":
|
||||
if Platform == "GoldenGate":
|
||||
ModuleRuby = 'RubyGoldenGate'
|
||||
elif Platform == "Tahoe":
|
||||
ModuleRuby = 'RubyTahoe'
|
||||
elif Platform == "Sequoia":
|
||||
ModuleRuby = 'RubySequoia'
|
||||
|
|
@ -465,12 +483,11 @@ def Parse_CLI_Args(config):
|
|||
candidates = dict()
|
||||
candidates['NIL'] = 'nil'
|
||||
candidates['SYS'] = 'Sys'
|
||||
candidates['MP314'] = 'MP314'
|
||||
candidates['HB314'] = 'HB314'
|
||||
candidates['ANA3'] = 'Ana3'
|
||||
candidates['MP313'] = 'MP313'
|
||||
candidates['HB313'] = 'HB313'
|
||||
candidates['ANA3'] = 'Ana3'
|
||||
candidates['MP312'] = 'MP312'
|
||||
candidates['HB312'] = 'HB312'
|
||||
candidates['MP311'] = 'MP311'
|
||||
candidates['HB311'] = 'HB311'
|
||||
candidates['HBAUTO'] = 'HBAuto'
|
||||
try:
|
||||
|
|
@ -484,7 +501,10 @@ def Parse_CLI_Args(config):
|
|||
ModulePython = 'nil'
|
||||
OSPython3FW = None
|
||||
elif choicePython == "Sys":
|
||||
if Platform == "Tahoe":
|
||||
if Platform == "GoldenGate":
|
||||
ModulePython = 'PythonGoldenGate'
|
||||
OSPython3FW = GoldenGatePy3FW
|
||||
elif Platform == "Tahoe":
|
||||
ModulePython = 'PythonTahoe'
|
||||
OSPython3FW = TahoePy3FW
|
||||
elif Platform == "Sequoia":
|
||||
|
|
@ -499,12 +519,12 @@ def Parse_CLI_Args(config):
|
|||
elif Platform == "Monterey":
|
||||
ModulePython = 'PythonMonterey'
|
||||
OSPython3FW = MontereyPy3FW
|
||||
elif choicePython == "MP313":
|
||||
ModulePython = 'Python313MacPorts'
|
||||
elif choicePython == "MP314":
|
||||
ModulePython = 'Python314MacPorts'
|
||||
OSPython3FW = None
|
||||
NonOSStdLang = True
|
||||
elif choicePython == "HB313":
|
||||
ModulePython = 'Python313Brew'
|
||||
elif choicePython == "HB314":
|
||||
ModulePython = 'Python314Brew'
|
||||
OSPython3FW = None
|
||||
NonOSStdLang = True
|
||||
elif choicePython == "Ana3":
|
||||
|
|
@ -514,12 +534,12 @@ def Parse_CLI_Args(config):
|
|||
ModulePython = 'PythonAnaconda3V6'
|
||||
OSPython3FW = None
|
||||
NonOSStdLang = True
|
||||
elif choicePython == "MP312":
|
||||
ModulePython = 'Python312MacPorts'
|
||||
elif choicePython == "MP313":
|
||||
ModulePython = 'Python313MacPorts'
|
||||
OSPython3FW = None
|
||||
NonOSStdLang = True
|
||||
elif choicePython == "HB312":
|
||||
ModulePython = 'Python312Brew'
|
||||
elif choicePython == "HB313":
|
||||
ModulePython = 'Python313Brew'
|
||||
OSPython3FW = None
|
||||
NonOSStdLang = True
|
||||
elif choicePython == "HB311":
|
||||
|
|
@ -544,6 +564,7 @@ def Parse_CLI_Args(config):
|
|||
BuildPymodWhl = opt.build_pymod_whl
|
||||
NoQtBindings = opt.no_qt_binding
|
||||
NoQtUiTools = opt.no_qt_uitools
|
||||
No32bitCoord = opt.no_32_bitcoord
|
||||
NoLibGit2 = opt.no_libgit2
|
||||
MakeOptions = opt.make_option
|
||||
DebugMode = opt.debug_build
|
||||
|
|
@ -630,6 +651,7 @@ def Parse_CLI_Args(config):
|
|||
config['NonOSStdLang'] = NonOSStdLang
|
||||
config['NoQtBindings'] = NoQtBindings
|
||||
config['NoQtUiTools'] = NoQtUiTools
|
||||
config['No32bitCoord'] = No32bitCoord
|
||||
config['NoLibGit2'] = NoLibGit2
|
||||
config['MakeOptions'] = MakeOptions
|
||||
config['DebugMode'] = DebugMode
|
||||
|
|
@ -674,6 +696,7 @@ def Get_Build_Parameters(config):
|
|||
ModuleSet = config['ModuleSet']
|
||||
NoQtBindings = config['NoQtBindings']
|
||||
NoQtUiTools = config['NoQtUiTools']
|
||||
No32bitCoord = config['No32bitCoord']
|
||||
NoLibGit2 = config['NoLibGit2']
|
||||
MakeOptions = config['MakeOptions']
|
||||
DebugMode = config['DebugMode']
|
||||
|
|
@ -701,34 +724,46 @@ def Get_Build_Parameters(config):
|
|||
(qt, ruby, python) = ModuleSet # ( 'qt6Brew', 'Sys', 'Sys' )
|
||||
ruby_python = "R%sP%s" % ( ruby.lower(), python.lower() )
|
||||
|
||||
# (C) Target directories and files
|
||||
MacPkgDir = "%s%s.pkg.macos-%s-%s-%s" % (PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
MacBinDir = "%s.bin.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
|
||||
MacBuildDir = "%s.build.macos-%s-%s-%s" % ( qt, Platform, mode, ruby_python)
|
||||
MacBuildLog = "%s.build.macos-%s-%s-%s.log" % ( qt, Platform, mode, ruby_python)
|
||||
# (C) Coordinate size
|
||||
if No32bitCoord:
|
||||
coordSize = "C64"
|
||||
else:
|
||||
coordSize = "C32"
|
||||
|
||||
# (D) Target directories and files
|
||||
MacPkgDir = "%s%s.pkg.macos-%s-%s-%s-%s" % (PackagePrefix, qt, Platform, coordSize, mode, ruby_python)
|
||||
MacBinDir = "%s.bin.macos-%s-%s-%s-%s" % ( qt, Platform, coordSize, mode, ruby_python)
|
||||
MacBuildDir = "%s.build.macos-%s-%s-%s-%s" % ( qt, Platform, coordSize, mode, ruby_python)
|
||||
MacBuildLog = "%s.build.macos-%s-%s-%s-%s.log" % ( qt, Platform, coordSize, mode, ruby_python)
|
||||
MacBuildDirQAT = MacBuildDir + ".macQAT"
|
||||
parameters['bin'] = MacBinDir
|
||||
parameters['build'] = MacBuildDir
|
||||
parameters['logfile'] = MacBuildLog
|
||||
|
||||
# (D) about Qt[5|6]
|
||||
# (E) about Qt[5|6]
|
||||
parameters['qmake'] = Qt56Dictionary[ModuleQt]['qmake']
|
||||
parameters['deploy_tool'] = Qt56Dictionary[ModuleQt]['deploy']
|
||||
parameters['qt_lib_root'] = Qt56Dictionary[ModuleQt]['libdir']
|
||||
|
||||
# (E) rpath
|
||||
# (F) rpath
|
||||
if OSPython3FW in [ MontereyPy3FW, VenturaPy3FW, SonomaPy3FW, SequoiaPy3FW, TahoePy3FW ]:
|
||||
parameters['rpath'] = OSPython3FW
|
||||
else:
|
||||
parameters['rpath'] = "@executable_path/../Frameworks"
|
||||
|
||||
# (F) want Qt bindings with Ruby scripts?
|
||||
# (G) want Qt bindings with Ruby scripts?
|
||||
parameters['no_qt_bindings'] = NoQtBindings
|
||||
|
||||
# (G) want QtUiTools?
|
||||
# (H) want QtUiTools?
|
||||
parameters['no_qt_uitools'] = NoQtUiTools
|
||||
|
||||
# (H) options to `make` tool
|
||||
# (I) want 32bitCoord?
|
||||
parameters['no_32_bitcoord'] = No32bitCoord
|
||||
|
||||
# (J) want libgit2?
|
||||
parameters['no_libgit2'] = NoLibGit2
|
||||
|
||||
# (K) options to `make` tool
|
||||
if not MakeOptions == "":
|
||||
parameters['make_options'] = MakeOptions
|
||||
try:
|
||||
|
|
@ -739,7 +774,7 @@ def Get_Build_Parameters(config):
|
|||
else:
|
||||
parameters['num_parallel'] = pnum
|
||||
|
||||
# (I) about Ruby
|
||||
# (L) about Ruby
|
||||
if ModuleRuby != "nil":
|
||||
parameters['ruby'] = RubyDictionary[ModuleRuby]['exe']
|
||||
parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc']
|
||||
|
|
@ -747,7 +782,7 @@ def Get_Build_Parameters(config):
|
|||
if 'inc2' in RubyDictionary[ModuleRuby]:
|
||||
parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2']
|
||||
|
||||
# (J) about Python
|
||||
# (M) about Python
|
||||
if ModulePython != "nil":
|
||||
parameters['python'] = PythonDictionary[ModulePython]['exe']
|
||||
parameters['pyinc'] = PythonDictionary[ModulePython]['inc']
|
||||
|
|
@ -759,28 +794,28 @@ def Get_Build_Parameters(config):
|
|||
config['MacBuildDirQAT'] = MacBuildDirQAT # relative path to build directory for QATest
|
||||
config['MacBuildLog'] = MacBuildLog # relative path to build log file
|
||||
|
||||
# (K) Extra parameters needed for deployment
|
||||
# (N) Extra parameters needed for deployment
|
||||
parameters['project_dir'] = ProjectDir
|
||||
|
||||
# (L) Extra parameters needed for <pymod>
|
||||
# (O) Extra parameters needed for <pymod>
|
||||
# <pymod> will be built if:
|
||||
# BuildPymodWhl = True
|
||||
# Platform = [ 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]
|
||||
# ModuleRuby = [ 'Ruby34MacPorts', 'Ruby34Brew', 'RubyAnaconda3' ]
|
||||
# ModulePython = [ 'Python313MacPorts', 'Python312MacPorts', 'Python311MacPorts',
|
||||
# 'Python313Brew', 'Python312Brew', 'Python311Brew',
|
||||
# 'PythonAnaconda3' ]
|
||||
# Platform = [ 'GoldenGate', 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]
|
||||
# ModuleRuby = [ 'Ruby34MacPorts', 'Ruby34Brew', 'RubyAnaconda3V5', 'RubyAnaconda3V6' ]
|
||||
# ModulePython = [ 'Python314MacPorts', 'Python313MacPorts',
|
||||
# 'Python314Brew', 'Python313Brew', 'Python311Brew',
|
||||
# 'PythonAnaconda3V5', 'PythonAnaconda3V6' ]
|
||||
parameters['BuildPymodWhl'] = BuildPymodWhl
|
||||
parameters['Platform'] = Platform
|
||||
parameters['ModuleRuby'] = ModuleRuby
|
||||
parameters['ModulePython'] = ModulePython
|
||||
|
||||
PymodDistDir = dict()
|
||||
if Platform in [ 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]:
|
||||
if Platform in [ 'GoldenGate', 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]:
|
||||
if ModuleRuby in [ 'Ruby34MacPorts', 'Ruby34Brew', 'RubyAnaconda3V5', 'RubyAnaconda3V6' ]:
|
||||
if ModulePython in [ 'Python313MacPorts', 'Python312MacPorts', 'Python311MacPorts' ]:
|
||||
if ModulePython in [ 'Python314MacPorts', 'Python313MacPorts' ]:
|
||||
PymodDistDir[ModulePython] = 'dist-MP3-%s' % ModuleQt
|
||||
elif ModulePython in [ 'Python313Brew', 'Python312Brew', 'Python311Brew' ]:
|
||||
elif ModulePython in [ 'Python314Brew', 'Python313Brew', 'Python311Brew' ]:
|
||||
PymodDistDir[ModulePython] = 'dist-HB3-%s' % ModuleQt
|
||||
elif ModulePython in [ 'PythonAnaconda3V5', 'PythonAnaconda3V6' ]:
|
||||
PymodDistDir[ModulePython] = 'dist-ana3-%s' % ModuleQt
|
||||
|
|
@ -799,10 +834,10 @@ def Build_pymod_wheel(parameters):
|
|||
#-----------------------------------------------------------------------------------------------------------
|
||||
# [1] <pymod> will be built if:
|
||||
# BuildPymodWhl = True
|
||||
# Platform = [ 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]
|
||||
# Platform = [ 'GoldenGate', 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]
|
||||
# ModuleRuby = [ 'Ruby34MacPorts', 'Ruby34Brew', 'RubyAnaconda3V5', 'RubyAnaconda3V6' ]
|
||||
# ModulePython = [ 'Python313MacPorts', 'Python312MacPorts', 'Python311MacPorts',
|
||||
# 'Python313Brew', 'Python312Brew', 'Python311Brew',
|
||||
# ModulePython = [ 'Python314MacPorts', 'Python313MacPorts',
|
||||
# 'Python314Brew', 'Python313Brew', 'Python311Brew',
|
||||
# 'PythonAnaconda3V5', 'PythonAnaconda3V6' ]
|
||||
#-----------------------------------------------------------------------------------------------------------
|
||||
BuildPymodWhl = parameters['BuildPymodWhl']
|
||||
|
|
@ -811,12 +846,12 @@ def Build_pymod_wheel(parameters):
|
|||
ModulePython = parameters['ModulePython']
|
||||
if not BuildPymodWhl:
|
||||
return 0
|
||||
if not Platform in [ 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]:
|
||||
if not Platform in [ 'GoldenGate', 'Tahoe', 'Sequoia', 'Sonoma', 'Ventura', 'Monterey' ]:
|
||||
return 0
|
||||
elif not ModuleRuby in [ 'Ruby34MacPorts', 'Ruby34Brew', 'RubyAnaconda3V5', 'RubyAnaconda3V6' ]:
|
||||
return 0
|
||||
elif not ModulePython in [ 'Python313MacPorts', 'Python312MacPorts', 'Python311MacPorts', \
|
||||
'Python313Brew', 'Python312Brew', 'Python311Brew', \
|
||||
elif not ModulePython in [ 'Python314MacPorts', 'Python313MacPorts', \
|
||||
'Python314Brew', 'Python313Brew', 'Python311Brew', \
|
||||
'PythonAnaconda3V5', 'PythonAnaconda3V6' ]:
|
||||
return 0
|
||||
|
||||
|
|
@ -1124,25 +1159,31 @@ def Run_Build_Command(config, parameters):
|
|||
cmd_args += " \\\n -build %s" % parameters['build']
|
||||
cmd_args += " \\\n -rpath %s" % parameters['rpath']
|
||||
|
||||
# (E) want Qt bindings with Ruby scripts?
|
||||
# (F) want Qt bindings with Ruby scripts?
|
||||
if parameters['no_qt_bindings']:
|
||||
cmd_args += " \\\n -without-qtbinding"
|
||||
else:
|
||||
cmd_args += " \\\n -with-qtbinding"
|
||||
|
||||
# (F) want QtUiTools?
|
||||
# (G) want QtUiTools?
|
||||
if parameters['no_qt_uitools']:
|
||||
cmd_args += " \\\n -without-qt-uitools"
|
||||
|
||||
# (G) don't want to use libgit2?
|
||||
if NoLibGit2:
|
||||
cmd_args += " \\\n -libgit2"
|
||||
# (I) want 32bitCoord?
|
||||
if parameters['no_32_bitcoord']:
|
||||
cmd_args += " \\\n -with-64bit-coord" # EXPERIMENTAL FEATURE
|
||||
else:
|
||||
cmd_args += " \\\n -without-64bit-coord" # default
|
||||
|
||||
# (H) options to `make` tool
|
||||
# (J) want libgit2?
|
||||
if parameters['no_libgit2']:
|
||||
cmd_args += " \\\n -nolibgit2"
|
||||
|
||||
# (K) options to `make` tool
|
||||
if 'make_options' in parameters:
|
||||
cmd_args += " \\\n -option %s" % parameters['make_options']
|
||||
|
||||
# (I) about Ruby
|
||||
# (L) about Ruby
|
||||
if 'ruby' in parameters:
|
||||
cmd_args += " \\\n -ruby %s" % parameters['ruby']
|
||||
cmd_args += " \\\n -rbinc %s" % parameters['rbinc']
|
||||
|
|
@ -1152,7 +1193,7 @@ def Run_Build_Command(config, parameters):
|
|||
else:
|
||||
cmd_args += " \\\n -noruby"
|
||||
|
||||
# (J) about Python
|
||||
# (M) about Python
|
||||
if 'python' in parameters:
|
||||
cmd_args += " \\\n -python %s" % parameters['python']
|
||||
cmd_args += " \\\n -pyinc %s" % parameters['pyinc']
|
||||
|
|
@ -1645,9 +1686,10 @@ def Deploy_Binaries_For_Bundle(config, parameters):
|
|||
regQt = re.compile(patQt)
|
||||
|
||||
# (4) Python frameworks (only for Homebrew) # in the case of Intel Mac...
|
||||
libPy3_1 = "%s/" % HBPython312FrameworkPath # /usr/local/opt/python@3.12/Frameworks/Python.framework/
|
||||
libPy3_2 = "%s/" % HBPython311FrameworkPath # /usr/local/opt/python@3.11/Frameworks/Python.framework/
|
||||
patPy3 = r'^(%s|%s)(.+)' % (libPy3_1, libPy3_2)
|
||||
libPy3_1 = "%s/" % HBPython314FrameworkPath # /usr/local/opt/python@3.14/Frameworks/Python.framework/
|
||||
libPy3_2 = "%s/" % HBPython313FrameworkPath # /usr/local/opt/python@3.13/Frameworks/Python.framework/
|
||||
libPy3_3 = "%s/" % HBPython311FrameworkPath # /usr/local/opt/python@3.11/Frameworks/Python.framework/
|
||||
patPy3 = r'^(%s|%s|%s)(.+)' % (libPy3_1, libPy3_2, libPy3_3)
|
||||
regPy3 = re.compile(patPy3)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
|
@ -1991,7 +2033,25 @@ def Deploy_Binaries_For_Bundle(config, parameters):
|
|||
cmd06 = "rm -rf %s" % binTarget
|
||||
|
||||
cmd07 = "mkdir %s" % sitepackagesTarget
|
||||
cmd08 = "cp -RL %s/{*distutils*,pip*,pkg_resources,setuptools*,wheel*} %s" % (sitepackagesSource, sitepackagesTarget)
|
||||
# cmd08 = "cp -RL %s/{*distutils*,pip*,pkg_resources,setuptools*,wheel*} %s" % (sitepackagesSource, sitepackagesTarget)
|
||||
# Updated for compatibility with modern Python environments (e.g., pip 26.0.1+).
|
||||
# Since 'pkg_resources' and other legacy paths may be absent in recent setuptools,
|
||||
# we use a loop to copy only available directories while suppressing errors.
|
||||
# Define patterns for essential packages to be bundled
|
||||
patterns = ['*distutils*', 'pip*', 'pkg_resources*', 'setuptools*', 'wheel*']
|
||||
sources = []
|
||||
|
||||
# Collect only existing paths to avoid "No such file or directory" errors,
|
||||
# especially for 'pkg_resources' which is deprecated and often missing in Python 3.11+.
|
||||
for p in patterns:
|
||||
sources.extend(glob.glob(os.path.join(sitepackagesSource, p)))
|
||||
|
||||
if sources:
|
||||
# Join all existing paths into a single string for the 'cp' command
|
||||
cmd08 = "cp -RL %s %s" % (" ".join(sources), sitepackagesTarget)
|
||||
else:
|
||||
# Fallback or log if no packages are found
|
||||
cmd08 = "echo 'No matching site-packages found to copy; skipping.'"
|
||||
|
||||
shell_commands = list()
|
||||
shell_commands.append(cmd01)
|
||||
|
|
@ -2267,7 +2327,7 @@ def Deploy_Binaries_For_Bundle(config, parameters):
|
|||
#-------------------------------------------------------------
|
||||
# [11] Sign the application bundle
|
||||
#-------------------------------------------------------------
|
||||
if Platform in ['Tahoe']:
|
||||
if Platform in ['GoldenGate', 'Tahoe']:
|
||||
print( " [11] Signing the macOS application bundle (ad-hoc) after all post-build edits (install_name_tool/strip)..." )
|
||||
appbundle = "%s/klayout.app" % AbsMacPkgDir
|
||||
res = Sign_App_Bundle(appbundle)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
# Here are dictionaries of ...
|
||||
# different modules for building KLayout (http://www.klayout.de/index.php)
|
||||
# version 0.30.5 or later on different Apple Mac OSX platforms.
|
||||
# version 0.30.9 or later on different Apple Mac OSX platforms.
|
||||
#
|
||||
# This file is imported by the 'build4mac.py' script.
|
||||
#===============================================================================
|
||||
|
|
@ -255,7 +255,7 @@ Qt56Dictionary = { 'Qt5MacPorts': Qt5MacPorts,
|
|||
# for the previous states.
|
||||
#-----------------------------------------------------
|
||||
RubyNil = [ 'nil' ]
|
||||
RubySys = [ 'RubyMonterey', 'RubyVentura', 'RubySonoma', 'RubySequoia', 'RubyTahoe' ]
|
||||
RubySys = [ 'RubyMonterey', 'RubyVentura', 'RubySonoma', 'RubySequoia', 'RubyTahoe', 'RubyGoldenGate' ]
|
||||
RubyExt = [ 'Ruby34MacPorts', 'Ruby34Brew', 'RubyAnaconda3' ]
|
||||
Rubies = RubyNil + RubySys + RubyExt
|
||||
|
||||
|
|
@ -324,11 +324,21 @@ RubyTahoe = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions
|
|||
'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % TahoeXcSDK
|
||||
}
|
||||
|
||||
# Bundled with Golden Gate (27.x)
|
||||
# [Key Type Name] = 'Sys'
|
||||
GoldenGateXcSDK = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
|
||||
GoldenGateCLTSDK = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
|
||||
RubyGoldenGate = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/bin/ruby',
|
||||
'inc': '%s/System/Library/Frameworks/Ruby.framework/Headers' % GoldenGateXcSDK,
|
||||
'inc2': '%s/System/Library/Frameworks/Ruby.framework/Headers/ruby' % GoldenGateXcSDK,
|
||||
'lib': '%s/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/libruby.tbd' % GoldenGateXcSDK
|
||||
}
|
||||
|
||||
# Ruby 3.4 from MacPorts (https://www.macports.org/)
|
||||
# install with 'sudo port install ruby34'
|
||||
# [Key Type Name] = 'MP34'
|
||||
Ruby34MacPorts = { 'exe': '/opt/local/bin/ruby3.4',
|
||||
'inc': '/opt/local/include/ruby-3.4.7',
|
||||
'inc': '/opt/local/include/ruby-3.4.10',
|
||||
'lib': '/opt/local/lib/libruby.3.4.dylib'
|
||||
}
|
||||
|
||||
|
|
@ -361,6 +371,7 @@ RubyDictionary = { 'nil' : None,
|
|||
'RubySonoma' : RubySonoma,
|
||||
'RubySequoia' : RubySequoia,
|
||||
'RubyTahoe' : RubyTahoe,
|
||||
'RubyGoldenGate' : RubyGoldenGate,
|
||||
'Ruby34MacPorts' : Ruby34MacPorts,
|
||||
'Ruby34Brew' : Ruby34Brew,
|
||||
'RubyAnaconda3V5' : RubyAnaconda3V5,
|
||||
|
|
@ -376,9 +387,9 @@ RubyDictionary = { 'nil' : None,
|
|||
# for the previous states.
|
||||
#-----------------------------------------------------
|
||||
PythonNil = [ 'nil' ]
|
||||
PythonSys = [ 'PythonMonterey', 'PythonVentura', 'PythonSonoma', 'PythonSequoia', 'PythonTahoe' ]
|
||||
PythonExt = [ 'Python311MacPorts', 'Python312MacPorts', 'Python313MacPorts' ]
|
||||
PythonExt += [ 'Python311Brew', 'Python312Brew', 'Python313Brew', 'PythonAutoBrew' ]
|
||||
PythonSys = [ 'PythonMonterey', 'PythonVentura', 'PythonSonoma', 'PythonSequoia', 'PythonTahoe', 'PythonGoldenGate' ]
|
||||
PythonExt = [ 'Python314MacPorts', 'Python313MacPorts' ]
|
||||
PythonExt += [ 'Python314Brew', 'Python313Brew', 'Python311Brew', 'PythonAutoBrew' ]
|
||||
PythonExt += [ 'PythonAnaconda3' ]
|
||||
Pythons = PythonNil + PythonSys + PythonExt
|
||||
|
||||
|
|
@ -430,20 +441,21 @@ PythonTahoe = { 'exe': '%s/Python3.framework/Versions/3.9/bin/python3.9' %
|
|||
'lib': '%s/Python3.framework/Versions/3.9/lib/libpython3.9.dylib' % TahoePy3FW
|
||||
}
|
||||
|
||||
# Python 3.11 from MacPorts (https://www.macports.org/)
|
||||
# install with 'sudo port install python311'
|
||||
# [Key Type Name] = 'MP311'
|
||||
Python311MacPorts = { 'exe': '/opt/local/Library/Frameworks/Python.framework/Versions/3.11/bin/python3.11',
|
||||
'inc': '/opt/local/Library/Frameworks/Python.framework/Versions/3.11/include/python3.11',
|
||||
'lib': '/opt/local/Library/Frameworks/Python.framework/Versions/3.11/lib/libpython3.11.dylib'
|
||||
# Bundled with Golden Gate (27.x)
|
||||
# [Key Type Name] = 'Sys'
|
||||
GoldenGatePy3FWXc = "/Applications/Xcode.app/Contents/Developer/Library/Frameworks"
|
||||
GoldenGatePy3FW = "/Library/Developer/CommandLineTools/Library/Frameworks"
|
||||
PythonGoldenGate = { 'exe': '%s/Python3.framework/Versions/3.9/bin/python3.9' % GoldenGatePy3FW,
|
||||
'inc': '%s/Python3.framework/Versions/3.9/include/python3.9' % GoldenGatePy3FW,
|
||||
'lib': '%s/Python3.framework/Versions/3.9/lib/libpython3.9.dylib' % GoldenGatePy3FW
|
||||
}
|
||||
|
||||
# Python 3.12 from MacPorts (https://www.macports.org/)
|
||||
# install with 'sudo port install python312'
|
||||
# [Key Type Name] = 'MP312'
|
||||
Python312MacPorts = { 'exe': '/opt/local/Library/Frameworks/Python.framework/Versions/3.12/bin/python3.12',
|
||||
'inc': '/opt/local/Library/Frameworks/Python.framework/Versions/3.12/include/python3.12',
|
||||
'lib': '/opt/local/Library/Frameworks/Python.framework/Versions/3.12/lib/libpython3.12.dylib'
|
||||
# Python 3.14 from MacPorts (https://www.macports.org/)
|
||||
# install with 'sudo port install python314'
|
||||
# [Key Type Name] = 'MP314'
|
||||
Python314MacPorts = { 'exe': '/opt/local/Library/Frameworks/Python.framework/Versions/3.14/bin/python3.14',
|
||||
'inc': '/opt/local/Library/Frameworks/Python.framework/Versions/3.14/include/python3.14',
|
||||
'lib': '/opt/local/Library/Frameworks/Python.framework/Versions/3.14/lib/libpython3.14.dylib'
|
||||
}
|
||||
|
||||
# Python 3.13 from MacPorts (https://www.macports.org/)
|
||||
|
|
@ -454,22 +466,13 @@ Python313MacPorts = { 'exe': '/opt/local/Library/Frameworks/Python.framework/Ver
|
|||
'lib': '/opt/local/Library/Frameworks/Python.framework/Versions/3.13/lib/libpython3.13.dylib'
|
||||
}
|
||||
|
||||
# Python 3.11 from Homebrew
|
||||
# install with 'brew install python@3.11'
|
||||
# [Key Type Name] = 'HB311'
|
||||
HBPython311FrameworkPath = '%s/opt/python@3.11/Frameworks/Python.framework' % DefaultHomebrewRoot
|
||||
Python311Brew = { 'exe': '%s/Versions/3.11/bin/python3.11' % HBPython311FrameworkPath,
|
||||
'inc': '%s/Versions/3.11/include/python3.11' % HBPython311FrameworkPath,
|
||||
'lib': '%s/Versions/3.11/lib/libpython3.11.dylib' % HBPython311FrameworkPath
|
||||
}
|
||||
|
||||
# Python 3.12 from Homebrew
|
||||
# install with 'brew install python@3.12'
|
||||
# [Key Type Name] = 'HB312'
|
||||
HBPython312FrameworkPath = '%s/opt/python@3.12/Frameworks/Python.framework' % DefaultHomebrewRoot
|
||||
Python312Brew = { 'exe': '%s/Versions/3.12/bin/python3.12' % HBPython312FrameworkPath,
|
||||
'inc': '%s/Versions/3.12/include/python3.12' % HBPython312FrameworkPath,
|
||||
'lib': '%s/Versions/3.12/lib/libpython3.12.dylib' % HBPython312FrameworkPath
|
||||
# Python 3.14 from Homebrew
|
||||
# install with 'brew install python@3.14'
|
||||
# [Key Type Name] = 'HB314'
|
||||
HBPython314FrameworkPath = '%s/opt/python@3.14/Frameworks/Python.framework' % DefaultHomebrewRoot
|
||||
Python314Brew = { 'exe': '%s/Versions/3.14/bin/python3.14' % HBPython314FrameworkPath,
|
||||
'inc': '%s/Versions/3.14/include/python3.14' % HBPython314FrameworkPath,
|
||||
'lib': '%s/Versions/3.14/lib/libpython3.14.dylib' % HBPython314FrameworkPath
|
||||
}
|
||||
|
||||
# Python 3.13 from Homebrew
|
||||
|
|
@ -481,6 +484,15 @@ Python313Brew = { 'exe': '%s/Versions/3.13/bin/python3.13' % HBPython313Fram
|
|||
'lib': '%s/Versions/3.13/lib/libpython3.13.dylib' % HBPython313FrameworkPath
|
||||
}
|
||||
|
||||
# Python 3.11 from Homebrew
|
||||
# install with 'brew install python@3.11'
|
||||
# [Key Type Name] = 'HB311'
|
||||
HBPython311FrameworkPath = '%s/opt/python@3.11/Frameworks/Python.framework' % DefaultHomebrewRoot
|
||||
Python311Brew = { 'exe': '%s/Versions/3.11/bin/python3.11' % HBPython311FrameworkPath,
|
||||
'inc': '%s/Versions/3.11/include/python3.11' % HBPython311FrameworkPath,
|
||||
'lib': '%s/Versions/3.11/lib/libpython3.11.dylib' % HBPython311FrameworkPath
|
||||
}
|
||||
|
||||
# Python 3.13 installed under [/opt|/Applications]/anaconda3/klayout-qt[5|6]
|
||||
# See the [Qt5] [Qt6] section above.
|
||||
# [Key Type Name] = 'Ana3'
|
||||
|
|
@ -551,13 +563,13 @@ PythonDictionary = { 'nil' : None,
|
|||
'PythonSonoma' : PythonSonoma,
|
||||
'PythonSequoia' : PythonSequoia,
|
||||
'PythonTahoe' : PythonTahoe,
|
||||
'PythonGoldenGate' : PythonGoldenGate,
|
||||
'Python314MacPorts' : Python314MacPorts,
|
||||
'Python313MacPorts' : Python313MacPorts,
|
||||
'Python314Brew' : Python314Brew,
|
||||
'Python313Brew' : Python313Brew,
|
||||
'PythonAnaconda3V5' : PythonAnaconda3V5,
|
||||
'PythonAnaconda3V6' : PythonAnaconda3V6,
|
||||
'Python312MacPorts' : Python312MacPorts,
|
||||
'Python312Brew' : Python312Brew,
|
||||
'Python311MacPorts' : Python311MacPorts,
|
||||
'Python311Brew' : Python311Brew
|
||||
}
|
||||
if _have_Homebrew_Python:
|
||||
|
|
@ -567,8 +579,8 @@ if _have_Homebrew_Python:
|
|||
# [4] KLayout executables including buddy tools
|
||||
#-----------------------------------------------------
|
||||
KLayoutExecs = [ 'klayout' ]
|
||||
KLayoutExecs += [ 'strm2cif', 'strm2dxf', 'strm2gds', 'strm2gdstxt', 'strm2mag', 'strm2oas' ]
|
||||
KLayoutExecs += [ 'strm2txt', 'strmclip', 'strmcmp', 'strmrun', 'strmxor' ]
|
||||
KLayoutExecs += [ 'strm2cif', 'strm2dxf', 'strm2gds', 'strm2gdstxt', 'strm2lstr', 'strm2mag' ]
|
||||
KLayoutExecs += [ 'strm2oas', 'strm2txt', 'strmclip', 'strmcmp', 'strmrun', 'strmxor' ]
|
||||
|
||||
#----------------
|
||||
# End of File
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
# Here are utility functions and classes ...
|
||||
# for building KLayout (http://www.klayout.de/index.php)
|
||||
# version 0.30.5 or later on different Apple Mac OSX platforms.
|
||||
# version 0.30.9 or later on different Apple Mac OSX platforms.
|
||||
#
|
||||
# This file is imported by 'build4mac.py' script.
|
||||
#========================================================================================
|
||||
|
|
|
|||
|
|
@ -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.30.5 or later on different Apple macOS platforms.\n"
|
||||
Usage += " for making a DMG file of KLayout 0.30.9 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-Sequoia-release-Rmp34Pmp313' | \n"
|
||||
Usage += " : like 'LW-qt5MP.pkg.macos-Sequoia-C32-release-Rmp34Pmp314' | \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"
|
||||
|
|
@ -106,7 +106,11 @@ def SetGlobals():
|
|||
|
||||
release = int( Release.split(".")[0] ) # take the first of ['21', '0', '0']
|
||||
LatestOS = ""
|
||||
if release == 25:
|
||||
if release == 27:
|
||||
GenOSName = "macOS"
|
||||
Platform = "GoldenGate"
|
||||
LatestOS = Platform
|
||||
elif release == 25:
|
||||
GenOSName = "macOS"
|
||||
Platform = "Tahoe"
|
||||
LatestOS = Platform
|
||||
|
|
@ -135,7 +139,7 @@ def SetGlobals():
|
|||
|
||||
if not Machine == "x86_64":
|
||||
# with an Apple Silicon Chip?
|
||||
if Machine == "arm64" and Platform in ["Tahoe", "Sequoia", "Sonoma", "Ventura", "Monterey"]:
|
||||
if Machine == "arm64" and Platform in ["GoldenGate", "Tahoe", "Sequoia", "Sonoma", "Ventura", "Monterey"]:
|
||||
print("")
|
||||
print( "### Your Mac equips an Apple Silicon Chip ###" )
|
||||
print("")
|
||||
|
|
@ -222,17 +226,17 @@ def SetGlobals():
|
|||
## To check the contents of the package directory
|
||||
#
|
||||
# The package directory name should look like:
|
||||
# * 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-qt5MP.pkg.macos-Sequoia-C32-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Sequoia-C32-release-Rana3Pana3
|
||||
# * LW-qt6Brew.pkg.macos-Sequoia-C32-release-Rhb34Phb312 --- (1)
|
||||
# * LW-qt5MP.pkg.macos-Sequoia-C32-release-Rmp33Pmp312
|
||||
# * HW-qt6Brew.pkg.macos-Sequoia-C32-release-RsysPhb311
|
||||
#
|
||||
# * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
|
||||
# * ST-qt6MP.pkg.macos-Sequoia-C32-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sequoia-C32-release-Rmp33Pmp312
|
||||
#
|
||||
# Generated DMG will be, for example,
|
||||
# (1) ---> LW-klayout-0.30.2-macOS-Sequoia-1-qt6Brew-Rhb34Phb312.dmg
|
||||
# (1) ---> LW-klayout-0.30.2-macOS-Sequoia-C32-1-qt6Brew-Rhb34Phb312.dmg
|
||||
#
|
||||
# @return on success, positive integer in [MB] that tells approx. occupied disc space;
|
||||
# on failure, -1
|
||||
|
|
@ -247,6 +251,7 @@ def CheckPkgDirectory():
|
|||
global BundleName
|
||||
global PackagePrefix
|
||||
global QtIdentification
|
||||
global CoordSize
|
||||
global BuildType
|
||||
global RubyPythonID
|
||||
global BackgroundPNG
|
||||
|
|
@ -272,18 +277,18 @@ def CheckPkgDirectory():
|
|||
|
||||
#-----------------------------------------------------------------------------------------------
|
||||
# [2] Identify (Qt, Ruby, Python) from PkgDir
|
||||
# * 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-qt5MP.pkg.macos-Sequoia-C32-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Sequoia-C32-release-Rana3Pana3
|
||||
# * LW-qt6Brew.pkg.macos-Sequoia-C32-release-Rhb34Phb312
|
||||
# * LW-qt5MP.pkg.macos-Sequoia-C32-release-Rmp33Pmp312
|
||||
# * HW-qt6Brew.pkg.macos-Sequoia-C32-release-RsysPhb311
|
||||
# * EX-qt5MP.pkg.macos-Sequoia-C32-release-Rhb34Pmp312
|
||||
#
|
||||
# * ST-qt6MP.pkg.macos-Sequoia-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sequoia-release-Rmp33Pmp312
|
||||
# * ST-qt6MP.pkg.macos-Sequoia-C32-release-RsysPsys
|
||||
# * LW-qt6MP.pkg.macos-Sequoia-C32-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]+)'
|
||||
# 0 1 2 3 4 5 6 7 8 9
|
||||
patQRP = r'(ST|LW|HW|EX)([-])([qt5|qt6][0-9A-Za-z]+)([.]pkg[.])([A-Za-z]+[-][A-Za-z]+[-])(C32|C64)([-])(release|debug)([-])([0-9A-Za-z]+)'
|
||||
regQRP = re.compile(patQRP)
|
||||
if not regQRP.match(PkgDir):
|
||||
print( "! Cannot identify (Qt, Ruby, Python) from the package directory name" )
|
||||
|
|
@ -309,14 +314,25 @@ def CheckPkgDirectory():
|
|||
else:
|
||||
BackgroundPNG = None
|
||||
raise Exception( "! neither qt5 nor qt6" )
|
||||
if pkgdirComponents[5] == 'release':
|
||||
|
||||
if pkgdirComponents[5] == 'C32':
|
||||
CoordSize = 'C32'
|
||||
elif pkgdirComponents[5] == 'C64':
|
||||
CoordSize = 'C64'
|
||||
else:
|
||||
CoordSize = None
|
||||
raise Exception( "! neither C32 nor C64" )
|
||||
|
||||
RubyPythonID = pkgdirComponents[7]
|
||||
if pkgdirComponents[7] == 'release':
|
||||
BuildType = 'release'
|
||||
elif pkgdirComponents[5] == 'debug':
|
||||
elif pkgdirComponents[7] == 'debug':
|
||||
BuildType = 'debug'
|
||||
else:
|
||||
BuildType = None
|
||||
raise Exception( "! neither release nor debug" )
|
||||
RubyPythonID = pkgdirComponents[7]
|
||||
|
||||
RubyPythonID = pkgdirComponents[9]
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
|
||||
|
|
@ -329,12 +345,12 @@ def CheckPkgDirectory():
|
|||
LatestOSMacPorts = Platform == LatestOS
|
||||
LatestOSMacPorts &= PackagePrefix == "LW"
|
||||
LatestOSMacPorts &= QtIdentification in [ "qt5MP", "qt6MP" ]
|
||||
LatestOSMacPorts &= RubyPythonID in [ "Rmp34Pmp313", "Rmp34Pmp312", "Rmp34Pmp311" ]
|
||||
LatestOSMacPorts &= RubyPythonID in [ "Rmp34Pmp314", "Rmp34Pmp313" ]
|
||||
|
||||
LatestOSHomebrew = Platform == LatestOS
|
||||
LatestOSHomebrew &= PackagePrefix == "LW"
|
||||
LatestOSHomebrew &= QtIdentification in [ "qt5Brew", "qt6Brew", "qt5MP", "qt6MP" ] # "qt[5|6]MP" are the alternatives
|
||||
LatestOSHomebrew &= RubyPythonID in [ "Rhb34Phb313", "Rhb34Phb312", "Rhb34Phb311", "Rhb34Phbauto" ]
|
||||
LatestOSHomebrew &= RubyPythonID in [ "Rhb34Phb314", "Rhb34Phb313", "Rhb34Phb311", "Rhb34Phbauto" ]
|
||||
|
||||
LatestOSAnaconda3 = Platform == LatestOS
|
||||
LatestOSAnaconda3 &= PackagePrefix == "LW"
|
||||
|
|
@ -555,8 +571,8 @@ def ParseCommandLineArguments():
|
|||
if opt.target_dmg != "":
|
||||
TargetDMG = opt.target_dmg
|
||||
else:
|
||||
TargetDMG = "%s-klayout-%s-%s-%s-%d-%s-%s.dmg" \
|
||||
% (PackagePrefix, KLVersion, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID)
|
||||
TargetDMG = "%s-klayout-%s-%s-%s-%s-%d-%s-%s.dmg" \
|
||||
% (PackagePrefix, KLVersion, GenOSName, Platform, CoordSize, DMGSerialNum, QtIdentification, RubyPythonID)
|
||||
if Machine == "arm64": # with an Apple Silicon Chip
|
||||
TargetDMG = Machine + TargetDMG
|
||||
if BuildType == "debug": # in the case of 'debug' build
|
||||
|
|
|
|||
|
|
@ -30,14 +30,16 @@ import pandas as pd
|
|||
#
|
||||
# @return matching platform name on success; "" on failure
|
||||
#------------------------------------------------------------------------------
|
||||
def Test_My_Platform( platforms=[ 'Monterey', 'Ventura', 'Sonoma', 'Sequoia', 'Tahoe' ] ):
|
||||
def Test_My_Platform( platforms=[ 'Monterey', 'Ventura', 'Sonoma', 'Sequoia', 'Tahoe', 'GoldenGate' ] ):
|
||||
(System, Node, Release, MacVersion, Machine, Processor) = platform.uname()
|
||||
|
||||
if not System == "Darwin":
|
||||
return ""
|
||||
|
||||
release = int( Release.split(".")[0] ) # take the first of ['21', '0', '0']
|
||||
if release == 25:
|
||||
if release == 27:
|
||||
Platform = "GoldenGate"
|
||||
elif release == 25:
|
||||
Platform = "Tahoe"
|
||||
elif release == 24:
|
||||
Platform = "Sequoia"
|
||||
|
|
@ -80,12 +82,13 @@ def Get_Build_Target_Dict():
|
|||
#
|
||||
# @param[in] targetDic build target dictionary
|
||||
# @param[in] platform platform name
|
||||
# @param[in] coordsize coordinate size (default='C32')
|
||||
#
|
||||
# @return (dictionary1, dictionary2)-tupple
|
||||
# dictionary1: key=(qtVer, mnemonic, bdType), value=build option list
|
||||
# dictionary2: key=(qtVer, mnemonic, bdType), value=log file name
|
||||
#------------------------------------------------------------------------------
|
||||
def Get_Build_Options( targetDic, platform ):
|
||||
def Get_Build_Options( targetDic, platform, coordsize='C32'):
|
||||
buildOp = dict()
|
||||
logfile = dict()
|
||||
|
||||
|
|
@ -99,49 +102,49 @@ def Get_Build_Options( targetDic, platform ):
|
|||
target = targetDic[key]
|
||||
if target == "std":
|
||||
buildOp[(qtVer, "std", "r")] = [ '-q', '%sMacPorts' % qtType, '-r', 'sys', '-p', 'sys' ]
|
||||
logfile[(qtVer, "std", "r")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPsys")
|
||||
logfile[(qtVer, "std", "r")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "RsysPsys")
|
||||
buildOp[(qtVer, "std", "d")] = [ '-q', '%sMacPorts' % qtType, '-r', 'sys', '-p', 'sys', '--debug' ]
|
||||
logfile[(qtVer, "std", "d")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "RsysPsys")
|
||||
logfile[(qtVer, "std", "d")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "RsysPsys")
|
||||
elif target == "ports":
|
||||
buildOp[(qtVer, "ports", "r")] = [ '-q', '%sMacPorts' % qtType, '-r', 'MP34', '-p', 'MP313' ]
|
||||
logfile[(qtVer, "ports", "r")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rmp34Pmp313")
|
||||
buildOp[(qtVer, "ports", "d")] = [ '-q', '%sMacPorts' % qtType, '-r', 'MP34', '-p', 'MP313', '--debug' ]
|
||||
logfile[(qtVer, "ports", "d")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "Rmp34Pmp313")
|
||||
buildOp[(qtVer, "ports", "r")] = [ '-q', '%sMacPorts' % qtType, '-r', 'MP34', '-p', 'MP314' ]
|
||||
logfile[(qtVer, "ports", "r")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "Rmp34Pmp314")
|
||||
buildOp[(qtVer, "ports", "d")] = [ '-q', '%sMacPorts' % qtType, '-r', 'MP34', '-p', 'MP314', '--debug' ]
|
||||
logfile[(qtVer, "ports", "d")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "Rmp34Pmp314")
|
||||
elif target == "brew":
|
||||
buildOp[(qtVer, "brew", "r")] = [ '-q', '%sBrew' % qtType, '-r', 'HB34', '-p', 'HB313' ]
|
||||
logfile[(qtVer, "brew", "r")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rhb34Phb313")
|
||||
buildOp[(qtVer, "brew", "d")] = [ '-q', '%sBrew' % qtType, '-r', 'HB34', '-p', 'HB313', '--debug' ]
|
||||
logfile[(qtVer, "brew", "d")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "Rhb34Phb313")
|
||||
buildOp[(qtVer, "brew", "r")] = [ '-q', '%sBrew' % qtType, '-r', 'HB34', '-p', 'HB314' ]
|
||||
logfile[(qtVer, "brew", "r")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "Rhb34Phb314")
|
||||
buildOp[(qtVer, "brew", "d")] = [ '-q', '%sBrew' % qtType, '-r', 'HB34', '-p', 'HB314', '--debug' ]
|
||||
logfile[(qtVer, "brew", "d")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "Rhb34Phb314")
|
||||
elif target == "brewHW":
|
||||
buildOp[(qtVer, "brewHW", "r")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HB311' ]
|
||||
logfile[(qtVer, "brewHW", "r")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPhb311")
|
||||
logfile[(qtVer, "brewHW", "r")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "RsysPhb311")
|
||||
buildOp[(qtVer, "brewHW", "d")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HB311', '--debug' ]
|
||||
logfile[(qtVer, "brewHW", "d")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "RsysPhb311")
|
||||
logfile[(qtVer, "brewHW", "d")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "RsysPhb311")
|
||||
elif target == "ana3":
|
||||
buildOp[(qtVer, "ana3", "r")] = [ '-q', '%sAna3' % qtType, '-r', 'Ana3', '-p', 'Ana3' ]
|
||||
logfile[(qtVer, "ana3", "r")] = "%sAna3.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rana3Pana3")
|
||||
logfile[(qtVer, "ana3", "r")] = "%sAna3.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "Rana3Pana3")
|
||||
buildOp[(qtVer, "ana3", "d")] = [ '-q', '%sAna3' % qtType, '-r', 'Ana3', '-p', 'Ana3', '--debug' ]
|
||||
logfile[(qtVer, "ana3", "d")] = "%sAna3.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "Rana3Pana3")
|
||||
logfile[(qtVer, "ana3", "d")] = "%sAna3.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "Rana3Pana3")
|
||||
elif target == "brewA":
|
||||
buildOp[(qtVer, "brewA", "r")] = [ '-q', '%sBrew' % qtType, '-r', 'HB34', '-p', 'HBAuto' ]
|
||||
logfile[(qtVer, "brewA", "r")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rhb34Phbauto")
|
||||
logfile[(qtVer, "brewA", "r")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "Rhb34Phbauto")
|
||||
buildOp[(qtVer, "brewA", "d")] = [ '-q', '%sBrew' % qtType, '-r', 'HB34', '-p', 'HBAuto', '--debug' ]
|
||||
logfile[(qtVer, "brewA", "d")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "Rhb34Phbauto")
|
||||
logfile[(qtVer, "brewA", "d")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "Rhb34Phbauto")
|
||||
elif target == "brewAHW":
|
||||
buildOp[(qtVer, "brewAHW", "r")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HBAuto' ]
|
||||
logfile[(qtVer, "brewAHW", "r")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPhbauto")
|
||||
logfile[(qtVer, "brewAHW", "r")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "RsysPhbauto")
|
||||
buildOp[(qtVer, "brewAHW", "d")] = [ '-q', '%sBrew' % qtType, '-r', 'sys', '-p', 'HBAuto', '--debug' ]
|
||||
logfile[(qtVer, "brewAHW", "d")] = "%sBrew.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "RsysPhbauto")
|
||||
logfile[(qtVer, "brewAHW", "d")] = "%sBrew.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "RsysPhbauto")
|
||||
elif target == "pbrew":
|
||||
buildOp[(qtVer, "pbrew", "r")] = [ '-q', '%sMacPorts' % qtType, '-r', 'HB34', '-p', 'HB313' ]
|
||||
logfile[(qtVer, "pbrew", "r")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "Rhb34Phb313")
|
||||
buildOp[(qtVer, "pbrew", "d")] = [ '-q', '%sMacPorts' % qtType, '-r', 'HB34', '-p', 'HB313', '--debug' ]
|
||||
logfile[(qtVer, "pbrew", "d")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "Rhb34Phb313")
|
||||
buildOp[(qtVer, "pbrew", "r")] = [ '-q', '%sMacPorts' % qtType, '-r', 'HB34', '-p', 'HB314' ]
|
||||
logfile[(qtVer, "pbrew", "r")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "Rhb34Phb314")
|
||||
buildOp[(qtVer, "pbrew", "d")] = [ '-q', '%sMacPorts' % qtType, '-r', 'HB34', '-p', 'HB314', '--debug' ]
|
||||
logfile[(qtVer, "pbrew", "d")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "Rhb34Phb314")
|
||||
elif target == "pbrewHW":
|
||||
buildOp[(qtVer, "pbrewHW", "r")] = [ '-q', '%sMacPorts' % qtType, '-r', 'sys', '-p', 'HB311' ]
|
||||
logfile[(qtVer, "pbrewHW", "r")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "release", "RsysPhb311")
|
||||
logfile[(qtVer, "pbrewHW", "r")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "release", "RsysPhb311")
|
||||
buildOp[(qtVer, "pbrewHW", "d")] = [ '-q', '%sMacPorts' % qtType, '-r', 'sys', '-p', 'HB311', '--debug' ]
|
||||
logfile[(qtVer, "pbrewHW", "d")] = "%sMP.build.macos-%s-%s-%s.log" % (qtType.lower(), platform, "debug", "RsysPhb311")
|
||||
logfile[(qtVer, "pbrewHW", "d")] = "%sMP.build.macos-%s-%s-%s-%s.log" % (qtType.lower(), platform, coordsize, "debug", "RsysPhb311")
|
||||
|
||||
if WithPymod:
|
||||
buildOp[(qtVer, "ports", "r")] = buildOp[(qtVer, "ports", "r")] + ['--buildPymod']
|
||||
|
|
@ -161,10 +164,11 @@ def Get_Build_Options( targetDic, platform ):
|
|||
#
|
||||
# @param[in] targetDic build target dictionary
|
||||
# @param[in] platform platform name
|
||||
# @param[in] coordsize coordinate size (default='C32')
|
||||
#
|
||||
# @return a dictionary; key=(qtVer, mnemonic, bdType), value=".macQAT" directory
|
||||
#------------------------------------------------------------------------------
|
||||
def Get_QAT_Directory( targetDic, platform ):
|
||||
def Get_QAT_Directory( targetDic, platform, coordsize='C32' ):
|
||||
dirQAT = dict()
|
||||
|
||||
for qtVer in [5, 6]:
|
||||
|
|
@ -176,32 +180,32 @@ def Get_QAT_Directory( targetDic, platform ):
|
|||
for key in targetDic.keys():
|
||||
target = targetDic[key]
|
||||
if target == "std":
|
||||
dirQAT[(qtVer, "std", "r")] = '%sMP.build.macos-%s-release-RsysPsys.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "std", "d")] = '%sMP.build.macos-%s-debug-RsysPsys.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "std", "r")] = '%sMP.build.macos-%s-%s-release-RsysPsys.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "std", "d")] = '%sMP.build.macos-%s-%s-debug-RsysPsys.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "ports":
|
||||
dirQAT[(qtVer, "ports", "r")] = '%sMP.build.macos-%s-release-Rmp34Pmp313.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "ports", "d")] = '%sMP.build.macos-%s-debug-Rmp34Pmp313.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "ports", "r")] = '%sMP.build.macos-%s-%s-release-Rmp34Pmp314.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "ports", "d")] = '%sMP.build.macos-%s-%s-debug-Rmp34Pmp314.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "brew":
|
||||
dirQAT[(qtVer, "brew", "r")] = '%sBrew.build.macos-%s-release-Rhb34Phb313.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brew", "d")] = '%sBrew.build.macos-%s-debug-Rhb34Phb313.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brew", "r")] = '%sBrew.build.macos-%s-%s-release-Rhb34Phb314.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "brew", "d")] = '%sBrew.build.macos-%s-%s-debug-Rhb34Phb314.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "brewHW":
|
||||
dirQAT[(qtVer, "brewHW", "r")] = '%sBrew.build.macos-%s-release-RsysPhb311.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brewHW", "d")] = '%sBrew.build.macos-%s-debug-RsysPhb311.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brewHW", "r")] = '%sBrew.build.macos-%s-%s-release-RsysPhb311.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "brewHW", "d")] = '%sBrew.build.macos-%s-%s-debug-RsysPhb311.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "ana3":
|
||||
dirQAT[(qtVer, "ana3", "r")] = '%sAna3.build.macos-%s-release-Rana3Pana3.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "ana3", "d")] = '%sAna3.build.macos-%s-debug-Rana3Pana3.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "ana3", "r")] = '%sAna3.build.macos-%s-%s-release-Rana3Pana3.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "ana3", "d")] = '%sAna3.build.macos-%s-%s-debug-Rana3Pana3.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "brewA":
|
||||
dirQAT[(qtVer, "brewA", "r")] = '%sBrew.build.macos-%s-release-Rhb34Phbauto.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brewA", "d")] = '%sBrew.build.macos-%s-debug-Rhb34Phbauto.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brewA", "r")] = '%sBrew.build.macos-%s-%s-release-Rhb34Phbauto.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "brewA", "d")] = '%sBrew.build.macos-%s-%s-debug-Rhb34Phbauto.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "brewAHW":
|
||||
dirQAT[(qtVer, "brewAHW", "r")] = '%sBrew.build.macos-%s-release-RsysPhbauto.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brewAHW", "d")] = '%sBrew.build.macos-%s-debug-RsysPhbauto.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "brewAHW", "r")] = '%sBrew.build.macos-%s-%s-release-RsysPhbauto.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "brewAHW", "d")] = '%sBrew.build.macos-%s-%s-debug-RsysPhbauto.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "pbrew":
|
||||
dirQAT[(qtVer, "pbrew", "r")] = '%sMP.build.macos-%s-release-Rhb34Phb313.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "pbrew", "d")] = '%sMP.build.macos-%s-debug-Rhb34Phb313.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "pbrew", "r")] = '%sMP.build.macos-%s-%s-release-Rhb34Phb314.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "pbrew", "d")] = '%sMP.build.macos-%s-%s-debug-Rhb34Phb314.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
elif target == "pbrewHW":
|
||||
dirQAT[(qtVer, "pbrewHW", "r")] = '%sMP.build.macos-%s-release-RsysPhb311.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "pbrewHW", "d")] = '%sMP.build.macos-%s-debug-RsysPhb311.macQAT' % (qtType.lower(), platform)
|
||||
dirQAT[(qtVer, "pbrewHW", "r")] = '%sMP.build.macos-%s-%s-release-RsysPhb311.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
dirQAT[(qtVer, "pbrewHW", "d")] = '%sMP.build.macos-%s-%s-debug-RsysPhb311.macQAT' % (qtType.lower(), platform, coordsize)
|
||||
|
||||
return dirQAT
|
||||
|
||||
|
|
@ -212,10 +216,11 @@ def Get_QAT_Directory( targetDic, platform ):
|
|||
# @param[in] platform platform name
|
||||
# @param[in] srlDMG serial number of DMG
|
||||
# @param[in] makeflag True to make; False to clean
|
||||
# @param[in] coordsize coordinate size (default='C32')
|
||||
#
|
||||
# @return a dictionary; key=(qtVer, mnemonic, bdType), value=build option list
|
||||
#------------------------------------------------------------------------------
|
||||
def Get_Package_Options( targetDic, platform, srlDMG, makeflag ):
|
||||
def Get_Package_Options( targetDic, platform, srlDMG, makeflag, coordsize='C32' ):
|
||||
packOp = dict()
|
||||
|
||||
if makeflag:
|
||||
|
|
@ -232,49 +237,49 @@ def Get_Package_Options( targetDic, platform, srlDMG, makeflag ):
|
|||
for key in targetDic.keys():
|
||||
target = targetDic[key]
|
||||
if target == "std":
|
||||
packOp[(qtVer, "std", "r")] = [ '-p', 'ST-%sMP.pkg.macos-%s-release-RsysPsys' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "std", "r")] = [ '-p', 'ST-%sMP.pkg.macos-%s-%s-release-RsysPsys' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "std", "d")] = [ '-p', 'ST-%sMP.pkg.macos-%s-debug-RsysPsys' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "std", "d")] = [ '-p', 'ST-%sMP.pkg.macos-%s-%s-debug-RsysPsys' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "ports":
|
||||
packOp[(qtVer, "ports", "r")] = [ '-p', 'LW-%sMP.pkg.macos-%s-release-Rmp34Pmp313' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "ports", "r")] = [ '-p', 'LW-%sMP.pkg.macos-%s-%s-release-Rmp34Pmp314' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "ports", "d")] = [ '-p', 'LW-%sMP.pkg.macos-%s-debug-Rmp34Pmp313' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "ports", "d")] = [ '-p', 'LW-%sMP.pkg.macos-%s-%s-debug-Rmp34Pmp314' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "brew":
|
||||
packOp[(qtVer, "brew", "r")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-release-Rhb34Phb313' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brew", "r")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-%s-release-Rhb34Phb314' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "brew", "d")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-debug-Rhb34Phb313' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brew", "d")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-%s-debug-Rhb34Phb314' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "brewHW":
|
||||
packOp[(qtVer, "brewHW", "r")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-release-RsysPhb311' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brewHW", "r")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-%s-release-RsysPhb311' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "brewHW", "d")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-debug-RsysPhb311' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brewHW", "d")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-%s-debug-RsysPhb311' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "ana3":
|
||||
packOp[(qtVer, "ana3", "r")] = [ '-p', 'LW-%sAna3.pkg.macos-%s-release-Rana3Pana3' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "ana3", "r")] = [ '-p', 'LW-%sAna3.pkg.macos-%s-%s-release-Rana3Pana3' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "ana3", "d")] = [ '-p', 'LW-%sAna3.pkg.macos-%s-debug-Rana3Pana3' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "ana3", "d")] = [ '-p', 'LW-%sAna3.pkg.macos-%s-%s-debug-Rana3Pana3' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "brewA":
|
||||
packOp[(qtVer, "brewA", "r")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-release-Rhb34Phbauto' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brewA", "r")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-%s-release-Rhb34Phbauto' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "brewA", "d")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-debug-Rhb34Phbauto' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brewA", "d")] = [ '-p', 'LW-%sBrew.pkg.macos-%s-%s-debug-Rhb34Phbauto' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "brewAHW":
|
||||
packOp[(qtVer, "brewAHW", "r")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-release-RsysPhbauto' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brewAHW", "r")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-%s-release-RsysPhbauto' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "brewAHW", "d")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-debug-RsysPhbauto' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "brewAHW", "d")] = [ '-p', 'HW-%sBrew.pkg.macos-%s-%s-debug-RsysPhbauto' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "pbrew":
|
||||
packOp[(qtVer, "pbrew", "r")] = [ '-p', 'LW-%sMP.pkg.macos-%s-release-Rhb34Phb313' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "pbrew", "r")] = [ '-p', 'LW-%sMP.pkg.macos-%s-%s-release-Rhb34Phb314' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "pbrew", "d")] = [ '-p', 'LW-%sMP.pkg.macos-%s-debug-Rhb34Phb313' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "pbrew", "d")] = [ '-p', 'LW-%sMP.pkg.macos-%s-%s-debug-Rhb34Phb314' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
elif target == "pbrewHW":
|
||||
packOp[(qtVer, "pbrewHW", "r")] = [ '-p', 'HW-%sMP.pkg.macos-%s-release-RsysPhb311' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "pbrewHW", "r")] = [ '-p', 'HW-%sMP.pkg.macos-%s-%s-release-RsysPhb311' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
packOp[(qtVer, "pbrewHW", "d")] = [ '-p', 'HW-%sMP.pkg.macos-%s-debug-RsysPhb311' % (qtType.lower(), platform),
|
||||
packOp[(qtVer, "pbrewHW", "d")] = [ '-p', 'HW-%sMP.pkg.macos-%s-%s-debug-RsysPhb311' % (qtType.lower(), platform, coordsize),
|
||||
'-s', '%d' % srlDMG, '%s' % flag ]
|
||||
return packOp
|
||||
|
||||
|
|
@ -299,7 +304,7 @@ def Parse_CommandLine_Arguments():
|
|||
global DryRun # True for dry-run
|
||||
|
||||
platform = Test_My_Platform()
|
||||
if platform in [ "Tahoe", "Sequoia", "Sonoma", "Ventura", "Monterey" ]:
|
||||
if platform in [ "GoldenGate", "Tahoe", "Sequoia", "Sonoma", "Ventura", "Monterey" ]:
|
||||
targetopt = "0,1,2,13,4"
|
||||
else:
|
||||
targetopt = ""
|
||||
|
|
@ -308,7 +313,7 @@ def Parse_CommandLine_Arguments():
|
|||
Usage += "----------------------------------------------------------------------------------------------------------\n"
|
||||
Usage += " nightlyBuild.py [EXPERIMENTAL]\n"
|
||||
Usage += " << To execute the jobs for making KLayout's DMGs for\n"
|
||||
Usage += " macOS Monterey, Ventura, Sonoma, or Sequoia >>\n"
|
||||
Usage += " macOS Monterey, Ventura, Sonoma, Sequoia, Tahoe, or GoldenGate >>\n"
|
||||
Usage += "\n"
|
||||
Usage += "$ [python] nightlyBuild.py\n"
|
||||
Usage += " option & argument : comment on option if any | default value\n"
|
||||
|
|
@ -343,7 +348,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.30.2' |\n"
|
||||
Usage += " (6) $ ./nightlyBuild.py --upload '0.30.9' |\n"
|
||||
Usage += " (7) $ ./nightlyBuild.py --cleandmg 1 |\n"
|
||||
Usage += "-----------------------------------------------------------------------------+----------------------------\n"
|
||||
|
||||
|
|
@ -434,7 +439,7 @@ def Parse_CommandLine_Arguments():
|
|||
print(Usage)
|
||||
sys.exit(0)
|
||||
|
||||
myPlatform = Test_My_Platform( [ 'Monterey', 'Ventura', 'Sonoma', 'Sequoia', 'Tahoe' ] )
|
||||
myPlatform = Test_My_Platform( [ '', 'Monterey', 'Ventura', 'Sonoma', 'Sequoia', 'Tahoe' ] )
|
||||
if myPlatform == "":
|
||||
print( "! Current platform is not [ 'Monterey', 'Ventura', 'Sonoma', 'Sequoia', 'Tahoe' ]" )
|
||||
print(Usage)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ def SetGlobals():
|
|||
Usage += "\n"
|
||||
Usage += " option & argument : descriptions | default value\n"
|
||||
Usage += " -------------------------------------------------------------------+---------------\n"
|
||||
Usage += " <-v|--version <number>>: in ['3.11', '3.12','3.13'] | ''\n"
|
||||
Usage += " <-v|--version <number>>: in ['3.11', '3.12','3.13', '3.14'] | ''\n"
|
||||
Usage += " [-u|-unlink] : unlink only | disabled\n"
|
||||
Usage += " [-?|--?] : print this usage and exit | disabled\n"
|
||||
Usage += "----------------------------------------------------------------------+-----------------\n"
|
||||
|
|
@ -49,7 +49,7 @@ def Parse_CLI_Args():
|
|||
|
||||
p.add_option( '-v', '--version',
|
||||
dest='version',
|
||||
help="python3 version=['3.11', '3.12', '3.13']" )
|
||||
help="python3 version=['3.11', '3.12', '3.13', '3.14']" )
|
||||
|
||||
p.add_option( '-u', '--unlink',
|
||||
action='store_true',
|
||||
|
|
@ -74,7 +74,7 @@ def Parse_CLI_Args():
|
|||
|
||||
Version = opt.version
|
||||
UnlinkOnly = opt.unlink
|
||||
if not Version in [ '3.11', '3.12', '3.13' ]:
|
||||
if not Version in [ '3.11', '3.12', '3.13', '3.14' ]:
|
||||
print( "! Unsupported Python 3 version <%s>" % Version )
|
||||
print(Usage)
|
||||
sys.exit(0)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ test-command = [
|
|||
"TESTSRC={package} python {package}/testdata/pymod/pya_tests.py"
|
||||
]
|
||||
# Disable building PyPy wheels on all platforms
|
||||
skip = "pp* cp36-* cp37-*"
|
||||
skip = "pp* cp36-* cp37-* cp38-* cp39-*"
|
||||
|
||||
[tool.cibuildwheel.linux]
|
||||
# beware: the before-all script does not persist environment variables!
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ ubuntu22)
|
|||
ubuntu24)
|
||||
depends="libqt5core5t64 (>= 5.15.13), libqt5designer5 (>= 5.15.13), libqt5gui5t64 (>= 5.15.13), libqt5multimedia5 (>= 5.15.13), libqt5multimediawidgets5 (>= 5.15.13), libqt5network5t64 (>= 5.15.13), libqt5opengl5t64 (>= 5.15.13), libqt5printsupport5t64 (>= 5.15.13), libqt5sql5t64 (>= 5.15.13), libqt5svg5 (>= 5.15.13), libqt5widgets5t64 (>= 5.15.13), libqt5xml5t64 (>= 5.15.13), libqt5xmlpatterns5 (>= 5.15.13), zlib1g (>= 1.3), libgit2-1.7 (>= 1.7.2), libruby3.2 (>= 3.2.3), python3 (>= 3.12.3), libpython3.12 (>= 3.12.3), libstdc++6 (>=14), libc6 (>= 2.39)"
|
||||
;;
|
||||
ubuntu26)
|
||||
depends="libqt5core5t64 (>= 5.15.18), libqt5designer5 (>= 5.15.18), libqt5gui5t64 (>= 5.15.18), libqt5multimedia5 (>= 5.15.18), libqt5multimediawidgets5 (>= 5.15.18), libqt5network5t64 (>= 5.15.18), libqt5opengl5t64 (>= 5.15.18), libqt5printsupport5t64 (>= 5.15.18), libqt5sql5t64 (>= 5.15.18), libqt5svg5 (>= 5.15.18), libqt5widgets5t64 (>= 5.15.18), libqt5xml5t64 (>= 5.15.18), libqt5xmlpatterns5 (>= 5.15.18), zlib1g (>= 1.3), libgit2-1.9 (>= 1.9.1), libruby3.3 (>= 3.3.8), python3 (>= 3.14.3), libpython3.14 (>= 3.14.3), libstdc++6 (>=16), libc6 (>= 2.43)"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown target '$target' (given as first argument)"
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -641,18 +641,23 @@ rename "QKeySequence", /QKeySequence::QKeySequence\(QKeySequence::StandardKey/,
|
|||
# TODO: basically, the layout object only takes ownership over the objects when
|
||||
# it has a QWidget parent itself. This is not reflected in the following simple scheme
|
||||
keep_arg "QBoxLayout", /::addLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::addSpacerItem/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertItem/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertLayout/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertSpacerItem/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertWidget/, 1 # will take ownership of item
|
||||
keep_arg "QHBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QVBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QGridLayout", /::addLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QGridLayout", /::addItem/, 0 # will take ownership of layout
|
||||
keep_arg "QGridLayout", /::addWidget/, 0 # will take ownership of layout
|
||||
keep_arg "QFormLayout", /::addItem/, 0 # will take ownership of layout
|
||||
keep_arg "QLayout", /::addChildLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::insertWidget/, 1 # will take ownership of item
|
||||
|
||||
|
|
|
|||
|
|
@ -840,23 +840,23 @@ rename "QKeySequence", /QKeySequence::QKeySequence\(QKeySequence::StandardKey/,
|
|||
# TODO: basically, the layout object only takes ownership over the objects when
|
||||
# it has a QWidget parent itself. This is not reflected in the following simple scheme
|
||||
keep_arg "QBoxLayout", /::addLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::addSpacerItem/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertItem/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertLayout/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertSpacerItem/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertWidget/, 1 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::addRow/, 1 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::addRow\(QWidget\s*\*/, 0 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::insertRow/, 2 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::insertRow\(QWidget\s*\*/, 1 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::setWidget/, 2 # will take ownership of item
|
||||
keep_arg "QHBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QVBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QGridLayout", /::addLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QGridLayout", /::addItem/, 0 # will take ownership of layout
|
||||
keep_arg "QGridLayout", /::addWidget/, 0 # will take ownership of layout
|
||||
keep_arg "QFormLayout", /::addItem/, 0 # will take ownership of layout
|
||||
keep_arg "QLayout", /::addChildLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::insertWidget/, 1 # will take ownership of item
|
||||
|
||||
|
|
@ -886,9 +886,13 @@ owner_arg "QWidget", /::setParent\(QWidget\s+\*/, 0 # will make self owned by ar
|
|||
# over ownership of it?
|
||||
# keep_arg "QTableWidget", /::setItemPrototype\(/, 0 # will take ownership of the child
|
||||
return_new "QLayout", /::takeAt/ # returns a free object
|
||||
return_new "QLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QBoxLayout", /::takeAt/ # returns a free object
|
||||
return_new "QHBoxLayout", /::takeAt/ # returns a free object
|
||||
return_new "QVBoxLayout", /::takeAt/ # returns a free object
|
||||
# TODO: QFormLayout: takeRow -> needs QFormLayout::TakeRowResult
|
||||
return_new "QGridLayout", /::takeAt/ # returns a free object
|
||||
return_new "QFormLayout", /::takeAt/ # returns a free object
|
||||
return_new "QStackedLayout", /::takeAt/ # returns a free object
|
||||
return_new "QStandardItem", /::take/ # returns a free object
|
||||
return_new "QStandardItemModel", /::take/ # returns a free object
|
||||
|
|
|
|||
|
|
@ -1162,23 +1162,23 @@ rename "QKeySequence", /QKeySequence::QKeySequence\(QKeySequence::StandardKey/,
|
|||
# TODO: basically, the layout object only takes ownership over the objects when
|
||||
# it has a QWidget parent itself. This is not reflected in the following simple scheme
|
||||
keep_arg "QBoxLayout", /::addLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::addSpacerItem/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertItem/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertLayout/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertSpacerItem/, 1 # will take ownership of item
|
||||
keep_arg "QBoxLayout", /::insertWidget/, 1 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::addRow/, 1 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::addRow\(QWidget\s*\*/, 0 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::insertRow/, 2 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::insertRow\(QWidget\s*\*/, 1 # will take ownership of item
|
||||
keep_arg "QFormLayout", /::setWidget/, 2 # will take ownership of item
|
||||
keep_arg "QHBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QVBoxLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QGridLayout", /::addLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QGridLayout", /::addItem/, 0 # will take ownership of layout
|
||||
keep_arg "QGridLayout", /::addWidget/, 0 # will take ownership of layout
|
||||
keep_arg "QFormLayout", /::addItem/, 0 # will take ownership of layout
|
||||
keep_arg "QLayout", /::addChildLayout/, 0 # will take ownership of layout
|
||||
keep_arg "QLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::addItem/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::addWidget/, 0 # will take ownership of item
|
||||
keep_arg "QStackedLayout", /::insertWidget/, 1 # will take ownership of item
|
||||
|
||||
|
|
@ -1208,11 +1208,20 @@ owner_arg "QWidget", /::setParent\(QWidget\s+\*/, 0 # will make self owned by ar
|
|||
# over ownership of it?
|
||||
# keep_arg "QTableWidget", /::setItemPrototype\(/, 0 # will take ownership of the child
|
||||
return_new "QLayout", /::takeAt/ # returns a free object
|
||||
return_new "QLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QBoxLayout", /::takeAt/ # returns a free object
|
||||
return_new "QBoxLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QHBoxLayout", /::takeAt/ # returns a free object
|
||||
return_new "QHBoxLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QVBoxLayout", /::takeAt/ # returns a free object
|
||||
return_new "QVBoxLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QFormLayout", /::takeAt/ # returns a free object
|
||||
return_new "QFormLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QGridLayout", /::takeAt/ # returns a free object
|
||||
return_new "QGridLayout", /::replaceWidget/ # returns a free object
|
||||
# TODO: QFormLayout: takeRow -> needs QFormLayout::TakeRowResult
|
||||
return_new "QStackedLayout", /::takeAt/ # returns a free object
|
||||
return_new "QStackedLayout", /::replaceWidget/ # returns a free object
|
||||
return_new "QStandardItem", /::take/ # returns a free object
|
||||
return_new "QStandardItemModel", /::take/ # returns a free object
|
||||
return_new "QTreeWidgetItem", /::take/ # returns a free object
|
||||
|
|
|
|||
|
|
@ -2995,12 +2995,8 @@ END
|
|||
ofile.puts("static void _call_cbs_#{mn}_#{hk}_#{i_var} (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) ")
|
||||
ofile.puts("{")
|
||||
ofile.puts(" __SUPPRESS_UNUSED_WARNING(args);")
|
||||
if !ant.empty?
|
||||
ofile.puts(" tl::Heap heap;")
|
||||
end
|
||||
ant.each_with_index do |at,ia|
|
||||
ofile.puts(" #{at.renamed_type(alist[ia]).gsi_decl_arg(decl_obj)} = args.read<#{at.gsi_decl_arg(decl_obj)} > (heap);")
|
||||
end
|
||||
produce_arg_read(ofile, decl_obj, func, alist, conf.kept_args(bd))
|
||||
produce_keep_self(ofile, alist, "(#{cls} *)cls", conf.owner_args(bd))
|
||||
if !rt.is_void?
|
||||
ofile.puts(" ret.write<#{rt.gsi_decl_return(decl_obj)} > ((#{rt.gsi_decl_return(decl_obj)})((#{clsn}_Adaptor *)cls)->cbs_#{mn}_#{hk}_#{i_var} (#{alist.join(', ')}));")
|
||||
else
|
||||
|
|
|
|||
|
|
@ -594,12 +594,12 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="t_snap_cbx">
|
||||
<widget class="QCheckBox" name="t_never_snap_cbx">
|
||||
<property name="toolTip">
|
||||
<string>If checked, snap to edges or vertices of objects unless disabled above</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Snap to objects</string>
|
||||
<string>Never snap to objects</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -893,7 +893,7 @@
|
|||
<tabstop>style_cb</tabstop>
|
||||
<tabstop>outline_cb</tabstop>
|
||||
<tabstop>t_angle_cb</tabstop>
|
||||
<tabstop>t_snap_cbx</tabstop>
|
||||
<tabstop>t_never_snap_cbx</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../icons/icons.qrc"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,242 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RulerOptions</class>
|
||||
<widget class="QWidget" name="RulerOptions">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>446</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>446</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Snapping</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="_5">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="snap_to_grid_cbx">
|
||||
<property name="text">
|
||||
<string>Snap to grid</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="snap_to_objects_cbx">
|
||||
<property name="text">
|
||||
<string>Snap to edge/vertex</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Angle Constraints</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="_2">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="angle_cb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Any Angle</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Diagonal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Diagonal only</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Orthogonal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Horizontal only</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Vertical only</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Ruler direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Note: certain rulers may ignore these options</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>121</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>scrollArea</tabstop>
|
||||
<tabstop>snap_to_grid_cbx</tabstop>
|
||||
<tabstop>snap_to_objects_cbx</tabstop>
|
||||
<tabstop>angle_cb</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -14,6 +14,7 @@ FORMS = \
|
|||
RulerConfigPage3.ui \
|
||||
RulerConfigPage4.ui \
|
||||
RulerPropertiesPage.ui \
|
||||
RulerOptions.ui \
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -22,10 +23,12 @@ FORMS = \
|
|||
HEADERS = \
|
||||
antConfigPage.h \
|
||||
antPropertiesPage.h \
|
||||
antRulerOptionsPage.h
|
||||
|
||||
SOURCES = \
|
||||
antConfigPage.cc \
|
||||
antPropertiesPage.cc \
|
||||
antRulerOptionsPage.cc
|
||||
|
||||
# Enabled without Qt:
|
||||
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ ConfigPage4::show ()
|
|||
mp_ui->style_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].style ());
|
||||
mp_ui->outline_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].outline ());
|
||||
mp_ui->t_angle_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].angle_constraint ());
|
||||
mp_ui->t_snap_cbx->setChecked (m_ruler_templates [m_current_template].snap ());
|
||||
mp_ui->t_never_snap_cbx->setChecked (! m_ruler_templates [m_current_template].snap ());
|
||||
mp_ui->t_mode_cb->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].mode ());
|
||||
|
||||
mp_ui->main_position->setCurrentIndex ((unsigned int) m_ruler_templates [m_current_template].main_position ());
|
||||
|
|
@ -410,7 +410,7 @@ ConfigPage4::commit ()
|
|||
ant::Template::ruler_mode_type mode = ant::Template::ruler_mode_type (mp_ui->t_mode_cb->currentIndex ());
|
||||
m_ruler_templates [m_current_template].set_mode (mode);
|
||||
|
||||
m_ruler_templates [m_current_template].snap (mp_ui->t_snap_cbx->isChecked ());
|
||||
m_ruler_templates [m_current_template].snap (! mp_ui->t_never_snap_cbx->isChecked ());
|
||||
|
||||
m_ruler_templates [m_current_template].set_main_position (Object::position_type (mp_ui->main_position->currentIndex ()));
|
||||
m_ruler_templates [m_current_template].set_main_xalign (Object::alignment_type (mp_ui->main_xalign->currentIndex ()));
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "layConverters.h"
|
||||
#include "layDispatcher.h"
|
||||
#include "layAbstractMenu.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "tlColor.h"
|
||||
#include "tlLog.h"
|
||||
#if defined(HAVE_QT)
|
||||
|
|
@ -139,11 +140,10 @@ PluginDeclaration::create_plugin (db::Manager *manager, lay::Dispatcher *, lay::
|
|||
}
|
||||
|
||||
std::vector<std::string>
|
||||
PluginDeclaration::additional_editor_options_pages () const
|
||||
PluginDeclaration::additional_editor_options_pages (lay::LayoutViewBase * /*view*/) const
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
// TODO: provide in a central place instead of borrowing from the edt module
|
||||
names.push_back ("GenericEditorOptions");
|
||||
names.push_back ("ant::RulerOptions");
|
||||
return names;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
virtual void uninitialize (lay::Dispatcher *);
|
||||
virtual bool menu_activated (const std::string &symbol) const;
|
||||
|
||||
virtual std::vector<std::string> additional_editor_options_pages () const;
|
||||
virtual std::vector<std::string> additional_editor_options_pages (lay::LayoutViewBase *view) const;
|
||||
|
||||
void register_annotation_template (const ant::Template &t, lay::Plugin *plugin = 0);
|
||||
void unregister_annotation_template (const std::string &category, lay::Plugin *plugin = 0);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
#include "antRulerOptionsPage.h"
|
||||
#include "antConfig.h"
|
||||
#include "laySnap.h"
|
||||
#include "layConverters.h"
|
||||
#include "layDispatcher.h"
|
||||
#include "tlString.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
#include "ui_RulerOptions.h"
|
||||
|
||||
namespace ant
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// RulerOptionsPage implementation
|
||||
|
||||
RulerOptionsPage::RulerOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
|
||||
: lay::EditorOptionsPageWidget (view, dispatcher)
|
||||
{
|
||||
mp_ui = new Ui::RulerOptions ();
|
||||
mp_ui->setupUi (this);
|
||||
|
||||
connect (mp_ui->angle_cb, SIGNAL (activated (int)), this, SLOT (edited ()));
|
||||
connect (mp_ui->snap_to_grid_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
|
||||
connect (mp_ui->snap_to_objects_cbx, SIGNAL (clicked ()), this, SLOT (edited ()));
|
||||
}
|
||||
|
||||
RulerOptionsPage::~RulerOptionsPage ()
|
||||
{
|
||||
delete mp_ui;
|
||||
mp_ui = 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
RulerOptionsPage::title () const
|
||||
{
|
||||
return tl::to_string (QObject::tr ("Ruler Options"));
|
||||
}
|
||||
|
||||
// Must match order in angle_cb
|
||||
static std::vector<lay::angle_constraint_type> s_ac_options =
|
||||
{
|
||||
lay::AC_Any,
|
||||
lay::AC_Diagonal,
|
||||
lay::AC_DiagonalOnly,
|
||||
lay::AC_Ortho,
|
||||
lay::AC_Horizontal,
|
||||
lay::AC_Vertical
|
||||
};
|
||||
|
||||
void
|
||||
RulerOptionsPage::apply (lay::Dispatcher *root)
|
||||
{
|
||||
lay::angle_constraint_type ac = lay::AC_Any;
|
||||
int ai = mp_ui->angle_cb->currentIndex ();
|
||||
if (ai >= 0 && ai < int (s_ac_options.size ())) {
|
||||
ac = s_ac_options [ai];
|
||||
}
|
||||
|
||||
lay::ACConverter acc;
|
||||
root->config_set (cfg_ruler_snap_mode, acc.to_string (ac));
|
||||
|
||||
root->config_set (cfg_ruler_obj_snap, tl::to_string (mp_ui->snap_to_objects_cbx->isChecked ()));
|
||||
root->config_set (cfg_ruler_grid_snap, tl::to_string (mp_ui->snap_to_grid_cbx->isChecked ()));
|
||||
}
|
||||
|
||||
void
|
||||
RulerOptionsPage::setup (lay::Dispatcher *root)
|
||||
{
|
||||
lay::ACConverter acc;
|
||||
lay::angle_constraint_type ac;
|
||||
|
||||
ac = lay::AC_Any;
|
||||
root->config_get (cfg_ruler_snap_mode, ac, acc);
|
||||
for (int ai = 0; ai < int (s_ac_options.size ()); ++ai) {
|
||||
if (s_ac_options [ai] == ac) {
|
||||
mp_ui->angle_cb->setCurrentIndex (ai);
|
||||
}
|
||||
}
|
||||
|
||||
bool snap_to_grid = false;
|
||||
root->config_get (cfg_ruler_grid_snap, snap_to_grid);
|
||||
mp_ui->snap_to_grid_cbx->setChecked (snap_to_grid);
|
||||
|
||||
bool snap_to_objects = false;
|
||||
root->config_get (cfg_ruler_obj_snap, snap_to_objects);
|
||||
mp_ui->snap_to_objects_cbx->setChecked (snap_to_objects);
|
||||
}
|
||||
|
||||
static tl::RegisteredClass<lay::EditorOptionsPageFactoryBase> s_factory_ruler_options (new lay::EditorOptionsPageFactory<RulerOptionsPage> ("ant::RulerOptions"), 0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
#ifndef HDR_antRulerOptionsPage
|
||||
#define HDR_antRulerOptionsPage
|
||||
|
||||
#include "antCommon.h"
|
||||
|
||||
#include "layEditorOptionsPageWidget.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class RulerOptions;
|
||||
}
|
||||
|
||||
namespace ant
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The generic properties page
|
||||
*/
|
||||
class RulerOptionsPage
|
||||
: public lay::EditorOptionsPageWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RulerOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
|
||||
~RulerOptionsPage ();
|
||||
|
||||
virtual std::string title () const;
|
||||
virtual int order () const { return -10; }
|
||||
void apply (lay::Dispatcher *root);
|
||||
void setup (lay::Dispatcher *root);
|
||||
|
||||
private:
|
||||
Ui::RulerOptions *mp_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1541,6 +1541,19 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
|
|||
}
|
||||
}
|
||||
|
||||
static int snap_prio (lay::PointSnapToObjectResult::ObjectSnap os)
|
||||
{
|
||||
if (os == lay::PointSnapToObjectResult::ObjectVertex) {
|
||||
return 3;
|
||||
} else if (os == lay::PointSnapToObjectResult::ObjectEdge) {
|
||||
return 2;
|
||||
} else if (os == lay::PointSnapToObjectResult::ObjectUnspecific) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Service::snap_rulers (lay::angle_constraint_type ac)
|
||||
{
|
||||
|
|
@ -1566,7 +1579,7 @@ Service::snap_rulers (lay::angle_constraint_type ac)
|
|||
auto snp = snap2_details (org1, p1, ruler, ac);
|
||||
double dist = p1.distance (snp.snapped_point);
|
||||
|
||||
if (min_dist < 0 || dist < min_dist) {
|
||||
if (min_dist < 0 || snap_prio (snp.object_snap) > snap_prio (min_snp.object_snap) || (snap_prio (snp.object_snap) == snap_prio (min_snp.object_snap) && dist < min_dist)) {
|
||||
min_snp = snp;
|
||||
min_dist = dist;
|
||||
min_delta = snp.snapped_point - p1;
|
||||
|
|
@ -1575,7 +1588,7 @@ Service::snap_rulers (lay::angle_constraint_type ac)
|
|||
snp = snap2_details (org2, p2, ruler, ac);
|
||||
dist = p2.distance (snp.snapped_point);
|
||||
|
||||
if (min_dist < 0 || dist < min_dist) {
|
||||
if (min_dist < 0 || snap_prio (snp.object_snap) > snap_prio (min_snp.object_snap) || (snap_prio (snp.object_snap) == snap_prio (min_snp.object_snap) && dist < min_dist)) {
|
||||
min_snp = snp;
|
||||
min_dist = dist;
|
||||
min_delta = snp.snapped_point - p2;
|
||||
|
|
@ -1597,7 +1610,7 @@ Service::move_transform (const db::DPoint & /*p*/, db::DFTrans tr, lay::angle_co
|
|||
return;
|
||||
}
|
||||
|
||||
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
|
||||
auto ac_eff = ac == lay::AC_Global ? lay::AC_Any : ac;
|
||||
clear_mouse_cursors ();
|
||||
|
||||
if (m_move_mode == MoveSelected) {
|
||||
|
|
@ -1621,20 +1634,21 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
|
|||
return;
|
||||
}
|
||||
|
||||
auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac;
|
||||
clear_mouse_cursors ();
|
||||
|
||||
if (m_move_mode == MoveSelected) {
|
||||
|
||||
auto ac_eff = ac == lay::AC_Global ? lay::AC_Any : ac;
|
||||
|
||||
db::DVector dp = p - m_p1;
|
||||
dp = lay::snap_angle (dp, ac_eff);
|
||||
|
||||
m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
|
||||
|
||||
propose_move_transformation (m_trans, 1);
|
||||
|
||||
snap_rulers (ac_eff);
|
||||
|
||||
propose_move_transformation (m_trans, 1);
|
||||
|
||||
for (std::vector<ant::View *>::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
|
||||
(*r)->transform_by (db::DCplxTrans (m_trans));
|
||||
}
|
||||
|
|
@ -1643,7 +1657,28 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
|
|||
|
||||
} else if (m_move_mode != MoveNone) {
|
||||
|
||||
db::DPoint ps = snap2_visual (m_p1, p, &m_current, ac);
|
||||
db::DPoint ps;
|
||||
|
||||
if (m_move_mode == MoveP1 && m_current.segments () == 1) {
|
||||
|
||||
// when moving p1 in a normal ruler, observe the currently active angle constraints and use p2 as reference
|
||||
db::DPoint pref = m_current.seg_p2 (m_seg_index);
|
||||
ps = snap2_visual (pref, p, &m_current, ac);
|
||||
|
||||
} else if (m_move_mode == MoveP2 && m_current.segments () == 1) {
|
||||
|
||||
// when moving p2 in a normal ruler, observe the currently active angle constraints and use p1 as reference
|
||||
db::DPoint pref = m_current.seg_p1 (m_seg_index);
|
||||
ps = snap2_visual (pref, p, &m_current, ac);
|
||||
|
||||
} else {
|
||||
|
||||
// other move modes use the angle constraint imposed by the modifier buttons
|
||||
// and the start point for reference
|
||||
ps = snap2_visual (m_p1, p, &m_current, ac == lay::AC_Global ? lay::AC_Any : ac);
|
||||
|
||||
}
|
||||
|
||||
m_trans = db::DTrans (ps - m_p1);
|
||||
|
||||
apply_partial_move (ps);
|
||||
|
|
@ -1834,6 +1869,7 @@ Service::edit_cancel ()
|
|||
m_move_mode = MoveNone;
|
||||
m_selected.clear ();
|
||||
selection_to_view ();
|
||||
clear_mouse_cursors ();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ INCLUDEPATH += $$RBA_INC
|
|||
DEPENDPATH += $$RBA_INC
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
LIBS += -lklayout_rba
|
||||
INCLUDEPATH += $$DRC_INC $$LVS_INC
|
||||
DEPENDPATH += $$DRC_INC $$LVS_INC
|
||||
LIBS += -lklayout_rba -lklayout_drc -lklayout_lvs
|
||||
} else {
|
||||
LIBS += -lklayout_rbastub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,10 +153,10 @@ void clip (ClipData &data)
|
|||
// write the layout
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (data.file_out);
|
||||
std::string of = save_options.set_format_from_filename (data.file_out).second;
|
||||
data.writer_options.configure (save_options, target_layout);
|
||||
|
||||
tl::OutputStream stream (data.file_out);
|
||||
tl::OutputStream stream (of);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (target_layout, stream);
|
||||
}
|
||||
|
|
@ -176,7 +176,9 @@ BD_PUBLIC int strmclip (int argc, char *argv[])
|
|||
<< tl::arg ("output", &data.file_out, "The output file",
|
||||
"The output format is determined from the suffix of the file. If the suffix indicates "
|
||||
"gzip compression, the file will be compressed on output. Examples for recognized suffixes are "
|
||||
"\".oas\", \".gds.gz\", \".dxf\" or \".gds2\"."
|
||||
"\".oas\", \".gds.gz\", \".dxf\" or \".gds2\". You can also use any name, and specify the "
|
||||
"desired suffix in square brackets after the file name. For example, 'file.clip[oas]' will "
|
||||
"create an OASIS file called 'file.clip'."
|
||||
)
|
||||
<< tl::arg ("-l|--clip-layer=spec", &data, &ClipData::set_clip_layer, "Specifies a layer to take the clip regions from",
|
||||
"If this option is given, the clip rectangles are taken from the given layer."
|
||||
|
|
|
|||
|
|
@ -33,11 +33,16 @@
|
|||
#include "pya.h"
|
||||
#include "gsi.h"
|
||||
#include "gsiExpression.h"
|
||||
#include "lymMacro.h"
|
||||
#include "lymMacroCollection.h"
|
||||
|
||||
#include "libForceLink.h"
|
||||
#include "rdbForceLink.h"
|
||||
#include "pexForceLink.h"
|
||||
#include "lymMacro.h"
|
||||
#include "lymMacroCollection.h"
|
||||
#if defined(HAVE_RUBY)
|
||||
# include "drcForceLink.h"
|
||||
# include "lvsForceLink.h"
|
||||
#endif
|
||||
|
||||
struct RunnerData
|
||||
{
|
||||
|
|
|
|||
|
|
@ -408,7 +408,9 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
<< tl::arg ("?output", &output, "The output file to which the XOR differences are written",
|
||||
"This argument is optional. If not given, the exit status alone will indicate whether the layouts "
|
||||
"are identical or not. The output is a layout file. The format of the file is derived "
|
||||
"from the file name's suffix (.oas[.gz] for (gzipped) OASIS, .gds[.gz] for (gzipped) GDS2 etc.)."
|
||||
"from the file name's suffix (.oas for OASIS, .gds[.gz] for (gzipped) GDS2 etc.). "
|
||||
"You can also use any name, and specify the desired suffix in square brackets after the file name. "
|
||||
"For example, 'file.xor[oas]' will create an OASIS file called 'file.xor'."
|
||||
)
|
||||
<< tl::arg ("-ta|--top-a=name", &top_a, "Specifies the top cell for the first layout",
|
||||
"Use this option to take a specific cell as the top cell from the first layout. All "
|
||||
|
|
@ -587,10 +589,10 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
if (output_layout.get ()) {
|
||||
|
||||
db::SaveLayoutOptions save_options;
|
||||
save_options.set_format_from_filename (output);
|
||||
std::string of = save_options.set_format_from_filename (output).second;
|
||||
writer_options.configure (save_options, *output_layout);
|
||||
|
||||
tl::OutputStream stream (output);
|
||||
tl::OutputStream stream (of);
|
||||
db::Writer writer (save_options);
|
||||
writer.write (*output_layout, stream);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ INCLUDEPATH += $$RBA_INC
|
|||
DEPENDPATH += $$RBA_INC
|
||||
|
||||
equals(HAVE_RUBY, "1") {
|
||||
LIBS += -lklayout_rba
|
||||
LIBS += -lklayout_rba -lklayout_drc -lklayout_lvs
|
||||
} else {
|
||||
LIBS += -lklayout_rbastub
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,6 +212,34 @@ TEST(7)
|
|||
db::compare_layouts (this, layout, input, db::NoNormalization);
|
||||
}
|
||||
|
||||
// Small DEF example with explicit format
|
||||
TEST(8)
|
||||
{
|
||||
std::string input = tl::testdata ();
|
||||
input += "/lefdef/strm2oas_small/in.defok[def]";
|
||||
|
||||
std::string input_au = tl::testdata ();
|
||||
input_au += "/lefdef/strm2oas_small/au.gds";
|
||||
|
||||
std::string output = this->tmp_file ("small_def");
|
||||
|
||||
const char *argv[] = { "x", 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);
|
||||
EXPECT_EQ (reader.format (), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, input_au, db::WriteGDS2);
|
||||
}
|
||||
|
||||
// Large LEF/DEF to OAS converter test
|
||||
TEST(10)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,6 +97,34 @@ TEST(2)
|
|||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (reader.format (), "GDS2");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
// with explicit output format
|
||||
TEST(3)
|
||||
{
|
||||
std::string input = tl::testdata ();
|
||||
input += "/bd/strm2clip_in.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strm2clip_au2.gds";
|
||||
|
||||
std::string output = this->tmp_file () + "[oas]";
|
||||
|
||||
const char *argv[] = { "x", input.c_str (), output.c_str (), "-r=0,-2,9,5", "-t", "INV2", "-x=CLIP_OUT" };
|
||||
|
||||
EXPECT_EQ (strmclip (sizeof (argv) / sizeof (argv[0]), (char **) argv), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
EXPECT_EQ (reader.format (), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NoNormalization);
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
TEST(1)
|
||||
{
|
||||
#if defined(HAVE_PYTHON)
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string cmd;
|
||||
std::string cmd_call;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// NOTE: because of system integrity, MacOS does not inherit DYLD_LIBRARY_PATH to child
|
||||
|
|
@ -39,19 +36,42 @@ TEST(1)
|
|||
const char *ldpath_name = "DYLD_LIBRARY_PATH";
|
||||
const char *ldpath = getenv (ldpath_name);
|
||||
if (ldpath) {
|
||||
cmd += std::string (ldpath_name) + "=\"" + ldpath + "\"; export " + ldpath_name + "; ";
|
||||
cmd_call += std::string (ldpath_name) + "=\"" + ldpath + "\"; export " + ldpath_name + "; ";
|
||||
}
|
||||
#endif
|
||||
|
||||
cmd += tl::combine_path (tl::get_inst_path (), "strmrun ") + fp;
|
||||
tl::info << cmd;
|
||||
cmd_call += tl::combine_path (tl::get_inst_path (), "strmrun");
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
{
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.py";
|
||||
|
||||
std::string cmd = cmd_call + " " + fp;
|
||||
tl::info << cmd;
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
|
||||
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
|
||||
}
|
||||
|
||||
{
|
||||
std::string fp (tl::testsrc ());
|
||||
fp += "/testdata/bd/strmrun.drc";
|
||||
|
||||
std::string cmd = cmd_call + " " + fp;
|
||||
tl::info << cmd;
|
||||
|
||||
tl::InputPipe pipe (cmd);
|
||||
tl::InputStream is (pipe);
|
||||
std::string data = is.read_all ();
|
||||
tl::info << data;
|
||||
|
||||
EXPECT_EQ (data, "This is DRC.\n");
|
||||
}
|
||||
|
||||
EXPECT_EQ (data, "Hello, world (0,-42;42,0)!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,52 @@ TEST(1A_Flat)
|
|||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
|
||||
EXPECT_EQ (std::string (reader.format ()), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"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 3/0 30\n"
|
||||
" 6/0 6/0 41\n"
|
||||
" 8/1 8/1 1\n"
|
||||
" 10/0 - (no such layer in first layout)\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1A_FlatWithExplicitOutputFormat)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testdata ();
|
||||
input_a += "/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testdata ();
|
||||
input_b += "/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strmxor_au1.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.xxx[oas]");
|
||||
|
||||
const char *argv[] = { "x", 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);
|
||||
|
||||
EXPECT_EQ (std::string (reader.format ()), "OASIS");
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
|
|
|
|||
|
|
@ -289,6 +289,11 @@ module RBA
|
|||
alias_method :_layout_base, :layout
|
||||
end
|
||||
|
||||
# makes PCellDeclaration's "name" method available
|
||||
if ! self.method_defined?(:_name_base)
|
||||
alias_method :_name_base, :name
|
||||
end
|
||||
|
||||
# import the Type... constants from PCellParameterDeclaration
|
||||
PCellParameterDeclaration.constants.each do |c|
|
||||
if !const_defined?(c)
|
||||
|
|
@ -595,7 +600,7 @@ module RBA
|
|||
|
||||
# default implementation
|
||||
def cell_name_impl
|
||||
self.name
|
||||
_name_base()
|
||||
end
|
||||
|
||||
# default implementation
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ DEFINES += MAKE_DB_LIBRARY
|
|||
|
||||
SOURCES = \
|
||||
dbArray.cc \
|
||||
dbBinarySerialize.cc \
|
||||
dbBox.cc \
|
||||
dbBoxConvert.cc \
|
||||
dbBoxScanner.cc \
|
||||
|
|
@ -34,6 +35,7 @@ SOURCES = \
|
|||
dbEdgeProcessor.cc \
|
||||
dbEdges.cc \
|
||||
dbEdgesLocalOperations.cc \
|
||||
dbFileBasedLibrary.cc \
|
||||
dbFillTool.cc \
|
||||
dbFuzzyCellMapping.cc \
|
||||
dbGenericShapeIterator.cc \
|
||||
|
|
@ -152,6 +154,7 @@ SOURCES = \
|
|||
gsiDeclDbRecursiveInstanceIterator.cc \
|
||||
gsiDeclDbRecursiveShapeIterator.cc \
|
||||
gsiDeclDbRegion.cc \
|
||||
gsiDeclDbSaveLayoutOptions.cc \
|
||||
gsiDeclDbShape.cc \
|
||||
gsiDeclDbShapeProcessor.cc \
|
||||
gsiDeclDbShapes.cc \
|
||||
|
|
@ -246,6 +249,7 @@ SOURCES = \
|
|||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
dbBinarySerialize.h \
|
||||
dbBoxConvert.h \
|
||||
dbBox.h \
|
||||
dbBoxScanner.h \
|
||||
|
|
@ -274,6 +278,7 @@ HEADERS = \
|
|||
dbEdges.h \
|
||||
dbEdgesLocalOperations.h \
|
||||
dbEdgesToContours.h \
|
||||
dbFileBasedLibrary.h \
|
||||
dbFillTool.h \
|
||||
dbFuzzyCellMapping.h \
|
||||
dbGenericShapeIterator.h \
|
||||
|
|
|
|||
|
|
@ -631,14 +631,14 @@ namespace {
|
|||
class OutputPairHolder
|
||||
{
|
||||
public:
|
||||
OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics)
|
||||
OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics, bool min_coherence)
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (output_mode == Positive || output_mode == Negative || output_mode == PositiveAndNegative) {
|
||||
m_positive.reset (new FlatRegion (merged_semantics));
|
||||
m_positive.reset (new FlatRegion (merged_semantics, 0.0, 0, min_coherence));
|
||||
m_results.push_back (& m_positive->raw_polygons ());
|
||||
} else {
|
||||
m_results.push_back ((db::Shapes *) 0);
|
||||
|
|
@ -667,7 +667,7 @@ private:
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
OutputPairHolder oph (output_mode, merged_semantics (), min_coherence ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
|
|
@ -717,7 +717,7 @@ AsIfFlatRegion::in_and_out_generic (const Region &other, InteractingOutputMode o
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged (), min_coherence ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
|
|
@ -756,7 +756,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
|
|||
std::vector<generic_shape_iterator<db::Edge> > others;
|
||||
others.push_back (counting ? other.begin_merged () : other.begin ());
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics (), 0.0, 0, min_coherence ()));
|
||||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_polygons ());
|
||||
|
||||
|
|
@ -768,7 +768,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged (), min_coherence ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
|
|
@ -814,7 +814,7 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOut
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged (), min_coherence ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
|
|
@ -941,7 +941,7 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons
|
|||
std::vector<generic_shape_iterator<db::Polygon> > others;
|
||||
others.push_back (other.begin_merged ());
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (other.merged_semantics () || other.is_merged ()));
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (other.merged_semantics () || other.is_merged (), 0.0, 0, min_coherence ()));
|
||||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_polygons ());
|
||||
|
||||
|
|
@ -1106,7 +1106,7 @@ AsIfFlatRegion::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db
|
|||
throw tl::Exception (tl::to_string (tr ("Scale and snap requires positive and non-null magnification or divisor values")));
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics ()));
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics (), 0.0, 0, min_coherence ()));
|
||||
|
||||
gx = std::max (db::Coord (1), gx);
|
||||
gy = std::max (db::Coord (1), gy);
|
||||
|
|
@ -1184,13 +1184,7 @@ AsIfFlatRegion::width_check (db::Coord d, const RegionCheckOptions &options) con
|
|||
EdgePairsDelegate *
|
||||
AsIfFlatRegion::space_or_isolated_check (db::Coord d, const RegionCheckOptions &options, bool isolated) const
|
||||
{
|
||||
if (options.opposite_filter != NoOppositeFilter || options.rect_filter != NoRectFilter || options.shielded) {
|
||||
// NOTE: we have to use the "foreign" scheme with a filter because only this scheme
|
||||
// guarantees that all subject shapes are visited.
|
||||
return run_check (db::SpaceRelation, isolated, foreign_regionptr (), d, options);
|
||||
} else {
|
||||
return run_check (db::SpaceRelation, isolated, subject_regionptr (), d, options);
|
||||
}
|
||||
return run_check (db::SpaceRelation, isolated, 0, d, options);
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
|
|
@ -1239,28 +1233,43 @@ EdgePairsDelegate *
|
|||
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
|
||||
{
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (pc_always_different (options.prop_constraint)) {
|
||||
if (! other && pc_always_different (options.prop_constraint)) {
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
bool needs_merged_primary = different_polygons || options.needs_merged ();
|
||||
bool needs_merged_primary = (! other && different_polygons) || options.needs_merged ();
|
||||
bool primary_is_merged = is_merged ();
|
||||
db::RegionIterator polygons;
|
||||
|
||||
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
|
||||
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
|
||||
if (! merged_semantics ()) {
|
||||
primary_is_merged = true; // means: don't merge again
|
||||
needs_merged_primary = false;
|
||||
polygons = begin ();
|
||||
} else if (! needs_merged_primary) {
|
||||
// The implementation may run faster if the primary is not merged
|
||||
primary_is_merged = false;
|
||||
polygons = begin_unmerged ();
|
||||
} else {
|
||||
primary_is_merged = true;
|
||||
polygons = begin_merged ();
|
||||
}
|
||||
|
||||
EdgeRelationFilter check (rel, d, options);
|
||||
|
||||
std::vector<db::RegionIterator> others;
|
||||
std::vector<bool> foreign;
|
||||
bool has_other = false;
|
||||
bool other_is_merged = true;
|
||||
|
||||
if (other == subject_regionptr () || other == foreign_regionptr ()) {
|
||||
foreign.push_back (other == foreign_regionptr ());
|
||||
if (! other) {
|
||||
|
||||
foreign.push_back (true);
|
||||
others.push_back (polygons);
|
||||
other_is_merged = primary_is_merged;
|
||||
|
||||
} else {
|
||||
|
||||
foreign.push_back (false);
|
||||
|
||||
if (! other->merged_semantics ()) {
|
||||
others.push_back (other->begin ());
|
||||
other_is_merged = true;
|
||||
|
|
@ -1272,7 +1281,13 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
others.push_back (other->begin ());
|
||||
other_is_merged = other->is_merged ();
|
||||
}
|
||||
has_other = true;
|
||||
|
||||
// adds another intruder section to implement subject merging ("primary_intruders")
|
||||
if (! primary_is_merged) {
|
||||
foreign.push_back (true);
|
||||
others.push_back (polygons);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdgePairs> output (new FlatEdgePairs ());
|
||||
|
|
@ -1282,7 +1297,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
|
||||
if (pc_skip (options.prop_constraint)) {
|
||||
|
||||
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options);
|
||||
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, other != 0, other_is_merged, options);
|
||||
|
||||
db::local_processor<db::Polygon, db::Polygon, db::EdgePair> proc;
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -1293,7 +1308,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
|
||||
} else {
|
||||
|
||||
db::check_local_operation_with_properties<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options);
|
||||
db::check_local_operation_with_properties<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, other != 0, other_is_merged, options);
|
||||
|
||||
db::local_processor<db::PolygonWithProperties, db::PolygonWithProperties, db::EdgePairWithProperties> proc;
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -1334,7 +1349,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
|
|||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const
|
||||
AsIfFlatRegion::merged (bool min_coh, unsigned int min_wc, bool join_properties_on_merge) const
|
||||
{
|
||||
if (empty ()) {
|
||||
|
||||
|
|
@ -1351,8 +1366,8 @@ AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc, bool join_prope
|
|||
|
||||
} else {
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
|
||||
merge_polygons_to (new_region->raw_polygons (), min_coherence, min_wc, join_properties_on_merge);
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0, 0, min_coh));
|
||||
merge_polygons_to (new_region->raw_polygons (), min_coh, min_wc, join_properties_on_merge);
|
||||
|
||||
return new_region.release ();
|
||||
|
||||
|
|
@ -1695,7 +1710,7 @@ AsIfFlatRegion::and_or_not_with (bool is_and, const Region &other, PropertyConst
|
|||
ep.insert (*p, n);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0.0, 0, min_coherence ()));
|
||||
db::BooleanOp op (is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
|
||||
db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/);
|
||||
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ());
|
||||
|
|
@ -1772,12 +1787,12 @@ AsIfFlatRegion::andnot_with (const Region &other, PropertyConstraint property_co
|
|||
ep.insert (*p, n);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region1 (new FlatRegion (true));
|
||||
std::unique_ptr<FlatRegion> new_region1 (new FlatRegion (true, 0.0, 0, min_coherence ()));
|
||||
db::BooleanOp op1 (db::BooleanOp::And);
|
||||
db::ShapeGenerator pc1 (new_region1->raw_polygons (), true /*clear*/);
|
||||
db::PolygonGenerator pg1 (pc1, false /*don't resolve holes*/, min_coherence ());
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region2 (new FlatRegion (true));
|
||||
std::unique_ptr<FlatRegion> new_region2 (new FlatRegion (true, 0.0, 0, min_coherence ()));
|
||||
db::BooleanOp op2 (db::BooleanOp::ANotB);
|
||||
db::ShapeGenerator pc2 (new_region2->raw_polygons (), true /*clear*/);
|
||||
db::PolygonGenerator pg2 (pc2, false /*don't resolve holes*/, min_coherence ());
|
||||
|
|
@ -1860,7 +1875,7 @@ AsIfFlatRegion::xor_with (const Region &other, PropertyConstraint prop_constrain
|
|||
ep.insert (*p, n);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0.0, 0, min_coherence ()));
|
||||
db::BooleanOp op (db::BooleanOp::Xor);
|
||||
db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/);
|
||||
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ());
|
||||
|
|
@ -1916,7 +1931,7 @@ AsIfFlatRegion::or_with (const Region &other, PropertyConstraint /*prop_constrai
|
|||
ep.insert (*p, n);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true));
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0.0, 0, min_coherence ()));
|
||||
db::BooleanOp op (db::BooleanOp::Or);
|
||||
db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/);
|
||||
db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ());
|
||||
|
|
|
|||
|
|
@ -138,6 +138,11 @@ public:
|
|||
|
||||
virtual RegionDelegate *add (const Region &other) const;
|
||||
|
||||
virtual RegionDelegate *peel (double /*complexity_factor*/) const
|
||||
{
|
||||
return const_cast<AsIfFlatRegion *> (this);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_outside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 1, false, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "dbBinarySerialize.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,623 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbBinarySerialize
|
||||
#define HDR_dbBinarySerialize
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbPoint.h"
|
||||
#include "dbVector.h"
|
||||
#include "dbEdge.h"
|
||||
#include "dbEdgePair.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbBox.h"
|
||||
#include "dbPath.h"
|
||||
#include "dbTrans.h"
|
||||
#include "dbText.h"
|
||||
#include "dbObjectWithProperties.h"
|
||||
|
||||
#include "tlBinaryStream.h"
|
||||
#include "tlException.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// Stream inserters
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &write_coord (tl::BinaryOutputStream &s, C c)
|
||||
{
|
||||
return s << c;
|
||||
}
|
||||
|
||||
inline tl::BinaryOutputStream &write_coord (tl::BinaryOutputStream &s, db::Coord c)
|
||||
{
|
||||
// NOTE: for compatibility across different builds we use 64 bit coordinates always
|
||||
return s << (int64_t) c;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &write_binary (tl::BinaryOutputStream &s, const db::point<C> &pt)
|
||||
{
|
||||
return write_coord (write_coord (s, pt.x ()), pt.y ());
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &write_binary (tl::BinaryOutputStream &s, const db::vector<C> &v)
|
||||
{
|
||||
return write_coord (write_coord (s, v.x ()), v.y ());
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::point<C> &pt)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
return write_binary (s, pt);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::vector<C> &v)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
return write_binary (s, v);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &write_binary (tl::BinaryOutputStream &s, const db::edge<C> &e)
|
||||
{
|
||||
write_binary (s, e.p1 ());
|
||||
write_binary (s, e.p2 ());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::edge<C> &e)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
return write_binary (s, e);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::box<C> &b)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
write_binary (s, b.p1 ());
|
||||
write_binary (s, b.p2 ());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::edge_pair<C> &ep)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
write_binary (s, ep.first ());
|
||||
write_binary (s, ep.second ());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &write_binary (tl::BinaryOutputStream &s, const db::polygon_contour<C> &c)
|
||||
{
|
||||
s << (uint64_t) c.size ();
|
||||
for (auto i = c.begin (); i != c.end (); ++i) {
|
||||
write_binary (s, *i);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::polygon<C> &p)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
s << (uint64_t) (p.holes () + 1);
|
||||
for (size_t h = 0; h < p.holes () + 1; ++h) {
|
||||
write_binary (s, p.contour (h));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::simple_polygon<C> &p)
|
||||
{
|
||||
// NOTE: the format of polygon and simple polygon are compatible
|
||||
s << (uint16_t) 1; // version
|
||||
s << (uint64_t) 1; // number of contours
|
||||
write_binary (s, p.hull ());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::unit_trans<C> &)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::disp_trans<C> &t)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
write_binary (s, t.disp ());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &write_binary (tl::BinaryOutputStream &s, const db::simple_trans<C> &t)
|
||||
{
|
||||
s << (uint16_t) t.rot ();
|
||||
write_binary (s, t.disp ());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::simple_trans<C> &t)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
return write_binary (s, t);
|
||||
}
|
||||
|
||||
template<class C, class D, class R>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::complex_trans<C, D, R> &t)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
write_binary (s, t.disp ());
|
||||
return s << (double) t.msin () << (double) t.mcos () << (double) (t.is_mirror () ? -t.mag () : t.mag ());
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::text<C> &t)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
s << t.string ();
|
||||
write_binary (s, t.trans ());
|
||||
write_coord (s, t.size ());
|
||||
return s << (int32_t) t.font () << (int32_t) t.halign () << (int32_t) t.valign ();
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::path<C> &p)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
s << (uint64_t) p.points ();
|
||||
for (auto i = p.begin (); i != p.end (); ++i) {
|
||||
write_binary (s, *i);
|
||||
}
|
||||
write_coord (s, p.width ());
|
||||
write_coord (s, p.bgn_ext ());
|
||||
write_coord (s, p.end_ext ());
|
||||
s << p.round ();
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
tl::BinaryOutputStream &operator<< (tl::BinaryOutputStream &s, const db::object_with_properties<T> &o)
|
||||
{
|
||||
s << (uint16_t) 1; // version
|
||||
|
||||
s << (const T &) o;
|
||||
|
||||
const auto &ps = db::properties (o.properties_id ());
|
||||
|
||||
s << (uint64_t) ps.size ();
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
s << db::property_name (i->first) << db::property_value (i->second);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// Stream extractors
|
||||
|
||||
class FutureBinarySerializationFormatException
|
||||
: public tl::Exception
|
||||
{
|
||||
public:
|
||||
FutureBinarySerializationFormatException ()
|
||||
: tl::Exception (tl::to_string (tr ("Binary serialization format version is too new for this build")))
|
||||
{ }
|
||||
};
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &read_coord (tl::BinaryInputStream &s, C &c)
|
||||
{
|
||||
return s >> c;
|
||||
}
|
||||
|
||||
inline tl::BinaryInputStream &read_coord (tl::BinaryInputStream &s, db::Coord &c)
|
||||
{
|
||||
// NOTE: for compatibility across different builds we use 64 bit coordinates always
|
||||
int64_t cc = 0;
|
||||
s >> cc;
|
||||
c = cc;
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &read_binary (tl::BinaryInputStream &s, db::point<C> &pt)
|
||||
{
|
||||
C x = 0, y = 0;
|
||||
read_coord (s, x);
|
||||
read_coord (s, y);
|
||||
pt = db::point<C> (x, y);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &read_binary (tl::BinaryInputStream &s, db::vector<C> &v)
|
||||
{
|
||||
C x = 0, y = 0;
|
||||
read_coord (s, x);
|
||||
read_coord (s, y);
|
||||
v = db::vector<C> (x, y);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::point<C> &pt)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
return read_binary (s, pt);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::vector<C> &v)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
return read_binary (s, v);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &read_binary (tl::BinaryInputStream &s, db::edge<C> &v)
|
||||
{
|
||||
db::point<C> p1, p2;
|
||||
read_binary (s, p1);
|
||||
read_binary (s, p2);
|
||||
v = db::edge<C> (p1, p2);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::edge<C> &e)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
return read_binary (s, e);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::box<C> &b)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
db::point<C> p1, p2;
|
||||
read_binary (s, p1);
|
||||
read_binary (s, p2);
|
||||
b = db::box<C> (p1, p2);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::edge_pair<C> &ep)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
db::edge<C> e1, e2;
|
||||
read_binary (s, e1);
|
||||
read_binary (s, e2);
|
||||
ep = db::edge_pair<C> (e1, e2);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &read_binary (tl::BinaryInputStream &s, db::polygon_contour<C> &c, bool hole)
|
||||
{
|
||||
uint64_t n = 0;
|
||||
s >> n;
|
||||
|
||||
std::vector<db::point<C> > pts;
|
||||
pts.reserve (n);
|
||||
while (n-- > 0) {
|
||||
pts.push_back (db::point<C> ());
|
||||
read_binary (s, pts.back ());
|
||||
}
|
||||
|
||||
// NOTE: not normalization or modification is applied
|
||||
c.assign (pts.begin (), pts.end (), hole, false, false, false);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::polygon<C> &p)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
uint64_t n = 0;
|
||||
s >> n;
|
||||
|
||||
p = db::polygon<C> ();
|
||||
if (n > 0) {
|
||||
p.reserve_holes (n - 1);
|
||||
}
|
||||
|
||||
db::polygon_contour<C> ctr;
|
||||
for (uint64_t h = 0; h < n; ++h) {
|
||||
read_binary (s, ctr, h > 0);
|
||||
if (h == 0) {
|
||||
p.assign_hull (ctr);
|
||||
} else {
|
||||
p.insert_hole (ctr);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::simple_polygon<C> &p)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
uint64_t n = 0;
|
||||
s >> n;
|
||||
tl_assert (n == (uint64_t) 1);
|
||||
|
||||
db::polygon_contour<C> ctr;
|
||||
read_binary (s, ctr, false);
|
||||
p.assign_hull (ctr);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::unit_trans<C> &)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::disp_trans<C> &t)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
db::vector<C> d;
|
||||
read_binary (s, d);
|
||||
t = db::disp_trans<C> (d);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &read_binary (tl::BinaryInputStream &s, db::simple_trans<C> &t)
|
||||
{
|
||||
uint16_t r = 0;
|
||||
s >> r;
|
||||
|
||||
db::vector<C> d;
|
||||
read_binary (s, d);
|
||||
|
||||
t = db::simple_trans<C> (r, d);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::simple_trans<C> &t)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
return read_binary (s, t);
|
||||
}
|
||||
|
||||
template<class C, class D, class R>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::complex_trans<C, D, R> &t)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
db::vector<R> d;
|
||||
read_binary (s, d);
|
||||
|
||||
double asin, acos, mag;
|
||||
s >> asin >> acos >> mag;
|
||||
|
||||
t = db::complex_trans<C, D, R> (d, asin, acos, mag);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::text<C> &t)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
std::string txt;
|
||||
s >> txt;
|
||||
|
||||
db::simple_trans<C> tr;
|
||||
read_binary (s, tr);
|
||||
|
||||
C size;
|
||||
read_coord (s, size);
|
||||
|
||||
int32_t font, halign, valign;
|
||||
s >> font >> halign >> valign;
|
||||
|
||||
t = db::text<C> (txt, tr, size, db::Font (font), db::HAlign (halign), db::VAlign (valign));
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class C>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::path<C> &p)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
uint64_t n = 0;
|
||||
s >> n;
|
||||
|
||||
std::vector<db::point<C> > pts;
|
||||
pts.reserve (n);
|
||||
while (n-- > 0) {
|
||||
pts.push_back (db::point<C> ());
|
||||
read_binary (s, pts.back ());
|
||||
}
|
||||
|
||||
C width, bgn_ext, end_ext;
|
||||
read_coord (s, width);
|
||||
read_coord (s, bgn_ext);
|
||||
read_coord (s, end_ext);
|
||||
|
||||
bool round;
|
||||
s >> round;
|
||||
|
||||
p = db::path<C> (pts.begin (), pts.end (), width, bgn_ext, end_ext, round);
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
tl::BinaryInputStream &operator>> (tl::BinaryInputStream &s, db::object_with_properties<T> &o)
|
||||
{
|
||||
uint16_t fmt = 0;
|
||||
s >> fmt;
|
||||
if (fmt > 1) {
|
||||
throw FutureBinarySerializationFormatException ();
|
||||
}
|
||||
|
||||
s >> (T &) o;
|
||||
|
||||
uint64_t n = 0;
|
||||
s >> n;
|
||||
|
||||
db::PropertiesSet ps;
|
||||
|
||||
while (n-- > 0) {
|
||||
tl::Variant name, value;
|
||||
s >> name >> value;
|
||||
ps.insert (name, value);
|
||||
}
|
||||
|
||||
o.properties_id (db::properties_id (ps));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// Converters of objects to a binary string
|
||||
|
||||
template<class T>
|
||||
std::vector<char> to_bytes (const T &t)
|
||||
{
|
||||
tl::OutputMemoryStream osm;
|
||||
{
|
||||
tl::BinaryOutputStream os (osm);
|
||||
os << t;
|
||||
}
|
||||
return std::vector<char> (osm.data (), osm.data () + osm.size ());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string to_bytes_str (const T &t)
|
||||
{
|
||||
tl::OutputMemoryStream osm;
|
||||
{
|
||||
tl::BinaryOutputStream os (osm);
|
||||
os << t;
|
||||
}
|
||||
return std::string (osm.data (), osm.size ());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void from_bytes (const char *data, size_t n, T &t)
|
||||
{
|
||||
tl::InputMemoryStream ism (data, n);
|
||||
tl::InputStream is (ism);
|
||||
tl::BinaryInputStream bis (is);
|
||||
bis >> t;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void from_bytes (const std::vector<char> &s, T &t)
|
||||
{
|
||||
tl::InputMemoryStream ism (s.begin ().operator-> (), s.size ());
|
||||
tl::InputStream is (ism);
|
||||
tl::BinaryInputStream bis (is);
|
||||
bis >> t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -42,15 +42,15 @@ namespace db
|
|||
/**
|
||||
* @brief A utility class for the box scanner implementation
|
||||
*/
|
||||
template <class BoxConvert, class Obj, class Prop, class SideOp>
|
||||
template <class BoxConvertAdaptor, class Obj, class Prop, class SideOp>
|
||||
struct bs_side_compare_func
|
||||
#if __cplusplus < 201703L
|
||||
: std::binary_function<std::pair<const Obj *, Prop>, std::pair<const Obj *, Prop>, bool>
|
||||
#endif
|
||||
{
|
||||
typedef typename BoxConvert::box_type box_type;
|
||||
typedef typename BoxConvertAdaptor::box_type box_type;
|
||||
|
||||
bs_side_compare_func (const BoxConvert &bc)
|
||||
bs_side_compare_func (const BoxConvertAdaptor &bc)
|
||||
: m_bc (bc)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -59,26 +59,26 @@ struct bs_side_compare_func
|
|||
bool operator() (const std::pair<const Obj *, Prop> &a, const std::pair<const Obj *, Prop> &b) const
|
||||
{
|
||||
SideOp sideop;
|
||||
return sideop (m_bc (*a.first)) < sideop (m_bc (*b.first));
|
||||
return sideop (m_bc (a)) < sideop (m_bc (b));
|
||||
}
|
||||
|
||||
private:
|
||||
BoxConvert m_bc;
|
||||
BoxConvertAdaptor m_bc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A utility class for the box scanner implementation
|
||||
*/
|
||||
template <class BoxConvert, class Obj, class Prop, class SideOp>
|
||||
template <class BoxConvertAdaptor, class Obj, class Prop, class SideOp>
|
||||
struct bs_side_compare_vs_const_func
|
||||
#if __cplusplus < 201703L
|
||||
: std::unary_function<std::pair<const Obj *, Prop>, bool>
|
||||
#endif
|
||||
{
|
||||
typedef typename BoxConvert::box_type box_type;
|
||||
typedef typename BoxConvertAdaptor::box_type box_type;
|
||||
typedef typename box_type::coord_type coord_type;
|
||||
|
||||
bs_side_compare_vs_const_func (const BoxConvert &bc, coord_type c)
|
||||
bs_side_compare_vs_const_func (const BoxConvertAdaptor &bc, coord_type c)
|
||||
: m_bc (bc), m_c (c)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -87,11 +87,11 @@ struct bs_side_compare_vs_const_func
|
|||
bool operator() (const std::pair<const Obj *, Prop> &a) const
|
||||
{
|
||||
SideOp sideop;
|
||||
return sideop (m_bc (*a.first)) < m_c;
|
||||
return sideop (m_bc (a)) < m_c;
|
||||
}
|
||||
|
||||
private:
|
||||
BoxConvert m_bc;
|
||||
BoxConvertAdaptor m_bc;
|
||||
coord_type m_c;
|
||||
};
|
||||
|
||||
|
|
@ -186,6 +186,34 @@ public:
|
|||
typedef std::vector<std::pair<const Obj *, Prop> > container_type;
|
||||
typedef typename container_type::iterator iterator_type;
|
||||
|
||||
template <class BoxConvert>
|
||||
struct box_convert_adaptor_take_first
|
||||
{
|
||||
typedef typename BoxConvert::box_type box_type;
|
||||
|
||||
box_convert_adaptor_take_first (const BoxConvert &bc)
|
||||
: m_bc (bc)
|
||||
{ }
|
||||
|
||||
box_type operator() (const std::pair<const Obj *, Prop> &p) const
|
||||
{
|
||||
return m_bc (*p.first);
|
||||
}
|
||||
|
||||
private:
|
||||
const BoxConvert &m_bc;
|
||||
};
|
||||
|
||||
struct BoxConvertAdaptorTakeSecond
|
||||
{
|
||||
typedef Prop box_type;
|
||||
|
||||
const box_type &operator() (const std::pair<const Obj *, Prop> &p) const
|
||||
{
|
||||
return p.second;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default ctor
|
||||
*/
|
||||
|
|
@ -288,7 +316,22 @@ public:
|
|||
bool process (Rec &rec, typename BoxConvert::box_type::coord_type enl, const BoxConvert &bc = BoxConvert ())
|
||||
{
|
||||
rec.initialize ();
|
||||
bool ret = do_process (rec, enl, bc);
|
||||
bool ret = do_process (rec, enl, box_convert_adaptor_take_first<BoxConvert> (bc));
|
||||
rec.finalize (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Same as "process", but allows specfying a box convert adaptor
|
||||
*
|
||||
* This version is useful for use with BoxConvertAdaptorTakeSecond. In that case, "Prop" needs to be
|
||||
* a box type and is used directly as the bounding box.
|
||||
*/
|
||||
template <class Rec, class BoxConvertAdaptor = BoxConvertAdaptorTakeSecond>
|
||||
bool process_with_adaptor (Rec &rec, typename BoxConvertAdaptor::box_type::coord_type enl, const BoxConvertAdaptor &bca = BoxConvertAdaptor ())
|
||||
{
|
||||
rec.initialize ();
|
||||
bool ret = do_process (rec, enl, bca);
|
||||
rec.finalize (ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -300,21 +343,21 @@ private:
|
|||
bool m_report_progress;
|
||||
std::string m_progress_desc;
|
||||
|
||||
template <class Rec, class BoxConvert>
|
||||
bool do_process (Rec &rec, typename BoxConvert::box_type::coord_type enl, const BoxConvert &bc = BoxConvert ())
|
||||
template <class Rec, class BoxConvertAdaptor>
|
||||
bool do_process (Rec &rec, typename BoxConvertAdaptor::box_type::coord_type enl, const BoxConvertAdaptor &bc = BoxConvertAdaptor ())
|
||||
{
|
||||
typedef typename BoxConvert::box_type box_type;
|
||||
typedef typename BoxConvertAdaptor::box_type box_type;
|
||||
typedef typename box_type::coord_type coord_type;
|
||||
typedef bs_side_compare_func<BoxConvert, Obj, Prop, box_bottom<Box> > bottom_side_compare_func;
|
||||
typedef bs_side_compare_func<BoxConvert, Obj, Prop, box_left<Box> > left_side_compare_func;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert, Obj, Prop, box_top<Box> > below_func;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert, Obj, Prop, box_right<Box> > left_func;
|
||||
typedef bs_side_compare_func<BoxConvertAdaptor, Obj, Prop, box_bottom<Box> > bottom_side_compare_func;
|
||||
typedef bs_side_compare_func<BoxConvertAdaptor, Obj, Prop, box_left<Box> > left_side_compare_func;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvertAdaptor, Obj, Prop, box_top<Box> > below_func;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvertAdaptor, Obj, Prop, box_right<Box> > left_func;
|
||||
|
||||
// sort out the entries with an empty bbox (we must not put that into sort)
|
||||
|
||||
typename container_type::iterator wi = m_pp.begin ();
|
||||
for (typename container_type::iterator ri = m_pp.begin (); ri != m_pp.end (); ++ri) {
|
||||
if (! bc (*ri->first).empty ()) {
|
||||
if (! bc (*ri).empty ()) {
|
||||
if (wi != ri) {
|
||||
*wi = *ri;
|
||||
}
|
||||
|
|
@ -334,9 +377,9 @@ private:
|
|||
// below m_scanner_thr elements use the brute force approach which is faster in that case
|
||||
|
||||
for (iterator_type i = m_pp.begin (); i != m_pp.end (); ++i) {
|
||||
box_type b1 = bc (*i->first);
|
||||
box_type b1 = bc (*i);
|
||||
for (iterator_type j = i + 1; j != m_pp.end (); ++j) {
|
||||
if (bs_boxes_overlap (b1, bc (*j->first), enl)) {
|
||||
if (bs_boxes_overlap (b1, bc (*j), enl)) {
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
if (rec.stop ()) {
|
||||
return false;
|
||||
|
|
@ -355,7 +398,7 @@ private:
|
|||
|
||||
std::sort (m_pp.begin (), m_pp.end (), bottom_side_compare_func (bc));
|
||||
|
||||
coord_type y = bc (*m_pp.front ().first).bottom ();
|
||||
coord_type y = bc (m_pp.front ()).bottom ();
|
||||
|
||||
iterator_type current = m_pp.begin ();
|
||||
iterator_type future = m_pp.begin ();
|
||||
|
|
@ -389,10 +432,10 @@ private:
|
|||
typename std::iterator_traits<iterator_type>::difference_type min_band_size = size_t ((future - current) * m_fill_factor);
|
||||
coord_type yy = y;
|
||||
do {
|
||||
yy = bc (*future->first).bottom ();
|
||||
yy = bc (*future).bottom ();
|
||||
do {
|
||||
++future;
|
||||
} while (future != m_pp.end () && bc (*future->first).bottom () == yy);
|
||||
} while (future != m_pp.end () && bc (*future).bottom () == yy);
|
||||
} while (future != m_pp.end () && future - current < min_band_size);
|
||||
|
||||
std::sort (current, future, left_side_compare_func (bc));
|
||||
|
|
@ -400,7 +443,7 @@ private:
|
|||
iterator_type c = current;
|
||||
iterator_type f = current;
|
||||
|
||||
coord_type x = bc (*c->first).left ();
|
||||
coord_type x = bc (*c).left ();
|
||||
|
||||
while (f != future) {
|
||||
|
||||
|
|
@ -412,10 +455,10 @@ private:
|
|||
typename std::iterator_traits<iterator_type>::difference_type min_box_size = size_t ((f - c) * m_fill_factor);
|
||||
coord_type xx = x;
|
||||
do {
|
||||
xx = bc (*f->first).left ();
|
||||
xx = bc (*f).left ();
|
||||
do {
|
||||
++f;
|
||||
} while (f != future && bc (*f->first).left () == xx);
|
||||
} while (f != future && bc (*f).left () == xx);
|
||||
} while (f != future && f - c < min_box_size);
|
||||
|
||||
if (m_report_progress) {
|
||||
|
|
@ -425,9 +468,13 @@ private:
|
|||
|
||||
for (iterator_type i = f0; i != f; ++i) {
|
||||
for (iterator_type j = c; j < i; ++j) {
|
||||
if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) {
|
||||
if (seen.find (std::make_pair (i->first, j->first)) == seen.end () && seen.find (std::make_pair (j->first, i->first)) == seen.end ()) {
|
||||
seen.insert (std::make_pair (i->first, j->first));
|
||||
if (bs_boxes_overlap (bc (*i), bc (*j), enl)) {
|
||||
std::pair<const Obj *, const Obj *> k (i->first, j->first);
|
||||
if (k.first < k.second) {
|
||||
std::swap (k.first, k.second);
|
||||
}
|
||||
if (seen.find (k) == seen.end ()) {
|
||||
seen.insert (k);
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
if (rec.stop ()) {
|
||||
return false;
|
||||
|
|
@ -534,6 +581,62 @@ public:
|
|||
typedef typename container_type1::iterator iterator_type1;
|
||||
typedef typename container_type2::iterator iterator_type2;
|
||||
|
||||
template <class BoxConvert>
|
||||
struct box_convert_adaptor_take_first1
|
||||
{
|
||||
typedef typename BoxConvert::box_type box_type;
|
||||
|
||||
box_convert_adaptor_take_first1 (const BoxConvert &bc)
|
||||
: m_bc (bc)
|
||||
{ }
|
||||
|
||||
box_type operator() (const std::pair<const Obj1 *, Prop1> &p) const
|
||||
{
|
||||
return m_bc (*p.first);
|
||||
}
|
||||
|
||||
private:
|
||||
const BoxConvert &m_bc;
|
||||
};
|
||||
|
||||
template <class BoxConvert>
|
||||
struct box_convert_adaptor_take_first2
|
||||
{
|
||||
typedef typename BoxConvert::box_type box_type;
|
||||
|
||||
box_convert_adaptor_take_first2 (const BoxConvert &bc)
|
||||
: m_bc (bc)
|
||||
{ }
|
||||
|
||||
box_type operator() (const std::pair<const Obj2 *, Prop2> &p) const
|
||||
{
|
||||
return m_bc (*p.first);
|
||||
}
|
||||
|
||||
private:
|
||||
const BoxConvert &m_bc;
|
||||
};
|
||||
|
||||
struct BoxConvertAdaptorTakeSecond1
|
||||
{
|
||||
typedef Prop1 box_type;
|
||||
|
||||
const box_type &operator() (const std::pair<const Obj1 *, Prop1> &p) const
|
||||
{
|
||||
return p.second;
|
||||
}
|
||||
};
|
||||
|
||||
struct BoxConvertAdaptorTakeSecond2
|
||||
{
|
||||
typedef Prop2 box_type;
|
||||
|
||||
const box_type &operator() (const std::pair<const Obj2 *, Prop2> &p) const
|
||||
{
|
||||
return p.second;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default ctor
|
||||
*/
|
||||
|
|
@ -678,7 +781,22 @@ public:
|
|||
bool process (Rec &rec, typename BoxConvert1::box_type::coord_type enl, const BoxConvert1 &bc1 = BoxConvert1 (), const BoxConvert2 &bc2 = BoxConvert2 ())
|
||||
{
|
||||
rec.initialize ();
|
||||
bool ret = do_process (rec, enl, bc1, bc2);
|
||||
bool ret = do_process (rec, enl, box_convert_adaptor_take_first1<BoxConvert1> (bc1), box_convert_adaptor_take_first2<BoxConvert2> (bc2));
|
||||
rec.finalize (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Same as "process", but allows specfying a box convert adaptor
|
||||
*
|
||||
* This version is useful for use with BoxConvertAdaptorTakeSecond. In that case, "Prop" needs to be
|
||||
* a box type and is used directly as the bounding box.
|
||||
*/
|
||||
template <class Rec, class BoxConvertAdaptor1 = BoxConvertAdaptorTakeSecond1, class BoxConvertAdaptor2 = BoxConvertAdaptorTakeSecond2>
|
||||
bool process_with_adaptor (Rec &rec, typename BoxConvertAdaptor1::box_type::coord_type enl, const BoxConvertAdaptor1 &bca1 = BoxConvertAdaptor1 (), const BoxConvertAdaptor2 &bca2 = BoxConvertAdaptor2 ())
|
||||
{
|
||||
rec.initialize ();
|
||||
bool ret = do_process (rec, enl, bca1, bca2);
|
||||
rec.finalize (ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -691,25 +809,25 @@ private:
|
|||
bool m_report_progress;
|
||||
std::string m_progress_desc;
|
||||
|
||||
template <class Rec, class BoxConvert1, class BoxConvert2>
|
||||
bool do_process (Rec &rec, typename BoxConvert1::box_type::coord_type enl, const BoxConvert1 &bc1 = BoxConvert1 (), const BoxConvert2 &bc2 = BoxConvert2 ())
|
||||
template <class Rec, class BoxConvertAdaptor1, class BoxConvertAdaptor2>
|
||||
bool do_process (Rec &rec, typename BoxConvertAdaptor1::box_type::coord_type enl, const BoxConvertAdaptor1 &bc1 = BoxConvertAdaptor1 (), const BoxConvertAdaptor2 &bc2 = BoxConvertAdaptor2 ())
|
||||
{
|
||||
typedef typename BoxConvert1::box_type box_type; // must be same as BoxConvert2::box_type
|
||||
typedef typename BoxConvertAdaptor1::box_type box_type; // must be same as BoxConvert2::box_type
|
||||
typedef typename box_type::coord_type coord_type;
|
||||
typedef bs_side_compare_func<BoxConvert1, Obj1, Prop1, box_bottom<Box> > bottom_side_compare_func1;
|
||||
typedef bs_side_compare_func<BoxConvert1, Obj1, Prop1, box_left<Box> > left_side_compare_func1;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert1, Obj1, Prop1, box_top<Box> > below_func1;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert1, Obj1, Prop1, box_right<Box> > left_func1;
|
||||
typedef bs_side_compare_func<BoxConvert2, Obj2, Prop2, box_bottom<Box> > bottom_side_compare_func2;
|
||||
typedef bs_side_compare_func<BoxConvert2, Obj2, Prop2, box_left<Box> > left_side_compare_func2;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert2, Obj2, Prop2, box_top<Box> > below_func2;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert2, Obj2, Prop2, box_right<Box> > left_func2;
|
||||
typedef bs_side_compare_func<BoxConvertAdaptor1, Obj1, Prop1, box_bottom<Box> > bottom_side_compare_func1;
|
||||
typedef bs_side_compare_func<BoxConvertAdaptor1, Obj1, Prop1, box_left<Box> > left_side_compare_func1;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvertAdaptor1, Obj1, Prop1, box_top<Box> > below_func1;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvertAdaptor1, Obj1, Prop1, box_right<Box> > left_func1;
|
||||
typedef bs_side_compare_func<BoxConvertAdaptor2, Obj2, Prop2, box_bottom<Box> > bottom_side_compare_func2;
|
||||
typedef bs_side_compare_func<BoxConvertAdaptor2, Obj2, Prop2, box_left<Box> > left_side_compare_func2;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvertAdaptor2, Obj2, Prop2, box_top<Box> > below_func2;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvertAdaptor2, Obj2, Prop2, box_right<Box> > left_func2;
|
||||
|
||||
// sort out the entries with an empty bbox (we must not put that into sort)
|
||||
|
||||
typename container_type1::iterator wi1 = m_pp1.begin ();
|
||||
for (typename container_type1::iterator ri1 = m_pp1.begin (); ri1 != m_pp1.end (); ++ri1) {
|
||||
if (! bc1 (*ri1->first).empty ()) {
|
||||
if (! bc1 (*ri1).empty ()) {
|
||||
if (wi1 != ri1) {
|
||||
*wi1 = *ri1;
|
||||
}
|
||||
|
|
@ -726,7 +844,7 @@ private:
|
|||
|
||||
typename container_type2::iterator wi2 = m_pp2.begin ();
|
||||
for (typename container_type2::iterator ri2 = m_pp2.begin (); ri2 != m_pp2.end (); ++ri2) {
|
||||
if (! bc2 (*ri2->first).empty ()) {
|
||||
if (! bc2 (*ri2).empty ()) {
|
||||
if (wi2 != ri2) {
|
||||
*wi2 = *ri2;
|
||||
}
|
||||
|
|
@ -757,9 +875,9 @@ private:
|
|||
// below m_scanner_thr elements use the brute force approach which is faster in that case
|
||||
|
||||
for (iterator_type1 i = m_pp1.begin (); i != m_pp1.end (); ++i) {
|
||||
box_type b1 = bc1 (*i->first);
|
||||
box_type b1 = bc1 (*i);
|
||||
for (iterator_type2 j = m_pp2.begin (); j != m_pp2.end (); ++j) {
|
||||
if (bs_boxes_overlap (b1, bc2 (*j->first), enl)) {
|
||||
if (bs_boxes_overlap (b1, bc2 (*j), enl)) {
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
if (rec.stop ()) {
|
||||
return false;
|
||||
|
|
@ -783,7 +901,7 @@ private:
|
|||
std::sort (m_pp1.begin (), m_pp1.end (), bottom_side_compare_func1 (bc1));
|
||||
std::sort (m_pp2.begin (), m_pp2.end (), bottom_side_compare_func2 (bc2));
|
||||
|
||||
coord_type y = std::min (bc1 (*m_pp1.front ().first).bottom (), bc2 (*m_pp2.front ().first).bottom ());
|
||||
coord_type y = std::min (bc1 (m_pp1.front ()).bottom (), bc2 (m_pp2.front ()).bottom ());
|
||||
|
||||
iterator_type1 current1 = m_pp1.begin ();
|
||||
iterator_type1 future1 = m_pp1.begin ();
|
||||
|
|
@ -833,16 +951,16 @@ private:
|
|||
coord_type yy = y;
|
||||
do {
|
||||
if (future1 != m_pp1.end () && future2 != m_pp2.end ()) {
|
||||
yy = std::min (bc1 (*future1->first).bottom (), bc2 (*future2->first).bottom ());
|
||||
yy = std::min (bc1 (*future1).bottom (), bc2 (*future2).bottom ());
|
||||
} else if (future1 != m_pp1.end ()) {
|
||||
yy = bc1 (*future1->first).bottom ();
|
||||
yy = bc1 (*future1).bottom ();
|
||||
} else {
|
||||
yy = bc2 (*future2->first).bottom ();
|
||||
yy = bc2 (*future2).bottom ();
|
||||
}
|
||||
while (future1 != m_pp1.end () && bc1 (*future1->first).bottom () == yy) {
|
||||
while (future1 != m_pp1.end () && bc1 (*future1).bottom () == yy) {
|
||||
++future1;
|
||||
}
|
||||
while (future2 != m_pp2.end () && bc2 (*future2->first).bottom () == yy) {
|
||||
while (future2 != m_pp2.end () && bc2 (*future2).bottom () == yy) {
|
||||
++future2;
|
||||
}
|
||||
} while ((future1 != m_pp1.end () || future2 != m_pp2.end ()) && size_t (future1 - current1) + size_t (future2 - current2) < min_band_size);
|
||||
|
|
@ -857,7 +975,7 @@ private:
|
|||
iterator_type2 c2 = current2;
|
||||
iterator_type2 f2 = current2;
|
||||
|
||||
coord_type x = std::min (bc1 (*c1->first).left (), bc2 (*c2->first).left ());
|
||||
coord_type x = std::min (bc1 (*c1).left (), bc2 (*c2).left ());
|
||||
|
||||
while (f1 != future1 || f2 != future2) {
|
||||
|
||||
|
|
@ -869,16 +987,16 @@ private:
|
|||
coord_type xx = x;
|
||||
do {
|
||||
if (f1 != future1 && f2 != future2) {
|
||||
xx = std::min (bc1 (*f1->first).left (), bc2 (*f2->first).left ());
|
||||
xx = std::min (bc1 (*f1).left (), bc2 (*f2).left ());
|
||||
} else if (f1 != future1) {
|
||||
xx = bc1 (*f1->first).left ();
|
||||
xx = bc1 (*f1).left ();
|
||||
} else if (f2 != future2) {
|
||||
xx = bc2 (*f2->first).left ();
|
||||
xx = bc2 (*f2).left ();
|
||||
}
|
||||
while (f1 != future1 && bc1 (*f1->first).left () == xx) {
|
||||
while (f1 != future1 && bc1 (*f1).left () == xx) {
|
||||
++f1;
|
||||
}
|
||||
while (f2 != future2 && bc2 (*f2->first).left () == xx) {
|
||||
while (f2 != future2 && bc2 (*f2).left () == xx) {
|
||||
++f2;
|
||||
}
|
||||
} while ((f1 != future1 || f2 != future2) && size_t (f1 - c1) + size_t (f2 - c2) < min_box_size);
|
||||
|
|
@ -886,7 +1004,7 @@ private:
|
|||
if (c1 != f1 && c2 != f2) {
|
||||
for (iterator_type1 i = c1; i != f1; ++i) {
|
||||
for (iterator_type2 j = c2; j < f2; ++j) {
|
||||
if (bs_boxes_overlap (bc1 (*i->first), bc2 (*j->first), enl)) {
|
||||
if (bs_boxes_overlap (bc1 (*i), bc2 (*j), enl)) {
|
||||
if (seen1.insert (std::make_pair (i->first, j->first)).second) {
|
||||
seen2.insert (std::make_pair (j->first, i->first));
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
|
|
|
|||
|
|
@ -945,7 +945,7 @@ std::string
|
|||
Cell::get_display_name () const
|
||||
{
|
||||
tl_assert (layout () != 0);
|
||||
if (is_ghost_cell () && empty ()) {
|
||||
if (is_real_ghost_cell ()) {
|
||||
return std::string ("(") + layout ()->cell_name (cell_index ()) + std::string (")");
|
||||
} else {
|
||||
return layout ()->cell_name (cell_index ());
|
||||
|
|
@ -959,6 +959,20 @@ Cell::set_name (const std::string &name)
|
|||
layout ()->rename_cell (cell_index (), name.c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
Cell::set_ghost_cell (bool g)
|
||||
{
|
||||
// NOTE: this change is not undo managed
|
||||
if (m_ghost_cell != g) {
|
||||
|
||||
m_ghost_cell = g;
|
||||
tl_assert (layout () != 0);
|
||||
// To trigger a redraw and cell tree rebuild
|
||||
layout ()->cell_name_changed ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cell::check_locked () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -857,7 +857,7 @@ public:
|
|||
void check_locked () const;
|
||||
|
||||
/**
|
||||
* @brief Tell, if this cell is a proxy cell
|
||||
* @brief Gets a value indicating if this cell is a proxy cell
|
||||
*
|
||||
* Proxy cells are such whose layout represents a snapshot of another entity.
|
||||
* Such cells can be PCell variants or library references for example.
|
||||
|
|
@ -867,6 +867,17 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating that this cell is a replica that can be skipped
|
||||
*
|
||||
* This attribute is evaluated by file writers to skip cell replicas for
|
||||
* library cells that do not want to replicated.
|
||||
*/
|
||||
virtual bool can_skip_replica () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the cell name
|
||||
*
|
||||
|
|
@ -925,15 +936,26 @@ public:
|
|||
return m_ghost_cell;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the cell is a "real" ghost cell
|
||||
*
|
||||
* A ghost cell is a real ghost cell only if the ghost cell flag is set
|
||||
* and the cell is empty. Only in that case for example the cell is written
|
||||
* to GDS files as a ghost cell.
|
||||
*
|
||||
* Otherwise, the ghost cell flag is mostly ignored.
|
||||
*/
|
||||
bool is_real_ghost_cell () const
|
||||
{
|
||||
return m_ghost_cell && empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the "ghost cell" flag
|
||||
*
|
||||
* See "is_ghost_cell" for a description of this property.
|
||||
*/
|
||||
void set_ghost_cell (bool g)
|
||||
{
|
||||
m_ghost_cell = g;
|
||||
}
|
||||
void set_ghost_cell (bool g);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the cell is locked
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ Pin &Circuit::add_pin (const std::string &name)
|
|||
void Circuit::remove_pin (size_t id)
|
||||
{
|
||||
if (id < m_pin_by_id.size () && ! tl::is_null_iterator (m_pin_by_id [id])) {
|
||||
connect_pin (id, 0);
|
||||
m_pins.erase (m_pin_by_id [id]);
|
||||
m_pin_by_id [id] = pin_list::iterator ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,14 +60,36 @@ ColdProxy::ColdProxy (db::cell_index_type ci, db::Layout &layout, const LayoutOr
|
|||
}
|
||||
i->second->push_back (this);
|
||||
}
|
||||
|
||||
layout.register_cold_proxy (this);
|
||||
}
|
||||
|
||||
ColdProxy::~ColdProxy ()
|
||||
{
|
||||
if (layout ()) {
|
||||
layout ()->unregister_cold_proxy (this);
|
||||
}
|
||||
|
||||
delete mp_context_info;
|
||||
mp_context_info = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ColdProxy::unregister ()
|
||||
{
|
||||
if (layout ()) {
|
||||
layout ()->unregister_cold_proxy (this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ColdProxy::reregister ()
|
||||
{
|
||||
if (layout ()) {
|
||||
layout ()->register_cold_proxy (this);
|
||||
}
|
||||
}
|
||||
|
||||
Cell *
|
||||
ColdProxy::clone (Layout &layout) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,6 +81,16 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reimplemented from Cell: unregisters the proxy at the layout
|
||||
*/
|
||||
virtual void unregister ();
|
||||
|
||||
/**
|
||||
* @brief Reimplemented from Cell: reregisters the proxy at the layout
|
||||
*/
|
||||
virtual void reregister ();
|
||||
|
||||
/**
|
||||
* @brief Gets a list of cold proxies for a given library name
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -541,31 +541,58 @@ CommonReaderBase::open_dl_uncached (db::Layout &layout, const LDPair &dl)
|
|||
}
|
||||
|
||||
unsigned int nl = layout.insert_layer (lp);
|
||||
|
||||
// change OASIS layer name if a layer already exists by layer/datatype, but has a different name
|
||||
if (! lp.name.empty () && layout.get_properties (nl).name != lp.name) {
|
||||
layout.set_properties (nl, lp);
|
||||
}
|
||||
|
||||
m_layer_map_out.map (dl, nl, lp);
|
||||
|
||||
m_layers_created.insert (nl);
|
||||
|
||||
return std::make_pair (true, nl);
|
||||
|
||||
} else if (li.size () == 1) {
|
||||
|
||||
m_layer_map_out.map (dl, *li.begin (), layout.get_properties (*li.begin ()));
|
||||
|
||||
return std::make_pair (true, *li.begin ());
|
||||
|
||||
} else {
|
||||
|
||||
for (std::set<unsigned int>::const_iterator i = li.begin (); i != li.end (); ++i) {
|
||||
m_layer_map_out.mmap (dl, *i, layout.get_properties (*i));
|
||||
for (auto i = li.begin (); i != li.end (); ++i) {
|
||||
|
||||
// change OASIS layer name if a layer exists by layer/datatype, but has a different name
|
||||
const tl::interval_map <db::ld_type, std::string> *names_dmap = m_layer_names.mapped (dl.layer);
|
||||
if (names_dmap != 0) {
|
||||
const std::string *name = names_dmap->mapped (dl.datatype);
|
||||
if (name != 0) {
|
||||
db::LayerProperties lp_out = layout.get_properties (*i);
|
||||
if (lp_out.name != *name) {
|
||||
lp_out.name = *name;
|
||||
layout.set_properties (*i, lp_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::map<std::set<unsigned int>, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li);
|
||||
if (mmp == m_multi_mapping_placeholders.end ()) {
|
||||
// create a placeholder layer
|
||||
mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first;
|
||||
}
|
||||
if (li.size () == 1) {
|
||||
|
||||
return std::make_pair (true, mmp->second);
|
||||
m_layer_map_out.map (dl, *li.begin (), layout.get_properties (*li.begin ()));
|
||||
|
||||
return std::make_pair (true, *li.begin ());
|
||||
|
||||
} else {
|
||||
|
||||
for (std::set<unsigned int>::const_iterator i = li.begin (); i != li.end (); ++i) {
|
||||
m_layer_map_out.mmap (dl, *i, layout.get_properties (*i));
|
||||
}
|
||||
|
||||
std::map<std::set<unsigned int>, unsigned int>::iterator mmp = m_multi_mapping_placeholders.find (li);
|
||||
if (mmp == m_multi_mapping_placeholders.end ()) {
|
||||
// create a placeholder layer
|
||||
mmp = m_multi_mapping_placeholders.insert (std::make_pair (li, layout.insert_layer ())).first;
|
||||
}
|
||||
|
||||
return std::make_pair (true, mmp->second);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -600,30 +627,7 @@ CommonReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
|||
// A cleanup may be necessary because of the following scenario: if library proxies contain subcells
|
||||
// which are proxies themselves, the proxy update may make them orphans (the proxies are regenerated).
|
||||
// The cleanup will removed these.
|
||||
|
||||
// Adressing issue #1835 (reading proxy-only GDS file renders empty layout) we do not delete
|
||||
// the first (non-cold) proxy if there are only proxy top cells.
|
||||
// We never clean up the top cell if there is a single one. This catches the case of having
|
||||
// defunct proxies for top cells.
|
||||
|
||||
std::set<db::cell_index_type> keep;
|
||||
if (layout.end_top_cells () - layout.begin_top_down () == 1) {
|
||||
keep.insert (*layout.begin_top_down ());
|
||||
} else {
|
||||
for (auto c = layout.begin_top_down (); c != layout.end_top_cells (); ++c) {
|
||||
const db::Cell *cptr = &layout.cell (*c);
|
||||
if (cptr->is_proxy ()) {
|
||||
if (! dynamic_cast <const db::ColdProxy *> (cptr) && keep.empty ()) {
|
||||
keep.insert (*c);
|
||||
}
|
||||
} else {
|
||||
keep.clear ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layout.cleanup (keep);
|
||||
layout.cleanup ();
|
||||
|
||||
return layer_map_out ();
|
||||
}
|
||||
|
|
@ -692,6 +696,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool supports_context () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual tl::XMLElementBase *xml_reader_options_element () const
|
||||
{
|
||||
return new db::ReaderOptionsXMLElement<db::CommonReaderOptions> ("common",
|
||||
|
|
|
|||
|
|
@ -859,7 +859,7 @@ namespace
|
|||
struct generic_result_adaptor
|
||||
{
|
||||
public:
|
||||
generic_result_adaptor<T> (std::vector<std::unordered_set<T> > *results)
|
||||
generic_result_adaptor (std::vector<std::unordered_set<T> > *results)
|
||||
: mp_results (results)
|
||||
{
|
||||
m_intermediate.reserve (results->size ());
|
||||
|
|
@ -1682,13 +1682,9 @@ CompoundRegionCheckOperationNode::computed_dist () const
|
|||
void
|
||||
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, db::Cell *cell, const shape_interactions<db::PolygonWithProperties, db::PolygonWithProperties> &interactions, std::vector<std::unordered_set<db::EdgePairWithProperties> > &results, const db::LocalProcessorBase *proc) const
|
||||
{
|
||||
// consider magnification variants
|
||||
db::EdgeRelationFilter check = m_check;
|
||||
check.set_distance (proc->dist_for_cell (cell, check.distance ()));
|
||||
|
||||
// TODO: needs a concept to deal with merged/non-merged inputs
|
||||
bool is_merged = true;
|
||||
db::check_local_operation<db::PolygonWithProperties, db::PolygonWithProperties> op (check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
|
||||
db::check_local_operation<db::PolygonWithProperties, db::PolygonWithProperties> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
|
||||
|
||||
tl_assert (results.size () == 1);
|
||||
if (results.front ().empty ()) {
|
||||
|
|
@ -1704,13 +1700,9 @@ CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache
|
|||
void
|
||||
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, db::Cell *cell, const shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties> &interactions, std::vector<std::unordered_set<db::EdgePairWithProperties> > &results, const db::LocalProcessorBase *proc) const
|
||||
{
|
||||
// consider magnification variants
|
||||
db::EdgeRelationFilter check = m_check;
|
||||
check.set_distance (proc->dist_for_cell (cell, check.distance ()));
|
||||
|
||||
// TODO: needs a concept to deal with merged/non-merged inputs
|
||||
bool is_merged = true;
|
||||
db::check_local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties> op (check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
|
||||
db::check_local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
|
||||
|
||||
tl_assert (results.size () == 1);
|
||||
if (results.front ().empty ()) {
|
||||
|
|
|
|||
|
|
@ -1758,7 +1758,7 @@ public:
|
|||
* Creates a local operation which utilizes the operation tree. "node" is the root of the operation tree.
|
||||
* Ownership of the node is *not* transferred to the local operation.
|
||||
*/
|
||||
compound_local_operation<TS, TI, TR> (CompoundRegionOperationNode *node)
|
||||
compound_local_operation (CompoundRegionOperationNode *node)
|
||||
: mp_node (node)
|
||||
{ }
|
||||
|
||||
|
|
@ -1802,7 +1802,7 @@ public:
|
|||
* Creates a local operation which utilizes the operation tree. "node" is the root of the operation tree.
|
||||
* Ownership of the node is *not* transferred to the local operation.
|
||||
*/
|
||||
compound_local_operation_with_properties<TS, TI, TR> (CompoundRegionOperationNode *node, db::PropertyConstraint prop_constraint)
|
||||
compound_local_operation_with_properties (CompoundRegionOperationNode *node, db::PropertyConstraint prop_constraint)
|
||||
: mp_node (node), m_prop_constraint (prop_constraint)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
|
|||
|
|
@ -179,8 +179,10 @@ DeepRegion::~DeepRegion ()
|
|||
DeepRegion::DeepRegion (const DeepRegion &other)
|
||||
: MutableRegion (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_polygons_valid (other.m_merged_polygons_valid),
|
||||
m_merged_polygons_min_coherence (other.m_merged_polygons_min_coherence),
|
||||
m_merged_polygons_boc_hash (other.m_merged_polygons_boc_hash),
|
||||
m_is_merged (other.m_is_merged)
|
||||
m_is_merged (other.m_is_merged),
|
||||
m_is_merged_min_coherence (other.m_is_merged_min_coherence)
|
||||
{
|
||||
if (m_merged_polygons_valid) {
|
||||
m_merged_polygons = other.m_merged_polygons.copy ();
|
||||
|
|
@ -196,8 +198,10 @@ DeepRegion::operator= (const DeepRegion &other)
|
|||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
|
||||
m_merged_polygons_valid = other.m_merged_polygons_valid;
|
||||
m_merged_polygons_min_coherence = other.m_merged_polygons_min_coherence;
|
||||
m_merged_polygons_boc_hash = other.m_merged_polygons_boc_hash;
|
||||
m_is_merged = other.m_is_merged;
|
||||
m_is_merged_min_coherence = other.m_is_merged_min_coherence;
|
||||
if (m_merged_polygons_valid) {
|
||||
m_merged_polygons = other.m_merged_polygons.copy ();
|
||||
}
|
||||
|
|
@ -210,9 +214,11 @@ DeepRegion::operator= (const DeepRegion &other)
|
|||
void DeepRegion::init ()
|
||||
{
|
||||
m_merged_polygons_valid = false;
|
||||
m_merged_polygons_min_coherence = false;
|
||||
m_merged_polygons_boc_hash = 0;
|
||||
m_merged_polygons = db::DeepLayer ();
|
||||
m_is_merged = false;
|
||||
m_is_merged_min_coherence = false;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
|
|
@ -228,7 +234,7 @@ void DeepRegion::merged_semantics_changed ()
|
|||
|
||||
void DeepRegion::min_coherence_changed ()
|
||||
{
|
||||
set_is_merged (false);
|
||||
// merged status is tracked in separate variables and is validated on inquiry
|
||||
}
|
||||
|
||||
void DeepRegion::join_properties_on_merge_changed ()
|
||||
|
|
@ -401,6 +407,13 @@ DeepRegion::begin_merged () const
|
|||
}
|
||||
}
|
||||
|
||||
RegionIteratorDelegate *
|
||||
DeepRegion::begin_unmerged () const
|
||||
{
|
||||
ensure_unmerged_polygons_valid ();
|
||||
return begin ();
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
DeepRegion::begin_iter () const
|
||||
{
|
||||
|
|
@ -445,6 +458,13 @@ DeepRegion::begin_merged_iter () const
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
DeepRegion::begin_unmerged_iter () const
|
||||
{
|
||||
ensure_unmerged_polygons_valid ();
|
||||
return begin_iter ();
|
||||
}
|
||||
|
||||
bool
|
||||
DeepRegion::empty () const
|
||||
{
|
||||
|
|
@ -454,7 +474,7 @@ DeepRegion::empty () const
|
|||
bool
|
||||
DeepRegion::is_merged () const
|
||||
{
|
||||
return m_is_merged;
|
||||
return m_is_merged && (m_is_merged_min_coherence == min_coherence ());
|
||||
}
|
||||
|
||||
const db::Polygon *
|
||||
|
|
@ -725,18 +745,21 @@ DeepRegion::merged_deep_layer () const
|
|||
bool
|
||||
DeepRegion::merged_polygons_available () const
|
||||
{
|
||||
return m_is_merged || (m_merged_polygons_valid && m_merged_polygons_boc_hash == deep_layer ().breakout_cells_hash ());
|
||||
return (m_is_merged && m_is_merged_min_coherence == min_coherence ()) ||
|
||||
(m_merged_polygons_valid && m_merged_polygons_min_coherence == min_coherence () && m_merged_polygons_boc_hash == deep_layer ().breakout_cells_hash ());
|
||||
}
|
||||
|
||||
void
|
||||
DeepRegion::ensure_merged_polygons_valid () const
|
||||
{
|
||||
if (! m_merged_polygons_valid || (! m_is_merged && m_merged_polygons_boc_hash != deep_layer ().breakout_cells_hash ())) {
|
||||
if (! m_merged_polygons_valid || m_merged_polygons_min_coherence != min_coherence () ||
|
||||
((! m_is_merged || m_is_merged_min_coherence != min_coherence ()) && m_merged_polygons_boc_hash != deep_layer ().breakout_cells_hash ())) {
|
||||
|
||||
if (m_is_merged) {
|
||||
if (m_is_merged && m_is_merged_min_coherence == min_coherence ()) {
|
||||
|
||||
// NOTE: this will reuse the deep layer reference
|
||||
m_merged_polygons = deep_layer ();
|
||||
m_merged_polygons_min_coherence = min_coherence ();
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -782,15 +805,59 @@ DeepRegion::ensure_merged_polygons_valid () const
|
|||
}
|
||||
|
||||
m_merged_polygons_valid = true;
|
||||
m_merged_polygons_min_coherence = min_coherence ();
|
||||
m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeepRegion::ensure_unmerged_polygons_valid () const
|
||||
{
|
||||
if (! m_is_merged ||
|
||||
(deep_layer ().store ()->max_area_ratio () == 0.0 && deep_layer ().store ()->max_vertex_count () == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_merged_polygons = deep_layer ().derived ();
|
||||
db::DeepLayer &polygons = const_cast<db::DeepLayer &> (deep_layer ());
|
||||
|
||||
m_merged_polygons_valid = true;
|
||||
m_merged_polygons_min_coherence = m_is_merged_min_coherence;
|
||||
m_is_merged = false;
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash ();
|
||||
|
||||
db::Layout &layout = polygons.layout ();
|
||||
polygons.swap (m_merged_polygons);
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (deep_layer ().layer ());
|
||||
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
db::PolygonSplitter splitter (pr, polygons.store ()->max_area_ratio (), polygons.store ()->max_vertex_count ());
|
||||
|
||||
splitter.start ();
|
||||
for (auto p = s.begin (db::ShapeIterator::All); ! p.at_end (); ++p) {
|
||||
if (p->is_polygon ()) {
|
||||
pr.set_prop_id (p->prop_id ());
|
||||
db::Polygon poly;
|
||||
p->polygon (poly);
|
||||
splitter.put (poly);
|
||||
}
|
||||
}
|
||||
splitter.flush ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeepRegion::set_is_merged (bool f)
|
||||
{
|
||||
m_is_merged = f;
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
m_merged_polygons_valid = false;
|
||||
m_merged_polygons_boc_hash = 0;
|
||||
m_merged_polygons = db::DeepLayer ();
|
||||
|
|
@ -826,6 +893,140 @@ DeepRegion::nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Var
|
|||
return new db::DeepRegion (result);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Implements a boolean, top-down NOT operation with property handling for the "peel" feature
|
||||
*/
|
||||
class PushHierLocalOperationWithProperties
|
||||
: public local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> >
|
||||
{
|
||||
public:
|
||||
PushHierLocalOperationWithProperties (double complexity_factor)
|
||||
: local_operation<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > (),
|
||||
m_complexity_factor (complexity_factor)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
OnEmptyIntruderHint on_empty_intruder_hint () const { return Copy; }
|
||||
|
||||
std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("'peel' operation"));
|
||||
}
|
||||
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, db::Cell * /*subject_cell*/, const shape_interactions<db::object_with_properties<db::PolygonRef>, db::object_with_properties<db::PolygonRef> > &interactions, std::vector<std::unordered_set<db::object_with_properties<db::PolygonRef> > > &results, const db::LocalProcessorBase *proc) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
auto &result = results.front ();
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const auto &subject = interactions.subject_shape (i->first);
|
||||
db::properties_id_type prop_id = subject.properties_id ();
|
||||
|
||||
if (i->second.empty ()) {
|
||||
|
||||
result.insert (subject);
|
||||
|
||||
} else {
|
||||
|
||||
ep.clear ();
|
||||
|
||||
const auto &subject = interactions.subject_shape (i->first);
|
||||
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
|
||||
ep.insert (*e, 0);
|
||||
}
|
||||
|
||||
size_t p2 = 1;
|
||||
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
|
||||
const auto &intruder = interactions.intruder_shape (*ii);
|
||||
for (auto e = intruder.second.begin_edge (); ! e.at_end(); ++e) {
|
||||
ep.insert (*e, p2);
|
||||
}
|
||||
p2 += 2;
|
||||
}
|
||||
|
||||
std::unordered_set<db::object_with_properties<db::PolygonRef> > result1;
|
||||
|
||||
db::BooleanOp op (db::BooleanOp::ANotB);
|
||||
db::polygon_ref_generator_with_properties<db::object_with_properties<db::PolygonRef> > pr (layout, result1, prop_id);
|
||||
db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ());
|
||||
db::PolygonGenerator pg (splitter, true, true);
|
||||
ep.set_base_verbosity (50);
|
||||
ep.process (pg, op);
|
||||
|
||||
if (result1.empty ()) {
|
||||
|
||||
// shortcut: nothing to do
|
||||
|
||||
} else if (m_complexity_factor < 0.0) {
|
||||
|
||||
// no complexity limit
|
||||
result.insert (result1.begin (), result1.end ());
|
||||
|
||||
} else if (m_complexity_factor == 0.0) {
|
||||
|
||||
// only remove shape if it is really entirely covered in this case
|
||||
result.insert (subject);
|
||||
|
||||
} else {
|
||||
|
||||
size_t vertices_before = subject.vertices ();
|
||||
size_t vertices_after = 0;
|
||||
for (auto r = result1.begin (); r != result1.end (); ++r) {
|
||||
vertices_after += r->vertices ();
|
||||
}
|
||||
|
||||
if (floor (0.5 + m_complexity_factor * vertices_before) >= vertices_after) {
|
||||
result.insert (result1.begin (), result1.end ());
|
||||
} else {
|
||||
result.insert (subject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
double m_complexity_factor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::peel (double complexity_factor) const
|
||||
{
|
||||
if (empty ()) {
|
||||
// we can return "this", as this method is only intended for in-place execution inside Region
|
||||
return const_cast<DeepRegion *> (this);
|
||||
}
|
||||
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
PushHierLocalOperationWithProperties op (complexity_factor);
|
||||
|
||||
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), deep_layer ().breakout_cells ());
|
||||
configure_proc (proc);
|
||||
proc.set_threads (deep_layer ().store ()->threads ());
|
||||
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
|
||||
|
||||
// with this setting, only top-down interactions are considered
|
||||
proc.set_top_down (true);
|
||||
|
||||
proc.run (&op, deep_layer ().layer (), deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return new DeepRegion (dl_out);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::and_with (const Region &other, PropertyConstraint property_constraint) const
|
||||
{
|
||||
|
|
@ -922,6 +1123,10 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr
|
|||
DeepLayer
|
||||
DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
|
||||
{
|
||||
// booleans run better on simple polygons
|
||||
ensure_unmerged_polygons_valid ();
|
||||
other->ensure_unmerged_polygons_valid ();
|
||||
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
if (pc_skip (property_constraint)) {
|
||||
|
|
@ -956,6 +1161,10 @@ DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint prope
|
|||
DeepLayer
|
||||
DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
|
||||
{
|
||||
// booleans run better on simple polygons
|
||||
ensure_unmerged_polygons_valid ();
|
||||
other->ensure_unmerged_polygons_valid ();
|
||||
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
DeepLayer dl_prep;
|
||||
|
||||
|
|
@ -1059,6 +1268,10 @@ DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint prope
|
|||
std::pair<DeepLayer, DeepLayer>
|
||||
DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const
|
||||
{
|
||||
// booleans run better on simple polygons
|
||||
ensure_unmerged_polygons_valid ();
|
||||
other->ensure_unmerged_polygons_valid ();
|
||||
|
||||
DeepLayer dl_out1 (deep_layer ().derived ());
|
||||
DeepLayer dl_out2 (deep_layer ().derived ());
|
||||
|
||||
|
|
@ -1179,6 +1392,10 @@ DeepRegion::add_in_place (const Region &other)
|
|||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
if (other_deep) {
|
||||
|
||||
// NOTE: as we don't benefit from merged shapes here, we prefer unmerged ones
|
||||
// for potentially better performance.
|
||||
other_deep->ensure_unmerged_polygons_valid ();
|
||||
|
||||
deep_layer ().add_from (other_deep->deep_layer ());
|
||||
|
||||
} else {
|
||||
|
|
@ -1822,6 +2039,7 @@ DeepRegion::merged () const
|
|||
|
||||
res->deep_layer ().layer ();
|
||||
|
||||
res->set_min_coherence (min_coherence ());
|
||||
res->set_is_merged (true);
|
||||
return res.release ();
|
||||
}
|
||||
|
|
@ -1885,6 +2103,10 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
|
|||
return clone ();
|
||||
}
|
||||
|
||||
// in case of negative sizing the output polygons will still be merged (on positive sizing they might
|
||||
// overlap after size and are not necessarily merged)
|
||||
bool will_be_merged = (d < 0 && (merged_semantics () || is_merged ()));
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (polygons.layout ());
|
||||
|
|
@ -1904,7 +2126,8 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
|
|||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
db::PolygonGenerator pg2 (pr, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::PolygonSplitter splitter (pr, will_be_merged ? 0.0 : polygons.store ()->max_area_ratio (), will_be_merged ? 0 : polygons.store ()->max_vertex_count ());
|
||||
db::PolygonGenerator pg2 (splitter, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::SizingPolygonFilter siz (pg2, d_with_mag, d_with_mag, mode);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
|
|
@ -1916,11 +2139,7 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
|
|||
|
||||
}
|
||||
|
||||
// in case of negative sizing the output polygons will still be merged (on positive sizing they might
|
||||
// overlap after size and are not necessarily merged)
|
||||
if (d < 0 && (merged_semantics () || is_merged ())) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
res->set_is_merged (will_be_merged);
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
|
@ -1938,6 +2157,10 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
|||
return sized (dx, mode);
|
||||
}
|
||||
|
||||
// in case of negative sizing the output polygons will still be merged (on positive sizing they might
|
||||
// overlap after size and are not necessarily merged)
|
||||
bool will_be_merged = (dx < 0 && dy < 0 && (merged_semantics () || is_merged ()));
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (polygons.layout ());
|
||||
|
|
@ -1964,7 +2187,8 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
|||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
db::PolygonGenerator pg2 (pr, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::PolygonSplitter splitter (pr, will_be_merged ? 0.0 : polygons.store ()->max_area_ratio (), will_be_merged ? 0 : polygons.store ()->max_vertex_count ());
|
||||
db::PolygonGenerator pg2 (splitter, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::SizingPolygonFilter siz (pg2, dx_with_mag, dy_with_mag, mode);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
|
|
@ -1976,11 +2200,7 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
|||
|
||||
}
|
||||
|
||||
// in case of negative sizing the output polygons will still be merged (on positive sizing they might
|
||||
// overlap after size and are not necessarily merged)
|
||||
if (dx < 0 && dy < 0 && (merged_semantics () || is_merged ())) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
res->set_is_merged (will_be_merged);
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
|
@ -2164,48 +2384,75 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
{
|
||||
if (empty ()) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
} else if (other && ! is_subject_regionptr (other) && other->empty () && ! options.negative) {
|
||||
} else if (other && other->empty () && ! options.negative) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (pc_always_different (options.prop_constraint)) {
|
||||
// TODO: this forces merged primaries, so maybe that is not a good optimization?
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
// delegate to AsIfFlatRegion if the other region is not a deep one
|
||||
const db::DeepRegion *other_deep = 0;
|
||||
unsigned int other_layer = 0;
|
||||
bool other_is_merged = true;
|
||||
|
||||
bool needs_merged_primary = different_polygons || options.needs_merged ();
|
||||
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
|
||||
|
||||
if (other == subject_regionptr ()) {
|
||||
other_layer = subject_idlayer ();
|
||||
other_is_merged = primary_is_merged;
|
||||
} else if (other == foreign_regionptr ()) {
|
||||
other_layer = foreign_idlayer ();
|
||||
other_is_merged = primary_is_merged;
|
||||
} else {
|
||||
if (other) {
|
||||
other_deep = dynamic_cast<const db::DeepRegion *> (other->delegate ());
|
||||
if (! other_deep) {
|
||||
return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, options);
|
||||
}
|
||||
}
|
||||
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (! other_deep && pc_always_different (options.prop_constraint)) {
|
||||
// TODO: this forces merged primaries, so maybe that is not a good optimization?
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
// primary input
|
||||
|
||||
bool needs_merged_primary = (! other_deep && different_polygons) || options.needs_merged ();
|
||||
bool primary_is_merged = false;
|
||||
|
||||
db::DeepLayer polygons;
|
||||
|
||||
if (! merged_semantics ()) {
|
||||
primary_is_merged = true; // means: don't merge again
|
||||
polygons = deep_layer ();
|
||||
} else if (! needs_merged_primary) {
|
||||
// The implementation may run faster if the primary is not merged
|
||||
primary_is_merged = false;
|
||||
ensure_unmerged_polygons_valid ();
|
||||
polygons = deep_layer ();
|
||||
} else {
|
||||
primary_is_merged = true;
|
||||
polygons = merged_deep_layer ();
|
||||
}
|
||||
|
||||
// other input
|
||||
|
||||
std::vector<unsigned int> other_layers;
|
||||
bool other_is_merged = true;
|
||||
|
||||
if (! other_deep) {
|
||||
|
||||
other_layers.push_back (foreign_idlayer ());
|
||||
other_is_merged = primary_is_merged;
|
||||
|
||||
} else {
|
||||
|
||||
if (! other->merged_semantics ()) {
|
||||
other_layer = other_deep->deep_layer ().layer ();
|
||||
other_layers.push_back (other_deep->deep_layer ().layer ());
|
||||
other_is_merged = true;
|
||||
} else if (options.whole_edges) {
|
||||
// NOTE: whole edges needs both inputs merged
|
||||
other_layer = other_deep->merged_deep_layer ().layer ();
|
||||
other_layers.push_back (other_deep->merged_deep_layer ().layer ());
|
||||
other_is_merged = true;
|
||||
} else {
|
||||
other_layer = other_deep->deep_layer ().layer ();
|
||||
other_layers.push_back (other_deep->deep_layer ().layer ());
|
||||
other_is_merged = other->is_merged ();
|
||||
}
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = needs_merged_primary ? merged_deep_layer () : deep_layer ();
|
||||
// adds another intruder section to implement subject merging ("primary_intruders")
|
||||
if (! primary_is_merged) {
|
||||
other_layers.push_back (foreign_idlayer ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EdgeRelationFilter check (rel, d, options);
|
||||
|
||||
|
|
@ -2229,7 +2476,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
configure_proc (proc);
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
|
||||
proc.run (&op, polygons.layer (), other_layer, res->deep_layer ().layer ());
|
||||
proc.run (&op, polygons.layer (), other_layers, res->deep_layer ().layer ());
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -2242,7 +2489,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
configure_proc (proc);
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
|
||||
proc.run (&op, polygons.layer (), other_layer, res->deep_layer ().layer ());
|
||||
proc.run (&op, polygons.layer (), other_layers, res->deep_layer ().layer ());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,11 @@ public:
|
|||
|
||||
virtual RegionIteratorDelegate *begin () const;
|
||||
virtual RegionIteratorDelegate *begin_merged () const;
|
||||
virtual RegionIteratorDelegate *begin_unmerged () const;
|
||||
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_unmerged_iter () const;
|
||||
|
||||
virtual bool empty () const;
|
||||
virtual bool is_merged () const;
|
||||
|
|
@ -138,6 +140,8 @@ public:
|
|||
virtual RegionDelegate *sized_inside (const Region &inside, bool outside, coord_type d, int steps, unsigned int mode) const;
|
||||
virtual RegionDelegate *sized_inside (const Region &inside, bool outside, coord_type dx, coord_type dy, int steps, unsigned int mode) const;
|
||||
|
||||
virtual RegionDelegate *peel (double complexity_factor) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
virtual RegionDelegate *nets (LayoutToNetlist *l2n, NetPropertyMode prop_mode, const tl::Variant &net_prop_name, const std::vector<const Net *> *nets) const;
|
||||
|
|
@ -175,11 +179,14 @@ private:
|
|||
|
||||
mutable DeepLayer m_merged_polygons;
|
||||
mutable bool m_merged_polygons_valid;
|
||||
mutable bool m_merged_polygons_min_coherence;
|
||||
mutable size_t m_merged_polygons_boc_hash;
|
||||
bool m_is_merged;
|
||||
mutable bool m_is_merged;
|
||||
mutable bool m_is_merged_min_coherence;
|
||||
|
||||
void init ();
|
||||
void ensure_merged_polygons_valid () const;
|
||||
void ensure_unmerged_polygons_valid () const;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -232,6 +232,14 @@ bool DeepLayer::operator== (const DeepLayer &other) const
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DeepLayer::swap (DeepLayer &other)
|
||||
{
|
||||
tl_assert (mp_store.get () == other.mp_store.get ());
|
||||
std::swap (m_layer, other.m_layer);
|
||||
std::swap (m_layout, other.m_layout);
|
||||
}
|
||||
|
||||
db::Layout &
|
||||
DeepLayer::layout ()
|
||||
{
|
||||
|
|
@ -563,13 +571,13 @@ static unsigned int init_layer (db::Layout &layout, const db::RecursiveShapeIter
|
|||
}
|
||||
|
||||
DeepShapeStore::DeepShapeStore ()
|
||||
: m_keep_layouts (true), m_wants_all_cells (false)
|
||||
: m_keep_layouts (true), m_wants_all_cells (false), m_sparse_array_limit (-1.0)
|
||||
{
|
||||
++s_instance_count;
|
||||
}
|
||||
|
||||
DeepShapeStore::DeepShapeStore (const std::string &topcell_name, double dbu)
|
||||
: m_keep_layouts (true), m_wants_all_cells (false)
|
||||
: m_keep_layouts (true), m_wants_all_cells (false), m_sparse_array_limit (-1.0)
|
||||
{
|
||||
++s_instance_count;
|
||||
|
||||
|
|
@ -857,6 +865,16 @@ bool DeepShapeStore::wants_all_cells () const
|
|||
return m_wants_all_cells;
|
||||
}
|
||||
|
||||
void DeepShapeStore::set_sparse_array_limit (double l)
|
||||
{
|
||||
m_sparse_array_limit = l;
|
||||
}
|
||||
|
||||
double DeepShapeStore::sparse_array_limit () const
|
||||
{
|
||||
return m_sparse_array_limit;
|
||||
}
|
||||
|
||||
void DeepShapeStore::set_reject_odd_polygons (bool f)
|
||||
{
|
||||
m_state.set_reject_odd_polygons (f);
|
||||
|
|
@ -1022,6 +1040,7 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator
|
|||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
builder.set_wants_all_cells (m_wants_all_cells);
|
||||
builder.set_sparse_array_limit (m_sparse_array_limit);
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
|
@ -1056,6 +1075,9 @@ DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator
|
|||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
builder.set_wants_all_cells (m_wants_all_cells);
|
||||
builder.set_sparse_array_limit (m_sparse_array_limit);
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
||||
|
|
@ -1367,7 +1389,6 @@ namespace
|
|||
{
|
||||
public:
|
||||
DeepShapeStoreToShapeTransformer (const DeepShapeStore &dss, const db::Layout &layout)
|
||||
: mp_layout (& layout)
|
||||
{
|
||||
// gets the text annotation property ID -
|
||||
// this is how the texts are passed for annotating the net names
|
||||
|
|
@ -1423,7 +1444,6 @@ namespace
|
|||
|
||||
private:
|
||||
std::pair<bool, db::property_names_id_type> m_text_annot_name_id;
|
||||
const db::Layout *mp_layout;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,11 @@ public:
|
|||
*/
|
||||
bool operator== (const DeepLayer &other) const;
|
||||
|
||||
/**
|
||||
* @brief Swap two layers
|
||||
*/
|
||||
void swap (DeepLayer &other);
|
||||
|
||||
/**
|
||||
* @brief Gets the layout object
|
||||
* The return value is guaranteed to be non-null.
|
||||
|
|
@ -696,6 +701,27 @@ public:
|
|||
*/
|
||||
bool wants_all_cells () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the "sparse array" limit
|
||||
*
|
||||
* Sparse arrays are instance arrays whose bounding box is no longer a
|
||||
* good approximation of the covered area. The "sparse array ratio" is
|
||||
* the area of the bounding box divided by the area of the bounding box
|
||||
* of a single instance.
|
||||
*
|
||||
* Arrays above this limit will be resolved into single instances.
|
||||
*
|
||||
* Setting this value to 0 will resolve all arrays. Setting this
|
||||
* value to a negative value will never split arrays. The latter
|
||||
* is the default.
|
||||
*/
|
||||
void set_sparse_array_limit (double l);
|
||||
|
||||
/**
|
||||
* @brief Gets the "sparse array" limit
|
||||
*/
|
||||
double sparse_array_limit () const;
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether to reject odd polygons
|
||||
*
|
||||
|
|
@ -853,6 +879,7 @@ private:
|
|||
std::list<DeepShapeStoreState> m_state_stack;
|
||||
bool m_keep_layouts;
|
||||
bool m_wants_all_cells;
|
||||
double m_sparse_array_limit;
|
||||
tl::Mutex m_lock;
|
||||
|
||||
struct DeliveryMappingCacheKey
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ public:
|
|||
virtual bool wants_variants () const { return false; }
|
||||
|
||||
private:
|
||||
bool m_inverted;
|
||||
db::EdgeAngleChecker m_checker;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,13 @@ EdgePairs::EdgePairs (DeepShapeStore &dss)
|
|||
mp_delegate = new DeepEdgePairs (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||
}
|
||||
|
||||
void
|
||||
EdgePairs::convert_to_deep (const db::DeepLayer &layer)
|
||||
{
|
||||
tl_assert (mp_delegate->deep () == 0);
|
||||
set_delegate (copy_data_id (new db::DeepEdgePairs (layer)));
|
||||
}
|
||||
|
||||
void
|
||||
EdgePairs::write (const std::string &fn) const
|
||||
{
|
||||
|
|
@ -113,9 +120,8 @@ EdgePairs::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,6 +204,11 @@ public:
|
|||
*/
|
||||
explicit EdgePairs (DeepShapeStore &dss);
|
||||
|
||||
/**
|
||||
* @brief Converts the shape collection to a deep one using the specified layer
|
||||
*/
|
||||
virtual void convert_to_deep (const db::DeepLayer &layer);
|
||||
|
||||
/**
|
||||
* @brief Writes the edge pair collection to a file
|
||||
*
|
||||
|
|
|
|||
|
|
@ -114,6 +114,13 @@ Edges::Edges (DeepShapeStore &dss)
|
|||
mp_delegate = new DeepEdges (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||
}
|
||||
|
||||
void
|
||||
Edges::convert_to_deep (const db::DeepLayer &layer)
|
||||
{
|
||||
tl_assert (mp_delegate->deep () == 0);
|
||||
set_delegate (copy_data_id (new db::DeepEdges (layer)));
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator &
|
||||
Edges::iter () const
|
||||
{
|
||||
|
|
@ -145,9 +152,8 @@ Edges::write (const std::string &fn) const
|
|||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
tl::OutputStream os (opt.set_format_from_filename (fn).second);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,6 +264,11 @@ public:
|
|||
*/
|
||||
explicit Edges (DeepShapeStore &dss);
|
||||
|
||||
/**
|
||||
* @brief Converts the shape collection to a deep one using the specified layer
|
||||
*/
|
||||
virtual void convert_to_deep (const db::DeepLayer &layer);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -244,7 +244,6 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
db::MagnificationAndOrientationReducer m_vars;
|
||||
EdgeAngleChecker m_checker;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,9 +46,11 @@ public:
|
|||
|
||||
virtual RegionIteratorDelegate *begin () const { return 0; }
|
||||
virtual RegionIteratorDelegate *begin_merged () const { return 0; }
|
||||
virtual RegionIteratorDelegate *begin_unmerged () const { return 0; }
|
||||
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_unmerged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
|
||||
|
||||
virtual bool empty () const { return true; }
|
||||
virtual size_t count () const { return 0; }
|
||||
|
|
@ -109,6 +111,8 @@ public:
|
|||
virtual RegionDelegate *add_in_place (const Region &other);
|
||||
virtual RegionDelegate *add (const Region &other) const;
|
||||
|
||||
virtual RegionDelegate *peel (double /*complexity_factor*/) const { return new EmptyRegion (); }
|
||||
|
||||
virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "dbFileBasedLibrary.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbCellMapping.h"
|
||||
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
FileBasedLibrary::FileBasedLibrary (const std::string &path, const std::string &name)
|
||||
: db::Library (), m_name (name), m_path (path), m_is_loaded (false)
|
||||
{
|
||||
set_description (tl::filename (path));
|
||||
|
||||
// preliminary name, may be replaced later
|
||||
if (! name.empty ()) {
|
||||
set_name (name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileBasedLibrary::merge_with_other_layout (const std::string &path)
|
||||
{
|
||||
m_other_paths.push_back (path);
|
||||
if (m_is_loaded) {
|
||||
merge_impl (path);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FileBasedLibrary::is_for_path (const std::string &path)
|
||||
{
|
||||
return m_other_paths.empty () && m_path == path;
|
||||
}
|
||||
|
||||
bool
|
||||
FileBasedLibrary::is_for_paths (const std::vector<std::string> &paths)
|
||||
{
|
||||
if (paths.size () != m_other_paths.size () + 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// this check is purely based on path strings
|
||||
std::set<std::string> p1 (paths.begin (), paths.end ());
|
||||
std::set<std::string> p2;
|
||||
p2.insert (m_path);
|
||||
p2.insert (m_other_paths.begin (), m_other_paths.end ());
|
||||
return p1 == p2;
|
||||
}
|
||||
|
||||
std::string
|
||||
FileBasedLibrary::load ()
|
||||
{
|
||||
if (! m_is_loaded) {
|
||||
return reload ();
|
||||
} else {
|
||||
return get_name ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
FileBasedLibrary::reload ()
|
||||
{
|
||||
std::string name = m_name.empty () ? tl::basename (m_path) : m_name;
|
||||
|
||||
layout ().clear ();
|
||||
|
||||
tl::InputStream stream (m_path);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout ());
|
||||
|
||||
// Use the libname if there is one
|
||||
if (m_name.empty ()) {
|
||||
db::Layout::meta_info_name_id_type libname_name_id = layout ().meta_info_name_id ("libname");
|
||||
for (db::Layout::meta_info_iterator m = layout ().begin_meta (); m != layout ().end_meta (); ++m) {
|
||||
if (m->first == libname_name_id && ! m->second.value.is_nil ()) {
|
||||
name = m->second.value.to_string ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto p = m_other_paths.begin (); p != m_other_paths.end (); ++p) {
|
||||
merge_impl (*p);
|
||||
}
|
||||
|
||||
m_is_loaded = true;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
FileBasedLibrary::merge_impl (const std::string &path)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
||||
tl::InputStream stream (path);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
|
||||
std::vector<db::cell_index_type> target_cells, source_cells;
|
||||
|
||||
// collect the cells to pull in (all top cells of the library layout)
|
||||
// NOTE: cells are not overwritten - the first layout wins, in terms
|
||||
// of cell names and also in terms of database unit.
|
||||
for (auto c = ly.begin_top_down (); c != ly.end_top_cells (); ++c) {
|
||||
std::string cn = ly.cell_name (*c);
|
||||
if (! layout ().has_cell (cn.c_str ())) {
|
||||
source_cells.push_back (*c);
|
||||
target_cells.push_back (layout ().add_cell (cn.c_str ()));
|
||||
}
|
||||
}
|
||||
|
||||
db::CellMapping cm;
|
||||
cm.create_multi_mapping_full (layout (), target_cells, ly, source_cells);
|
||||
layout ().copy_tree_shapes (ly, cm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2026 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbFileBasedLibrary
|
||||
#define HDR_dbFileBasedLibrary
|
||||
|
||||
#include "dbLibrary.h"
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A Library specialization that ties a library to a file
|
||||
*
|
||||
* This object supports loading a library from multiple files and merging them into
|
||||
* a single library (e.g. for loading a directory of cell files).
|
||||
*/
|
||||
class DB_PUBLIC FileBasedLibrary
|
||||
: public db::Library
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a file-based library object
|
||||
*
|
||||
* @param path The file path
|
||||
* @param name The library name
|
||||
*
|
||||
* If the library name is an empty string, the library name is taken from
|
||||
* a GDS LIBNAME or from the file name in the path.
|
||||
*
|
||||
* Note that you need to call "load" in order to actually load the file.
|
||||
*/
|
||||
FileBasedLibrary (const std::string &path, const std::string &name = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Merges another file into this library
|
||||
*
|
||||
* If the library was not loaded already, the merge requests are postponed
|
||||
* until "load" is called.
|
||||
*/
|
||||
void merge_with_other_layout (const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Loads the files
|
||||
*
|
||||
* If the files are already loaded, this method does nothing.
|
||||
* It returns the name of the library derived from the first file
|
||||
* or the name given in the constructor. The constructor name has
|
||||
* priority.
|
||||
*/
|
||||
std::string load ();
|
||||
|
||||
/**
|
||||
* @brief Implements the reload feature
|
||||
*/
|
||||
virtual std::string reload ();
|
||||
|
||||
/**
|
||||
* @brief Set the paths
|
||||
* This method is provided for test purposes only.
|
||||
*/
|
||||
void set_paths (const std::string &path, const std::list<std::string> &other_paths = std::list<std::string> ())
|
||||
{
|
||||
m_path = path;
|
||||
m_other_paths = other_paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the library is for the given path
|
||||
*/
|
||||
bool is_for_path (const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the library is for the given path
|
||||
*/
|
||||
bool is_for_paths (const std::vector<std::string> &paths);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_path;
|
||||
std::list<std::string> m_other_paths;
|
||||
bool m_is_loaded;
|
||||
|
||||
void merge_impl (const std::string &path);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -33,41 +33,55 @@ namespace db
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// FlatRegion implementation
|
||||
|
||||
FlatRegion::FlatRegion ()
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false))
|
||||
FlatRegion::FlatRegion (double area_ratio, size_t max_vertex_count)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)),
|
||||
m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (const FlatRegion &other)
|
||||
: MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons)
|
||||
: MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons),
|
||||
m_area_ratio (other.m_area_ratio), m_max_vertex_count (other.m_max_vertex_count)
|
||||
{
|
||||
init ();
|
||||
set_min_coherence (other.min_coherence ());
|
||||
m_is_merged = other.m_is_merged;
|
||||
m_is_merged_min_coherence = other.m_is_merged_min_coherence;
|
||||
m_merged_polygons_valid = other.m_merged_polygons_valid;
|
||||
m_merged_polygons_min_coherence = other.m_merged_polygons_min_coherence;
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false))
|
||||
FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged, double area_ratio, size_t max_vertex_count, bool min_coh)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)),
|
||||
m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count)
|
||||
{
|
||||
init ();
|
||||
set_min_coherence (min_coh);
|
||||
m_is_merged = is_merged;
|
||||
m_is_merged_min_coherence = min_coh;
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false))
|
||||
FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged, double area_ratio, size_t max_vertex_count, bool min_coh)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)),
|
||||
m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count)
|
||||
{
|
||||
init ();
|
||||
set_min_coherence (min_coh);
|
||||
m_is_merged = is_merged;
|
||||
m_is_merged_min_coherence = min_coh;
|
||||
transform_generic (trans);
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false))
|
||||
FlatRegion::FlatRegion (bool is_merged, double area_ratio, size_t max_vertex_count, bool min_coh)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)),
|
||||
m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count)
|
||||
{
|
||||
init ();
|
||||
set_min_coherence (min_coh);
|
||||
m_is_merged = is_merged;
|
||||
m_is_merged_min_coherence = min_coh;
|
||||
}
|
||||
|
||||
FlatRegion::~FlatRegion ()
|
||||
|
|
@ -78,6 +92,7 @@ FlatRegion::~FlatRegion ()
|
|||
void FlatRegion::set_is_merged (bool m)
|
||||
{
|
||||
m_is_merged = m;
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
}
|
||||
|
||||
void FlatRegion::invalidate_cache ()
|
||||
|
|
@ -90,7 +105,9 @@ void FlatRegion::invalidate_cache ()
|
|||
void FlatRegion::init ()
|
||||
{
|
||||
m_is_merged = false;
|
||||
m_is_merged_min_coherence = false;
|
||||
m_merged_polygons_valid = false;
|
||||
m_merged_polygons_min_coherence = false;
|
||||
}
|
||||
|
||||
void FlatRegion::merged_semantics_changed ()
|
||||
|
|
@ -107,9 +124,7 @@ void FlatRegion::join_properties_on_merge_changed ()
|
|||
|
||||
void FlatRegion::min_coherence_changed ()
|
||||
{
|
||||
m_is_merged = false;
|
||||
mp_merged_polygons->clear ();
|
||||
m_merged_polygons_valid = false;
|
||||
// merged status is tracked in separate variables and is validated on inquiry
|
||||
}
|
||||
|
||||
void FlatRegion::reserve (size_t n)
|
||||
|
|
@ -117,15 +132,44 @@ void FlatRegion::reserve (size_t n)
|
|||
mp_polygons->reserve (db::Polygon::tag (), n);
|
||||
}
|
||||
|
||||
bool
|
||||
FlatRegion::merged_polygons_valid () const
|
||||
{
|
||||
return m_merged_polygons_valid && m_merged_polygons_min_coherence == min_coherence ();
|
||||
}
|
||||
|
||||
bool
|
||||
FlatRegion::merged_polygons_available () const
|
||||
{
|
||||
return is_merged () || merged_polygons_valid ();
|
||||
}
|
||||
|
||||
void
|
||||
FlatRegion::ensure_merged_polygons_valid () const
|
||||
{
|
||||
if (! m_merged_polygons_valid) {
|
||||
if (! merged_polygons_valid ()) {
|
||||
merge_polygons_to (*mp_merged_polygons, min_coherence (), 0, join_properties_on_merge ());
|
||||
m_merged_polygons_valid = true;
|
||||
m_merged_polygons_min_coherence = min_coherence ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FlatRegion::ensure_unmerged_polygons_valid () const
|
||||
{
|
||||
if (! m_is_merged || (m_area_ratio == 0.0 && m_max_vertex_count == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp_merged_polygons.reset (new db::Shapes (*mp_polygons));
|
||||
m_merged_polygons_valid = true;
|
||||
m_merged_polygons_min_coherence = m_is_merged_min_coherence;
|
||||
m_is_merged = false;
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
|
||||
break_polygons (*mp_polygons, m_max_vertex_count, m_area_ratio);
|
||||
}
|
||||
|
||||
RegionIteratorDelegate *FlatRegion::begin () const
|
||||
{
|
||||
return new FlatRegionIterator (mp_polygons.get_const ());
|
||||
|
|
@ -133,7 +177,7 @@ RegionIteratorDelegate *FlatRegion::begin () const
|
|||
|
||||
RegionIteratorDelegate *FlatRegion::begin_merged () const
|
||||
{
|
||||
if (! merged_semantics () || m_is_merged) {
|
||||
if (! merged_semantics () || is_merged ()) {
|
||||
return begin ();
|
||||
} else {
|
||||
ensure_merged_polygons_valid ();
|
||||
|
|
@ -141,6 +185,12 @@ RegionIteratorDelegate *FlatRegion::begin_merged () const
|
|||
}
|
||||
}
|
||||
|
||||
RegionIteratorDelegate *FlatRegion::begin_unmerged () const
|
||||
{
|
||||
ensure_unmerged_polygons_valid ();
|
||||
return begin ();
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_iter () const
|
||||
{
|
||||
return std::make_pair (db::RecursiveShapeIterator (*mp_polygons), db::ICplxTrans ());
|
||||
|
|
@ -148,7 +198,7 @@ std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_iter ()
|
|||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_merged_iter () const
|
||||
{
|
||||
if (! merged_semantics () || m_is_merged) {
|
||||
if (! merged_semantics () || is_merged ()) {
|
||||
return begin_iter ();
|
||||
} else {
|
||||
ensure_merged_polygons_valid ();
|
||||
|
|
@ -156,6 +206,12 @@ std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_merged_i
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatRegion::begin_unmerged_iter () const
|
||||
{
|
||||
ensure_unmerged_polygons_valid ();
|
||||
return begin_iter ();
|
||||
}
|
||||
|
||||
bool FlatRegion::empty () const
|
||||
{
|
||||
return mp_polygons->empty ();
|
||||
|
|
@ -173,7 +229,7 @@ size_t FlatRegion::hier_count () const
|
|||
|
||||
bool FlatRegion::is_merged () const
|
||||
{
|
||||
return m_is_merged;
|
||||
return m_is_merged && m_is_merged_min_coherence == min_coherence ();
|
||||
}
|
||||
|
||||
Box FlatRegion::compute_bbox () const
|
||||
|
|
@ -215,6 +271,7 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter)
|
|||
mp_merged_polygons->clear ();
|
||||
invalidate_cache ();
|
||||
m_is_merged = filter.requires_raw_input () ? false : merged_semantics ();
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
@ -245,6 +302,7 @@ RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter
|
|||
mp_merged_polygons->clear ();
|
||||
invalidate_cache ();
|
||||
m_is_merged = filter.result_is_merged () && merged_semantics ();
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
set_merged_semantics (false);
|
||||
|
|
@ -255,14 +313,15 @@ RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter
|
|||
|
||||
RegionDelegate *FlatRegion::merged_in_place ()
|
||||
{
|
||||
if (! m_is_merged) {
|
||||
if (! is_merged ()) {
|
||||
|
||||
if (m_merged_polygons_valid) {
|
||||
if (merged_polygons_valid ()) {
|
||||
|
||||
db::Shapes &merged_polygons = *mp_merged_polygons;
|
||||
mp_polygons->swap (merged_polygons);
|
||||
merged_polygons.clear ();
|
||||
m_is_merged = true;
|
||||
m_is_merged_min_coherence = min_coherence ();
|
||||
return this;
|
||||
|
||||
} else {
|
||||
|
|
@ -274,7 +333,7 @@ RegionDelegate *FlatRegion::merged_in_place ()
|
|||
}
|
||||
}
|
||||
|
||||
RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge)
|
||||
RegionDelegate *FlatRegion::merged_in_place (bool min_coh, unsigned int min_wc, bool join_properties_on_merge)
|
||||
{
|
||||
if (empty ()) {
|
||||
|
||||
|
|
@ -291,9 +350,11 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi
|
|||
} else {
|
||||
|
||||
invalidate_cache ();
|
||||
merge_polygons_to (*mp_polygons, min_coherence, min_wc, join_properties_on_merge);
|
||||
merge_polygons_to (*mp_polygons, min_coh, min_wc, join_properties_on_merge);
|
||||
|
||||
set_min_coherence (min_coh);
|
||||
m_is_merged = true;
|
||||
m_is_merged_min_coherence = min_coh;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -302,19 +363,35 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi
|
|||
|
||||
RegionDelegate *FlatRegion::merged () const
|
||||
{
|
||||
if (! m_is_merged) {
|
||||
if (! is_merged ()) {
|
||||
|
||||
if (m_merged_polygons_valid) {
|
||||
return new FlatRegion (*mp_merged_polygons, true);
|
||||
} else {
|
||||
return AsIfFlatRegion::merged (min_coherence (), 0, join_properties_on_merge ());
|
||||
if (! merged_polygons_valid ()) {
|
||||
ensure_merged_polygons_valid ();
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (*mp_merged_polygons, true, 0, 0, min_coherence ()));
|
||||
|
||||
new_region->set_max_vertex_count (m_max_vertex_count);
|
||||
new_region->set_area_ratio (m_area_ratio);
|
||||
|
||||
return new_region.release ();
|
||||
|
||||
} else {
|
||||
return clone ();
|
||||
}
|
||||
}
|
||||
|
||||
RegionDelegate *FlatRegion::merged (bool min_coh, unsigned int min_wc, bool jp) const
|
||||
{
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (true, 0, 0, min_coh));
|
||||
merge_polygons_to (new_region->raw_polygons (), min_coh, min_wc, jp);
|
||||
|
||||
new_region->set_max_vertex_count (m_max_vertex_count);
|
||||
new_region->set_area_ratio (m_area_ratio);
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *FlatRegion::add (const Region &other) const
|
||||
{
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (*this));
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ public:
|
|||
typedef db::layer<db::PolygonWithProperties, db::unstable_layer_tag> polygon_layer_wp_type;
|
||||
typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type;
|
||||
|
||||
FlatRegion ();
|
||||
FlatRegion (const db::Shapes &polygons, bool is_merged = false);
|
||||
FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false);
|
||||
FlatRegion (bool is_merged);
|
||||
FlatRegion (double area_ratio = 0.0, size_t max_vertex_count = 0);
|
||||
FlatRegion (const db::Shapes &polygons, bool is_merged = false, double area_ratio = 0.0, size_t max_vertex_count = 0, bool min_coh = false);
|
||||
FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false, double area_ratio = 0.0, size_t max_vertex_count = 0, bool min_coh = false);
|
||||
FlatRegion (bool is_merged, double area_ratio = 0.0, size_t max_vertex_count = 0, bool min_coh = false);
|
||||
|
||||
FlatRegion (const FlatRegion &other);
|
||||
|
||||
|
|
@ -69,9 +69,11 @@ public:
|
|||
|
||||
virtual RegionIteratorDelegate *begin () const;
|
||||
virtual RegionIteratorDelegate *begin_merged () const;
|
||||
virtual RegionIteratorDelegate *begin_unmerged () const;
|
||||
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_unmerged_iter () const;
|
||||
|
||||
virtual bool empty () const;
|
||||
virtual size_t count () const;
|
||||
|
|
@ -83,10 +85,9 @@ public:
|
|||
virtual RegionDelegate *merged_in_place ();
|
||||
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, bool join_properties_on_merge) const
|
||||
{
|
||||
return db::AsIfFlatRegion::merged (min_coherence, min_wc, join_properties_on_merge);
|
||||
}
|
||||
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const;
|
||||
|
||||
bool merged_polygons_available () const;
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter);
|
||||
|
|
@ -136,6 +137,7 @@ protected:
|
|||
virtual Box compute_bbox () const;
|
||||
void invalidate_cache ();
|
||||
void set_is_merged (bool m);
|
||||
bool merged_polygons_valid () const;
|
||||
|
||||
private:
|
||||
friend class AsIfFlatRegion;
|
||||
|
|
@ -143,13 +145,28 @@ private:
|
|||
|
||||
FlatRegion &operator= (const FlatRegion &other);
|
||||
|
||||
bool m_is_merged;
|
||||
mutable bool m_is_merged;
|
||||
mutable bool m_is_merged_min_coherence;
|
||||
mutable tl::copy_on_write_ptr<db::Shapes> mp_polygons;
|
||||
mutable tl::copy_on_write_ptr<db::Shapes> mp_merged_polygons;
|
||||
mutable bool m_merged_polygons_valid;
|
||||
mutable bool m_merged_polygons_min_coherence;
|
||||
double m_area_ratio;
|
||||
size_t m_max_vertex_count;
|
||||
|
||||
void init ();
|
||||
void ensure_merged_polygons_valid () const;
|
||||
void ensure_unmerged_polygons_valid () const;
|
||||
|
||||
void set_area_ratio (double ar)
|
||||
{
|
||||
m_area_ratio = ar;
|
||||
}
|
||||
|
||||
void set_max_vertex_count (size_t mc)
|
||||
{
|
||||
m_max_vertex_count = mc;
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform_generic (const Trans &trans)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbShapes.h"
|
||||
|
|
@ -1794,7 +1793,7 @@ public:
|
|||
cell_clusters_box_converter (const db::Layout &layout, const hier_clusters<T> &tree)
|
||||
: mp_layout (&layout), mp_tree (&tree)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
m_cache.resize (layout.cells (), 0);
|
||||
}
|
||||
|
||||
const box_type &operator() (const db::CellInst &cell_inst) const
|
||||
|
|
@ -1804,10 +1803,10 @@ public:
|
|||
|
||||
const box_type &operator() (db::cell_index_type cell_index) const
|
||||
{
|
||||
typename std::map<db::cell_index_type, box_type>::const_iterator b = m_cache.find (cell_index);
|
||||
if (b != m_cache.end ()) {
|
||||
const box_type *b = m_cache [cell_index];
|
||||
if (b) {
|
||||
|
||||
return b->second;
|
||||
return *b;
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -1820,13 +1819,17 @@ public:
|
|||
box += inst_array.bbox (*this);
|
||||
}
|
||||
|
||||
return m_cache.insert (std::make_pair (cell_index, box)).first->second;
|
||||
m_cached_boxes.push_front (box);
|
||||
b = m_cached_boxes.begin ().operator-> ();
|
||||
m_cache [cell_index] = b;
|
||||
return *b;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::map<db::cell_index_type, box_type> m_cache;
|
||||
mutable std::vector<const box_type *> m_cache;
|
||||
mutable tl::slist<box_type> m_cached_boxes;
|
||||
const db::Layout *mp_layout;
|
||||
const hier_clusters<T> *mp_tree;
|
||||
};
|
||||
|
|
@ -1889,8 +1892,8 @@ namespace
|
|||
*/
|
||||
template <class T>
|
||||
struct hc_receiver
|
||||
: public db::box_scanner_receiver<db::Instance, unsigned int>,
|
||||
public db::box_scanner_receiver2<local_cluster<T>, unsigned int, db::Instance, unsigned int>
|
||||
: public db::box_scanner_receiver<db::Instance, db::Box>,
|
||||
public db::box_scanner_receiver2<local_cluster<T>, db::Box, db::Instance, db::Box>
|
||||
{
|
||||
public:
|
||||
typedef typename hier_clusters<T>::box_type box_type;
|
||||
|
|
@ -1960,7 +1963,7 @@ public:
|
|||
/**
|
||||
* @brief Receiver main event for instance-to-instance interactions
|
||||
*/
|
||||
void add (const db::Instance *i1, unsigned int /*p1*/, const db::Instance *i2, unsigned int /*p2*/)
|
||||
void add (const db::Instance *i1, db::Box /*p1*/, const db::Instance *i2, db::Box /*p2*/)
|
||||
{
|
||||
db::ICplxTrans t;
|
||||
|
||||
|
|
@ -1973,7 +1976,7 @@ public:
|
|||
/**
|
||||
* @brief Single-instance treatment - may be required because of interactions between array members
|
||||
*/
|
||||
void finish (const db::Instance *i, unsigned int /*p1*/)
|
||||
void finish (const db::Instance *i, db::Box /*p1*/)
|
||||
{
|
||||
consider_single_inst (*i);
|
||||
}
|
||||
|
|
@ -1981,7 +1984,7 @@ public:
|
|||
/**
|
||||
* @brief Receiver main event for local-to-instance interactions
|
||||
*/
|
||||
void add (const local_cluster<T> *c1, unsigned int /*p1*/, const db::Instance *i2, unsigned int /*p2*/)
|
||||
void add (const local_cluster<T> *c1, db::Box /*p1*/, const db::Instance *i2, db::Box /*p2*/)
|
||||
{
|
||||
std::list<ClusterInstanceInteraction> ic;
|
||||
|
||||
|
|
@ -1993,10 +1996,10 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Finally join the clusters in the join set
|
||||
* @brief Finally generate cluster-to-instance interactions and join the clusters in the join set
|
||||
*
|
||||
* This step is postponed because doing this while the iteration happens would
|
||||
* invalidate the box trees.
|
||||
* invalidate the box trees and disturb the propagation mechanism.
|
||||
*/
|
||||
void finish_cluster_to_instance_interactions ()
|
||||
{
|
||||
|
|
@ -2081,7 +2084,7 @@ private:
|
|||
const db::Connectivity *mp_conn;
|
||||
const std::set<db::cell_index_type> *mp_breakout_cells;
|
||||
typedef std::list<std::set<id_type> > join_set_list;
|
||||
std::map<id_type, typename join_set_list::iterator> m_cm2join_map;
|
||||
std::unordered_map<id_type, typename join_set_list::iterator> m_cm2join_map;
|
||||
join_set_list m_cm2join_sets;
|
||||
std::map<std::pair<size_t, size_t>, int> m_soft_connections;
|
||||
std::list<ClusterInstanceInteraction> m_ci_interactions;
|
||||
|
|
@ -2551,8 +2554,8 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
typename std::map<id_type, typename join_set_list::iterator>::const_iterator x = m_cm2join_map.find (a);
|
||||
typename std::map<id_type, typename join_set_list::iterator>::const_iterator y = m_cm2join_map.find (b);
|
||||
typename std::unordered_map<id_type, typename join_set_list::iterator>::const_iterator x = m_cm2join_map.find (a);
|
||||
typename std::unordered_map<id_type, typename join_set_list::iterator>::const_iterator y = m_cm2join_map.find (b);
|
||||
|
||||
if (x == m_cm2join_map.end ()) {
|
||||
|
||||
|
|
@ -2579,6 +2582,11 @@ private:
|
|||
|
||||
} else if (x->second != y->second) {
|
||||
|
||||
// the y set should be the smaller one for better efficiency
|
||||
if (x->second->size () < y->second->size ()) {
|
||||
std::swap (x, y);
|
||||
}
|
||||
|
||||
// join two superclusters
|
||||
typename join_set_list::iterator yset = y->second;
|
||||
x->second->insert (yset->begin (), yset->end ());
|
||||
|
|
@ -2591,12 +2599,12 @@ private:
|
|||
|
||||
#if defined(DEBUG_HIER_NETWORK_PROCESSOR)
|
||||
// concistency check for debugging
|
||||
for (typename std::map<id_type, typename join_set_list::iterator>::const_iterator j = m_cm2join_map.begin (); j != m_cm2join_map.end (); ++j) {
|
||||
for (auto j = m_cm2join_map.begin (); j != m_cm2join_map.end (); ++j) {
|
||||
tl_assert (j->second->find (j->first) != j->second->end ());
|
||||
}
|
||||
|
||||
for (typename std::list<std::set<id_type> >::const_iterator i = m_cm2join_sets.begin (); i != m_cm2join_sets.end (); ++i) {
|
||||
for (typename std::set<id_type>::const_iterator j = i->begin(); j != i->end(); ++j) {
|
||||
for (auto i = m_cm2join_sets.begin (); i != m_cm2join_sets.end (); ++i) {
|
||||
for (auto j = i->begin(); j != i->end(); ++j) {
|
||||
tl_assert(m_cm2join_map.find (*j) != m_cm2join_map.end ());
|
||||
tl_assert(m_cm2join_map[*j] == i);
|
||||
}
|
||||
|
|
@ -2604,8 +2612,8 @@ private:
|
|||
|
||||
// the sets must be disjunct
|
||||
std::set<id_type> all;
|
||||
for (typename std::list<std::set<id_type> >::const_iterator i = m_cm2join_sets.begin (); i != m_cm2join_sets.end (); ++i) {
|
||||
for (typename std::set<id_type>::const_iterator j = i->begin(); j != i->end(); ++j) {
|
||||
for (auto i = m_cm2join_sets.begin (); i != m_cm2join_sets.end (); ++i) {
|
||||
for (auto j = i->begin(); j != i->end(); ++j) {
|
||||
tl_assert(all.find (*j) == all.end());
|
||||
all.insert(*j);
|
||||
}
|
||||
|
|
@ -2700,23 +2708,13 @@ private:
|
|||
} else if (x1 != x2) {
|
||||
|
||||
int soft = ic->soft;
|
||||
|
||||
// for instance-to-instance interactions the number of connections is more important for the
|
||||
// cost of the join operation: make the one with more connections the target
|
||||
// TODO: this will be SLOW for STL's not providing a fast size()
|
||||
if (mp_cell_clusters->connections_for_cluster (x1).size () < mp_cell_clusters->connections_for_cluster (x2).size ()) {
|
||||
std::swap (x1, x2);
|
||||
soft = -soft;
|
||||
}
|
||||
|
||||
if (soft != 0) {
|
||||
|
||||
register_soft_connection (x1, x2, soft);
|
||||
|
||||
} else {
|
||||
|
||||
mp_cell_clusters->join_cluster_with (x1, x2);
|
||||
mp_cell_clusters->remove_cluster (x2);
|
||||
mark_to_join (x1, x2);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3081,15 +3079,15 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
|
|||
static std::string desc = tl::to_string (tr ("Instance to instance treatment"));
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 30, desc);
|
||||
|
||||
db::box_scanner<db::Instance, unsigned int> bs (true, desc);
|
||||
db::box_scanner<db::Instance, db::Box> bs (true, desc);
|
||||
|
||||
for (std::vector<db::Instance>::const_iterator inst = inst_storage.begin (); inst != inst_storage.end (); ++inst) {
|
||||
if (! is_breakout_cell (breakout_cells, inst->cell_index ())) {
|
||||
bs.insert (inst.operator-> (), 0);
|
||||
bs.insert (inst.operator-> (), cibc (*inst));
|
||||
}
|
||||
}
|
||||
|
||||
bs.process (*rec, 1 /*touching*/, cibc);
|
||||
bs.process_with_adaptor (*rec, 1 /*touching*/);
|
||||
}
|
||||
|
||||
// handle local to instance connections
|
||||
|
|
@ -3101,7 +3099,8 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
|
|||
static std::string desc = tl::to_string (tr ("Local to instance treatment"));
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 30, desc);
|
||||
|
||||
db::box_scanner2<db::local_cluster<T>, unsigned int, db::Instance, unsigned int> bs2 (true, desc);
|
||||
local_cluster_box_convert<T> lcbc;
|
||||
db::box_scanner2<db::local_cluster<T>, db::Box, db::Instance, db::Box> bs2 (true, desc);
|
||||
|
||||
for (typename connected_clusters<T>::const_iterator c = local.begin (); c != local.end (); ++c) {
|
||||
|
||||
|
|
@ -3110,22 +3109,23 @@ hier_clusters<T>::build_hier_connections (cell_clusters_box_converter<T> &cbc, c
|
|||
std::back_insert_iterator<std::list<local_cluster<T> > > iout = std::back_inserter (heap);
|
||||
size_t n = c->split (area_ratio, iout);
|
||||
if (n == 0) {
|
||||
bs2.insert1 (c.operator-> (), 0);
|
||||
bs2.insert1 (c.operator-> (), lcbc (*c));
|
||||
} else {
|
||||
typename std::list<local_cluster<T> >::iterator h = heap.end ();
|
||||
while (n-- > 0) {
|
||||
bs2.insert1 ((--h).operator-> (), 0);
|
||||
--h;
|
||||
bs2.insert1 (h.operator-> (), lcbc (*h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<db::Instance>::const_iterator inst = inst_storage.begin (); inst != inst_storage.end (); ++inst) {
|
||||
if (! is_breakout_cell (breakout_cells, inst->cell_index ())) {
|
||||
bs2.insert2 (inst.operator-> (), 0);
|
||||
bs2.insert2 (inst.operator-> (), cibc (*inst));
|
||||
}
|
||||
}
|
||||
|
||||
bs2.process (*rec, 1 /*touching*/, local_cluster_box_convert<T> (), cibc);
|
||||
bs2.process_with_adaptor (*rec, 1 /*touching*/);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -622,21 +622,28 @@ public:
|
|||
typedef typename local_processor_cell_contexts<TS, TI, TR>::context_key_type interactions_value_type;
|
||||
typedef std::unordered_map<std::pair<db::cell_index_type, db::ICplxTrans>, interactions_value_type> interactions_type;
|
||||
|
||||
interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, interactions_type *result)
|
||||
: mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result), m_rt (subject_layout)
|
||||
interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, const std::map<unsigned int, db::Coord> &override_distance, interactions_type *result)
|
||||
: mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), m_override_distance (override_distance), mp_result (result), m_rt (subject_layout)
|
||||
{
|
||||
// nothing yet ..
|
||||
}
|
||||
|
||||
void add (const db::CellInstArray *inst, unsigned int, const TI *ref, unsigned int layer)
|
||||
{
|
||||
collect_instance_shape_interactions (inst, layer, *ref, m_dist);
|
||||
db::Coord d = m_dist;
|
||||
auto od = m_override_distance.find (layer);
|
||||
if (od != m_override_distance.end ()) {
|
||||
d = std::min (d, od->second);
|
||||
}
|
||||
|
||||
collect_instance_shape_interactions (inst, layer, *ref, d);
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_subject_layout;
|
||||
unsigned int m_subject_layer;
|
||||
db::Coord m_dist;
|
||||
std::map<unsigned int, db::Coord> m_override_distance;
|
||||
interactions_type *mp_result;
|
||||
db::shape_reference_translator_with_trans<TI, db::ICplxTrans> m_rt;
|
||||
|
||||
|
|
@ -681,11 +688,11 @@ private:
|
|||
// LocalProcessorContextComputationTask implementation
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
local_processor_context_computation_task<TS, TI, TR>::local_processor_context_computation_task (const local_processor<TS, TI, TR> *proc, local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist)
|
||||
local_processor_context_computation_task<TS, TI, TR>::local_processor_context_computation_task (const local_processor<TS, TI, TR> *proc, local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist, const std::map<unsigned int, db::Coord> &override_distance)
|
||||
: tl::Task (),
|
||||
mp_proc (proc), mp_contexts (&contexts), mp_parent_context (parent_context),
|
||||
mp_subject_parent (subject_parent), mp_subject_cell (subject_cell), m_subject_cell_inst (subject_cell_inst),
|
||||
mp_intruder_cell (intruder_cell), m_dist (dist)
|
||||
mp_intruder_cell (intruder_cell), m_dist (dist), m_override_distance (override_distance)
|
||||
{
|
||||
// This is quick, but will take away the intruders from the caller
|
||||
m_intruders.swap (intruders);
|
||||
|
|
@ -695,7 +702,7 @@ template <class TS, class TI, class TR>
|
|||
void
|
||||
local_processor_context_computation_task<TS, TI, TR>::perform ()
|
||||
{
|
||||
mp_proc->compute_contexts (*mp_contexts, mp_parent_context, mp_subject_parent, mp_subject_cell, m_subject_cell_inst, mp_intruder_cell, m_intruders, m_dist);
|
||||
mp_proc->compute_contexts (*mp_contexts, mp_parent_context, mp_subject_parent, mp_subject_cell, m_subject_cell_inst, mp_intruder_cell, m_intruders, m_dist, m_override_distance);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
|
@ -714,7 +721,6 @@ local_processor_result_computation_task<TS, TI, TR>::perform ()
|
|||
{
|
||||
mp_cell_contexts->compute_results (*mp_contexts, mp_cell, mp_op, m_output_layers, mp_proc);
|
||||
|
||||
// erase the contexts we don't need any longer
|
||||
{
|
||||
tl::MutexLocker locker (& mp_contexts->lock ());
|
||||
|
||||
|
|
@ -734,7 +740,10 @@ local_processor_result_computation_task<TS, TI, TR>::perform ()
|
|||
}
|
||||
#endif
|
||||
|
||||
mp_contexts->context_map ().erase (mp_cell);
|
||||
// release some memory
|
||||
auto ctx = mp_contexts->context_map ().find (mp_cell);
|
||||
tl_assert (ctx != mp_contexts->context_map ().end ());
|
||||
ctx->second.cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -742,7 +751,7 @@ local_processor_result_computation_task<TS, TI, TR>::perform ()
|
|||
// LocalProcessorBase implementation
|
||||
|
||||
LocalProcessorBase::LocalProcessorBase ()
|
||||
: m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_boolean_core (false),
|
||||
: m_report_progress (true), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_top_down (false), m_boolean_core (false),
|
||||
m_base_verbosity (30), mp_vars (0), mp_current_cell (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -881,15 +890,6 @@ void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned
|
|||
compute_results (contexts, op, output_layers);
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
void local_processor<TS, TI, TR>::push_results (db::Cell *cell, unsigned int output_layer, const std::unordered_set<TR> &result) const
|
||||
{
|
||||
if (! result.empty ()) {
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->shapes (output_layer).insert (result.begin (), result.end ());
|
||||
}
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS, TI, TR> &contexts, const local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers) const
|
||||
{
|
||||
|
|
@ -907,8 +907,18 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
contexts.set_intruder_layers (intruder_layers);
|
||||
contexts.set_subject_layer (subject_layer);
|
||||
|
||||
// collect override distances per layer ID
|
||||
auto od = op->override_distance ();
|
||||
std::map<unsigned int, db::Coord> override_distance;
|
||||
for (auto il = intruder_layers.begin (); il != intruder_layers.end (); ++il) {
|
||||
auto o = od.find ((unsigned int) (il - intruder_layers.begin ()));
|
||||
if (o != od.end ()) {
|
||||
override_distance [*il] = o->second;
|
||||
}
|
||||
}
|
||||
|
||||
typename local_processor_cell_contexts<TS, TI, TR>::context_key_type intruders;
|
||||
issue_compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist ());
|
||||
issue_compute_contexts (contexts, 0, 0, mp_subject_top, db::ICplxTrans (), mp_intruder_top, intruders, op->dist (), override_distance);
|
||||
|
||||
if (mp_cc_job.get ()) {
|
||||
mp_cc_job->start ();
|
||||
|
|
@ -929,14 +939,15 @@ void local_processor<TS, TI, TR>::issue_compute_contexts (local_processor_contex
|
|||
const db::ICplxTrans &subject_cell_inst,
|
||||
const db::Cell *intruder_cell,
|
||||
typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders,
|
||||
db::Coord dist) const
|
||||
db::Coord dist,
|
||||
const std::map<unsigned int, db::Coord> &override_distance) const
|
||||
{
|
||||
bool is_small_job = subject_cell->begin ().at_end ();
|
||||
|
||||
if (! is_small_job && mp_cc_job.get ()) {
|
||||
mp_cc_job->schedule (new local_processor_context_computation_task<TS, TI, TR> (this, contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist));
|
||||
mp_cc_job->schedule (new local_processor_context_computation_task<TS, TI, TR> (this, contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist, override_distance));
|
||||
} else {
|
||||
compute_contexts (contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist);
|
||||
compute_contexts (contexts, parent_context, subject_parent, subject_cell, subject_cell_inst, intruder_cell, intruders, dist, override_distance);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -948,7 +959,8 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
const db::ICplxTrans &subject_cell_inst,
|
||||
const db::Cell *intruder_cell,
|
||||
const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders,
|
||||
db::Coord dist_top) const
|
||||
db::Coord dist_top,
|
||||
const std::map<unsigned int, db::Coord> &override_distance) const
|
||||
{
|
||||
CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts)
|
||||
|
||||
|
|
@ -1041,84 +1053,96 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: can we shortcut this if interactions is empty?
|
||||
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
|
||||
// in top-down mode we are not interested in cell-to-cell interactions, nor shape-to-instance interactions
|
||||
// except local ones (shape-to-child cells), hence we skip this part
|
||||
if (! top_down ()) {
|
||||
|
||||
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
|
||||
// TODO: can we shortcut this if interactions is empty?
|
||||
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
|
||||
|
||||
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
|
||||
interaction_registration_inst2inst<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions);
|
||||
|
||||
unsigned int id = 0;
|
||||
|
||||
if (subject_cell == intruder_cell) {
|
||||
|
||||
// Use the same id's for same instances - this way we can easily detect same instances
|
||||
// and don't make them self-interacting
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
unsigned int iid = ++id;
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), iid);
|
||||
}
|
||||
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert2 (&i->cell_inst (), iid);
|
||||
}
|
||||
auto od = override_distance.find (*il);
|
||||
db::Coord d = dist;
|
||||
if (od != override_distance.end ()) {
|
||||
d = std::min (d, od->second);
|
||||
}
|
||||
|
||||
} else {
|
||||
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), ++id);
|
||||
}
|
||||
}
|
||||
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
|
||||
interaction_registration_inst2inst<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), d, &interactions);
|
||||
|
||||
if (intruder_cell) {
|
||||
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
|
||||
unsigned int id = 0;
|
||||
|
||||
if (subject_cell == intruder_cell) {
|
||||
|
||||
// Use the same id's for same instances - this way we can easily detect same instances
|
||||
// and don't make them self-interacting
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
unsigned int iid = ++id;
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), iid);
|
||||
}
|
||||
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert2 (&i->cell_inst (), ++id);
|
||||
scanner.insert2 (&i->cell_inst (), iid);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), ++id);
|
||||
}
|
||||
}
|
||||
|
||||
if (intruder_cell) {
|
||||
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bci (i->cell_inst ()).empty () && ! intruder_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert2 (&i->cell_inst (), ++id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
|
||||
if (! inst_bci (*i).empty ()) {
|
||||
scanner.insert2 (i.operator-> (), ++id);
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, inst_bci);
|
||||
|
||||
}
|
||||
|
||||
for (std::set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
|
||||
if (! inst_bci (*i).empty ()) {
|
||||
scanner.insert2 (i.operator-> (), ++id);
|
||||
if (! intruders.second.empty () || ! intruder_shapes.empty ()) {
|
||||
|
||||
db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
|
||||
db::addressable_object_from_shape<TI> heap;
|
||||
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, override_distance, &interactions);
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, inst_bci);
|
||||
|
||||
}
|
||||
|
||||
if (! intruders.second.empty () || ! intruder_shapes.empty ()) {
|
||||
|
||||
db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
|
||||
db::addressable_object_from_shape<TI> heap;
|
||||
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
|
||||
|
||||
for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) {
|
||||
if (! inst_bcs (i->cell_inst ()).empty () && ! subject_cell_is_breakout (i->cell_index ())) {
|
||||
scanner.insert1 (&i->cell_inst (), 0);
|
||||
for (typename std::map<unsigned int, std::set<TI> >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) {
|
||||
for (typename std::set<TI>::const_iterator i = il->second.begin (); i != il->second.end (); ++i) {
|
||||
scanner.insert2 (i.operator-> (), il->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (typename std::map<unsigned int, std::set<TI> >::const_iterator il = intruders.second.begin (); il != intruders.second.end (); ++il) {
|
||||
for (typename std::set<TI>::const_iterator i = il->second.begin (); i != il->second.end (); ++i) {
|
||||
scanner.insert2 (i.operator-> (), il->first);
|
||||
for (std::map<unsigned int, const db::Shapes *>::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) {
|
||||
for (db::Shapes::shape_iterator i = im->second->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
|
||||
scanner.insert2 (heap (*i), im->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<unsigned int, const db::Shapes *>::const_iterator im = intruder_shapes.begin (); im != intruder_shapes.end (); ++im) {
|
||||
for (db::Shapes::shape_iterator i = im->second->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
|
||||
scanner.insert2 (heap (*i), im->first);
|
||||
}
|
||||
}
|
||||
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
|
||||
|
||||
scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1128,7 +1152,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
db::Cell *subject_child_cell = &mp_subject_layout->cell (i->first.first);
|
||||
db::Cell *intruder_child_cell = (subject_cell == intruder_cell ? subject_child_cell : 0);
|
||||
|
||||
issue_compute_contexts (contexts, cell_context, subject_cell, subject_child_cell, i->first.second, intruder_child_cell, i->second, dist);
|
||||
issue_compute_contexts (contexts, cell_context, subject_cell, subject_child_cell, i->first.second, intruder_child_cell, i->second, dist, override_distance);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1248,7 +1272,7 @@ local_processor<TS, TI, TR>::compute_results (local_processor_contexts<TS, TI, T
|
|||
typename local_processor_contexts<TS, TI, TR>::iterator cpc = contexts.context_map ().find (&mp_subject_layout->cell (*bu));
|
||||
if (cpc != contexts.context_map ().end ()) {
|
||||
cpc->second.compute_results (contexts, cpc->first, op, output_layers, this);
|
||||
contexts.context_map ().erase (cpc);
|
||||
cpc->second.cleanup (); // release some memory
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1261,6 +1285,24 @@ local_processor<TS, TI, TR>::compute_results (local_processor_contexts<TS, TI, T
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// deliver the results
|
||||
{
|
||||
tl::MutexLocker locker (& mp_subject_layout->lock ());
|
||||
for (auto c = contexts.begin (); c != contexts.end (); ++c) {
|
||||
|
||||
db::Cell *cell = c->first;
|
||||
auto r = c->second.result ().begin ();
|
||||
auto rend = c->second.result ().end ();
|
||||
|
||||
for (auto o = output_layers.begin (); r != rend && o != output_layers.end (); ++o, ++r) {
|
||||
if (! r->empty ()) {
|
||||
cell->shapes (*o).insert (r->begin (), r->end ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
@ -1369,7 +1411,8 @@ template <class TS, class TI, class TR>
|
|||
void
|
||||
local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_contexts<TS, TI, TR> &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation<TS, TI, TR> *op, const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, std::vector<std::unordered_set<TR> > &result) const
|
||||
{
|
||||
db::Coord dist = dist_for_cell (subject_cell->cell_index (), op->dist ());
|
||||
auto override_distance = op->override_distance ();
|
||||
db::Coord dist_global = dist_for_cell (subject_cell->cell_index (), op->dist ());
|
||||
|
||||
const db::Shapes *subject_shapes = &subject_cell->shapes (contexts.subject_layer ());
|
||||
db::shape_to_object<TS> s2o;
|
||||
|
|
@ -1395,6 +1438,13 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
unsigned int il_index = 0;
|
||||
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il, ++il_index) {
|
||||
|
||||
// compute effective distance
|
||||
db::Coord dist = dist_global;
|
||||
auto od = override_distance.find (il_index);
|
||||
if (od != override_distance.end ()) {
|
||||
dist = std::min (dist, dist_for_cell (subject_cell->cell_index (), od->second));
|
||||
}
|
||||
|
||||
unsigned int ail = contexts.actual_intruder_layer (*il);
|
||||
bool foreign = contexts.is_foreign (*il);
|
||||
|
||||
|
|
@ -1406,14 +1456,14 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
}
|
||||
}
|
||||
|
||||
// local shapes vs. child cell
|
||||
|
||||
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, ail);
|
||||
|
||||
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (*il);
|
||||
static std::set<TI> empty_intruders;
|
||||
|
||||
if (! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
|
||||
// local shapes vs. local shapes
|
||||
|
||||
if (! top_down () && ! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
|
||||
|
||||
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||
|
||||
|
|
@ -1428,6 +1478,8 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
|
||||
}
|
||||
|
||||
// local shapes vs. child cells
|
||||
|
||||
if (! subject_shapes->empty () && ! ((! intruder_cell || intruder_cell->begin ().at_end ()) && intruders.first.empty ())) {
|
||||
|
||||
db::box_scanner2<TS, int, db::CellInstArray, int> scanner;
|
||||
|
|
@ -1441,7 +1493,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
|
||||
unsigned int inst_id = 0;
|
||||
|
||||
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||
if (! top_down () && subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
|
||||
|
||||
// Same cell, same layer -> no shape to child instance interactions because this will be taken care of
|
||||
// by the instances themselves (and their intruders). This also means, we prefer to deal with
|
||||
|
|
@ -1614,15 +1666,16 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
|
|||
|
||||
// build the subjects in the intruders list
|
||||
|
||||
db::Coord dist = op->dist ();
|
||||
db::Coord dist_global = op->dist ();
|
||||
auto override_distance = op->override_distance ();
|
||||
|
||||
db::Box subjects_box = safe_box_enlarged (subjects.bbox (), dist, dist);
|
||||
db::Box subjects_box = safe_box_enlarged (subjects.bbox (), dist_global, dist_global);
|
||||
|
||||
db::Box intruders_box;
|
||||
for (typename std::vector<generic_shape_iterator<TI> >::const_iterator il = intruders.begin (); il != intruders.end (); ++il) {
|
||||
intruders_box += il->bbox ();
|
||||
}
|
||||
intruders_box = safe_box_enlarged (intruders_box, dist, dist);
|
||||
intruders_box = safe_box_enlarged (intruders_box, dist_global, dist_global);
|
||||
|
||||
db::Box common_box = intruders_box & subjects_box;
|
||||
if (common_box.empty () || common_box.width () == 0 || common_box.height () == 0) {
|
||||
|
|
@ -1651,6 +1704,12 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
|
|||
|
||||
bool ff = foreign.size () > il_index && foreign [il_index];
|
||||
|
||||
db::Coord dist = dist_global;
|
||||
auto od = override_distance.find (il_index);
|
||||
if (od != override_distance.end ()) {
|
||||
dist = std::min (dist, od->second);
|
||||
}
|
||||
|
||||
if (*il == subjects && ! ff) {
|
||||
|
||||
interaction_registration_shape1_scanner_combo<TS, TI> scanner (&interactions, il_index, report_progress (), scan_description);
|
||||
|
|
@ -1717,6 +1776,12 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
|
|||
|
||||
bool ff = foreign.size () > il_index && foreign [il_index];
|
||||
|
||||
db::Coord dist = dist_global;
|
||||
auto od = override_distance.find (il_index);
|
||||
if (od != override_distance.end ()) {
|
||||
dist = std::min (dist, od->second);
|
||||
}
|
||||
|
||||
if (*il == subjects && ! ff) {
|
||||
|
||||
interaction_registration_shape1_scanner_combo<TS, TI> scanner (&interactions, il_index, report_progress (), scan_description);
|
||||
|
|
@ -1770,6 +1835,7 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,9 +244,20 @@ public:
|
|||
return m_contexts.end ();
|
||||
}
|
||||
|
||||
const std::vector<std::unordered_set<TR> > &result () const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
void cleanup ()
|
||||
{
|
||||
m_contexts.clear ();
|
||||
}
|
||||
|
||||
private:
|
||||
const db::Cell *mp_intruder_cell;
|
||||
std::unordered_map<context_key_type, db::local_processor_cell_context<TS, TI, TR> > m_contexts;
|
||||
std::vector<std::unordered_set<TR> > m_result;
|
||||
};
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
|
|
@ -348,7 +359,7 @@ class DB_PUBLIC local_processor_context_computation_task
|
|||
: public tl::Task
|
||||
{
|
||||
public:
|
||||
local_processor_context_computation_task (const local_processor<TS, TI, TR> *proc, local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist);
|
||||
local_processor_context_computation_task (const local_processor<TS, TI, TR> *proc, local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist, const std::map<unsigned int, db::Coord> &override_distance);
|
||||
void perform ();
|
||||
|
||||
private:
|
||||
|
|
@ -361,6 +372,7 @@ private:
|
|||
const db::Cell *mp_intruder_cell;
|
||||
typename local_processor_cell_contexts<TS, TI, TR>::context_key_type m_intruders;
|
||||
db::Coord m_dist;
|
||||
std::map<unsigned int, db::Coord> m_override_distance;
|
||||
};
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
|
|
@ -454,6 +466,16 @@ public:
|
|||
return m_nthreads;
|
||||
}
|
||||
|
||||
void set_top_down (bool f)
|
||||
{
|
||||
m_top_down = f;
|
||||
}
|
||||
|
||||
bool top_down () const
|
||||
{
|
||||
return m_top_down;
|
||||
}
|
||||
|
||||
void set_max_vertex_count (size_t max_vertex_count)
|
||||
{
|
||||
m_max_vertex_count = max_vertex_count;
|
||||
|
|
@ -514,6 +536,7 @@ private:
|
|||
unsigned int m_nthreads;
|
||||
size_t m_max_vertex_count;
|
||||
double m_area_ratio;
|
||||
bool m_top_down;
|
||||
bool m_boolean_core;
|
||||
int m_base_verbosity;
|
||||
const db::VariantsCollectorBase *mp_vars;
|
||||
|
|
@ -556,9 +579,8 @@ private:
|
|||
|
||||
void next () const;
|
||||
size_t get_progress () const;
|
||||
void compute_contexts (db::local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist) const;
|
||||
void issue_compute_contexts (db::local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist) const;
|
||||
void push_results (db::Cell *cell, unsigned int output_layer, const std::unordered_set<TR> &result) const;
|
||||
void compute_contexts (db::local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist, const std::map<unsigned int, Coord> &override_distance) const;
|
||||
void issue_compute_contexts (db::local_processor_contexts<TS, TI, TR> &contexts, db::local_processor_cell_context<TS, TI, TR> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, db::Coord dist, const std::map<unsigned int, Coord> &override_distance) const;
|
||||
void compute_local_cell (const db::local_processor_contexts<TS, TI, TR> &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation<TS, TI, TR> *op, const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders, std::vector<std::unordered_set<TR> > &result) const;
|
||||
|
||||
bool subject_cell_is_breakout (db::cell_index_type ci) const
|
||||
|
|
|
|||
|
|
@ -446,7 +446,12 @@ local_processor_cell_contexts<TS, TI, TR>::compute_results (const local_processo
|
|||
proc->compute_local_cell (contexts, cell, mp_intruder_cell, op, *c->first, res);
|
||||
}
|
||||
|
||||
if (common.empty ()) {
|
||||
bool common_empty = true;
|
||||
for (auto c = common.begin (); common_empty && c != common.end (); ++c) {
|
||||
common_empty = c->empty ();
|
||||
}
|
||||
|
||||
if (common_empty) {
|
||||
|
||||
CRONOLOGY_COMPUTE_BRACKET(event_propagate)
|
||||
for (std::vector<unsigned int>::const_iterator o = output_layers.begin (); o != output_layers.end (); ++o) {
|
||||
|
|
@ -519,9 +524,30 @@ local_processor_cell_contexts<TS, TI, TR>::compute_results (const local_processo
|
|||
|
||||
}
|
||||
|
||||
for (std::vector<unsigned int>::const_iterator o = output_layers.begin (); o != output_layers.end (); ++o) {
|
||||
size_t oi = o - output_layers.begin ();
|
||||
proc->push_results (cell, *o, common[oi]);
|
||||
// store the results
|
||||
|
||||
bool common_empty = true;
|
||||
for (auto c = common.begin (); common_empty && c != common.end (); ++c) {
|
||||
common_empty = c->empty ();
|
||||
}
|
||||
|
||||
if (! common_empty) {
|
||||
if (m_result.empty ()) {
|
||||
m_result.swap (common);
|
||||
} else {
|
||||
if (m_result.size () < common.size ()) {
|
||||
m_result.resize (common.size ());
|
||||
}
|
||||
auto t = m_result.begin ();
|
||||
for (auto s = common.begin (); s != common.end (); ++s, ++t) {
|
||||
if (t->empty ()) {
|
||||
t->swap (*s);
|
||||
} else {
|
||||
t->insert (s->begin (), s->end ());
|
||||
s->clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,14 +152,14 @@ static std::pair<bool, std::set<db::Box> > compute_clip_variant (const db::Box &
|
|||
}
|
||||
|
||||
HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, const db::ICplxTrans &trans, HierarchyBuilderShapeReceiver *pipe)
|
||||
: mp_target (target), m_target_layer (target_layer), m_wants_all_cells (false), m_trans (trans)
|
||||
: mp_target (target), m_target_layer (target_layer), m_wants_all_cells (false), m_trans (trans), m_sparse_array_limit (-1.0)
|
||||
{
|
||||
set_shape_receiver (pipe);
|
||||
reset ();
|
||||
}
|
||||
|
||||
HierarchyBuilder::HierarchyBuilder (db::Layout *target, const db::ICplxTrans &trans, HierarchyBuilderShapeReceiver *pipe)
|
||||
: mp_target (target), m_target_layer (0), m_wants_all_cells (false), m_trans (trans)
|
||||
: mp_target (target), m_target_layer (0), m_wants_all_cells (false), m_trans (trans), m_sparse_array_limit (-1.0)
|
||||
{
|
||||
set_shape_receiver (pipe);
|
||||
reset ();
|
||||
|
|
@ -396,13 +396,56 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
|
||||
// for new cells, create this instance
|
||||
if (m_cell_stack.back ().first || m_cm_new_entry) {
|
||||
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
|
||||
new_inst.object () = db::CellInst (new_cell);
|
||||
new_inst.transform (always_apply);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
|
||||
// check if the cell array is "sparse" according to
|
||||
// "sparse_array_limit" and resolve into single instances if so
|
||||
bool resolve = false;
|
||||
if (m_sparse_array_limit >= 0.0 && inst.size () > 1) {
|
||||
|
||||
if (m_sparse_array_limit == 0.0) {
|
||||
resolve = true;
|
||||
} else {
|
||||
db::box_convert<db::CellInst> bc (*iter->layout ());
|
||||
auto a1 = bc (inst.object ()).area ();
|
||||
auto aa = inst.bbox (bc).area ();
|
||||
if (a1 * m_sparse_array_limit * inst.size () < aa) {
|
||||
resolve = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (resolve) {
|
||||
|
||||
// resolve the instances of the array
|
||||
for (auto i = inst.begin (); !i.at_end (); ++i) {
|
||||
|
||||
db::CellInstArray new_inst;
|
||||
if (inst.is_complex ()) {
|
||||
new_inst = db::CellInstArray (db::CellInst (new_cell), inst.complex_trans (*i));
|
||||
} else {
|
||||
new_inst = db::CellInstArray (db::CellInst (new_cell), *i);
|
||||
}
|
||||
new_inst.transform (always_apply);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
|
||||
new_inst.object () = db::CellInst (new_cell);
|
||||
new_inst.transform (always_apply);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// To see the cell once, use NI_single. If we did see the cell already, skip the whole instance array.
|
||||
|
|
|
|||
|
|
@ -314,6 +314,25 @@ public:
|
|||
m_wants_all_cells = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the "sparse array" limit
|
||||
*
|
||||
* Sparse arrays are instance arrays whose bounding box is no longer a
|
||||
* good approximation of the covered area. The "sparse array ratio" is
|
||||
* the area of the bounding box divided by the area of the bounding box
|
||||
* of a single instance.
|
||||
*
|
||||
* Arrays above this limit will be resolved into single instances.
|
||||
*
|
||||
* Setting this value to 0 will resolve all arrays. Setting this
|
||||
* value to a negative value will never split arrays. The latter
|
||||
* is the default.
|
||||
*/
|
||||
void set_sparse_array_limit (double l)
|
||||
{
|
||||
m_sparse_array_limit = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the builder - performs a new initial pass
|
||||
*/
|
||||
|
|
@ -440,6 +459,8 @@ private:
|
|||
db::Cell *mp_initial_cell;
|
||||
|
||||
db::ICplxTrans m_trans;
|
||||
|
||||
double m_sparse_array_limit;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ static bool read_ld (tl::Extractor &ex, ld_type &l, bool with_relative)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
LayerProperties::read (tl::Extractor &ex, bool as_target)
|
||||
{
|
||||
layer = db::any_ld ();
|
||||
|
|
@ -207,6 +207,8 @@ LayerProperties::read (tl::Extractor &ex, bool as_target)
|
|||
layer = l;
|
||||
datatype = d;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (ex.try_read_word_or_quoted (name)) {
|
||||
|
||||
if (ex.test ("(")) {
|
||||
|
|
@ -223,6 +225,10 @@ LayerProperties::read (tl::Extractor &ex, bool as_target)
|
|||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,10 @@ struct DB_PUBLIC LayerProperties
|
|||
* relative layer/datatype specifications in the format "*+1" or "*-100".
|
||||
* "*" for layer or datatype is for "don't care" (on input) or "leave as is"
|
||||
* (for output).
|
||||
*
|
||||
* Returns true, if a layer was read successfully.
|
||||
*/
|
||||
void read (tl::Extractor &ex, bool as_target = false);
|
||||
bool read (tl::Extractor &ex, bool as_target = false);
|
||||
|
||||
/**
|
||||
* @brief "Logical" equality
|
||||
|
|
|
|||
|
|
@ -337,6 +337,37 @@ private:
|
|||
// -----------------------------------------------------------------
|
||||
// Implementation of the ProxyContextInfo class
|
||||
|
||||
bool
|
||||
LayoutOrCellContextInfo::operator== (const LayoutOrCellContextInfo &other) const
|
||||
{
|
||||
return lib_name == other.lib_name &&
|
||||
cell_name == other.cell_name &&
|
||||
pcell_name == other.pcell_name &&
|
||||
pcell_parameters == other.pcell_parameters &&
|
||||
meta_info == other.meta_info;
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutOrCellContextInfo::operator< (const LayoutOrCellContextInfo &other) const
|
||||
{
|
||||
if (lib_name != other.lib_name) {
|
||||
return lib_name < other.lib_name;
|
||||
}
|
||||
if (cell_name != other.cell_name) {
|
||||
return cell_name < other.cell_name;
|
||||
}
|
||||
if (pcell_name != other.pcell_name) {
|
||||
return pcell_name < other.pcell_name;
|
||||
}
|
||||
if (pcell_parameters != other.pcell_parameters) {
|
||||
return pcell_parameters < other.pcell_parameters;
|
||||
}
|
||||
if (meta_info != other.meta_info) {
|
||||
return meta_info < other.meta_info;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LayoutOrCellContextInfo
|
||||
LayoutOrCellContextInfo::deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to)
|
||||
{
|
||||
|
|
@ -540,6 +571,7 @@ Layout::clear ()
|
|||
m_pcell_ids.clear ();
|
||||
|
||||
m_lib_proxy_map.clear ();
|
||||
m_cold_proxy_map.clear ();
|
||||
m_meta_info.clear ();
|
||||
}
|
||||
|
||||
|
|
@ -568,6 +600,7 @@ Layout::operator= (const Layout &d)
|
|||
}
|
||||
|
||||
m_lib_proxy_map = d.m_lib_proxy_map;
|
||||
m_cold_proxy_map = d.m_cold_proxy_map;
|
||||
|
||||
m_cell_ptrs.resize (d.m_cell_ptrs.size (), 0);
|
||||
|
||||
|
|
@ -674,14 +707,12 @@ Layout::set_technology_name (const std::string &tech)
|
|||
|
||||
for (db::Layout::iterator c = begin (); c != end (); ++c) {
|
||||
|
||||
std::map<db::lib_id_type, db::lib_id_type>::const_iterator m;
|
||||
|
||||
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
|
||||
if (! lib_proxy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((m = mapping.find (lib_proxy->lib_id ())) != mapping.end ()) {
|
||||
if (mapping.find (lib_proxy->lib_id ()) != mapping.end ()) {
|
||||
|
||||
db::Library *lib = db::LibraryManager::instance ().lib (lib_proxy->lib_id ());
|
||||
db::Cell *lib_cell = &lib->layout ().cell (lib_proxy->library_cell_index ());
|
||||
|
|
@ -712,7 +743,10 @@ Layout::set_technology_name (const std::string &tech)
|
|||
db::cell_index_type ci = lp->first->Cell::cell_index ();
|
||||
db::PCellVariant *lib_pcell = lp->second;
|
||||
|
||||
std::pair<bool, pcell_id_type> pn = lib_pcell->layout ()->pcell_by_name (lp->first->get_basic_name ().c_str ());
|
||||
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
|
||||
tl_assert (new_lib != 0);
|
||||
|
||||
std::pair<bool, pcell_id_type> pn = new_lib->layout ().pcell_by_name (lp->first->get_basic_name ().c_str ());
|
||||
|
||||
if (! pn.first) {
|
||||
|
||||
|
|
@ -723,8 +757,6 @@ Layout::set_technology_name (const std::string &tech)
|
|||
|
||||
} else {
|
||||
|
||||
db::Library *new_lib = db::LibraryManager::instance ().lib (mapping [lp->first->lib_id ()]);
|
||||
|
||||
const db::PCellDeclaration *old_pcell_decl = lib_pcell->layout ()->pcell_declaration (lib_pcell->pcell_id ());
|
||||
const db::PCellDeclaration *new_pcell_decl = new_lib->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
|
@ -809,6 +841,7 @@ Layout::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat
|
|||
db::mem_stat (stat, purpose, cat, m_pcells, true, (void *) this);
|
||||
db::mem_stat (stat, purpose, cat, m_pcell_ids, true, (void *) this);
|
||||
db::mem_stat (stat, purpose, cat, m_lib_proxy_map, true, (void *) this);
|
||||
db::mem_stat (stat, purpose, cat, m_cold_proxy_map, true, (void *) this);
|
||||
db::mem_stat (stat, purpose, cat, m_meta_info, true, (void *) this);
|
||||
db::mem_stat (stat, purpose, cat, m_shape_repository, true, (void *) this);
|
||||
db::mem_stat (stat, purpose, cat, m_array_repository, true, (void *) this);
|
||||
|
|
@ -1417,7 +1450,7 @@ Layout::add_cell (const char *name)
|
|||
if (cm != m_cell_map.end ()) {
|
||||
|
||||
const db::Cell &c= cell (cm->second);
|
||||
if (c.is_ghost_cell () && c.empty ()) {
|
||||
if (c.is_real_ghost_cell ()) {
|
||||
// ghost cells are available as new cells - the idea is to
|
||||
// treat them as non-existing.
|
||||
return cm->second;
|
||||
|
|
@ -1505,6 +1538,11 @@ Layout::register_cell_name (const char *name, cell_index_type ci)
|
|||
void
|
||||
Layout::rename_cell (cell_index_type id, const char *name)
|
||||
{
|
||||
static const char *anonymous_name = "";
|
||||
if (! name) {
|
||||
name = anonymous_name;
|
||||
}
|
||||
|
||||
tl_assert (id < m_cell_names.size ());
|
||||
|
||||
if (strcmp (m_cell_names [id], name) != 0) {
|
||||
|
|
@ -1521,7 +1559,10 @@ Layout::rename_cell (cell_index_type id, const char *name)
|
|||
delete [] m_cell_names [id];
|
||||
m_cell_names [id] = cp;
|
||||
|
||||
m_cell_map.insert (std::make_pair (cp, id));
|
||||
// NOTE: anonymous cells (empty name string) are not registered in the cell name map
|
||||
if (*cp != 0) {
|
||||
m_cell_map.insert (std::make_pair (cp, id));
|
||||
}
|
||||
|
||||
// to enforce a redraw and a rebuild
|
||||
cell_name_changed ();
|
||||
|
|
@ -1681,6 +1722,84 @@ Layout::refresh ()
|
|||
}
|
||||
}
|
||||
|
||||
std::set<db::cell_index_type>
|
||||
Layout::cells_to_cleanup (const std::set<db::cell_index_type> &keep_always) const
|
||||
{
|
||||
std::set<db::cell_index_type> to_clean;
|
||||
|
||||
// Adressing issue #1835 (reading proxy-only GDS file renders empty layout) we do not delete
|
||||
// the first (non-cold) proxy if there are only proxy top cells.
|
||||
// We never clean up the top cell if there is a single one. This catches the case of having
|
||||
// defunct proxies for top cells.
|
||||
|
||||
if (end_top_cells () - begin_top_down () > 1) {
|
||||
|
||||
std::set<db::cell_index_type> keep;
|
||||
|
||||
for (auto c = begin_top_down (); c != end_top_cells (); ++c) {
|
||||
const db::Cell *cptr = &cell (*c);
|
||||
if (cptr->is_proxy ()) {
|
||||
if (! dynamic_cast <const db::ColdProxy *> (cptr) && keep.empty ()) {
|
||||
keep.insert (*c);
|
||||
}
|
||||
} else {
|
||||
keep.clear ();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (auto c = begin_top_down (); c != end_top_cells (); ++c) {
|
||||
if (cell (*c).is_proxy () && keep.find (*c) == keep.end () && keep_always.find (*c) == keep_always.end ()) {
|
||||
to_clean.insert (*c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// determine all cells that can be deleted as well because they are called
|
||||
// by cells registered for cleanup and nowhere else
|
||||
|
||||
if (! to_clean.empty ()) {
|
||||
|
||||
// collect the called cells
|
||||
std::set <db::cell_index_type> all_called;
|
||||
for (auto c = to_clean.begin (); c != to_clean.end (); ++c) {
|
||||
cell (*c).collect_called_cells (all_called, -1);
|
||||
}
|
||||
|
||||
// remove all called cells which are not proxies - we don't want to
|
||||
// clean up those and their children.
|
||||
std::set <db::cell_index_type> called;
|
||||
for (auto c = all_called.begin (); c != all_called.end (); ++c) {
|
||||
if (cell (*c).is_proxy ()) {
|
||||
called.insert (*c);
|
||||
}
|
||||
}
|
||||
|
||||
// From these cells erase all cells that have parents outside the subtree of our cell.
|
||||
// Make sure this is done recursively by doing this top-down.
|
||||
for (auto c = begin_top_down (); c != end_top_down (); ++c) {
|
||||
if (called.find (*c) != called.end ()) {
|
||||
const db::Cell &ccref = cell (*c);
|
||||
for (db::Cell::parent_cell_iterator pc = ccref.begin_parent_cells (); pc != ccref.end_parent_cells (); ++pc) {
|
||||
if (to_clean.find (*pc) == to_clean.end () && called.find (*pc) == called.end ()) {
|
||||
// we have a parent outside the subset considered currently (either the cell was never in or
|
||||
// it was removed itself already): remove this cell from the set of valid subcells.
|
||||
called.erase (*c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_clean.insert (called.begin (), called.end ());
|
||||
|
||||
}
|
||||
|
||||
return to_clean;
|
||||
}
|
||||
|
||||
void
|
||||
Layout::cleanup (const std::set<db::cell_index_type> &keep)
|
||||
{
|
||||
|
|
@ -1690,27 +1809,109 @@ Layout::cleanup (const std::set<db::cell_index_type> &keep)
|
|||
return;
|
||||
}
|
||||
|
||||
// deleting cells may create new top cells which need to be deleted as well, hence we iterate
|
||||
// until there are no more cells to delete
|
||||
while (true) {
|
||||
if (tl::verbosity () >= 30) {
|
||||
tl::info << "Cleaning up layout ..";
|
||||
}
|
||||
|
||||
// delete all cells that are top cells and are proxies. Those cells are proxies no longer required.
|
||||
std::set<cell_index_type> cells_to_delete;
|
||||
for (top_down_iterator c = begin_top_down (); c != end_top_cells (); ++c) {
|
||||
if (cell (*c).is_proxy ()) {
|
||||
cells_to_delete.insert (*c);
|
||||
// Do some polishing of the proxies - sometimes, specifically when resolving indirect library references,
|
||||
// different proxies to the same library object exist. We can identify them and clean them up, so there
|
||||
// is a single reference. We can also try to ensure that cell names reflect the library cell names.
|
||||
// The latter is good for LVS for example.
|
||||
|
||||
{
|
||||
update();
|
||||
db::LayoutLocker locker (this);
|
||||
|
||||
// join library proxies pointing to the same object
|
||||
|
||||
for (auto c = m_lib_proxy_map.begin (); c != m_lib_proxy_map.end (); ) {
|
||||
|
||||
auto c0 = c++;
|
||||
size_t n = 1;
|
||||
while (c != m_lib_proxy_map.end () && c->first == c0->first) {
|
||||
++n;
|
||||
++c;
|
||||
}
|
||||
|
||||
if (n > 1) {
|
||||
auto cc = c0;
|
||||
++cc;
|
||||
while (cc != c) {
|
||||
if (keep.find (cc->second) == keep.end ()) {
|
||||
if (tl::verbosity () >= 30) {
|
||||
tl::info << "Joining lib proxy " << cell_name (cc->second) << " into " << cell_name (c0->second);
|
||||
}
|
||||
replace_instances_of (cc->second, c0->second);
|
||||
}
|
||||
++cc;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::set<db::cell_index_type>::const_iterator k = keep.begin (); k != keep.end (); ++k) {
|
||||
cells_to_delete.erase (*k);
|
||||
// join cold proxies pointing to the same object
|
||||
|
||||
for (auto c = m_cold_proxy_map.begin (); c != m_cold_proxy_map.end (); ) {
|
||||
|
||||
auto c0 = c++;
|
||||
size_t n = 1;
|
||||
while (c != m_cold_proxy_map.end () && c->first == c0->first) {
|
||||
++n;
|
||||
++c;
|
||||
}
|
||||
|
||||
if (n > 1) {
|
||||
auto cc = c0;
|
||||
++cc;
|
||||
while (cc != c) {
|
||||
if (keep.find (cc->second) == keep.end ()) {
|
||||
if (tl::verbosity () >= 30) {
|
||||
tl::info << "Joining cold proxy " << cell_name (cc->second) << " into " << cell_name (c0->second);
|
||||
}
|
||||
replace_instances_of (cc->second, c0->second);
|
||||
}
|
||||
++cc;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (cells_to_delete.empty ()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Remove all cells that are targeted for cleanup
|
||||
|
||||
{
|
||||
std::set<cell_index_type> cells_to_delete = cells_to_cleanup (keep);
|
||||
if (! cells_to_delete.empty ()) {
|
||||
delete_cells (cells_to_delete);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Try to ensure that cell names reflect the library cell names. The latter is good for LVS for example.
|
||||
|
||||
for (auto c = m_lib_proxy_map.begin (); c != m_lib_proxy_map.end (); ++c) {
|
||||
|
||||
std::string bn = cell (c->second).get_basic_name ();
|
||||
if (bn != cell_name (c->second) && ! cell_by_name (bn.c_str ()).first) {
|
||||
if (tl::verbosity () >= 30) {
|
||||
tl::info << "Renaming lib proxy " << cell_name (c->second) << " to " << bn;
|
||||
}
|
||||
rename_cell (c->second, bn.c_str ());
|
||||
}
|
||||
|
||||
delete_cells (cells_to_delete);
|
||||
}
|
||||
|
||||
for (auto c = m_cold_proxy_map.begin (); c != m_cold_proxy_map.end (); ++c) {
|
||||
|
||||
std::string bn = cell (c->second).get_basic_name ();
|
||||
if (bn != cell_name (c->second) && ! cell_by_name (bn.c_str ()).first) {
|
||||
if (tl::verbosity () >= 30) {
|
||||
tl::info << "Renaming cold proxy " << cell_name (c->second) << " to " << bn;
|
||||
}
|
||||
rename_cell (c->second, bn.c_str ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -2830,12 +3031,7 @@ Layout::has_context_info (cell_index_type cell_index) const
|
|||
}
|
||||
}
|
||||
|
||||
const db::Cell &cref = cell (cell_index);
|
||||
if (cref.is_proxy () && ! cref.is_top ()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return cell (cell_index).is_proxy ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -2987,6 +3183,14 @@ Layout::fill_meta_info_from_context (cell_index_type cell_index, const LayoutOrC
|
|||
|
||||
void
|
||||
Layout::restore_proxies (ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
if (restore_proxies_without_cleanup (layer_mapping)) {
|
||||
cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Layout::restore_proxies_without_cleanup (ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
std::vector<db::ColdProxy *> cold_proxies;
|
||||
|
||||
|
|
@ -3004,9 +3208,7 @@ Layout::restore_proxies (ImportLayerMapping *layer_mapping)
|
|||
}
|
||||
}
|
||||
|
||||
if (needs_cleanup) {
|
||||
cleanup ();
|
||||
}
|
||||
return needs_cleanup;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -3145,13 +3347,32 @@ Layout::variant_name (cell_index_type cell_index) const
|
|||
void
|
||||
Layout::register_lib_proxy (db::LibraryProxy *lib_proxy)
|
||||
{
|
||||
m_lib_proxy_map.insert (std::make_pair (std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ()), lib_proxy->Cell::cell_index ()));
|
||||
auto key = std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ());
|
||||
|
||||
auto l = m_lib_proxy_map.find (key);
|
||||
while (l != m_lib_proxy_map.end () && l->first == key) {
|
||||
if (l->second == lib_proxy->Cell::cell_index ()) {
|
||||
return;
|
||||
}
|
||||
++l;
|
||||
}
|
||||
|
||||
m_lib_proxy_map.insert (std::make_pair (key, lib_proxy->Cell::cell_index ()));
|
||||
}
|
||||
|
||||
void
|
||||
Layout::unregister_lib_proxy (db::LibraryProxy *lib_proxy)
|
||||
{
|
||||
m_lib_proxy_map.erase (std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ()));
|
||||
auto key = std::make_pair (lib_proxy->lib_id (), lib_proxy->library_cell_index ());
|
||||
|
||||
auto l = m_lib_proxy_map.find (key);
|
||||
while (l != m_lib_proxy_map.end () && l->first == key) {
|
||||
if (l->second == lib_proxy->Cell::cell_index ()) {
|
||||
m_lib_proxy_map.erase (l);
|
||||
break;
|
||||
}
|
||||
++l;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3171,9 +3392,13 @@ Layout::get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_t
|
|||
cell_index_type
|
||||
Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
||||
{
|
||||
lib_proxy_map::const_iterator lp = m_lib_proxy_map.find (std::make_pair (lib->get_id (), cell_index));
|
||||
if (lp != m_lib_proxy_map.end ()) {
|
||||
auto key = std::make_pair (lib->get_id (), cell_index);
|
||||
|
||||
lib_proxy_map::const_iterator lp = m_lib_proxy_map.find (key);
|
||||
if (lp != m_lib_proxy_map.end () && lp->first == key) {
|
||||
|
||||
return lp->second;
|
||||
|
||||
} else {
|
||||
|
||||
// create a new unique name
|
||||
|
|
@ -3204,35 +3429,82 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layout::register_cold_proxy (db::ColdProxy *cold_proxy)
|
||||
{
|
||||
auto l = m_cold_proxy_map.find (cold_proxy->context_info ());
|
||||
while (l != m_cold_proxy_map.end () && l->first == cold_proxy->context_info ()) {
|
||||
if (l->second == cold_proxy->Cell::cell_index ()) {
|
||||
return;
|
||||
}
|
||||
++l;
|
||||
}
|
||||
|
||||
m_cold_proxy_map.insert (std::make_pair (cold_proxy->context_info (), cold_proxy->Cell::cell_index ()));
|
||||
}
|
||||
|
||||
void
|
||||
Layout::unregister_cold_proxy (db::ColdProxy *cold_proxy)
|
||||
{
|
||||
auto l = m_cold_proxy_map.find (cold_proxy->context_info ());
|
||||
while (l != m_cold_proxy_map.end () && l->first == cold_proxy->context_info ()) {
|
||||
if (l->second == cold_proxy->Cell::cell_index ()) {
|
||||
m_cold_proxy_map.erase (l);
|
||||
break;
|
||||
}
|
||||
++l;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, cell_index_type>
|
||||
Layout::find_cold_proxy (const db::LayoutOrCellContextInfo &info)
|
||||
{
|
||||
cold_proxy_map::const_iterator lp = m_cold_proxy_map.find (info);
|
||||
if (lp != m_cold_proxy_map.end () && lp->first == info) {
|
||||
return std::make_pair (true, lp->second);
|
||||
} else {
|
||||
return std::make_pair (false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
cell_index_type
|
||||
Layout::create_cold_proxy (const db::LayoutOrCellContextInfo &info)
|
||||
{
|
||||
// create a new unique name
|
||||
std::string b;
|
||||
if (! info.cell_name.empty ()) {
|
||||
b = info.cell_name;
|
||||
} else if (! info.pcell_name.empty ()) {
|
||||
b = info.pcell_name;
|
||||
cold_proxy_map::const_iterator lp = m_cold_proxy_map.find (info);
|
||||
if (lp != m_cold_proxy_map.end () && lp->first == info) {
|
||||
|
||||
return lp->second;
|
||||
|
||||
} else {
|
||||
|
||||
// create a new unique name
|
||||
std::string b;
|
||||
if (! info.cell_name.empty ()) {
|
||||
b = info.cell_name;
|
||||
} else if (! info.pcell_name.empty ()) {
|
||||
b = info.pcell_name;
|
||||
}
|
||||
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
|
||||
b = uniquify_cell_name (b.c_str ());
|
||||
}
|
||||
|
||||
// create a new cell (a LibraryProxy)
|
||||
cell_index_type new_index = allocate_new_cell ();
|
||||
|
||||
ColdProxy *proxy = new ColdProxy (new_index, *this, info);
|
||||
m_cells.push_back_ptr (proxy);
|
||||
m_cell_ptrs [new_index] = proxy;
|
||||
|
||||
// enter its index and cell_name
|
||||
register_cell_name (b.c_str (), new_index);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||
}
|
||||
|
||||
return new_index;
|
||||
|
||||
}
|
||||
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
|
||||
b = uniquify_cell_name (b.c_str ());
|
||||
}
|
||||
|
||||
// create a new cell (a LibraryProxy)
|
||||
cell_index_type new_index = allocate_new_cell ();
|
||||
|
||||
ColdProxy *proxy = new ColdProxy (new_index, *this, info);
|
||||
m_cells.push_back_ptr (proxy);
|
||||
m_cell_ptrs [new_index] = proxy;
|
||||
|
||||
// enter its index and cell_name
|
||||
register_cell_name (b.c_str (), new_index);
|
||||
|
||||
if (manager () && manager ()->transacting ()) {
|
||||
manager ()->queue (this, new NewRemoveCellOp (new_index, m_cell_names [new_index], false /*new*/, 0));
|
||||
}
|
||||
|
||||
return new_index;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class PCellDeclaration;
|
|||
class PCellHeader;
|
||||
class Library;
|
||||
class LibraryProxy;
|
||||
class ColdProxy;
|
||||
class CellMapping;
|
||||
class LayerMapping;
|
||||
class Region;
|
||||
|
|
@ -427,6 +428,9 @@ struct DB_PUBLIC LayoutOrCellContextInfo
|
|||
std::map<std::string, tl::Variant> pcell_parameters;
|
||||
std::map<std::string, std::pair<tl::Variant, std::string> > meta_info;
|
||||
|
||||
bool operator== (const LayoutOrCellContextInfo &other) const;
|
||||
bool operator< (const LayoutOrCellContextInfo &other) const;
|
||||
|
||||
static LayoutOrCellContextInfo deserialize (std::vector<std::string>::const_iterator from, std::vector<std::string>::const_iterator to);
|
||||
void serialize (std::vector<std::string> &strings);
|
||||
|
||||
|
|
@ -469,7 +473,8 @@ public:
|
|||
typedef db::pcell_id_type pcell_id_type;
|
||||
typedef std::map<std::string, pcell_id_type> pcell_name_map;
|
||||
typedef pcell_name_map::const_iterator pcell_iterator;
|
||||
typedef std::map<std::pair<lib_id_type, cell_index_type>, cell_index_type> lib_proxy_map;
|
||||
typedef std::multimap<std::pair<lib_id_type, cell_index_type>, cell_index_type> lib_proxy_map;
|
||||
typedef std::multimap<db::LayoutOrCellContextInfo, cell_index_type> cold_proxy_map;
|
||||
typedef LayerIterator layer_iterator;
|
||||
typedef size_t meta_info_name_id_type;
|
||||
typedef std::map<meta_info_name_id_type, MetaInfo> meta_info_map;
|
||||
|
|
@ -1003,6 +1008,12 @@ public:
|
|||
*/
|
||||
void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0, bool retain_layout = false);
|
||||
|
||||
/**
|
||||
* @brief Find an existing cold proxy for a given context
|
||||
* @return A pair of success flag and cell index of the proxy
|
||||
*/
|
||||
std::pair<bool, cell_index_type> find_cold_proxy (const db::LayoutOrCellContextInfo &info);
|
||||
|
||||
/**
|
||||
* @brief Creates a cold proxy representing the given context information
|
||||
*/
|
||||
|
|
@ -1115,7 +1126,16 @@ public:
|
|||
* Library updates may enabled lost connections which are help in cold proxies. This method will recover
|
||||
* these connections.
|
||||
*/
|
||||
void restore_proxies(ImportLayerMapping *layer_mapping = 0);
|
||||
void restore_proxies (ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Restores proxies as far as possible, no cleanup included
|
||||
*
|
||||
* This method is equivalent to "restore_proxies", but does not include a cleanup.
|
||||
* Instead it returns a value of true, indicating that something got changed
|
||||
* and a cleanup is required.
|
||||
*/
|
||||
bool restore_proxies_without_cleanup (ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Replaces the given cell index with the new cell
|
||||
|
|
@ -1662,6 +1682,19 @@ public:
|
|||
*/
|
||||
void cleanup (const std::set<db::cell_index_type> &keep = std::set<db::cell_index_type> ());
|
||||
|
||||
/**
|
||||
* @brief Gets a list of cells which are cleanup candidates
|
||||
*
|
||||
* The returned list also includes cells that are indirectly cleaned up.
|
||||
* The cleanup only removes top cells which represent unused proxies
|
||||
* with some exceptions - for example proxies that are single top cells
|
||||
* are retained.
|
||||
*
|
||||
* However, removing the top cells should not produce new top cells
|
||||
* of proxies, so these cells need to be removed as well.
|
||||
*/
|
||||
std::set<db::cell_index_type> cells_to_cleanup (const std::set<db::cell_index_type> &keep = std::set<db::cell_index_type> ()) const;
|
||||
|
||||
/**
|
||||
* @brief Calls "update" on all cells of the layout
|
||||
*
|
||||
|
|
@ -1830,6 +1863,20 @@ public:
|
|||
*/
|
||||
void unregister_lib_proxy (db::LibraryProxy *lib_proxy);
|
||||
|
||||
/**
|
||||
* @brief Register a cold proxy
|
||||
*
|
||||
* This method is used by ColdProxy to register itself.
|
||||
*/
|
||||
void register_cold_proxy (db::ColdProxy *cold_proxy);
|
||||
|
||||
/**
|
||||
* @brief Unregister a cold proxy
|
||||
*
|
||||
* This method is used by ColdProxy to unregister itself.
|
||||
*/
|
||||
void unregister_cold_proxy (db::ColdProxy *cold_proxy);
|
||||
|
||||
/**
|
||||
* @brief Gets the editable status of this layout
|
||||
*
|
||||
|
|
@ -2144,6 +2191,7 @@ private:
|
|||
std::vector<pcell_header_type *> m_pcells;
|
||||
pcell_name_map m_pcell_ids;
|
||||
lib_proxy_map m_lib_proxy_map;
|
||||
cold_proxy_map m_cold_proxy_map;
|
||||
bool m_do_cleanup;
|
||||
bool m_editable;
|
||||
std::map<std::string, meta_info_name_id_type> m_meta_info_name_map;
|
||||
|
|
|
|||
|
|
@ -183,6 +183,14 @@ public:
|
|||
return m_busy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Issue a "cell name changed event"
|
||||
*/
|
||||
void cell_name_changed ()
|
||||
{
|
||||
cell_name_changed_event ();
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class PropertiesRepository;
|
||||
|
||||
|
|
@ -191,14 +199,6 @@ protected:
|
|||
*/
|
||||
virtual void do_update () { }
|
||||
|
||||
/**
|
||||
* @brief Issue a "prop id's changed event"
|
||||
*/
|
||||
void cell_name_changed ()
|
||||
{
|
||||
cell_name_changed_event ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Issue a "layer properties changed event"
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
|
|||
std::string param_name;
|
||||
read_word_or_quoted (param_name);
|
||||
int primary = read_int ();
|
||||
int default_value = read_double ();
|
||||
double default_value = read_double ();
|
||||
if (! dc->has_parameter_with_name (param_name)) {
|
||||
db::DeviceParameterDefinition pd;
|
||||
pd.set_name (param_name);
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ copy_or_propagate_shapes (db::Layout &target,
|
|||
|
||||
db::Cell &target_cell = target.cell (cm->second);
|
||||
transformer->insert_transformed (target_cell.shapes (target_layer), source_cell.shapes (source_layer), trans * propagate_trans);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,20 +26,24 @@
|
|||
#include "dbPCellDeclaration.h"
|
||||
#include "dbPCellVariant.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "tlTimer.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
Library::Library()
|
||||
: m_id (std::numeric_limits<lib_id_type>::max ()), m_layout (true)
|
||||
Library::Library ()
|
||||
: m_id (std::numeric_limits<lib_id_type>::max ()), m_layout (true), m_replicate (true)
|
||||
{
|
||||
m_layout.set_library (this);
|
||||
}
|
||||
|
||||
Library::Library(const Library &d)
|
||||
: gsi::ObjectBase (), tl::Object (), m_name (d.m_name), m_description (d.m_description), m_id (std::numeric_limits<lib_id_type>::max ()), m_layout (d.m_layout)
|
||||
Library::Library (const Library &d)
|
||||
: gsi::ObjectBase (), tl::Object (),
|
||||
m_name (d.m_name), m_description (d.m_description),
|
||||
m_id (std::numeric_limits<lib_id_type>::max ()), m_layout (d.m_layout),
|
||||
m_replicate (d.m_replicate)
|
||||
{
|
||||
m_layout.set_library (this);
|
||||
}
|
||||
|
|
@ -55,7 +59,7 @@ Library::~Library ()
|
|||
bool
|
||||
Library::is_for_technology (const std::string &name) const
|
||||
{
|
||||
return m_technologies.find (name) != m_technologies.end ();
|
||||
return (! m_technologies.empty () && name == "*") || m_technologies.find (name) != m_technologies.end ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -64,6 +68,12 @@ Library::for_technologies () const
|
|||
return ! m_technologies.empty ();
|
||||
}
|
||||
|
||||
void
|
||||
Library::set_technologies (const std::set<std::string> &t)
|
||||
{
|
||||
m_technologies = t;
|
||||
}
|
||||
|
||||
void
|
||||
Library::set_technology (const std::string &t)
|
||||
{
|
||||
|
|
@ -108,10 +118,12 @@ Library::unregister_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly)
|
|||
if (! --c->second) {
|
||||
db::cell_index_type ci = c->first;
|
||||
m_refcount.erase (c);
|
||||
// remove cells which are itself proxies and are no longer used
|
||||
db::Cell *lib_cell = &layout ().cell (ci);
|
||||
if (lib_cell && lib_cell->is_proxy () && lib_cell->parent_cells () == 0) {
|
||||
layout ().delete_cell (ci);
|
||||
if (layout ().is_valid_cell_index (ci)) {
|
||||
// remove cells which are itself proxies and are no longer used
|
||||
db::Cell *lib_cell = &layout ().cell (ci);
|
||||
if (lib_cell && lib_cell->is_proxy () && lib_cell->parent_cells () == 0) {
|
||||
layout ().delete_cell (ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
retired_state_changed_event ();
|
||||
|
|
@ -145,6 +157,12 @@ Library::is_retired (const db::cell_index_type library_cell_index) const
|
|||
return (i != m_refcount.end () && j != m_retired_count.end () && i->second == j->second);
|
||||
}
|
||||
|
||||
void
|
||||
Library::set_replicate (bool f)
|
||||
{
|
||||
m_replicate = f;
|
||||
}
|
||||
|
||||
void
|
||||
Library::rename (const std::string &name)
|
||||
{
|
||||
|
|
@ -164,122 +182,175 @@ Library::rename (const std::string &name)
|
|||
void
|
||||
Library::refresh ()
|
||||
{
|
||||
std::string name = reload ();
|
||||
rename (name);
|
||||
refresh_without_restore ();
|
||||
|
||||
layout ().refresh ();
|
||||
// proxies need to be restored in a special case when a library has a proxy to itself.
|
||||
// The layout readers will not be able to create library references in this case.
|
||||
layout ().restore_proxies ();
|
||||
}
|
||||
|
||||
void
|
||||
Library::refresh_without_restore ()
|
||||
{
|
||||
db::LibraryManager::instance ().unregister_lib (this);
|
||||
|
||||
try {
|
||||
|
||||
m_name = reload ();
|
||||
|
||||
} catch (...) {
|
||||
|
||||
// fallback - leave the library, but with empty layout
|
||||
layout ().clear ();
|
||||
db::LibraryManager::instance ().register_lib (this);
|
||||
|
||||
throw;
|
||||
|
||||
}
|
||||
|
||||
// re-register, potentially under the new name
|
||||
db::LibraryManager::instance ().register_lib (this);
|
||||
|
||||
// This is basically only needed for coerce_parameters in a persistent way.
|
||||
// During "register_lib", this is already called in PCell update, but cannot be persisted then.
|
||||
remap_to (this);
|
||||
}
|
||||
|
||||
void
|
||||
Library::remap_to (db::Library *other)
|
||||
Library::remap_to (db::Library *other, db::Layout *original_layout)
|
||||
{
|
||||
if (! original_layout) {
|
||||
original_layout = &layout ();
|
||||
}
|
||||
|
||||
// Hint: in the loop over the referrers we might unregister (delete from m_referrers) a referrer because no more cells refer to us.
|
||||
// Hence we must not directly iterate of m_referrers.
|
||||
std::vector<std::pair<db::Layout *, int> > referrers;
|
||||
std::vector<db::Layout *> referrers;
|
||||
for (std::map<db::Layout *, int>::const_iterator r = m_referrers.begin (); r != m_referrers.end (); ++r) {
|
||||
referrers.push_back (*r);
|
||||
referrers.push_back (r->first);
|
||||
}
|
||||
|
||||
// Sort for deterministic order of resolution
|
||||
std::sort (referrers.begin (), referrers.end (), tl::sort_by_id ());
|
||||
|
||||
// Remember the layouts that will finally need a cleanup
|
||||
std::set<db::Layout *> needs_cleanup;
|
||||
|
||||
for (std::vector<std::pair<db::Layout *, int> >::const_iterator r = referrers.begin (); r != referrers.end (); ++r) {
|
||||
// NOTE: resolution may create new references due to replicas.
|
||||
// Hence, loop until no further references are resolved.
|
||||
bool any = true;
|
||||
while (any) {
|
||||
|
||||
std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> > pcells_to_map;
|
||||
std::vector<db::LibraryProxy *> lib_cells_to_map;
|
||||
any = false;
|
||||
|
||||
for (db::Layout::iterator c = r->first->begin (); c != r->first->end (); ++c) {
|
||||
for (std::vector<db::Layout *>::const_iterator r = referrers.begin (); r != referrers.end (); ++r) {
|
||||
|
||||
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (&*c);
|
||||
if (lib_proxy && lib_proxy->lib_id () == get_id ()) {
|
||||
std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> > pcells_to_map;
|
||||
std::vector<db::LibraryProxy *> lib_cells_to_map;
|
||||
|
||||
for (auto c = (*r)->begin (); c != (*r)->end (); ++c) {
|
||||
|
||||
db::LibraryProxy *lib_proxy = dynamic_cast<db::LibraryProxy *> (c.operator-> ());
|
||||
if (lib_proxy && lib_proxy->lib_id () == get_id ()) {
|
||||
|
||||
if (! original_layout->is_valid_cell_index (lib_proxy->library_cell_index ())) {
|
||||
// safety feature, should not happen
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Cell *lib_cell = &original_layout->cell (lib_proxy->library_cell_index ());
|
||||
db::PCellVariant *lib_pcell = dynamic_cast <db::PCellVariant *> (lib_cell);
|
||||
if (lib_pcell) {
|
||||
pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell));
|
||||
} else {
|
||||
lib_cells_to_map.push_back (lib_proxy);
|
||||
}
|
||||
|
||||
needs_cleanup.insert (*r);
|
||||
|
||||
db::Cell *lib_cell = &layout ().cell (lib_proxy->library_cell_index ());
|
||||
db::PCellVariant *lib_pcell = dynamic_cast <db::PCellVariant *> (lib_cell);
|
||||
if (lib_pcell) {
|
||||
pcells_to_map.push_back (std::make_pair (lib_proxy, lib_pcell));
|
||||
} else {
|
||||
lib_cells_to_map.push_back (lib_proxy);
|
||||
}
|
||||
|
||||
needs_cleanup.insert (r->first);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// We do PCell resolution before the library proxy resolution. The reason is that
|
||||
// PCells may generate library proxies in their instantiation. Hence we must instantiate
|
||||
// the PCells before we can resolve them.
|
||||
for (std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> >::const_iterator lp = pcells_to_map.begin (); lp != pcells_to_map.end (); ++lp) {
|
||||
|
||||
// We do PCell resolution before the library proxy resolution. The reason is that
|
||||
// PCells may generate library proxies in their instantiation. Hence we must instantiate
|
||||
// the PCells before we can resolve them.
|
||||
for (std::vector<std::pair<db::LibraryProxy *, db::PCellVariant *> >::const_iterator lp = pcells_to_map.begin (); lp != pcells_to_map.end (); ++lp) {
|
||||
db::cell_index_type ci = lp->first->Cell::cell_index ();
|
||||
db::PCellVariant *lib_pcell = lp->second;
|
||||
|
||||
db::cell_index_type ci = lp->first->Cell::cell_index ();
|
||||
db::PCellVariant *lib_pcell = lp->second;
|
||||
std::pair<bool, pcell_id_type> pn (false, 0);
|
||||
if (other) {
|
||||
pn = other->layout ().pcell_by_name (original_layout->cell (lp->first->library_cell_index ()).get_basic_name ().c_str ());
|
||||
}
|
||||
|
||||
std::pair<bool, pcell_id_type> pn (false, 0);
|
||||
if (other) {
|
||||
pn = other->layout ().pcell_by_name (lp->first->get_basic_name ().c_str ());
|
||||
}
|
||||
|
||||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
const db::PCellDeclaration *old_pcell_decl = layout ().pcell_declaration (lib_pcell->pcell_id ());
|
||||
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
if (! pn.first) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
(*r)->get_context_info (ci, info);
|
||||
(*r)->create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
db::pcell_parameters_type new_parameters = new_pcell_decl->map_parameters (lib_pcell->parameters_by_name ());
|
||||
const db::PCellDeclaration *old_pcell_decl = original_layout->pcell_declaration (lib_pcell->pcell_id ());
|
||||
const db::PCellDeclaration *new_pcell_decl = other->layout ().pcell_declaration (pn.second);
|
||||
if (! old_pcell_decl || ! new_pcell_decl) {
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::LayoutOrCellContextInfo info;
|
||||
(*r)->get_context_info (ci, info);
|
||||
(*r)->create_cold_proxy_as (info, ci);
|
||||
|
||||
} else {
|
||||
|
||||
db::pcell_parameters_type new_parameters = new_pcell_decl->map_parameters (lib_pcell->parameters_by_name ());
|
||||
|
||||
// coerce the new parameters if requested
|
||||
try {
|
||||
db::pcell_parameters_type plist = new_parameters;
|
||||
new_pcell_decl->coerce_parameters (other->layout (), plist);
|
||||
plist.swap (new_parameters);
|
||||
} catch (tl::Exception &ex) {
|
||||
// ignore exception - we will do that again on update() to establish an error message
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
|
||||
lp->first->remap (other->get_id (), other->layout ().get_pcell_variant (pn.second, new_parameters));
|
||||
|
||||
// coerce the new parameters if requested
|
||||
try {
|
||||
db::pcell_parameters_type plist = new_parameters;
|
||||
new_pcell_decl->coerce_parameters (other->layout (), plist);
|
||||
plist.swap (new_parameters);
|
||||
} catch (tl::Exception &ex) {
|
||||
// ignore exception - we will do that again on update() to establish an error message
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
|
||||
lp->first->remap (other->get_id (), other->layout ().get_pcell_variant (pn.second, new_parameters));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for (std::vector<db::LibraryProxy *>::const_iterator lp = lib_cells_to_map.begin (); lp != lib_cells_to_map.end (); ++lp) {
|
||||
|
||||
for (std::vector<db::LibraryProxy *>::const_iterator lp = lib_cells_to_map.begin (); lp != lib_cells_to_map.end (); ++lp) {
|
||||
db::cell_index_type ci = (*lp)->Cell::cell_index ();
|
||||
|
||||
db::cell_index_type ci = (*lp)->Cell::cell_index ();
|
||||
std::pair<bool, cell_index_type> cn (false, 0);
|
||||
if (other) {
|
||||
cn = other->layout ().cell_by_name (original_layout->cell_name ((*lp)->library_cell_index ()));
|
||||
}
|
||||
|
||||
std::pair<bool, cell_index_type> cn (false, 0);
|
||||
if (other) {
|
||||
cn = other->layout ().cell_by_name ((*lp)->get_basic_name ().c_str ());
|
||||
}
|
||||
if (! cn.first) {
|
||||
|
||||
if (! cn.first) {
|
||||
// substitute by a cold proxy
|
||||
db::LayoutOrCellContextInfo info;
|
||||
(*r)->get_context_info (ci, info);
|
||||
(*r)->create_cold_proxy_as (info, ci);
|
||||
|
||||
// substitute by a cold proxy
|
||||
db::LayoutOrCellContextInfo info;
|
||||
r->first->get_context_info (ci, info);
|
||||
r->first->create_cold_proxy_as (info, ci);
|
||||
} else {
|
||||
|
||||
} else {
|
||||
if ((*lp)->lib_id () != other->get_id () || (*lp)->library_cell_index () != cn.second) {
|
||||
// we potentially need another iteration
|
||||
any = true;
|
||||
}
|
||||
|
||||
(*lp)->remap (other->get_id (), cn.second);
|
||||
(*lp)->remap (other->get_id (), cn.second);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ public:
|
|||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
Library();
|
||||
Library ();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
Library(const Library &);
|
||||
Library (const Library &);
|
||||
|
||||
/**
|
||||
* @brief The destructor
|
||||
|
|
@ -138,6 +138,13 @@ public:
|
|||
*/
|
||||
bool for_technologies () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the technology names this library is associated with
|
||||
*
|
||||
* This will reset the list of technologies to this set.
|
||||
*/
|
||||
void set_technologies (const std::set<std::string> &t);
|
||||
|
||||
/**
|
||||
* @brief Sets the technology name this library is associated with
|
||||
*
|
||||
|
|
@ -172,6 +179,27 @@ public:
|
|||
m_description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the library produces replicas
|
||||
*
|
||||
* If this value is true (the default), layout written will include the
|
||||
* actual layout of a library cell (replica). With this, it is possible
|
||||
* to regenerate the layout without actually having the library at the
|
||||
* cost of additional bytes in the file.
|
||||
*
|
||||
* Setting this flag to false avoids this replication, but a layout
|
||||
* cannot be regenerated without having this library.
|
||||
*/
|
||||
void set_replicate (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the library produces replicas
|
||||
*/
|
||||
bool replicate () const
|
||||
{
|
||||
return m_replicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Getter for the library Id property
|
||||
*/
|
||||
|
|
@ -225,6 +253,13 @@ public:
|
|||
*/
|
||||
void refresh ();
|
||||
|
||||
/**
|
||||
* @brief Refreshes the library on all clients without restoring proxies
|
||||
*
|
||||
* This method is intended to be used internally for bulk refreshes.
|
||||
*/
|
||||
void refresh_without_restore ();
|
||||
|
||||
/**
|
||||
* @brief Renames the library
|
||||
*
|
||||
|
|
@ -237,8 +272,11 @@ public:
|
|||
* @brief Remap the library proxies to a different library
|
||||
*
|
||||
* After remapping, "other" can replace "this".
|
||||
* When calling with "other=this", a pointer to the original
|
||||
* layout needs to be supplied, because in that case, the
|
||||
* layout of "this" is already replaced.
|
||||
*/
|
||||
void remap_to (db::Library *other);
|
||||
void remap_to (db::Library *other, Layout *original_layout = 0);
|
||||
|
||||
/**
|
||||
* @brief This event is fired if proxies get retired on unretired
|
||||
|
|
@ -253,6 +291,7 @@ private:
|
|||
db::Layout m_layout;
|
||||
std::map<db::Layout *, int> m_referrers;
|
||||
std::map<db::cell_index_type, int> m_refcount, m_retired_count;
|
||||
bool m_replicate;
|
||||
|
||||
// no copying.
|
||||
Library &operator=(const Library &);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace db
|
|||
|
||||
static LibraryManager *sp_instance (0);
|
||||
|
||||
LibraryManager &
|
||||
DB_PUBLIC LibraryManager &
|
||||
LibraryManager::instance ()
|
||||
{
|
||||
if (sp_instance == 0) {
|
||||
|
|
@ -249,13 +249,38 @@ LibraryManager::register_lib (Library *library)
|
|||
// "restore_proxies" takes care not to re-substitute cold proxies.
|
||||
|
||||
const tl::weak_collection<db::ColdProxy> &cold_proxies = db::ColdProxy::cold_proxies_per_lib_name (library->get_name ());
|
||||
std::set<db::Layout *> to_refresh;
|
||||
|
||||
std::set<db::Layout *> to_refresh_set;
|
||||
for (tl::weak_collection<db::ColdProxy>::const_iterator p = cold_proxies.begin (); p != cold_proxies.end (); ++p) {
|
||||
to_refresh.insert (const_cast<db::Layout *> (p->layout ()));
|
||||
to_refresh_set.insert (const_cast<db::Layout *> (p->layout ()));
|
||||
}
|
||||
|
||||
for (std::set<db::Layout *>::const_iterator l = to_refresh.begin (); l != to_refresh.end (); ++l) {
|
||||
(*l)->restore_proxies (0);
|
||||
// Sort for deterministic order of resolution
|
||||
std::vector<db::Layout *> to_refresh (to_refresh_set.begin (), to_refresh_set.end ());
|
||||
std::sort (to_refresh.begin (), to_refresh.end (), tl::sort_by_id ());
|
||||
|
||||
std::set<db::Layout *> needs_cleanup;
|
||||
|
||||
// NOTE: "restore proxies" can create new proxies, because indirect references.
|
||||
// Hence we need to repeat the process.
|
||||
bool any = true;
|
||||
while (any) {
|
||||
|
||||
any = false;
|
||||
|
||||
for (auto l = to_refresh.begin (); l != to_refresh.end (); ++l) {
|
||||
if ((*l)->restore_proxies_without_cleanup ()) {
|
||||
any = true;
|
||||
needs_cleanup.insert (*l);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// do the cleanup
|
||||
for (auto l = needs_cleanup.begin (); l != needs_cleanup.end (); ++l) {
|
||||
(*l)->cleanup ();
|
||||
}
|
||||
|
||||
// issue the change notification
|
||||
|
|
@ -284,9 +309,27 @@ LibraryManager::lib_internal (lib_id_type id) const
|
|||
void
|
||||
LibraryManager::refresh_all ()
|
||||
{
|
||||
// NOTE: libraries may get deleted during the refresh, so better use weak pointers here
|
||||
// to track lifetime. Libraries appearing are not considered.
|
||||
|
||||
std::vector<tl::weak_ptr<Library> > libs;
|
||||
libs.reserve (m_libs.size ());
|
||||
for (auto l = m_libs.begin (); l != m_libs.end (); ++l) {
|
||||
libs.push_back (tl::weak_ptr<Library> (*l));
|
||||
}
|
||||
|
||||
for (auto l = libs.begin (); l != libs.end (); ++l) {
|
||||
if (l->get ()) {
|
||||
(*l)->refresh_without_restore ();
|
||||
}
|
||||
}
|
||||
|
||||
// restore proxies on all libraries - as the refresh happens in random order, dependencies
|
||||
// are not necessarily resolved. This is done here.
|
||||
|
||||
for (std::vector<Library *>::iterator l = m_libs.begin (); l != m_libs.end (); ++l) {
|
||||
if (*l) {
|
||||
(*l)->refresh ();
|
||||
(*l)->layout ().restore_proxies ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "dbLibraryProxy.h"
|
||||
#include "dbColdProxy.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbLayout.h"
|
||||
|
|
@ -187,25 +188,6 @@ LibraryProxy::get_layer_indices (db::Layout &layout, db::ImportLayerMapping *lay
|
|||
return m_layer_indices;
|
||||
}
|
||||
|
||||
class LibraryCellIndexMapper
|
||||
{
|
||||
public:
|
||||
LibraryCellIndexMapper (Layout &layout, Library *lib)
|
||||
: mp_lib (lib), mp_layout (&layout)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
cell_index_type operator() (cell_index_type cell_index_in_lib)
|
||||
{
|
||||
return mp_layout->get_lib_proxy (mp_lib, cell_index_in_lib);
|
||||
}
|
||||
|
||||
private:
|
||||
Library *mp_lib;
|
||||
Layout *mp_layout;
|
||||
};
|
||||
|
||||
void
|
||||
LibraryProxy::update (db::ImportLayerMapping *layer_mapping)
|
||||
{
|
||||
|
|
@ -215,32 +197,69 @@ LibraryProxy::update (db::ImportLayerMapping *layer_mapping)
|
|||
Library *lib = LibraryManager::instance ().lib (lib_id ());
|
||||
const db::Cell &source_cell = lib->layout ().cell (library_cell_index ());
|
||||
|
||||
db::ICplxTrans tr;
|
||||
bool need_transform = false;
|
||||
if (fabs (layout ()->dbu () - lib->layout ().dbu ()) > 1e-6) {
|
||||
need_transform = true;
|
||||
tr = db::ICplxTrans (lib->layout ().dbu () / layout ()->dbu ());
|
||||
}
|
||||
|
||||
clear_shapes ();
|
||||
clear_insts ();
|
||||
|
||||
for (unsigned int l = 0; l < lib->layout ().layers (); ++l) {
|
||||
if (layer_indices [l] >= 0) {
|
||||
shapes ((unsigned int) layer_indices [l]).assign_transformed (source_cell.shapes (l), tr);
|
||||
shapes ((unsigned int) layer_indices [l]).assign_transformed (source_cell.shapes (l), db::ICplxTrans (lib->layout ().dbu () / layout ()->dbu ()));
|
||||
}
|
||||
}
|
||||
|
||||
LibraryCellIndexMapper cell_index_mapper (*layout (), lib);
|
||||
for (Cell::const_iterator i = source_cell.begin (); ! i.at_end (); ++i) {
|
||||
|
||||
for (Cell::const_iterator inst = source_cell.begin (); !inst.at_end (); ++inst) {
|
||||
db::Instance new_inst = insert (*inst, cell_index_mapper);
|
||||
if (need_transform) {
|
||||
replace (new_inst, new_inst.cell_inst ().transformed_into (tr));
|
||||
db::CellInstArray inst = i->cell_inst ();
|
||||
|
||||
Library *real_lib = lib;
|
||||
cell_index_type real_cil = inst.object ().cell_index ();
|
||||
|
||||
// use the "final lib", so we refer to the actual lib instead
|
||||
// of building chains of lib references
|
||||
LibraryProxy *lp;
|
||||
while ((lp = dynamic_cast<LibraryProxy *> (&real_lib->layout ().cell (real_cil))) != 0) {
|
||||
real_cil = lp->library_cell_index ();
|
||||
real_lib = db::LibraryManager::instance ().lib (lp->lib_id ());
|
||||
}
|
||||
|
||||
ColdProxy *cp = dynamic_cast<ColdProxy *> (&real_lib->layout ().cell (real_cil));
|
||||
if (cp) {
|
||||
|
||||
// The final item is a cold proxy ("<defunct>" cell) - treat it like
|
||||
// a library proxy as it may become one in the future, but replace it
|
||||
// by a cold proxy now.
|
||||
|
||||
auto p = layout ()->find_cold_proxy (cp->context_info ());
|
||||
if (p.first) {
|
||||
// reuse existing proxy
|
||||
inst.object ().cell_index (p.second);
|
||||
} else {
|
||||
// create a new proxy, reusing the first library proxy's replica
|
||||
inst.object ().cell_index (layout ()->get_lib_proxy (real_lib, real_cil));
|
||||
layout ()->create_cold_proxy_as (cp->context_info (), inst.object ().cell_index ());
|
||||
}
|
||||
|
||||
} else {
|
||||
inst.object ().cell_index (layout ()->get_lib_proxy (real_lib, real_cil));
|
||||
}
|
||||
|
||||
inst.transform_into (db::ICplxTrans (lib->layout ().dbu () / layout ()->dbu ()));
|
||||
|
||||
if (i->has_prop_id ()) {
|
||||
insert (db::CellInstArrayWithProperties (inst, i->prop_id ()));
|
||||
} else {
|
||||
insert (inst);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LibraryProxy::can_skip_replica () const
|
||||
{
|
||||
const Library *lib = LibraryManager::instance ().lib (lib_id ());
|
||||
return lib && ! lib->replicate ();
|
||||
}
|
||||
|
||||
std::string
|
||||
LibraryProxy::get_basic_name () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -93,6 +93,14 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating that this cell is a replica that can be skipped
|
||||
*
|
||||
* This attribute is evaluated by file writers to skip cell replicas for
|
||||
* library cells that do not want to replicated.
|
||||
*/
|
||||
virtual bool can_skip_replica () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the basic name
|
||||
*
|
||||
|
|
@ -129,12 +137,12 @@ public:
|
|||
/**
|
||||
* @brief Reimplemented from Cell: unregisters the proxy at the layout
|
||||
*/
|
||||
void unregister ();
|
||||
virtual void unregister ();
|
||||
|
||||
/**
|
||||
* @brief Reimplemented from Cell: reregisters the proxy at the layout
|
||||
*/
|
||||
void reregister ();
|
||||
virtual void reregister ();
|
||||
|
||||
private:
|
||||
lib_id_type m_lib_id;
|
||||
|
|
|
|||