mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into 2.5d-view-devel
This commit is contained in:
commit
1dc9d11745
21
Changelog
21
Changelog
|
|
@ -2,17 +2,34 @@
|
|||
|
||||
* Enhancement: %GITHUB%/issues/521
|
||||
Enhanced API for ObjectInstPath
|
||||
* Bugfix: %GITHUB%/issues/524
|
||||
Failed queries leave layout in undefined state
|
||||
* Enhancement: %GITHUB%/issues/558
|
||||
Edges#extents, Texts#extents and EdgePairs#extents now
|
||||
work hierarchically in deep mode. In DRC, this means,
|
||||
"extents" is a deep-enabled method now.
|
||||
* Enhancement: %GITHUB%/issues/563
|
||||
True support for text objects in DRC/LVS (text layers)
|
||||
* Enhancement: ability to utilize a LayoutView as a Widget
|
||||
Standalone instantiation of a LayoutView object is
|
||||
supported now. So it becomes possible to create
|
||||
custom MainWindow UIs and embed a layout view there.
|
||||
|
||||
0.26.5 (2020-xx-xx):
|
||||
|
||||
* Bugfix: %GITHUB%/issues/539
|
||||
An internal error happened on netlist flatten sometimes
|
||||
* Bugfix: %GITHUB%/issues/524
|
||||
Failed queries leave layout in undefined state
|
||||
* Bugfix: %GITHUB%/issues/525
|
||||
Report true source line in DRC and LVS verbose mode
|
||||
* Bugfix: %GITHUB%/issues/526
|
||||
Makes script debugging more reliable
|
||||
* Enhancement: %GITHUB%/issues/527
|
||||
Wildcard layer mapping for stream readers
|
||||
* Bugfix: %GITHUB%/issues/544
|
||||
Duplicate .global statements in SPICE netlists created
|
||||
duplicate pins
|
||||
* Bugfix: diff tool bug with paths
|
||||
Differences in path points where no reported
|
||||
* Enhancement: documentation clarifications and typos fixed
|
||||
|
||||
0.26.4 (2020-03-02):
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ node("master") {
|
|||
stage("Checkout sources") {
|
||||
|
||||
checkout scm
|
||||
checkout_private()
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>de.klayout.KLayout</id>
|
||||
|
||||
<name>KLayout</name>
|
||||
<summary>KLayout, viewer and editor for mask layouts</summary>
|
||||
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0-or-later</project_license>
|
||||
|
||||
<description>
|
||||
<p>
|
||||
Mask layout viewer and editor for the chip design engineer.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
<launchable type="desktop-id">klayout.desktop</launchable>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://www.klayout.de/intro-image.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<developer_name>Matthias Köfferlein</developer_name>
|
||||
<provides>
|
||||
<binary>klayout</binary>
|
||||
</provides>
|
||||
</component>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Relevant KLayout version: 0.26.4
|
||||
Relevant KLayout version: 0.26.5
|
||||
|
||||
# 1. Introduction
|
||||
This directory **`macbuild`** contains different files required for building KLayout (http://www.klayout.de/) version 0.26.1 or later for different 64-bit Mac OSXs including:
|
||||
|
|
@ -26,6 +26,11 @@ Alternatively, you can use "Qt5" from Homebrew (https://brew.sh/) which is usual
|
|||
$HOME/opt/anaconda3/pkgs/qt-{version}
|
||||
```
|
||||
|
||||
If you have installed Anaconda3 under $HOME/opt/anaconda3/, make a symbolic link:
|
||||
```
|
||||
/Applications/anaconda3/ ---> $HOME/opt/anaconda3/
|
||||
```
|
||||
|
||||
# 3. Script language support: Ruby and Python
|
||||
By default, supported script languages, i.e., Ruby and Python, are those standard ones bundled with the OS.<br>
|
||||
As for Catalina (10.15),
|
||||
|
|
@ -220,8 +225,8 @@ $ cd /where/'build.sh'/exists
|
|||
$ ./makeDMG4mac.py -p ST-qt5MP.pkg.macos-Catalina-release-RsysPsys -m
|
||||
```
|
||||
This command will generate the two files below:<br>
|
||||
* **`ST-klayout-0.26.4-macOS-Catalina-1-qt5MP-RsysPsys.dmg`** ---(1) the main DMG file
|
||||
* **`ST-klayout-0.26.4-macOS-Catalina-1-qt5MP-RsysPsys.dmg.md5`** ---(2) MD5-value text file
|
||||
* **`ST-klayout-0.26.5-macOS-Catalina-1-qt5MP-RsysPsys.dmg`** ---(1) the main DMG file
|
||||
* **`ST-klayout-0.26.5-macOS-Catalina-1-qt5MP-RsysPsys.dmg.md5`** ---(2) MD5-value text file
|
||||
|
||||
# Known issues
|
||||
Because we assume some specific versions of non-OS-standard Ruby and Python, updating MacPorts, Homebrew, or Anaconda3 may cause build- and link errors.<br>
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 204 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -3,19 +3,20 @@
|
|||
* Template File:
|
||||
* macbuild/Resources/template-KLayoutDMG.applescript
|
||||
*
|
||||
* On the runtime, "makeDMG4mac.py" will generate the actual AppleScrip File:
|
||||
* On the runtime, "makeDMG4mac.py" will generate the actual AppleScrip File
|
||||
* "macbuild/Resources/KLayoutDMG.applescript"
|
||||
* from this template. Hence, the generated actual scrip file does not need
|
||||
* to be version controlled by Git.
|
||||
*
|
||||
* Description:
|
||||
* A template AppleScript to make a fancy DMG installer of KLayout
|
||||
* (http://www.klayout.de/index.php) bundles.
|
||||
* This is a template AppleScript to make a fancy DMG installer of KLayout
|
||||
* (http://www.klayout.de/index.php) application bundles.
|
||||
* "makeDMG4mac.py" will read this template and generate the actual AppleScript to execute.
|
||||
* Values to be found and replaced by "makeDMG4mac.py" are marked by ${KEYWORD}.
|
||||
* Those values to be found and replaced by "makeDMG4mac.py" are marked by ${KEYWORD} in this
|
||||
* template file.
|
||||
*
|
||||
* The background image was designed using Logoist3 (http://www.syniumsoftware.com/en/logoist)
|
||||
* and exported to a PNG file of 1000 x 500 pix size.
|
||||
* The background PNG image file (1000 x 500 pix size) was designed by using Logoist3
|
||||
* (http://www.syniumsoftware.com/en/logoist).
|
||||
*-----------------------------------------------------------------------------------------------
|
||||
* This is a derivative work of Ref. 2) below. Refer to "macbuild/LICENSE" file.
|
||||
* Ref.
|
||||
|
|
@ -65,14 +66,16 @@ on run (volumeName) -- most likely, the volume name is "KLayout"
|
|||
set arrangement to not arranged
|
||||
end tell
|
||||
|
||||
-- [6] Set the background PNG image (1000 x 700 pix) file name stored
|
||||
-- [6] Set the background PNG image file name stored
|
||||
set background picture of opts to file ".background:${BACKGROUND_PNG_FILE}"
|
||||
|
||||
-- [7] Set positions of each icon
|
||||
-- ITEM_1 = klayout.app {860, 165}
|
||||
-- ITEM_2 = Applications {860, 345}
|
||||
-- ITEM_3 = AUX. holder {700, 450}
|
||||
set position of item "${ITEM_1}" to {${X1}, ${Y1}}
|
||||
set position of item "${ITEM_2}" to {${X2}, ${Y2}}
|
||||
${ITEM_3}
|
||||
|
||||
-- [8] Update the contents of container
|
||||
close
|
||||
|
|
|
|||
|
|
@ -441,14 +441,16 @@ def RunMainBuildBash():
|
|||
global DeploymentF
|
||||
global DeploymentP
|
||||
global PackagePrefix
|
||||
global MacPkgDir # relative path to package directory
|
||||
global MacBinDir # relative path to binary directory
|
||||
global MacBuildDir # relative path to build directory
|
||||
global MacBuildLog # relative path to build log file
|
||||
global AbsMacPkgDir # absolute path to package directory
|
||||
global AbsMacBinDir # absolute path to binary directory
|
||||
global AbsMacBuildDir # absolute path to build directory
|
||||
global AbsMacBuildLog # absolute path to build log file
|
||||
global MacPkgDir # relative path to package directory
|
||||
global MacBinDir # relative path to binary directory
|
||||
global MacBuildDir # relative path to build directory
|
||||
global MacBuildDirQAT # relative path to build directory for QATest
|
||||
global MacBuildLog # relative path to build log file
|
||||
global AbsMacPkgDir # absolute path to package directory
|
||||
global AbsMacBinDir # absolute path to binary directory
|
||||
global AbsMacBuildDir # absolute path to build directory
|
||||
global AbsMacBuildDirQAT # absolute path to build directory for QATest
|
||||
global AbsMacBuildLog # absolute path to build log file
|
||||
|
||||
#-----------------------------------------------------
|
||||
# [1] Set parameters passed to the main Bash script
|
||||
|
|
@ -468,14 +470,16 @@ def RunMainBuildBash():
|
|||
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)
|
||||
AbsMacPkgDir = "%s/%s%s.pkg.macos-%s-%s-%s" % (ProjectDir, PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
AbsMacBinDir = "%s/%s.bin.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildDir = "%s/%s.build.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildLog = "%s/%s.build.macos-%s-%s-%s.log" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
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)
|
||||
AbsMacPkgDir = "%s/%s%s.pkg.macos-%s-%s-%s" % (ProjectDir, PackagePrefix, qt, Platform, mode, ruby_python)
|
||||
AbsMacBinDir = "%s/%s.bin.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildDir = "%s/%s.build.macos-%s-%s-%s" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
AbsMacBuildLog = "%s/%s.build.macos-%s-%s-%s.log" % (ProjectDir, qt, Platform, mode, ruby_python)
|
||||
MacBuildDirQAT = MacBuildDir + ".macQAT"
|
||||
AbsMacBuildDirQAT = AbsMacBuildDir + ".macQAT"
|
||||
|
||||
# (D) Qt5
|
||||
if ModuleQt == 'Qt5MacPorts':
|
||||
|
|
@ -554,6 +558,45 @@ def RunMainBuildBash():
|
|||
print( "### <%s>: successfully built KLayout" % myscript, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# [4] Prepare "*.macQAT/" directory for the QATest.
|
||||
# Binaries under "*.macQAT/" such as *.dylib will be touched later.
|
||||
#------------------------------------------------------------------------
|
||||
print( "### Preparing <%s>" % MacBuildDirQAT )
|
||||
if os.path.isdir( MacBuildDirQAT ):
|
||||
shutil.rmtree( MacBuildDirQAT )
|
||||
|
||||
os.chdir( MacBuildDir )
|
||||
tarFile = "../macQATest.tar"
|
||||
tarCmdC = "tar cf %s ." % tarFile
|
||||
if subprocess.call( tarCmdC, shell=True ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to create <%s>" % (myscript, tarFile), file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 1
|
||||
|
||||
os.chdir( "../" )
|
||||
os.mkdir( MacBuildDirQAT )
|
||||
os.chdir( MacBuildDirQAT )
|
||||
tarCmdX = "tar xf %s" % tarFile
|
||||
if subprocess.call( tarCmdX, shell=True ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to unpack <%s>" % (myscript, tarFile), file=sys.stderr )
|
||||
print( "-------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 1
|
||||
|
||||
os.remove( tarFile )
|
||||
os.chdir( "../" )
|
||||
shutil.copy2( "macbuild/macQAT.sh", MacBuildDirQAT )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: prepared the initial *.macQAT/" % myscript, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
return 0
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -573,10 +616,12 @@ def DeployBinariesForBundle():
|
|||
global MacPkgDir
|
||||
global MacBinDir
|
||||
global MacBuildDir
|
||||
global MacBuildDirQAT
|
||||
global MacBuildLog
|
||||
global AbsMacPkgDir
|
||||
global AbsMacBinDir
|
||||
global AbsMacBuildDir
|
||||
global AbsMacBuildDirQAT
|
||||
global AbsMacBuildLog
|
||||
global Version
|
||||
global DeployVerbose
|
||||
|
|
|
|||
|
|
@ -42,11 +42,12 @@ Qt5Brew = { 'qmake' : '/usr/local/opt/qt/bin/qmake',
|
|||
'deploy': '/usr/local/opt/qt/bin/macdeployqt'
|
||||
}
|
||||
|
||||
# Qt5 bundled with anaconda3 installed under $HOME/opt/anaconda3/
|
||||
# installed by the standard installation package
|
||||
# Qt5 bundled with anaconda3 installed under /Applications/anaconda3/
|
||||
# The standard installation deploys the tool under $HOME/opt/anaconda3/.
|
||||
# If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/
|
||||
# [Key Type Name] = 'Qt5Ana3'
|
||||
Qt5Ana3 = { 'qmake' : '%s/opt/anaconda3/bin/qmake' % MyHome,
|
||||
'deploy': '%s/opt/anaconda3/bin/macdeployqt' % MyHome
|
||||
Qt5Ana3 = { 'qmake' : '/Applications/anaconda3/bin/qmake',
|
||||
'deploy': '/Applications/anaconda3/bin/macdeployqt'
|
||||
}
|
||||
|
||||
#-----------------------------------------------------
|
||||
|
|
@ -120,18 +121,19 @@ Ruby26MacPorts = { 'exe': '/opt/local/bin/ruby2.6',
|
|||
# Ruby 2.7 from Homebrew *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# install with 'brew install ruby'
|
||||
# [Key Type Name] = 'HB27'
|
||||
HBRuby27Path = '/usr/local/Cellar/ruby/2.7.0'
|
||||
HBRuby27Path = '/usr/local/opt/ruby'
|
||||
Ruby27Brew = { 'exe': '%s/bin/ruby' % HBRuby27Path,
|
||||
'inc': '%s/include/ruby-2.7.0' % HBRuby27Path,
|
||||
'lib': '%s/lib/libruby.2.7.dylib' % HBRuby27Path
|
||||
}
|
||||
|
||||
# Ruby 2.5 bundled with anaconda3 installed under $HOME/opt/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# install with 'conda install ruby'
|
||||
# Ruby 2.5 bundled with anaconda3 installed under /Applications/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# The standard installation deploys the tool under $HOME/opt/anaconda3/.
|
||||
# If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/
|
||||
# [Key Type Name] = 'Ana3'
|
||||
RubyAnaconda3 = { 'exe': '%s/opt/anaconda3/bin/ruby' % MyHome,
|
||||
'inc': '%s/opt/anaconda3/include/ruby-2.5.0' % MyHome,
|
||||
'lib': '%s/opt/anaconda3/lib/libruby.2.5.1.dylib' % MyHome
|
||||
RubyAnaconda3 = { 'exe': '/Applications/anaconda3/bin/ruby',
|
||||
'inc': '/Applications/anaconda3/include/ruby-2.5.0',
|
||||
'lib': '/Applications/anaconda3/lib/libruby.2.5.1.dylib'
|
||||
}
|
||||
|
||||
# Consolidated dictionary kit for Ruby
|
||||
|
|
@ -213,18 +215,19 @@ Python37MacPorts= { 'exe': '/opt/local/Library/Frameworks/Python.framework/Versi
|
|||
# Python 3.7 from Homebrew *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# install with 'brew install python'
|
||||
# [Key Type Name] = 'HB37'
|
||||
HBPython37FrameworkPath = '/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework'
|
||||
HBPython37FrameworkPath = '/usr/local/opt/python3/Frameworks/Python.framework'
|
||||
Python37Brew = { 'exe': '%s/Versions/3.7/bin/python3.7m' % HBPython37FrameworkPath,
|
||||
'inc': '%s/Versions/3.7/include/python3.7m' % HBPython37FrameworkPath,
|
||||
'lib': '%s/Versions/3.7/lib/libpython3.7m.dylib' % HBPython37FrameworkPath
|
||||
}
|
||||
|
||||
# Python 3.7 bundled with anaconda3 installed under $HOME/opt/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# installed by the standard installation package
|
||||
# Python 3.7 bundled with anaconda3 installed under /Applications/anaconda3/ *+*+*+ EXPERIMENTAL *+*+*+
|
||||
# The standard installation deploys the tool under $HOME/opt/anaconda3/.
|
||||
# If so, you need to make a symbolic link: /Applications/anaconda3 ---> $HOME/opt/anaconda3/
|
||||
# [Key Type Name] = 'Ana3'
|
||||
PythonAnaconda3 = { 'exe': '%s/opt/anaconda3/bin/python3.7m' % MyHome,
|
||||
'inc': '%s/opt/anaconda3/include/python3.7m' % MyHome,
|
||||
'lib': '%s/opt/anaconda3/lib/libpython3.7m.dylib' % MyHome
|
||||
PythonAnaconda3 = { 'exe': '/Applications/anaconda3/bin/python3.7m',
|
||||
'inc': '/Applications/anaconda3/include/python3.7m',
|
||||
'lib': '/Applications/anaconda3/lib/libpython3.7m.dylib'
|
||||
}
|
||||
|
||||
# Consolidated dictionary kit for Python
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
#!/bin/bash
|
||||
|
||||
#===============================================================================
|
||||
# File: "macbuild/macQAT.sh"
|
||||
#
|
||||
# The top Bash script to run "ut_runner" after building KLayout
|
||||
# (http://www.klayout.de/index.php) version 0.26.1 or later on different Apple
|
||||
# ßMac OSX platforms.
|
||||
#
|
||||
# This script must be copied to a "*.macQAT/" directory to run.
|
||||
#===============================================================================
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Functions
|
||||
#----------------------------------------------------------------
|
||||
function GetPresentDir() {
|
||||
path=$1
|
||||
array=( `echo $path | tr -s '/' ' '`)
|
||||
last_index=`expr ${#array[@]} - 1`
|
||||
echo ${array[${last_index}]}
|
||||
return 0
|
||||
}
|
||||
|
||||
function HidePrivateDir() {
|
||||
if [ -d "../private" ]; then
|
||||
ret=$(/bin/mv ../private ../private.stash)
|
||||
fi
|
||||
}
|
||||
|
||||
function ShowPrivateDir() {
|
||||
if [ -d "../private.stash" ]; then
|
||||
ret=$(/bin/mv ../private.stash ../private)
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Variables
|
||||
#----------------------------------------------------------------
|
||||
gitSHA1=$(git rev-parse --short HEAD 2>/dev/null)
|
||||
timestamp=$(date "+%Y_%m%d_%H%M")
|
||||
presentDir=$(GetPresentDir `pwd`)
|
||||
logfile=QATest_${gitSHA1}_${timestamp}__${presentDir}.log
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Environment variables for "ut_runner"
|
||||
#----------------------------------------------------------------
|
||||
export TESTSRC=..
|
||||
export TESTTMP=QATest_${gitSHA1}_${timestamp}__${presentDir}
|
||||
export DYLD_LIBRARY_PATH=$(pwd):$(pwd)/db_plugins
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Environment variables for "ut_runner"
|
||||
#----------------------------------------------------------------
|
||||
if [ $# -eq 1 ]; then
|
||||
if [ "$1" == "-h" ]; then
|
||||
./ut_runner -h
|
||||
exit 0
|
||||
fi
|
||||
if [ "$1" == "-r" ]; then
|
||||
echo "### Dumping the log to" $logfile "..."
|
||||
HidePrivateDir
|
||||
./ut_runner -x pymod -c 2>&1 | tee $logfile
|
||||
ShowPrivateDir
|
||||
exit 0
|
||||
else
|
||||
echo ""
|
||||
echo " Git SHA1 = ${gitSHA1}"
|
||||
echo " Time stamp = ${timestamp}"
|
||||
echo " Log file = ${logfile}"
|
||||
echo " Usage:"
|
||||
echo " ./QATest.sh -h: to get the help of 'ut_runner'"
|
||||
echo " ./QATest.sh -r: to run the tests with '-c' option: continues after an error"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo " Git SHA1 = ${gitSHA1}"
|
||||
echo " Time stamp = ${timestamp}"
|
||||
echo " Log file = ${logfile}"
|
||||
echo " Usage:"
|
||||
echo " ./QATest.sh -h: to get the help of 'ut_runner'"
|
||||
echo " ./QATest.sh -r: to run the tests with '-c' option: continues after an error"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#--------------
|
||||
# End of File
|
||||
#--------------
|
||||
|
|
@ -17,6 +17,7 @@ import sys
|
|||
import os
|
||||
import re
|
||||
import shutil
|
||||
import zipfile
|
||||
import glob
|
||||
import platform
|
||||
import optparse
|
||||
|
|
@ -36,6 +37,7 @@ from build4mac_util import *
|
|||
def SetGlobals():
|
||||
global ProjectDir # project directory where "build.sh" exists
|
||||
global Usage # string on usage
|
||||
global LatestOS # the latest generic OS name
|
||||
global GenOSName # generic OS name
|
||||
global Platform # platform
|
||||
global PkgDir # the package directory where "klayout.app" exists
|
||||
|
|
@ -47,7 +49,7 @@ def SetGlobals():
|
|||
global PackagePrefix # the package prefix: 'ST-', 'LW-', 'HW-', or 'EX-'
|
||||
global QtIdentification # Qt identification
|
||||
global RubyPythonID # Ruby- and Python-identification
|
||||
global Version # KLayout's version
|
||||
global KLVersion # KLayout's version
|
||||
global OccupiedDS # approx. occupied disc space
|
||||
global BackgroundPNG # the background PNG image file
|
||||
global VolumeIcons # the volume icon file
|
||||
|
|
@ -56,6 +58,11 @@ def SetGlobals():
|
|||
global VolumeDMG # the volume name of DMG
|
||||
global TargetDMG # the name of target DMG file
|
||||
global RootApplications # reserved directory name for applications
|
||||
global LatestOSMacPorts # True if 'LatestOS with MacPorts'
|
||||
global LatestOSHomebrew # True if 'LatestOS with Homebrew'
|
||||
global LatestOSAnaconda3 # True if 'LatestOS with Anaconda3'
|
||||
global DicLightWeight # dictionary for LW-* packages
|
||||
global Item3AppleScript # ITEM_3 in the Apple script
|
||||
# auxiliary variables on platform
|
||||
global System # 6-tuple from platform.uname()
|
||||
global Node # - do -
|
||||
|
|
@ -93,9 +100,11 @@ def SetGlobals():
|
|||
quit()
|
||||
|
||||
release = int( Release.split(".")[0] ) # take the first of ['19', '0', '0']
|
||||
LatestOS = ""
|
||||
if release == 19:
|
||||
GenOSName = "macOS"
|
||||
Platform = "Catalina"
|
||||
LatestOS = Platform
|
||||
elif release == 18:
|
||||
GenOSName = "macOS"
|
||||
Platform = "Mojave"
|
||||
|
|
@ -130,7 +139,7 @@ def SetGlobals():
|
|||
PackagePrefix = ""
|
||||
QtIdentification = ""
|
||||
RubyPythonID = ""
|
||||
Version = GetKLayoutVersionFrom( "./version.sh" )
|
||||
KLVersion = GetKLayoutVersionFrom( "./version.sh" )
|
||||
OccupiedDS = -1
|
||||
BackgroundPNG = "KLayoutDMG-Back.png"
|
||||
VolumeIcons = "KLayoutHDD.icns"
|
||||
|
|
@ -139,6 +148,30 @@ def SetGlobals():
|
|||
VolumeDMG = "KLayout"
|
||||
TargetDMG = ""
|
||||
RootApplications = "/Applications"
|
||||
LatestOSMacPorts = False
|
||||
LatestOSHomebrew = False
|
||||
LatestOSAnaconda3 = False
|
||||
DicLightWeight = dict()
|
||||
Item3AppleScript = ""
|
||||
# Populate DicLightWeight
|
||||
DicLightWeight[ "ports" ] = dict()
|
||||
DicLightWeight[ "brew" ] = dict()
|
||||
DicLightWeight[ "ana3" ] = dict()
|
||||
|
||||
DicLightWeight[ "ports" ]["zip"] = "macbuild/Resources/script-bundle-P.zip"
|
||||
DicLightWeight[ "ports" ]["src"] = "script-bundle-P"
|
||||
DicLightWeight[ "ports" ]["des"] = "MacPortsUser-ReadMeFirst"
|
||||
DicLightWeight[ "ports" ]["item3"] = 'set position of item "MacPortsUser-ReadMeFirst" to {700, 400}'
|
||||
|
||||
DicLightWeight[ "brew" ]["zip"] = "macbuild/Resources/script-bundle-B.zip"
|
||||
DicLightWeight[ "brew" ]["src"] = "script-bundle-B"
|
||||
DicLightWeight[ "brew" ]["des"] = "HomebrewUser-ReadMeFirst"
|
||||
DicLightWeight[ "brew" ]["item3"] = 'set position of item "HomebrewUser-ReadMeFirst" to {700, 400}'
|
||||
|
||||
DicLightWeight[ "ana3" ]["zip"] = "macbuild/Resources/script-bundle-A.zip"
|
||||
DicLightWeight[ "ana3" ]["src"] = "script-bundle-A"
|
||||
DicLightWeight[ "ana3" ]["des"] = "Anaconda3User-ReadMeFirst"
|
||||
DicLightWeight[ "ana3" ]["item3"] = 'set position of item "Anaconda3User-ReadMeFirst" to {700, 400}'
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
## To check the contents of the package directory
|
||||
|
|
@ -156,11 +189,19 @@ def SetGlobals():
|
|||
# on failure, -1
|
||||
#------------------------------------------------------------------------------
|
||||
def CheckPkgDirectory():
|
||||
global Platform
|
||||
global OpClean
|
||||
global OpMake
|
||||
global DefaultBundleName
|
||||
global BundleName
|
||||
global PackagePrefix
|
||||
global QtIdentification
|
||||
global RubyPythonID
|
||||
global LatestOSMacPorts
|
||||
global LatestOSHomebrew
|
||||
global LatestOSAnaconda3
|
||||
global DicLightWeight
|
||||
global Item3AppleScript
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [1] Check the contents of the package directory
|
||||
|
|
@ -175,30 +216,12 @@ def CheckPkgDirectory():
|
|||
print( "" )
|
||||
return -1
|
||||
|
||||
os.chdir(PkgDir)
|
||||
if not os.path.isdir( DefaultBundleName ):
|
||||
print( "! The package directory <%s> does not hold <%s> bundle" % (PkgDir, DefaultBundleName), file=sys.stderr )
|
||||
print( "" )
|
||||
os.chdir(ProjectDir)
|
||||
return -1
|
||||
|
||||
command = "\du -sm %s" % DefaultBundleName
|
||||
sizeApp = int( os.popen(command).read().strip("\n").split("\t")[0] )
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [2] Change the application bundle name on demand
|
||||
#-----------------------------------------------------------------------------
|
||||
if BundleName == "":
|
||||
BundleName = DefaultBundleName
|
||||
else:
|
||||
os.rename( DefaultBundleName, BundleName )
|
||||
os.chdir(ProjectDir)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [3] Identify (Qt, Ruby, Python)
|
||||
# [2] Identify (Qt, Ruby, Python) from PkgDir
|
||||
#
|
||||
# * ST-qt5MP.pkg.macos-Catalina-release-RsysPsys
|
||||
# * LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3
|
||||
# * LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37
|
||||
# * HW-qt5Brew.pkg.macos-Catalina-release-RsysPhb37
|
||||
# * EX-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37
|
||||
#-----------------------------------------------------------------------------
|
||||
|
|
@ -213,7 +236,93 @@ def CheckPkgDirectory():
|
|||
PackagePrefix = pkgdirComponents[0]
|
||||
QtIdentification = pkgdirComponents[2]
|
||||
RubyPythonID = pkgdirComponents[5]
|
||||
return sizeApp
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# [3] Check if the "LatestOS" with MacPorts / Homebrew / Anaconda3
|
||||
#-----------------------------------------------------------------------------
|
||||
LatestOSMacPorts = Platform == LatestOS
|
||||
LatestOSMacPorts &= PackagePrefix == "LW"
|
||||
LatestOSMacPorts &= QtIdentification == "qt5MP"
|
||||
LatestOSMacPorts &= RubyPythonID == "Rmp26Pmp37"
|
||||
|
||||
LatestOSHomebrew = Platform == LatestOS
|
||||
LatestOSHomebrew &= PackagePrefix == "LW"
|
||||
LatestOSHomebrew &= QtIdentification == "qt5Brew"
|
||||
LatestOSHomebrew &= RubyPythonID == "Rhb27Phb37"
|
||||
|
||||
LatestOSAnaconda3 = Platform == LatestOS
|
||||
LatestOSAnaconda3 &= PackagePrefix == "LW"
|
||||
LatestOSAnaconda3 &= QtIdentification == "qt5Ana3"
|
||||
LatestOSAnaconda3 &= RubyPythonID == "Rana3Pana3"
|
||||
|
||||
if LatestOSMacPorts:
|
||||
mydic = DicLightWeight["ports"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
if LatestOSHomebrew:
|
||||
mydic = DicLightWeight["brew"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
if LatestOSAnaconda3:
|
||||
mydic = DicLightWeight["ana3"]
|
||||
srcDir = PkgDir + "/" + mydic["src"]
|
||||
desDir = PkgDir + "/" + mydic["des"]
|
||||
if OpMake:
|
||||
with zipfile.ZipFile( mydic["zip"], 'r' ) as zip_ref:
|
||||
zip_ref.extractall(PkgDir)
|
||||
os.rename( srcDir, desDir )
|
||||
if OpClean:
|
||||
if os.path.isdir(srcDir):
|
||||
shutil.rmtree(srcDir)
|
||||
if os.path.isdir(desDir):
|
||||
shutil.rmtree(desDir)
|
||||
Item3AppleScript = mydic["item3"]
|
||||
|
||||
#------------------------------------------------------
|
||||
# [4] Check the presence of the default bundle
|
||||
#------------------------------------------------------
|
||||
os.chdir(PkgDir)
|
||||
if not os.path.isdir( DefaultBundleName ):
|
||||
print( "! The package directory <%s> does not hold <%s> bundle" % (PkgDir, DefaultBundleName), file=sys.stderr )
|
||||
print( "" )
|
||||
os.chdir(ProjectDir)
|
||||
return -1
|
||||
|
||||
#------------------------------------------------------
|
||||
# [5] Check the occupied disk space
|
||||
#------------------------------------------------------
|
||||
command = "\du -sm %s" % DefaultBundleName
|
||||
sizeApp = int( os.popen(command).read().strip("\n").split("\t")[0] )
|
||||
|
||||
#------------------------------------------------------
|
||||
# [6] Change the application bundle name if required
|
||||
#------------------------------------------------------
|
||||
if OpMake and BundleName != "" and BundleName != DefaultBundleName:
|
||||
os.rename( DefaultBundleName, BundleName )
|
||||
os.chdir(ProjectDir)
|
||||
return sizeApp
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
## To get command line parameters
|
||||
|
|
@ -231,7 +340,7 @@ def ParseCommandLineArguments():
|
|||
global PackagePrefix
|
||||
global QtIdentification
|
||||
global RubyPythonID
|
||||
global Version
|
||||
global KLVersion
|
||||
global OccupiedDS
|
||||
global TargetDMG
|
||||
|
||||
|
|
@ -290,7 +399,7 @@ def ParseCommandLineArguments():
|
|||
base, ext = os.path.splitext( os.path.basename(opt.bundle_name) )
|
||||
BundleName = base + ".app"
|
||||
else:
|
||||
BundleName = ""
|
||||
BundleName = DefaultBundleName
|
||||
|
||||
if (OpClean and OpMake) or (not OpClean and not OpMake):
|
||||
print( "! Specify <-c|--clean> OR <-m|--make>", file=sys.stderr )
|
||||
|
|
@ -307,7 +416,7 @@ def ParseCommandLineArguments():
|
|||
quit()
|
||||
else:
|
||||
TargetDMG = "%s-klayout-%s-%s-%s-%d-%s-%s.dmg" \
|
||||
% (PackagePrefix, Version, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID)
|
||||
% (PackagePrefix, KLVersion, GenOSName, Platform, DMGSerialNum, QtIdentification, RubyPythonID)
|
||||
return
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -362,8 +471,9 @@ def MakeTargetDMGFile(msg=""):
|
|||
WIN_WIDTH='1000', WIN_HEIGHT='500',
|
||||
FULL_PATH_DS_STORE='/Volumes/%s/.DS_Store' % VolumeDMG,
|
||||
BACKGROUND_PNG_FILE=BackgroundPNG,
|
||||
ITEM_1='%s' % BundleName, X1='860', Y1='165',
|
||||
ITEM_2='Applications', X2='860', Y2='345',
|
||||
ITEM_1='%s' % BundleName, X1='900', Y1='165',
|
||||
ITEM_2='Applications', X2='900', Y2='345',
|
||||
ITEM_3=Item3AppleScript,
|
||||
CHECK_BASH='[ -f " & dotDSStore & " ]; echo $?'
|
||||
)
|
||||
try:
|
||||
|
|
@ -523,10 +633,10 @@ def MakeTargetDMGFile(msg=""):
|
|||
print( " generated MD5 checksum file <%s>" % md5TargetDMG )
|
||||
print( "" )
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# [3] Rename the application bundle if required
|
||||
#-------------------------------------------------------------
|
||||
if not BundleName == DefaultBundleName:
|
||||
#-------------------------------------------------------------------------
|
||||
# [3] Rename back the application bundle to the default name if required
|
||||
#-------------------------------------------------------------------------
|
||||
if BundleName != "" and BundleName != DefaultBundleName:
|
||||
dirPresent = "%s/%s" % (PkgDir, BundleName)
|
||||
dirDefault = "%s/%s" % (PkgDir, DefaultBundleName)
|
||||
os.rename( dirPresent, dirDefault )
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function # to use print() of Python 3 in Python >= 2.7
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import glob
|
||||
import platform
|
||||
import optparse
|
||||
import subprocess
|
||||
|
||||
Variation = [ 'std', 'ports', 'brew', 'ana3' ]
|
||||
|
||||
Usage = "\n"
|
||||
Usage += "------------------------------------------------------------------------------------------\n"
|
||||
Usage += " nightyCatalina.py [EXPERIMENTAL] \n"
|
||||
Usage += " << To execute the jobs for making KLatyout's DMGs for macOS Catalina >> \n"
|
||||
Usage += "\n"
|
||||
Usage += "$ [python] nightyCatalina.py \n"
|
||||
Usage += " option & argument : comment on option if any | default value\n"
|
||||
Usage += " -------------------------------------------------------------------+--------------\n"
|
||||
Usage += " [--build] : build and deploy | disabled\n"
|
||||
Usage += " [--makedmg <srlno>] : make DMG | disabled\n"
|
||||
Usage += " [--cleandmg <srlno>] : clean DMG | disabled\n"
|
||||
Usage += " [--upload <dropbox>] : upload to $HOME/Dropbox/klayout/<dropbox> | disabled\n"
|
||||
Usage += " [-?|--?] : print this usage and exit | disabled\n"
|
||||
Usage += "----------------------------------------------------------------------+-------------------\n"
|
||||
|
||||
def ParseCommandLineArguments():
|
||||
global Usage
|
||||
global Build # operation flag
|
||||
global MakeDMG # operation flag
|
||||
global CleanDMG # operation flag
|
||||
global Upload # operation flag
|
||||
global SrlDMG # DMG serial number
|
||||
global Dropbox # Dropbox directory
|
||||
|
||||
p = optparse.OptionParser( usage=Usage )
|
||||
p.add_option( '--build',
|
||||
action='store_true',
|
||||
dest='build',
|
||||
default=False,
|
||||
help='build and deploy' )
|
||||
|
||||
p.add_option( '--makedmg',
|
||||
dest='makedmg',
|
||||
help='make DMG' )
|
||||
|
||||
p.add_option( '--cleandmg',
|
||||
dest='cleandmg',
|
||||
help='clean DMG' )
|
||||
|
||||
p.add_option( '--upload',
|
||||
dest='upload',
|
||||
help='upload to Dropbox' )
|
||||
|
||||
p.add_option( '-?', '--??',
|
||||
action='store_true',
|
||||
dest='checkusage',
|
||||
default=False,
|
||||
help='check usage (false)' )
|
||||
|
||||
p.set_defaults( build = False,
|
||||
makedmg = "",
|
||||
cleandmg = "",
|
||||
upload = "",
|
||||
checkusage = False )
|
||||
|
||||
opt, args = p.parse_args()
|
||||
if opt.checkusage:
|
||||
print(Usage)
|
||||
quit()
|
||||
|
||||
Build = False
|
||||
MakeDMG = False
|
||||
CleanDMG = False
|
||||
Upload = False
|
||||
|
||||
Build = opt.build
|
||||
|
||||
if not opt.makedmg == "":
|
||||
MakeDMG = True
|
||||
CleanDMG = False
|
||||
SrlDMG = int(opt.makedmg)
|
||||
|
||||
if not opt.cleandmg == "":
|
||||
MakeDMG = False
|
||||
CleanDMG = True
|
||||
SrlDMG = int(opt.cleandmg)
|
||||
|
||||
if not opt.upload == "":
|
||||
Upload = True
|
||||
Dropbox = opt.upload
|
||||
|
||||
if not (Build or MakeDMG or CleanDMG or Upload):
|
||||
print( "! No option selected" )
|
||||
print(Usage)
|
||||
quit()
|
||||
|
||||
|
||||
def BuildDeploy():
|
||||
PyBuild = "./build4mac.py"
|
||||
|
||||
Build = dict()
|
||||
Build["std"] = [ '-q', 'Qt5MacPorts', '-r', 'sys', '-p', 'sys' ]
|
||||
Build["ports"] = [ '-q', 'Qt5MacPorts', '-r', 'MP26', '-p', 'MP37' ]
|
||||
Build["brew"] = [ '-q', 'Qt5Brew', '-r', 'HB27', '-p', 'HB37' ]
|
||||
Build["ana3"] = [ '-q', 'Qt5Ana3', '-r', 'Ana3', '-p', 'Ana3' ]
|
||||
|
||||
for key in Variation:
|
||||
command1 = [ PyBuild ] + Build[key]
|
||||
if key == "std":
|
||||
command2 = [ PyBuild ] + Build[key] + ['-y']
|
||||
else:
|
||||
command2 = [ PyBuild ] + Build[key] + ['-Y']
|
||||
print(command1)
|
||||
print(command2)
|
||||
#continue
|
||||
|
||||
if subprocess.call( command1, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to build KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully built KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
if subprocess.call( command2, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to deploy KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully deployed KLayout" % PyBuild, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
|
||||
def DMG_Make( srlDMG ):
|
||||
PyDMG = "./makeDMG4mac.py"
|
||||
Stash = "./DMGStash"
|
||||
|
||||
Pack = dict()
|
||||
Pack["std"] = [ '-p', 'ST-qt5MP.pkg.macos-Catalina-release-RsysPsys', '-s', '%d' % srlDMG, '-m' ]
|
||||
Pack["ports"] = [ '-p', 'LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37', '-s', '%d' % srlDMG, '-m' ]
|
||||
Pack["brew"] = [ '-p', 'LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37', '-s', '%d' % srlDMG, '-m' ]
|
||||
Pack["ana3"] = [ '-p', 'LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3', '-s', '%d' % srlDMG, '-m' ]
|
||||
|
||||
if os.path.isdir( Stash ):
|
||||
shutil.rmtree( Stash )
|
||||
os.mkdir( Stash )
|
||||
|
||||
for key in Variation:
|
||||
command3 = [ PyDMG ] + Pack[key]
|
||||
print(command3)
|
||||
#continue
|
||||
|
||||
if subprocess.call( command3, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to make KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully made KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
dmgs = glob.glob( "*.dmg*" )
|
||||
for item in dmgs:
|
||||
shutil.move( item, Stash )
|
||||
|
||||
|
||||
def DMG_Clean( srlDMG ):
|
||||
PyDMG = "./makeDMG4mac.py"
|
||||
Stash = "./DMGStash"
|
||||
|
||||
Pack = dict()
|
||||
Pack["std"] = [ '-p', 'ST-qt5MP.pkg.macos-Catalina-release-RsysPsys', '-s', '%d' % srlDMG, '-c' ]
|
||||
Pack["ports"] = [ '-p', 'LW-qt5MP.pkg.macos-Catalina-release-Rmp26Pmp37', '-s', '%d' % srlDMG, '-c' ]
|
||||
Pack["brew"] = [ '-p', 'LW-qt5Brew.pkg.macos-Catalina-release-Rhb27Phb37', '-s', '%d' % srlDMG, '-c' ]
|
||||
Pack["ana3"] = [ '-p', 'LW-qt5Ana3.pkg.macos-Catalina-release-Rana3Pana3', '-s', '%d' % srlDMG, '-c' ]
|
||||
|
||||
if os.path.isdir( Stash ):
|
||||
shutil.rmtree( Stash )
|
||||
|
||||
for key in Variation:
|
||||
command3 = [ PyDMG ] + Pack[key]
|
||||
print(command3)
|
||||
#continue
|
||||
|
||||
if subprocess.call( command3, shell=False ) != 0:
|
||||
print( "", file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "!!! <%s>: failed to clean KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "-----------------------------------------------------------------", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
sys.exit(1)
|
||||
else:
|
||||
print( "", file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "### <%s>: successfully cleaned KLayout DMG" % PyDMG, file=sys.stderr )
|
||||
print( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", file=sys.stderr )
|
||||
print( "", file=sys.stderr )
|
||||
|
||||
|
||||
def UploadToDropbox( targetdir ):
|
||||
Stash = "./DMGStash"
|
||||
|
||||
distDir = os.environ["HOME"] + "/Dropbox/klayout/" + targetdir
|
||||
if not os.path.isdir(distDir):
|
||||
os.makedirs(distDir)
|
||||
|
||||
dmgs = glob.glob( "%s/*.dmg*" % Stash )
|
||||
for item in dmgs:
|
||||
shutil.copy2( item, distDir )
|
||||
|
||||
|
||||
def Main():
|
||||
ParseCommandLineArguments()
|
||||
|
||||
if Build:
|
||||
BuildDeploy()
|
||||
elif MakeDMG:
|
||||
DMG_Make( SrlDMG )
|
||||
elif CleanDMG:
|
||||
DMG_Clean( SrlDMG )
|
||||
elif Upload:
|
||||
UploadToDropbox( Dropbox )
|
||||
|
||||
#===================================================================================
|
||||
if __name__ == "__main__":
|
||||
Main()
|
||||
|
||||
#---------------
|
||||
# End of file
|
||||
#---------------
|
||||
|
|
@ -2,9 +2,45 @@
|
|||
# Run with:
|
||||
# ./klayout -z -r ./create_drc_samples.rb -t -c klayoutrc_drc_samples
|
||||
|
||||
class QRCGenerator
|
||||
|
||||
def res_path
|
||||
"src/lay/lay"
|
||||
end
|
||||
|
||||
def img_path
|
||||
"doc/images"
|
||||
end
|
||||
|
||||
def initialize
|
||||
@path = res_path + "/" + "layDRCLVSHelpResources.qrc"
|
||||
@file = File.open(@path, "w")
|
||||
@file.puts("<RCC>")
|
||||
@file.puts(" <qresource prefix=\"/help/images\">")
|
||||
end
|
||||
|
||||
def <<(str)
|
||||
@file.puts(str)
|
||||
end
|
||||
|
||||
def finish
|
||||
@file.puts(" </qresource>")
|
||||
@file.puts("</RCC>")
|
||||
@file.close
|
||||
puts "---> resource file written to #{@path}"
|
||||
end
|
||||
|
||||
def self.instance
|
||||
@@inst ||= QRCGenerator::new
|
||||
@@inst
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def run_demo(gen, cmd, out)
|
||||
|
||||
img_path = "src/lay/lay/doc/images"
|
||||
res_path = QRCGenerator::instance.res_path
|
||||
img_path = QRCGenerator::instance.img_path
|
||||
|
||||
mw = RBA::Application::instance::main_window
|
||||
|
||||
|
|
@ -81,7 +117,9 @@ def run_demo(gen, cmd, out)
|
|||
input1 = input(1, 0)
|
||||
input = input1
|
||||
input2 = input(2, 0)
|
||||
#{cmd}.data
|
||||
labels1 = labels(1, 0)
|
||||
labels = labels1
|
||||
(#{cmd}).data
|
||||
SCRIPT
|
||||
|
||||
if data.is_a?(RBA::Region)
|
||||
|
|
@ -101,15 +139,19 @@ SCRIPT
|
|||
elsif data.is_a?(RBA::EdgePairs)
|
||||
cell.shapes(lout_poly).insert_as_polygons(data, 1)
|
||||
cell.shapes(lout).insert(data.edges)
|
||||
elsif data.is_a?(RBA::Texts)
|
||||
cell.shapes(lout).insert(data)
|
||||
end
|
||||
|
||||
view.update_content
|
||||
view.save_image(img_path + "/" + out, 400, 400)
|
||||
view.save_image(res_path + "/" + img_path + "/" + out, 400, 400)
|
||||
|
||||
puts "---> written #{img_path}/#{out}"
|
||||
puts "---> written #{res_path}/#{img_path}/#{out}"
|
||||
|
||||
mw.close_all
|
||||
|
||||
QRCGenerator::instance << " <file alias=\"#{out}\">#{img_path}/#{out}</file>"
|
||||
|
||||
end
|
||||
|
||||
class Gen
|
||||
|
|
@ -631,3 +673,41 @@ run_demo gen, "input.corners.sized(0.1)", "drc_corners1.png"
|
|||
run_demo gen, "input.corners(90.0).sized(0.1)", "drc_corners2.png"
|
||||
run_demo gen, "input.corners(-90.0 .. -45.0).sized(0.1)", "drc_corners3.png"
|
||||
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Text::new("ABC", RBA::Trans::new(RBA::Vector::new(0, 2000))))
|
||||
s1.insert(RBA::Text::new("A", RBA::Trans::new(RBA::Vector::new(0, 6000))))
|
||||
s1.insert(RBA::Text::new("XYZ", RBA::Trans::new(RBA::Vector::new(4000, 2000))))
|
||||
s1.insert(RBA::Text::new("A*", RBA::Trans::new(RBA::Vector::new(4000, 6000))))
|
||||
end
|
||||
end
|
||||
|
||||
gen = Gen::new
|
||||
|
||||
run_demo gen, "labels.texts(\"A*\")", "drc_texts1.png"
|
||||
run_demo gen, "labels.texts(text(\"A*\"))", "drc_texts2.png"
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Text::new("T1", RBA::Trans::new(RBA::Vector::new(0, 2000))))
|
||||
s1.insert(RBA::Text::new("T2", RBA::Trans::new(RBA::Vector::new(2000, 2000))))
|
||||
s1.insert(RBA::Text::new("T3", RBA::Trans::new(RBA::Vector::new(4000, 2000))))
|
||||
pts = [
|
||||
RBA::Point::new(2000, 0),
|
||||
RBA::Point::new(2000, 4000),
|
||||
RBA::Point::new(6000, 4000),
|
||||
RBA::Point::new(6000, 0)
|
||||
];
|
||||
s2.insert(RBA::Polygon::new(pts))
|
||||
end
|
||||
end
|
||||
|
||||
gen = Gen::new
|
||||
|
||||
run_demo gen, "labels & input2", "drc_textpoly1.png"
|
||||
run_demo gen, "labels - input2", "drc_textpoly2.png"
|
||||
|
||||
|
||||
QRCGenerator::instance.finish
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ ubuntu16)
|
|||
ubuntu18)
|
||||
depends="libqt4-designer (>= 4.8.7), libqt4-xml (>= 4.8.7), libqt4-sql (>= 4.8.7), libqt4-network (>= 4.8.7), libqtcore4 (>= 4.8.7), libqtgui4 (>= 4.8.7), zlib1g (>= 1.2.11), libruby2.5 (>= 2.5.1), python3 (>= 3.6.5), libpython3.6 (>= 3.6.5), libstdc++6 (>= 8), libc6 (>= 2.27)"
|
||||
;;
|
||||
ubuntu20)
|
||||
depends="libqt5core5a (>= 5.12.8), libqt5designer5 (>= 5.12.8), libqt5gui5 (>= 5.12.8), libqt5multimedia5 (>= 5.12.8), libqt5multimediawidgets5 (>= 5.12.8), libqt5network5 (>= 5.12.8), libqt5opengl5 (>= 5.12.8), libqt5printsupport5 (>= 5.12.8), libqt5sql5 (>= 5.12.8), libqt5svg5 (>= 5.12.8), libqt5widgets5 (>= 5.12.8), libqt5xml5 (>= 5.12.8), libqt5xmlpatterns5 (>= 5.12.8), zlib1g (>= 1.2.11), libruby2.7 (>= 2.7.0), python3 (>= 3.8.2), libpython3.8 (>= 3.8.2), libstdc++6 (>=10), libc6 (>= 2.31)"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown target '$target' (given as first argument)"
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -2798,8 +2798,8 @@ END
|
|||
ofile.puts("}")
|
||||
ofile.puts("")
|
||||
|
||||
mdecl << "new qt_gsi::GenericMethod (\"#{pp}#{mn_name}\", \"@hide\", #{const.to_s}, &_init_cbs_#{mn}_#{hk}_#{i_var}, &_call_cbs_#{mn}_#{hk}_#{i_var});"
|
||||
mdecl << "new qt_gsi::GenericMethod (\"#{pp}#{mn_name}\", \"@brief Virtual method #{sig}\\nThis method can be reimplemented in a derived class.\", #{const.to_s}, &_init_cbs_#{mn}_#{hk}_#{i_var}, &_call_cbs_#{mn}_#{hk}_#{i_var}, &_set_callback_cbs_#{mn}_#{hk}_#{i_var});"
|
||||
mdecl << "new qt_gsi::GenericMethod (\"#{pp}#{mn_name}\", \"@brief Virtual method #{sig}\\nThis method can be reimplemented in a derived class.\", #{const.to_s}, &_init_cbs_#{mn}_#{hk}_#{i_var}, &_call_cbs_#{mn}_#{hk}_#{i_var});"
|
||||
mdecl << "new qt_gsi::GenericMethod (\"#{pp}#{mn_name}\", \"@hide\", #{const.to_s}, &_init_cbs_#{mn}_#{hk}_#{i_var}, &_call_cbs_#{mn}_#{hk}_#{i_var}, &_set_callback_cbs_#{mn}_#{hk}_#{i_var});"
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -87,5 +87,6 @@ BD_PUBLIC int strmrun (int argc, char *argv[])
|
|||
|
||||
lym::Macro macro;
|
||||
macro.load_from (script);
|
||||
macro.set_file_path (script);
|
||||
return macro.run ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
xor_data.threads = threads;
|
||||
xor_data.tile_size = tile_size;
|
||||
xor_data.output_layout = output_layout.get ();
|
||||
xor_data.output_cell = output_top;
|
||||
xor_data.l2l_map = l2l_map;
|
||||
xor_data.results = &results;
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,20 @@ SOURCES = \
|
|||
gsiDeclDbNetlistCrossReference.cc \
|
||||
gsiDeclDbLayoutVsSchematic.cc \
|
||||
dbNetlistObject.cc \
|
||||
dbD25TechnologyComponent.cc
|
||||
dbD25TechnologyComponent.cc \
|
||||
gsiDeclDbTexts.cc \
|
||||
dbTexts.cc \
|
||||
dbDeepTexts.cc \
|
||||
dbAsIfFlatTexts.cc \
|
||||
dbTextsDelegate.cc \
|
||||
dbEmptyTexts.cc \
|
||||
dbFlatTexts.cc \
|
||||
dbTextsUtils.cc \
|
||||
dbOriginalLayerTexts.cc \
|
||||
dbNetShape.cc \
|
||||
dbShapeCollection.cc \
|
||||
gsiDeclDbShapeCollection.cc \
|
||||
dbShapeCollectionUtils.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -333,7 +346,18 @@ HEADERS = \
|
|||
dbLayoutVsSchematicFormatDefs.h \
|
||||
dbLayoutVsSchematic.h \
|
||||
dbNetlistObject.h \
|
||||
dbD25TechnologyComponent.h
|
||||
dbD25TechnologyComponent.h \
|
||||
dbTexts.h \
|
||||
dbDeepTexts.h \
|
||||
dbAsIfFlatTexts.h \
|
||||
dbTextsDelegate.h \
|
||||
dbEmptyTexts.h \
|
||||
dbFlatTexts.h \
|
||||
dbTextsUtils.h \
|
||||
dbOriginalLayerTexts.h \
|
||||
dbNetShape.h \
|
||||
dbShapeCollection.h \
|
||||
dbShapeCollectionUtils.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ struct basic_array_iterator
|
|||
|
||||
virtual long index_a () const { return -1; }
|
||||
virtual long index_b () const { return -1; }
|
||||
|
||||
|
||||
virtual size_t quad_id () const { return 0; }
|
||||
virtual box_type quad_box () const { return box_type::world (); }
|
||||
virtual void skip_quad () { }
|
||||
|
||||
virtual disp_type get () const = 0;
|
||||
|
||||
virtual basic_array_iterator<Coord> *clone () const = 0;
|
||||
|
|
@ -111,8 +115,12 @@ struct ArrayBase
|
|||
|
||||
virtual bool equal (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool less (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *) const = 0;
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const = 0;
|
||||
|
||||
bool in_repository;
|
||||
|
|
@ -554,6 +562,12 @@ struct regular_array
|
|||
return (m_a == d->m_a && m_b == d->m_b && m_amax == d->m_amax && m_bmax == d->m_bmax);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
return (m_a.equal (d->m_a) && m_b.equal (d->m_b) && m_amax == d->m_amax && m_bmax == d->m_bmax);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
|
|
@ -562,6 +576,14 @@ struct regular_array
|
|||
m_amax < d->m_amax || (m_amax == d->m_amax && m_bmax < d->m_bmax)))));
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
return m_a.less (d->m_a) || (m_a.equal (d->m_a) && (
|
||||
m_b.less (d->m_b) || (m_b.equal (d->m_b) && (
|
||||
m_amax < d->m_amax || (m_amax == d->m_amax && m_bmax < d->m_bmax)))));
|
||||
}
|
||||
|
||||
virtual bool is_regular_array (vector_type &a, vector_type &b, unsigned long &amax, unsigned long &bmax) const
|
||||
{
|
||||
a = m_a;
|
||||
|
|
@ -702,6 +724,18 @@ struct regular_complex_array
|
|||
return regular_array<Coord>::equal (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
return regular_array<Coord>::fuzzy_equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
|
|
@ -714,6 +748,18 @@ struct regular_complex_array
|
|||
return regular_array<Coord>::less (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return m_acos < d->m_acos;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return m_mag < d->m_mag;
|
||||
}
|
||||
return regular_array<Coord>::fuzzy_less (b);
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -806,6 +852,21 @@ struct iterated_array_iterator
|
|||
return new iterated_array_iterator <Coord> (*this);
|
||||
}
|
||||
|
||||
virtual size_t quad_id () const
|
||||
{
|
||||
return m_t.quad_id ();
|
||||
}
|
||||
|
||||
virtual box_type quad_box () const
|
||||
{
|
||||
return m_t.quad_box ();
|
||||
}
|
||||
|
||||
virtual void skip_quad ()
|
||||
{
|
||||
m_t.skip_quad ();
|
||||
}
|
||||
|
||||
private:
|
||||
box_tree_const_iterator m_b, m_e;
|
||||
box_tree_touching_iterator m_t;
|
||||
|
|
@ -964,6 +1025,20 @@ struct iterated_array
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
if (m_v.size () != d->m_v.size ()) {
|
||||
return false;
|
||||
}
|
||||
for (const_iterator p1 = m_v.begin (), p2 = d->m_v.begin (); p1 != m_v.end (); ++p1, ++p2) {
|
||||
if (! p1->equal (*p2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
|
|
@ -978,6 +1053,20 @@ struct iterated_array
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
if (m_v.size () != d->m_v.size ()) {
|
||||
return (m_v.size () < d->m_v.size ());
|
||||
}
|
||||
for (const_iterator p1 = m_v.begin (), p2 = d->m_v.begin (); p1 != m_v.end (); ++p1, ++p2) {
|
||||
if (! p1->equal (*p2)) {
|
||||
return (p1->less (*p2));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -1085,6 +1174,18 @@ struct iterated_complex_array
|
|||
return iterated_array<Coord>::equal (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
return iterated_array<Coord>::fuzzy_equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
|
|
@ -1097,6 +1198,18 @@ struct iterated_complex_array
|
|||
return iterated_array<Coord>::less (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return m_acos < d->m_acos;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return m_mag < d->m_mag;
|
||||
}
|
||||
return iterated_array<Coord>::fuzzy_less (b);
|
||||
}
|
||||
|
||||
virtual complex_trans_type complex_trans (const simple_trans_type &s) const
|
||||
{
|
||||
return complex_trans_type (s, m_acos, m_mag);
|
||||
|
|
@ -1187,7 +1300,12 @@ struct single_complex_inst
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
return equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const double epsilon = 1e-10;
|
||||
const single_complex_inst<Coord> *d = static_cast<const single_complex_inst<Coord> *> (b);
|
||||
|
|
@ -1200,6 +1318,11 @@ struct single_complex_inst
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
return less (b);
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -1420,6 +1543,36 @@ struct array_iterator
|
|||
return mp_base ? mp_base->index_b () : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will return the quad ID
|
||||
*/
|
||||
size_t quad_id () const
|
||||
{
|
||||
return mp_base ? mp_base->quad_id () : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will return the quad bounding box
|
||||
*
|
||||
* Note that this method will only return a valid quad box is the quad_id is non-null.
|
||||
*
|
||||
* This method will return the bounding box of all array offsets in the quad.
|
||||
*/
|
||||
db::box<Coord> quad_box () const
|
||||
{
|
||||
return mp_base ? mp_base->quad_box () : db::box<Coord>::world ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will skip the current quad
|
||||
*/
|
||||
void skip_quad ()
|
||||
{
|
||||
if (mp_base) {
|
||||
mp_base->skip_quad ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
trans_type m_trans;
|
||||
basic_array_iterator <Coord> *mp_base;
|
||||
|
|
@ -1592,6 +1745,32 @@ struct array
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The iterated array constructor
|
||||
*
|
||||
* This is basically a convenience function that creates
|
||||
* an appropriate basic_array object.
|
||||
*/
|
||||
template <class Iter>
|
||||
array (const Obj &obj, const trans_type &trans, Iter from, Iter to)
|
||||
: m_obj (obj), m_trans (trans), mp_base (new iterated_array <coord_type> (from, to))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The complex iterated array constructor
|
||||
*
|
||||
* This is basically a convenience function that creates
|
||||
* an appropriate basic_array object.
|
||||
*/
|
||||
template <class Iter>
|
||||
array (const Obj &obj, const complex_trans_type &ct, Iter from, Iter to)
|
||||
: m_obj (obj), m_trans (ct), mp_base (new iterated_complex_array <coord_type> (ct.rcos (), ct.mag (), from, to))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The singular complex instance constructor
|
||||
*
|
||||
|
|
@ -1835,6 +2014,32 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box from the iterator's current quad
|
||||
*
|
||||
* The bounding box is that of all objects in the current quad and
|
||||
* is confined to the array's total bounding box.
|
||||
*/
|
||||
template <class Iter, class BoxConv>
|
||||
box_type quad_box (const Iter &iter, const BoxConv &bc) const
|
||||
{
|
||||
box_type bb;
|
||||
if (mp_base) {
|
||||
bb = mp_base->bbox (box_type (0, 0, 0, 0));
|
||||
}
|
||||
bb &= iter.quad_box ();
|
||||
|
||||
if (mp_base) {
|
||||
if (mp_base->is_complex ()) {
|
||||
return bb * box_type (mp_base->complex_trans (simple_trans_type (m_trans)) * bc (m_obj));
|
||||
} else {
|
||||
return bb * (m_trans * bc (m_obj));
|
||||
}
|
||||
} else {
|
||||
return bb * (m_trans * bc (m_obj));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The number of single instances in the array
|
||||
*/
|
||||
|
|
@ -1918,6 +2123,21 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator for equality (fuzzy version)
|
||||
*/
|
||||
bool equal (const array<Obj, Trans> &d) const
|
||||
{
|
||||
if (! mp_base) {
|
||||
return (m_trans.equal (d.m_trans) && m_obj == d.m_obj && ! d.mp_base);
|
||||
} else {
|
||||
if (! m_trans.equal (d.m_trans) || ! (m_obj == d.m_obj) || type () != d.type ()) {
|
||||
return false;
|
||||
}
|
||||
return mp_base && mp_base->fuzzy_equal (d.mp_base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A sorting order criterion
|
||||
*/
|
||||
|
|
@ -1943,6 +2163,31 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A fuzzy sorting order criterion
|
||||
*/
|
||||
bool less (const array<Obj, Trans> &d) const
|
||||
{
|
||||
if (! (m_obj == d.m_obj)) {
|
||||
return (m_obj < d.m_obj);
|
||||
}
|
||||
if (! m_trans.equal (d.m_trans)) {
|
||||
return m_trans.less (d.m_trans);
|
||||
}
|
||||
if (type () != d.type ()) {
|
||||
return (type () < d.type ());
|
||||
}
|
||||
if (mp_base == d.mp_base) {
|
||||
return false;
|
||||
} else if (! mp_base) {
|
||||
return true;
|
||||
} else if (! d.mp_base) {
|
||||
return false;
|
||||
} else {
|
||||
return mp_base->fuzzy_less (d.mp_base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator
|
||||
*
|
||||
|
|
@ -2263,7 +2508,7 @@ struct array
|
|||
}
|
||||
db::mem_stat (stat, purpose, cat, m_obj, true, (void *) this);
|
||||
if (mp_base) {
|
||||
db::mem_stat (stat, purpose, cat, *mp_base, false, (void *) this);
|
||||
mp_base->mem_stat (stat, purpose, cat, false, (void *) this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ AsIfFlatEdgePairs::AsIfFlatEdgePairs ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatEdgePairs::AsIfFlatEdgePairs (const AsIfFlatEdgePairs &other)
|
||||
: EdgePairsDelegate (other), m_bbox_valid (other.m_bbox_valid), m_bbox (other.m_bbox)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatEdgePairs::~AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -75,7 +81,7 @@ AsIfFlatEdgePairs::in (const EdgePairs &other, bool invert) const
|
|||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (false));
|
||||
std::auto_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
|
||||
|
||||
for (EdgePairsIterator o (begin ()); ! o.at_end (); ++o) {
|
||||
if ((op.find (*o) == op.end ()) == invert) {
|
||||
|
|
@ -125,6 +131,28 @@ void AsIfFlatEdgePairs::invalidate_bbox ()
|
|||
m_bbox_valid = false;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> region (new FlatRegion ());
|
||||
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
region->set_merged_semantics (false);
|
||||
}
|
||||
|
||||
std::vector<db::Polygon> res_polygons;
|
||||
|
||||
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
res_polygons.clear ();
|
||||
filter.process (*e, res_polygons);
|
||||
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
|
||||
region->insert (*pr);
|
||||
}
|
||||
}
|
||||
|
||||
return region.release ();
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class DB_PUBLIC AsIfFlatEdgePairs
|
|||
{
|
||||
public:
|
||||
AsIfFlatEdgePairs ();
|
||||
AsIfFlatEdgePairs (const AsIfFlatEdgePairs &other);
|
||||
virtual ~AsIfFlatEdgePairs ();
|
||||
|
||||
virtual size_t size () const;
|
||||
|
|
@ -51,6 +52,8 @@ public:
|
|||
|
||||
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const;
|
||||
|
||||
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
|
||||
|
||||
virtual EdgePairsDelegate *add_in_place (const EdgePairs &other)
|
||||
{
|
||||
return add (other);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,22 @@ AsIfFlatEdges::~AsIfFlatEdges ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatEdges::AsIfFlatEdges (const AsIfFlatEdges &other)
|
||||
: EdgesDelegate (other), m_bbox_valid (false)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
AsIfFlatEdges &
|
||||
AsIfFlatEdges::operator= (const AsIfFlatEdges &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_bbox_valid = other.m_bbox_valid;
|
||||
m_bbox = other.m_bbox;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
AsIfFlatEdges::to_string (size_t nmax) const
|
||||
{
|
||||
|
|
@ -170,7 +186,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const
|
|||
{
|
||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableEdgeDelivery e (begin (), true);
|
||||
AddressableEdgeDelivery e (begin (), has_valid_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert (e.operator-> (), 1);
|
||||
|
|
@ -497,7 +513,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
|
|||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve (size () + (other ? other->size () : 0));
|
||||
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_edges ());
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
|
||||
|
||||
size_t n = 0;
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
|
|
|
|||
|
|
@ -185,10 +185,10 @@ protected:
|
|||
virtual RegionDelegate *pull_generic (const Region ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const;
|
||||
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
|
||||
AsIfFlatEdges (const AsIfFlatEdges &other);
|
||||
|
||||
private:
|
||||
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
|
||||
|
||||
mutable bool m_bbox_valid;
|
||||
mutable db::Box m_bbox;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbFlatRegion.h"
|
||||
#include "dbFlatEdgePairs.h"
|
||||
#include "dbFlatEdges.h"
|
||||
#include "dbFlatTexts.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbEmptyEdgePairs.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
|
|
@ -55,6 +56,23 @@ AsIfFlatRegion::~AsIfFlatRegion ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatRegion::AsIfFlatRegion (const AsIfFlatRegion &other)
|
||||
: RegionDelegate (other), m_bbox_valid (false)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
AsIfFlatRegion &
|
||||
AsIfFlatRegion::operator= (const AsIfFlatRegion &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_bbox_valid = other.m_bbox_valid;
|
||||
m_bbox = other.m_bbox;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
AsIfFlatRegion::to_string (size_t nmax) const
|
||||
{
|
||||
|
|
@ -364,6 +382,50 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
|
|||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
if (! inverse) {
|
||||
return new EmptyRegion ();
|
||||
} else {
|
||||
return clone ();
|
||||
}
|
||||
} else if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (size ());
|
||||
scanner.reserve2 (other.size ());
|
||||
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion (true));
|
||||
region_to_text_interaction_filter<FlatRegion, db::Text> filter (*output, inverse);
|
||||
|
||||
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
if (inverse) {
|
||||
filter.preset (p.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
AddressableTextDelivery e (other.addressable_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
|
||||
if (inverse) {
|
||||
filter.fill_output ();
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const
|
||||
{
|
||||
|
|
@ -440,7 +502,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
|
|||
std::auto_ptr<FlatEdges> output (new FlatEdges (false));
|
||||
region_to_edge_interaction_filter<Shapes, db::Edge> filter (output->raw_edges (), false);
|
||||
|
||||
AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ());
|
||||
AddressablePolygonDelivery p (begin (), has_valid_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
|
|
@ -457,6 +519,39 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
|
|||
return output.release ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatRegion::pull_generic (const Texts &other) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return other.delegate ()->clone ();
|
||||
} else if (empty ()) {
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (size ());
|
||||
scanner.reserve2 (other.size ());
|
||||
|
||||
std::auto_ptr<FlatTexts> output (new FlatTexts (false));
|
||||
region_to_text_interaction_filter<Shapes, db::Text, db::Text> filter (output->raw_texts (), false);
|
||||
|
||||
AddressablePolygonDelivery p (begin (), has_valid_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressableTextDelivery e (other.addressable_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -202,6 +202,16 @@ public:
|
|||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, false, false);
|
||||
|
|
@ -227,6 +237,11 @@ public:
|
|||
return pull_generic (other);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *pull_interacting (const Texts &other) const
|
||||
{
|
||||
return pull_generic (other);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *pull_overlapping (const Region &other) const
|
||||
{
|
||||
return pull_generic (other, 0, false);
|
||||
|
|
@ -247,16 +262,20 @@ protected:
|
|||
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &other) const;
|
||||
virtual TextsDelegate *pull_generic (const Texts &other) const;
|
||||
|
||||
template <class Trans>
|
||||
static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes);
|
||||
template <class Trans>
|
||||
static void produce_markers_for_angle_check (const db::Polygon &poly, const Trans &tr, double min, double max, bool inverse, db::Shapes &shapes);
|
||||
|
||||
private:
|
||||
AsIfFlatRegion &operator= (const AsIfFlatRegion &other);
|
||||
AsIfFlatRegion (const AsIfFlatRegion &other);
|
||||
|
||||
private:
|
||||
|
||||
mutable bool m_bbox_valid;
|
||||
mutable db::Box m_bbox;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,412 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbAsIfFlatTexts.h"
|
||||
#include "dbFlatTexts.h"
|
||||
#include "dbFlatRegion.h"
|
||||
#include "dbFlatEdges.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbBoxConvert.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbTextsUtils.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// AsIfFlagTexts implementation
|
||||
|
||||
AsIfFlatTexts::AsIfFlatTexts ()
|
||||
: TextsDelegate (), m_bbox_valid (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatTexts::AsIfFlatTexts (const AsIfFlatTexts &other)
|
||||
: TextsDelegate (other), m_bbox_valid (other.m_bbox_valid), m_bbox (other.m_bbox)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatTexts::~AsIfFlatTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatTexts &
|
||||
AsIfFlatTexts::operator= (const AsIfFlatTexts &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_bbox_valid = other.m_bbox_valid;
|
||||
m_bbox = other.m_bbox;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
AsIfFlatTexts::to_string (size_t nmax) const
|
||||
{
|
||||
std::ostringstream os;
|
||||
TextsIterator p (begin ());
|
||||
bool first = true;
|
||||
for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) {
|
||||
if (! first) {
|
||||
os << ";";
|
||||
}
|
||||
first = false;
|
||||
os << p->to_string ();
|
||||
}
|
||||
if (! p.at_end ()) {
|
||||
os << "...";
|
||||
}
|
||||
return os.str ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::in (const Texts &other, bool invert) const
|
||||
{
|
||||
std::set <db::Text> op;
|
||||
for (TextsIterator o (other.begin ()); ! o.at_end (); ++o) {
|
||||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts ());
|
||||
|
||||
for (TextsIterator o (begin ()); ! o.at_end (); ++o) {
|
||||
if ((op.find (*o) == op.end ()) == invert) {
|
||||
new_texts->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
}
|
||||
|
||||
size_t
|
||||
AsIfFlatTexts::size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
Box AsIfFlatTexts::bbox () const
|
||||
{
|
||||
if (! m_bbox_valid) {
|
||||
m_bbox = compute_bbox ();
|
||||
m_bbox_valid = true;
|
||||
}
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
Box AsIfFlatTexts::compute_bbox () const
|
||||
{
|
||||
db::Box b;
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
b += t->box ();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
void AsIfFlatTexts::update_bbox (const db::Box &b)
|
||||
{
|
||||
m_bbox = b;
|
||||
m_bbox_valid = true;
|
||||
}
|
||||
|
||||
void AsIfFlatTexts::invalidate_bbox ()
|
||||
{
|
||||
m_bbox_valid = false;
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::filtered (const TextFilterBase &filter) const
|
||||
{
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts ());
|
||||
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (filter.selected (*p)) {
|
||||
new_texts->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> region (new FlatRegion ());
|
||||
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
region->set_merged_semantics (false);
|
||||
}
|
||||
|
||||
std::vector<db::Polygon> res_polygons;
|
||||
|
||||
for (TextsIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
res_polygons.clear ();
|
||||
filter.process (*e, res_polygons);
|
||||
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
|
||||
region->insert (*pr);
|
||||
}
|
||||
}
|
||||
|
||||
return region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::polygons (db::Coord e) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion ());
|
||||
|
||||
for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) {
|
||||
db::Box box = tp->box ();
|
||||
box.enlarge (db::Vector (e, e));
|
||||
output->insert (db::Polygon (box));
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatTexts::edges () const
|
||||
{
|
||||
std::auto_ptr<FlatEdges> output (new FlatEdges ());
|
||||
|
||||
for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) {
|
||||
db::Box box = tp->box ();
|
||||
output->insert (db::Edge (box.p1 (), box.p2 ()));
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::add (const Texts &other) const
|
||||
{
|
||||
FlatTexts *other_flat = dynamic_cast<FlatTexts *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts (*other_flat));
|
||||
new_texts->invalidate_cache ();
|
||||
|
||||
size_t n = new_texts->raw_texts ().size () + size ();
|
||||
|
||||
new_texts->reserve (n);
|
||||
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
|
||||
} else {
|
||||
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts ());
|
||||
|
||||
size_t n = size () + other.size ();
|
||||
|
||||
new_texts->reserve (n);
|
||||
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AsIfFlatTexts::equals (const Texts &other) const
|
||||
{
|
||||
if (empty () != other.empty ()) {
|
||||
return false;
|
||||
}
|
||||
if (size () != other.size ()) {
|
||||
return false;
|
||||
}
|
||||
TextsIterator o1 (begin ());
|
||||
TextsIterator o2 (other.begin ());
|
||||
while (! o1.at_end () && ! o2.at_end ()) {
|
||||
if (*o1 != *o2) {
|
||||
return false;
|
||||
}
|
||||
++o1;
|
||||
++o2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AsIfFlatTexts::less (const Texts &other) const
|
||||
{
|
||||
if (empty () != other.empty ()) {
|
||||
return empty () < other.empty ();
|
||||
}
|
||||
if (size () != other.size ()) {
|
||||
return (size () < other.size ());
|
||||
}
|
||||
TextsIterator o1 (begin ());
|
||||
TextsIterator o2 (other.begin ());
|
||||
while (! o1.at_end () && ! o2.at_end ()) {
|
||||
if (*o1 != *o2) {
|
||||
return *o1 < *o2;
|
||||
}
|
||||
++o1;
|
||||
++o2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
AsIfFlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
// improves performance when inserting an original layout into the same layout
|
||||
db::LayoutLocker locker (layout);
|
||||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
shapes.insert (*t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsIfFlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
// improves performance when inserting an original layout into the same layout
|
||||
db::LayoutLocker locker (layout);
|
||||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
db::Box box = t->box ();
|
||||
box.enlarge (db::Vector (enl, enl));
|
||||
shapes.insert (db::SimplePolygon (box));
|
||||
}
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::selected_interacting_generic (const Region &other, bool inverse) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty () || empty ()) {
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Text, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableTextDelivery e (begin (), has_valid_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert1 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressablePolygonDelivery p = other.addressable_polygons ();
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert2 (p.operator-> (), 1);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatTexts> output (new FlatTexts ());
|
||||
|
||||
if (! inverse) {
|
||||
|
||||
text_to_region_interaction_filter<FlatTexts, db::Text> filter (*output);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
} else {
|
||||
|
||||
std::set<db::Text> interacting;
|
||||
text_to_region_interaction_filter<std::set<db::Text>, db::Text> filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (TextsIterator o (begin ()); ! o.at_end (); ++o) {
|
||||
if (interacting.find (*o) == interacting.end ()) {
|
||||
output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::pull_generic (const Region &other) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty () || empty ()) {
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Text, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableTextDelivery e (begin (), has_valid_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert1 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressablePolygonDelivery p = other.addressable_merged_polygons ();
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert2 (p.operator-> (), 1);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion (true));
|
||||
|
||||
text_to_region_interaction_filter<FlatRegion, db::Text> filter (*output);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::pull_interacting (const Region &other) const
|
||||
{
|
||||
return pull_generic (other);
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::selected_interacting (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::selected_not_interacting (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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_dbAsIfFlatTexts
|
||||
#define HDR_dbAsIfFlatTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbTextsDelegate.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* @brief Provides default flat implementations
|
||||
*/
|
||||
class DB_PUBLIC AsIfFlatTexts
|
||||
: public TextsDelegate
|
||||
{
|
||||
public:
|
||||
AsIfFlatTexts ();
|
||||
AsIfFlatTexts (const AsIfFlatTexts &other);
|
||||
virtual ~AsIfFlatTexts ();
|
||||
|
||||
virtual size_t size () const;
|
||||
virtual std::string to_string (size_t) const;
|
||||
virtual Box bbox () const;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter)
|
||||
{
|
||||
return filtered (filter);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &) const;
|
||||
|
||||
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &filter) const;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other)
|
||||
{
|
||||
return add (other);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &, bool) const;
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const;
|
||||
virtual TextsDelegate *selected_interacting (const Region &other) const;
|
||||
virtual TextsDelegate *selected_not_interacting (const Region &other) const;
|
||||
|
||||
protected:
|
||||
void update_bbox (const db::Box &box);
|
||||
void invalidate_bbox ();
|
||||
AsIfFlatTexts &operator= (const AsIfFlatTexts &other);
|
||||
|
||||
private:
|
||||
|
||||
mutable bool m_bbox_valid;
|
||||
mutable db::Box m_bbox;
|
||||
|
||||
virtual db::Box compute_bbox () const;
|
||||
virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -168,40 +168,43 @@ public:
|
|||
typedef typename Tree::coord_type coord_type;
|
||||
typedef typename Tree::box_type box_type;
|
||||
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, unsigned int quad)
|
||||
: m_center (center)
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, const box_type &qbox, unsigned int quad)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
m_lenq[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
mp_children[i] = 0;
|
||||
}
|
||||
mp_parent = (box_tree_node *)((char *) parent + quad);
|
||||
if (parent) {
|
||||
parent->mp_children [quad] = this;
|
||||
point_type corner;
|
||||
if (quad == 0) {
|
||||
corner = qbox.upper_right ();
|
||||
} else if (quad == 1) {
|
||||
corner = qbox.upper_left ();
|
||||
} else if (quad == 2) {
|
||||
corner = qbox.lower_left ();
|
||||
} else if (quad == 3) {
|
||||
corner = qbox.lower_right ();
|
||||
}
|
||||
|
||||
init (parent, center, corner, quad);
|
||||
}
|
||||
|
||||
~box_tree_node ()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mp_children [i]) {
|
||||
delete mp_children [i];
|
||||
mp_children [i] = 0;
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
delete c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box_tree_node *clone (box_tree_node *parent = 0, unsigned int quad = 0) const
|
||||
{
|
||||
box_tree_node *n = new box_tree_node (parent, m_center, quad);
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
n->m_lenq[i] = m_lenq[i];
|
||||
}
|
||||
box_tree_node *n = new box_tree_node (parent, m_center, m_corner, quad);
|
||||
n->m_lenq = m_lenq;
|
||||
n->m_len = m_len;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
if (mp_children[i]) {
|
||||
mp_children[i]->clone (n, i);
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
c->clone (n, i);
|
||||
} else {
|
||||
n->m_childrefs [i] = m_childrefs [i];
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
|
@ -209,17 +212,39 @@ public:
|
|||
|
||||
box_tree_node *child (int i) const
|
||||
{
|
||||
return mp_children [i];
|
||||
if ((m_childrefs [i] & 1) == 0) {
|
||||
return reinterpret_cast<box_tree_node *> (m_childrefs [i]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void lenq (int i, size_t l)
|
||||
{
|
||||
m_lenq[i + 1] = l;
|
||||
if (i < 0) {
|
||||
m_lenq = l;
|
||||
} else {
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
c->m_len = l;
|
||||
} else {
|
||||
m_childrefs [i] = l * 2 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t lenq (int i) const
|
||||
{
|
||||
return m_lenq[i + 1];
|
||||
if (i < 0) {
|
||||
return m_lenq;
|
||||
} else {
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
return c->m_len;
|
||||
} else {
|
||||
return m_childrefs [i] >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box_tree_node *parent () const
|
||||
|
|
@ -238,8 +263,8 @@ public:
|
|||
stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mp_children [i]) {
|
||||
mp_children [i]->mem_stat (stat, purpose, cat, no_self, parent);
|
||||
if (child (i)) {
|
||||
child (i)->mem_stat (stat, purpose, cat, no_self, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -249,14 +274,52 @@ public:
|
|||
return m_center;
|
||||
}
|
||||
|
||||
box_type quad_box (int quad) const
|
||||
{
|
||||
box_type qb = box_type::world ();
|
||||
if (parent ()) {
|
||||
qb = box_type (m_corner, parent ()->center ());
|
||||
}
|
||||
|
||||
switch (quad) {
|
||||
case 0: return box_type (m_center, qb.upper_right ());
|
||||
case 1: return box_type (m_center, qb.upper_left ());
|
||||
case 2: return box_type (m_center, qb.lower_left ());
|
||||
case 3: return box_type (m_center, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
box_tree_node *mp_parent;
|
||||
size_t m_lenq [5];
|
||||
box_tree_node *mp_children [4];
|
||||
point_type m_center;
|
||||
size_t m_lenq, m_len;
|
||||
size_t m_childrefs [4];
|
||||
point_type m_center, m_corner;
|
||||
|
||||
box_tree_node (const box_tree_node &d);
|
||||
box_tree_node &operator= (const box_tree_node &d);
|
||||
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, const point_type &corner, unsigned int quad)
|
||||
{
|
||||
init (parent, center, corner, quad);
|
||||
}
|
||||
|
||||
void init (box_tree_node *parent, const point_type ¢er, const point_type &corner, unsigned int quad)
|
||||
{
|
||||
m_center = center;
|
||||
m_corner = corner;
|
||||
|
||||
m_lenq = m_len = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_childrefs [i] = 0;
|
||||
}
|
||||
|
||||
mp_parent = (box_tree_node *)((char *) parent + quad);
|
||||
if (parent) {
|
||||
m_len = (parent->m_childrefs [quad] >> 1);
|
||||
parent->m_childrefs [quad] = size_t (this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -459,28 +522,9 @@ public:
|
|||
box_type quad_box () const
|
||||
{
|
||||
if (! mp_node) {
|
||||
|
||||
return box_type::world ();
|
||||
|
||||
} else {
|
||||
|
||||
point_type c = mp_node->center ();
|
||||
box_type qb;
|
||||
if (! mp_node->parent ()) {
|
||||
qb = box_type::world ();
|
||||
} else {
|
||||
point_type pc = mp_node->parent ()->center ();
|
||||
qb = box_type (c - (pc - c), pc);
|
||||
}
|
||||
|
||||
switch (m_quad) {
|
||||
case 0: return box_type (c, qb.upper_right ());
|
||||
case 1: return box_type (c, qb.upper_left ());
|
||||
case 2: return box_type (c, qb.lower_left ());
|
||||
case 3: return box_type (c, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
|
||||
return mp_node->quad_box (m_quad);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -577,12 +621,16 @@ private:
|
|||
return m_quad < 4;
|
||||
}
|
||||
|
||||
// down one level
|
||||
// down as many levels as required for the next non-empty quad
|
||||
// returns true if this is possible
|
||||
bool down ()
|
||||
{
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (c) {
|
||||
while (true) {
|
||||
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (! c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_node = c;
|
||||
m_quad = -1;
|
||||
|
|
@ -595,12 +643,11 @@ private:
|
|||
// nothing to visit: up again
|
||||
up ();
|
||||
return false;
|
||||
} else {
|
||||
} else if (m_quad < 0) {
|
||||
// stay in main chunk
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -670,7 +717,7 @@ private:
|
|||
* whose box overlaps or touches a specified test box.
|
||||
*/
|
||||
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100>
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100, unsigned int thin_aspect = 4>
|
||||
class box_tree
|
||||
{
|
||||
public:
|
||||
|
|
@ -1175,7 +1222,16 @@ private:
|
|||
|
||||
// the bins are: overall, ur, ul, ll, lr, empty
|
||||
element_iterator qloc [6] = { from, from, from, from, from, from };
|
||||
point_type center (bbox.center ());
|
||||
point_type center;
|
||||
if (bbox.width () < bbox.height () / thin_aspect) {
|
||||
// separate by height only
|
||||
center = point_type (bbox.left (), bbox.bottom () + bbox.height () / 2);
|
||||
} else if (bbox.height () < bbox.width () / thin_aspect) {
|
||||
// separate by width only
|
||||
center = point_type (bbox.left () + bbox.width () / 2, bbox.bottom ());
|
||||
} else {
|
||||
center = bbox.center ();
|
||||
}
|
||||
|
||||
for (element_iterator e = from; e != to; ++e) {
|
||||
|
||||
|
|
@ -1224,7 +1280,7 @@ private:
|
|||
if (nn >= min_quads) {
|
||||
|
||||
// create a new node representing this tree
|
||||
box_tree_node *node = new box_tree_node (parent, center, quad);
|
||||
box_tree_node *node = new box_tree_node (parent, center, bbox, quad);
|
||||
if (parent == 0) {
|
||||
mp_root = node;
|
||||
}
|
||||
|
|
@ -1460,28 +1516,9 @@ public:
|
|||
box_type quad_box () const
|
||||
{
|
||||
if (! mp_node) {
|
||||
|
||||
return box_type::world ();
|
||||
|
||||
} else {
|
||||
|
||||
point_type c = mp_node->center ();
|
||||
box_type qb;
|
||||
if (! mp_node->parent ()) {
|
||||
qb = box_type::world ();
|
||||
} else {
|
||||
point_type pc = mp_node->parent ()->center ();
|
||||
qb = box_type (c - (pc - c), pc);
|
||||
}
|
||||
|
||||
switch (m_quad) {
|
||||
case 0: return box_type (c, qb.upper_right ());
|
||||
case 1: return box_type (c, qb.upper_left ());
|
||||
case 2: return box_type (c, qb.lower_left ());
|
||||
case 3: return box_type (c, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
|
||||
return mp_node->quad_box (m_quad);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1578,12 +1615,16 @@ private:
|
|||
return m_quad < 4;
|
||||
}
|
||||
|
||||
// down one level
|
||||
// down as many levels as required for the next non-empty quad
|
||||
// returns true if this is possible
|
||||
bool down ()
|
||||
{
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (c) {
|
||||
while (true) {
|
||||
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (! c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_node = c;
|
||||
m_quad = -1;
|
||||
|
|
@ -1596,12 +1637,11 @@ private:
|
|||
// nothing to visit: up again
|
||||
up ();
|
||||
return false;
|
||||
} else {
|
||||
} else if (m_quad < 0) {
|
||||
// stay in main chunk
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1638,7 +1678,7 @@ private:
|
|||
* is sorted.
|
||||
*/
|
||||
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100>
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100, unsigned int thin_aspect = 4>
|
||||
class unstable_box_tree
|
||||
{
|
||||
public:
|
||||
|
|
@ -2103,7 +2143,16 @@ private:
|
|||
}
|
||||
|
||||
obj_iterator qloc [5] = { from, from, from, from, from };
|
||||
point_type center (bbox.center ());
|
||||
point_type center;
|
||||
if (bbox.width () < bbox.height () / thin_aspect) {
|
||||
// separate by height only
|
||||
center = point_type (bbox.left (), bbox.bottom () + bbox.height () / 2);
|
||||
} else if (bbox.height () < bbox.width () / thin_aspect) {
|
||||
// separate by width only
|
||||
center = point_type (bbox.left () + bbox.width () / 2, bbox.bottom ());
|
||||
} else {
|
||||
center = bbox.center ();
|
||||
}
|
||||
|
||||
for (obj_iterator e = from; e != to; ++e) {
|
||||
|
||||
|
|
@ -2158,7 +2207,7 @@ private:
|
|||
if (nn >= min_quads) {
|
||||
|
||||
// create a new node representing this tree
|
||||
box_tree_node *node = new box_tree_node (parent, center, quad);
|
||||
box_tree_node *node = new box_tree_node (parent, center, bbox, quad);
|
||||
if (parent == 0) {
|
||||
mp_root = node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,6 +301,30 @@ public:
|
|||
return m_instances.transform_into (ref, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transforms the cell by the given transformation.
|
||||
*
|
||||
* The transformation is applied to all instances and shapes. Magnified transformations will
|
||||
* render magnified instances. See \transform_into for a version which avoids this.
|
||||
*
|
||||
* @param t The transformation to apply
|
||||
*/
|
||||
template <class Trans>
|
||||
void transform (const Trans &t)
|
||||
{
|
||||
m_instances.transform (t);
|
||||
for (typename shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
|
||||
if (! s->second.empty ()) {
|
||||
// Note: don't use the copy ctor here - it will copy the attachment to the manager
|
||||
// and create problems when destroyed. Plus: swap would be more efficient. But by using
|
||||
// assign_transformed we get undo support for free.
|
||||
shapes_type d;
|
||||
d = s->second;
|
||||
s->second.assign_transformed (d, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transforms the cell into a new coordinate system.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -57,6 +57,22 @@ db::Trans MagnificationReducer::reduce (const db::Trans &) const
|
|||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
db::ICplxTrans XYAnisotropyAndMagnificationReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
double a = trans.angle ();
|
||||
if (a > 180.0 - db::epsilon) {
|
||||
a -= 180.0;
|
||||
}
|
||||
return db::ICplxTrans (trans.mag (), a, false, db::Vector ());
|
||||
}
|
||||
|
||||
db::Trans XYAnisotropyAndMagnificationReducer::reduce (const db::Trans &trans) const
|
||||
{
|
||||
return db::Trans (trans.angle () % 2, false, db::Vector ());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
db::ICplxTrans MagnificationAndOrientationReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,18 @@ struct DB_PUBLIC MagnificationReducer
|
|||
db::Trans reduce (const db::Trans &) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A reducer for magnification and XYAnisotropy
|
||||
*
|
||||
* This reducer is used for cases where an x and y-value is given, e.g. anisotropic size.
|
||||
*/
|
||||
struct DB_PUBLIC XYAnisotropyAndMagnificationReducer
|
||||
: public TransformationReducer
|
||||
{
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
|
||||
db::Trans reduce (const db::Trans &trans) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A magnification and orientation reducer
|
||||
*
|
||||
|
|
|
|||
|
|
@ -333,17 +333,41 @@ void Circuit::remove_pin (size_t id)
|
|||
|
||||
void Circuit::add_net (Net *net)
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
if (net->circuit ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Net already part of a circuit")));
|
||||
}
|
||||
|
||||
m_nets.push_back (net);
|
||||
net->set_circuit (this);
|
||||
}
|
||||
|
||||
void Circuit::remove_net (Net *net)
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
if (net->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Net not withing given circuit")));
|
||||
}
|
||||
|
||||
m_nets.erase (net);
|
||||
}
|
||||
|
||||
void Circuit::join_nets (Net *net, Net *with)
|
||||
{
|
||||
if (! net) {
|
||||
return;
|
||||
}
|
||||
if (net == with || ! with) {
|
||||
return;
|
||||
}
|
||||
if (net->circuit () != this || with->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Nets not withing given circuit")));
|
||||
}
|
||||
|
||||
while (with->begin_terminals () != with->end_terminals ()) {
|
||||
db::Device *device = const_cast<db::Device *> (with->begin_terminals ()->device ());
|
||||
device->connect_terminal (with->begin_terminals ()->terminal_id (), net);
|
||||
|
|
@ -368,6 +392,13 @@ void Circuit::join_nets (Net *net, Net *with)
|
|||
|
||||
void Circuit::add_device (Device *device)
|
||||
{
|
||||
if (! device) {
|
||||
return;
|
||||
}
|
||||
if (device->circuit ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device already in a circuit")));
|
||||
}
|
||||
|
||||
device->set_circuit (this);
|
||||
|
||||
size_t id = 0;
|
||||
|
|
@ -382,11 +413,25 @@ void Circuit::add_device (Device *device)
|
|||
|
||||
void Circuit::remove_device (Device *device)
|
||||
{
|
||||
if (! device) {
|
||||
return;
|
||||
}
|
||||
if (device->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device not withing given circuit")));
|
||||
}
|
||||
|
||||
m_devices.erase (device);
|
||||
}
|
||||
|
||||
void Circuit::add_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
if (! subcircuit) {
|
||||
return;
|
||||
}
|
||||
if (subcircuit->circuit ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Subcircuit already in a circuit")));
|
||||
}
|
||||
|
||||
subcircuit->set_circuit (this);
|
||||
|
||||
size_t id = 0;
|
||||
|
|
@ -401,6 +446,13 @@ void Circuit::add_subcircuit (SubCircuit *subcircuit)
|
|||
|
||||
void Circuit::remove_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
if (! subcircuit) {
|
||||
return;
|
||||
}
|
||||
if (subcircuit->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Subcircuit not withing given circuit")));
|
||||
}
|
||||
|
||||
m_subcircuits.erase (subcircuit);
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +468,12 @@ void Circuit::unregister_ref (SubCircuit *r)
|
|||
|
||||
void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
|
||||
{
|
||||
tl_assert (subcircuit != 0);
|
||||
if (! subcircuit) {
|
||||
return;
|
||||
}
|
||||
if (subcircuit->circuit () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Subcircuit not withing given circuit")));
|
||||
}
|
||||
|
||||
const db::Circuit *c = subcircuit->circuit_ref ();
|
||||
|
||||
|
|
@ -426,15 +483,21 @@ void Circuit::flatten_subcircuit (SubCircuit *subcircuit)
|
|||
|
||||
for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
|
||||
// TODO: cannot join pins through subcircuits currently
|
||||
tl_assert (n->pin_count () <= 1);
|
||||
|
||||
db::Net *outside_net = 0;
|
||||
|
||||
if (n->pin_count () > 0) {
|
||||
|
||||
size_t pin_id = n->begin_pins ()->pin_id ();
|
||||
outside_net = subcircuit->net_for_pin (pin_id);
|
||||
for (db::Net::const_pin_iterator p = n->begin_pins (); p != n->end_pins (); ++p) {
|
||||
|
||||
size_t pin_id = p->pin_id ();
|
||||
|
||||
if (outside_net) {
|
||||
join_nets (outside_net, subcircuit->net_for_pin (pin_id));
|
||||
} else {
|
||||
outside_net = subcircuit->net_for_pin (pin_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
|
|||
|
|
@ -86,34 +86,33 @@ private:
|
|||
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs ()
|
||||
: AsIfFlatEdgePairs (), m_deep_layer ()
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatEdgePairs (), m_deep_layer (dss.create_edge_pair_layer (si))
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
set_deep_layer (dss.create_edge_pair_layer (si));
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
: AsIfFlatEdgePairs (), m_deep_layer (dss.create_edge_pair_layer (si, trans))
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
set_deep_layer (dss.create_edge_pair_layer (si, trans));
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const DeepEdgePairs &other)
|
||||
: AsIfFlatEdgePairs (other),
|
||||
m_deep_layer (other.m_deep_layer.copy ())
|
||||
: AsIfFlatEdgePairs (other), db::DeepShapeCollectionDelegateBase (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const DeepLayer &dl)
|
||||
: AsIfFlatEdgePairs (), m_deep_layer (dl)
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
set_deep_layer (dl);
|
||||
}
|
||||
|
||||
DeepEdgePairs::~DeepEdgePairs ()
|
||||
|
|
@ -133,7 +132,7 @@ EdgePairsIteratorDelegate *DeepEdgePairs::begin () const
|
|||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> DeepEdgePairs::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
|
@ -141,7 +140,7 @@ std::pair<db::RecursiveShapeIterator, db::ICplxTrans> DeepEdgePairs::begin_iter
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -151,10 +150,10 @@ size_t DeepEdgePairs::size () const
|
|||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size ();
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
@ -167,7 +166,7 @@ std::string DeepEdgePairs::to_string (size_t nmax) const
|
|||
|
||||
Box DeepEdgePairs::bbox () const
|
||||
{
|
||||
return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ());
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
bool DeepEdgePairs::empty () const
|
||||
|
|
@ -241,14 +240,20 @@ EdgePairsDelegate *DeepEdgePairs::filtered (const EdgePairFilterBase &filter) co
|
|||
return AsIfFlatEdgePairs::filtered (filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const
|
||||
{
|
||||
return shape_collection_processed_impl<db::EdgePair, db::Polygon, db::DeepRegion> (deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const
|
||||
{
|
||||
db::DeepLayer new_layer = m_deep_layer.derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
db::Polygon poly = s->edge_pair ().normalized ().to_polygon (e);
|
||||
if (poly.vertices () >= 3) {
|
||||
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
|
|
@ -261,12 +266,12 @@ RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const
|
|||
|
||||
EdgesDelegate *DeepEdgePairs::generic_edges (bool first, bool second) const
|
||||
{
|
||||
db::DeepLayer new_layer = m_deep_layer.derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
db::EdgePair ep = s->edge_pair ();
|
||||
if (first) {
|
||||
output.insert (ep.first ());
|
||||
|
|
@ -304,8 +309,8 @@ EdgePairsDelegate *DeepEdgePairs::in (const EdgePairs &other, bool invert) const
|
|||
bool DeepEdgePairs::equals (const EdgePairs &other) const
|
||||
{
|
||||
const DeepEdgePairs *other_delegate = dynamic_cast<const DeepEdgePairs *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()
|
||||
&& other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) {
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatEdgePairs::equals (other);
|
||||
|
|
@ -315,8 +320,8 @@ bool DeepEdgePairs::equals (const EdgePairs &other) const
|
|||
bool DeepEdgePairs::less (const EdgePairs &other) const
|
||||
{
|
||||
const DeepEdgePairs *other_delegate = dynamic_cast<const DeepEdgePairs *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) {
|
||||
return other_delegate->m_deep_layer.layer () < m_deep_layer.layer ();
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatEdgePairs::less (other);
|
||||
}
|
||||
|
|
@ -324,13 +329,12 @@ bool DeepEdgePairs::less (const EdgePairs &other) const
|
|||
|
||||
void DeepEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
m_deep_layer.insert_into (layout, into_cell, into_layer);
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
void DeepEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace db {
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepEdgePairs
|
||||
: public db::AsIfFlatEdgePairs
|
||||
: public db::AsIfFlatEdgePairs, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepEdgePairs ();
|
||||
|
|
@ -63,6 +63,7 @@ public:
|
|||
|
||||
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter);
|
||||
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const;
|
||||
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
|
||||
|
||||
virtual EdgePairsDelegate *add_in_place (const EdgePairs &other);
|
||||
virtual EdgePairsDelegate *add (const EdgePairs &other) const;
|
||||
|
|
@ -80,21 +81,14 @@ public:
|
|||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
const DeepLayer &deep_layer () const
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
|
||||
DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
DeepEdgePairs &operator= (const DeepEdgePairs &other);
|
||||
|
||||
DeepLayer m_deep_layer;
|
||||
|
||||
void init ();
|
||||
EdgesDelegate *generic_edges (bool first, bool second) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -96,14 +96,16 @@ private:
|
|||
// DeepEdges implementation
|
||||
|
||||
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, bool as_edges)
|
||||
: AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si, as_edges)), m_merged_edges ()
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
{
|
||||
set_deep_layer (dss.create_edge_layer (si, as_edges));
|
||||
init ();
|
||||
}
|
||||
|
||||
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges, bool merged_semantics)
|
||||
: AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si, as_edges, trans)), m_merged_edges ()
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
{
|
||||
set_deep_layer (dss.create_edge_layer (si, as_edges, trans));
|
||||
init ();
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
|
@ -111,7 +113,7 @@ DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
|||
DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
{
|
||||
m_deep_layer = dss.create_from_flat (other);
|
||||
set_deep_layer (dss.create_from_flat (other));
|
||||
|
||||
init ();
|
||||
set_merged_semantics (other.merged_semantics ());
|
||||
|
|
@ -124,8 +126,9 @@ DeepEdges::DeepEdges ()
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges (const DeepLayer &dl)
|
||||
: AsIfFlatEdges (), m_deep_layer (dl)
|
||||
: AsIfFlatEdges ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
init ();
|
||||
}
|
||||
|
||||
|
|
@ -135,8 +138,7 @@ DeepEdges::~DeepEdges ()
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges (const DeepEdges &other)
|
||||
: AsIfFlatEdges (other),
|
||||
m_deep_layer (other.m_deep_layer.copy ()),
|
||||
: AsIfFlatEdges (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_edges_valid (other.m_merged_edges_valid),
|
||||
m_is_merged (other.m_is_merged)
|
||||
{
|
||||
|
|
@ -145,6 +147,25 @@ DeepEdges::DeepEdges (const DeepEdges &other)
|
|||
}
|
||||
}
|
||||
|
||||
DeepEdges &
|
||||
DeepEdges::operator= (const DeepEdges &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
AsIfFlatEdges::operator= (other);
|
||||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
|
||||
m_merged_edges_valid = other.m_merged_edges_valid;
|
||||
m_is_merged = other.m_is_merged;
|
||||
if (m_merged_edges_valid) {
|
||||
m_merged_edges = other.m_merged_edges;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DeepEdges::init ()
|
||||
{
|
||||
m_merged_edges_valid = false;
|
||||
|
|
@ -182,7 +203,7 @@ DeepEdges::begin_merged () const
|
|||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
DeepEdges::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
|
@ -190,7 +211,7 @@ DeepEdges::begin_iter () const
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -262,8 +283,8 @@ DeepEdges::iter () const
|
|||
bool DeepEdges::equals (const Edges &other) const
|
||||
{
|
||||
const DeepEdges *other_delegate = dynamic_cast<const DeepEdges *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()
|
||||
&& other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) {
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatEdges::equals (other);
|
||||
|
|
@ -273,8 +294,8 @@ bool DeepEdges::equals (const Edges &other) const
|
|||
bool DeepEdges::less (const Edges &other) const
|
||||
{
|
||||
const DeepEdges *other_delegate = dynamic_cast<const DeepEdges *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) {
|
||||
return other_delegate->m_deep_layer.layer () < m_deep_layer.layer ();
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatEdges::less (other);
|
||||
}
|
||||
|
|
@ -384,27 +405,27 @@ DeepEdges::ensure_merged_edges_valid () const
|
|||
if (m_is_merged) {
|
||||
|
||||
// NOTE: this will reuse the deep layer reference
|
||||
m_merged_edges = m_deep_layer;
|
||||
m_merged_edges = deep_layer ();
|
||||
|
||||
} else {
|
||||
|
||||
m_merged_edges = m_deep_layer.derived ();
|
||||
m_merged_edges = deep_layer ().derived ();
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
db::hier_clusters<db::Edge> hc;
|
||||
db::Connectivity conn;
|
||||
conn.connect (m_deep_layer);
|
||||
conn.connect (deep_layer ());
|
||||
hc.set_base_verbosity (base_verbosity() + 10);
|
||||
hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Edges, conn);
|
||||
hc.build (layout, deep_layer ().initial_cell (), conn);
|
||||
|
||||
// collect the clusters and merge them into big polygons
|
||||
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
|
||||
// hopefully more efficient that collecting everything and will lead to reuse of parts.
|
||||
|
||||
ClusterMerger cm (m_deep_layer.layer (), hc, report_progress (), progress_desc ());
|
||||
ClusterMerger cm (deep_layer ().layer (), hc, report_progress (), progress_desc ());
|
||||
cm.set_base_verbosity (base_verbosity () + 10);
|
||||
|
||||
// TODO: iterate only over the called cells?
|
||||
|
|
@ -436,17 +457,17 @@ DeepEdges::set_is_merged (bool f)
|
|||
void
|
||||
DeepEdges::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
m_deep_layer.insert_into (layout, into_cell, into_layer);
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
size_t DeepEdges::size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size ();
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
@ -454,7 +475,7 @@ size_t DeepEdges::size () const
|
|||
|
||||
Box DeepEdges::bbox () const
|
||||
{
|
||||
return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ());
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
DeepEdges::length_type DeepEdges::length (const db::Box &box) const
|
||||
|
|
@ -504,157 +525,37 @@ EdgesDelegate *DeepEdges::process_in_place (const EdgeProcessorBase &filter)
|
|||
EdgesDelegate *
|
||||
DeepEdges::processed (const EdgeProcessorBase &filter) const
|
||||
{
|
||||
return processed_impl<db::Edge, db::DeepEdges> (filter);
|
||||
return shape_collection_processed_impl<db::Edge, db::Edge, db::DeepEdges> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
DeepEdges::processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filter) const
|
||||
{
|
||||
return processed_impl<db::EdgePair, db::DeepEdgePairs> (filter);
|
||||
return shape_collection_processed_impl<db::Edge, db::EdgePair, db::DeepEdgePairs> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepEdges::processed_to_polygons (const EdgeToPolygonProcessorBase &filter) const
|
||||
{
|
||||
return processed_impl<db::Polygon, db::DeepRegion> (filter);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class Result> struct delivery;
|
||||
|
||||
template <>
|
||||
struct delivery<db::Polygon>
|
||||
{
|
||||
delivery (db::Layout *layout, db::Shapes *shapes)
|
||||
: mp_layout (layout), mp_shapes (shapes)
|
||||
{ }
|
||||
|
||||
void put (const db::Polygon &result)
|
||||
{
|
||||
tl::MutexLocker locker (&mp_layout->lock ());
|
||||
mp_shapes->insert (db::PolygonRef (result, mp_layout->shape_repository ()));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
db::Shapes *mp_shapes;
|
||||
};
|
||||
|
||||
template <class Result>
|
||||
struct delivery
|
||||
{
|
||||
delivery (db::Layout *, db::Shapes *shapes)
|
||||
: mp_shapes (shapes)
|
||||
{ }
|
||||
|
||||
void put (const Result &result)
|
||||
{
|
||||
mp_shapes->insert (result);
|
||||
}
|
||||
|
||||
private:
|
||||
db::Shapes *mp_shapes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class Result, class OutputContainer>
|
||||
OutputContainer *
|
||||
DeepEdges::processed_impl (const edge_processor<Result> &filter) const
|
||||
{
|
||||
const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
|
||||
|
||||
std::auto_ptr<VariantsCollectorBase> vars;
|
||||
if (filter.vars ()) {
|
||||
|
||||
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
|
||||
|
||||
vars->collect (edges.layout (), edges.initial_cell ());
|
||||
|
||||
if (filter.wants_variants ()) {
|
||||
const_cast<db::DeepLayer &> (edges).separate_variants (*vars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (edges.layout ());
|
||||
|
||||
std::vector<Result> heap;
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
|
||||
std::auto_ptr<OutputContainer> res (new OutputContainer (edges.derived ()));
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
res->set_merged_semantics (false);
|
||||
}
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (filter.requires_raw_input () ? edges.layer () : edges.layer ());
|
||||
|
||||
if (vars.get ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes *st;
|
||||
if (vv.size () == 1) {
|
||||
st = & c->shapes (res->deep_layer ().layer ());
|
||||
} else {
|
||||
st = & to_commit [c->cell_index ()] [v->first];
|
||||
}
|
||||
|
||||
delivery<Result> delivery (&layout, st);
|
||||
|
||||
const db::ICplxTrans &tr = v->first;
|
||||
db::ICplxTrans trinv = tr.inverted ();
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
|
||||
heap.clear ();
|
||||
filter.process (si->edge ().transformed (tr), heap);
|
||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||
delivery.put (i->transformed (trinv));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
delivery<Result> delivery (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
|
||||
filter.process (si->edge (), heap);
|
||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||
delivery.put (*i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! to_commit.empty () && vars.get ()) {
|
||||
res->deep_layer ().commit_shapes (*vars, to_commit);
|
||||
}
|
||||
|
||||
if (filter.result_is_merged ()) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
return res.release ();
|
||||
return shape_collection_processed_impl<db::Edge, db::Polygon, db::DeepRegion> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepEdges::filter_in_place (const EdgeFilterBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return filtered (filter);
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepEdges::filtered (const EdgeFilterBase &filter) const
|
||||
{
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
DeepEdges *
|
||||
DeepEdges::apply_filter (const EdgeFilterBase &filter) const
|
||||
{
|
||||
const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
|
||||
|
||||
|
|
@ -730,7 +631,7 @@ EdgesDelegate *DeepEdges::merged_in_place ()
|
|||
ensure_merged_edges_valid ();
|
||||
|
||||
// NOTE: this makes both layers share the same resource
|
||||
m_deep_layer = m_merged_edges;
|
||||
set_deep_layer (m_merged_edges);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
@ -753,17 +654,17 @@ EdgesDelegate *DeepEdges::merged () const
|
|||
DeepLayer
|
||||
DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
db::EdgeBoolAndOrNotLocalOperation local_op (op);
|
||||
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
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 ());
|
||||
|
||||
proc.run (&local_op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
|
@ -771,17 +672,17 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
|
|||
DeepLayer
|
||||
DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
db::EdgeToPolygonLocalOperation op (outside, include_borders);
|
||||
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
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 ());
|
||||
|
||||
proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
|
@ -1051,7 +952,7 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
|
|||
db::Connectivity conn (db::Connectivity::EdgesConnectByPoints);
|
||||
conn.connect (edges);
|
||||
hc.set_base_verbosity (base_verbosity () + 10);
|
||||
hc.build (layout, edges.initial_cell (), db::ShapeIterator::Edges, conn);
|
||||
hc.build (layout, edges.initial_cell (), conn);
|
||||
|
||||
// TODO: iterate only over the called cells?
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
|
@ -1278,7 +1179,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
scanner.insert1 (&subject, 0);
|
||||
}
|
||||
|
|
@ -1295,7 +1196,7 @@ public:
|
|||
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
if (interacting.find (subject) == interacting.end ()) {
|
||||
result.insert (subject);
|
||||
|
|
@ -1374,7 +1275,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
scanner.insert1 (&subject, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class DeepRegion;
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepEdges
|
||||
: public db::AsIfFlatEdges
|
||||
: public db::AsIfFlatEdges, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepEdges ();
|
||||
|
|
@ -144,26 +144,21 @@ public:
|
|||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
const DeepLayer &deep_layer () const
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
return this;
|
||||
}
|
||||
|
||||
DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
void set_is_merged (bool f);
|
||||
|
||||
protected:
|
||||
virtual void merged_semantics_changed ();
|
||||
void set_is_merged (bool f);
|
||||
|
||||
private:
|
||||
friend class DeepRegion;
|
||||
|
||||
DeepEdges &operator= (const DeepEdges &other);
|
||||
|
||||
DeepLayer m_deep_layer;
|
||||
mutable DeepLayer m_merged_edges;
|
||||
mutable bool m_merged_edges_valid;
|
||||
bool m_is_merged;
|
||||
|
|
@ -178,6 +173,8 @@ private:
|
|||
virtual RegionDelegate *pull_generic (const Region ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const;
|
||||
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
|
||||
|
||||
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "dbRegionUtils.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepEdgePairs.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbFlatRegion.h"
|
||||
#include "dbHierProcessor.h"
|
||||
|
|
@ -101,14 +102,16 @@ private:
|
|||
// DeepRegion implementation
|
||||
|
||||
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
: AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons ()
|
||||
: AsIfFlatRegion (), m_merged_polygons ()
|
||||
{
|
||||
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count));
|
||||
init ();
|
||||
}
|
||||
|
||||
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count)
|
||||
: AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans)), m_merged_polygons ()
|
||||
: AsIfFlatRegion (), m_merged_polygons ()
|
||||
{
|
||||
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans));
|
||||
init ();
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
|
@ -116,7 +119,7 @@ DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, c
|
|||
DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss)
|
||||
: AsIfFlatRegion (), m_merged_polygons ()
|
||||
{
|
||||
m_deep_layer = dss.create_from_flat (other, false);
|
||||
set_deep_layer (dss.create_from_flat (other, false));
|
||||
|
||||
init ();
|
||||
set_merged_semantics (other.merged_semantics ());
|
||||
|
|
@ -129,8 +132,9 @@ DeepRegion::DeepRegion ()
|
|||
}
|
||||
|
||||
DeepRegion::DeepRegion (const DeepLayer &dl)
|
||||
: AsIfFlatRegion (), m_deep_layer (dl)
|
||||
: AsIfFlatRegion ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
init ();
|
||||
}
|
||||
|
||||
|
|
@ -140,8 +144,7 @@ DeepRegion::~DeepRegion ()
|
|||
}
|
||||
|
||||
DeepRegion::DeepRegion (const DeepRegion &other)
|
||||
: AsIfFlatRegion (other),
|
||||
m_deep_layer (other.m_deep_layer.copy ()),
|
||||
: AsIfFlatRegion (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_polygons_valid (other.m_merged_polygons_valid),
|
||||
m_is_merged (other.m_is_merged)
|
||||
{
|
||||
|
|
@ -150,6 +153,25 @@ DeepRegion::DeepRegion (const DeepRegion &other)
|
|||
}
|
||||
}
|
||||
|
||||
DeepRegion &
|
||||
DeepRegion::operator= (const DeepRegion &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
AsIfFlatRegion::operator= (other);
|
||||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
|
||||
m_merged_polygons_valid = other.m_merged_polygons_valid;
|
||||
m_is_merged = other.m_is_merged;
|
||||
if (m_merged_polygons_valid) {
|
||||
m_merged_polygons = other.m_merged_polygons;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DeepRegion::init ()
|
||||
{
|
||||
m_merged_polygons_valid = false;
|
||||
|
|
@ -192,7 +214,7 @@ DeepRegion::begin_merged () const
|
|||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
DeepRegion::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
|
@ -200,7 +222,7 @@ DeepRegion::begin_iter () const
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -273,8 +295,8 @@ bool
|
|||
DeepRegion::equals (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_delegate = dynamic_cast<const DeepRegion *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()
|
||||
&& other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) {
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatRegion::equals (other);
|
||||
|
|
@ -285,8 +307,8 @@ bool
|
|||
DeepRegion::less (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_delegate = dynamic_cast<const DeepRegion *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) {
|
||||
return other_delegate->m_deep_layer.layer () < m_deep_layer.layer ();
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatRegion::less (other);
|
||||
}
|
||||
|
|
@ -421,27 +443,27 @@ DeepRegion::ensure_merged_polygons_valid () const
|
|||
if (m_is_merged) {
|
||||
|
||||
// NOTE: this will reuse the deep layer reference
|
||||
m_merged_polygons = m_deep_layer;
|
||||
m_merged_polygons = deep_layer ();
|
||||
|
||||
} else {
|
||||
|
||||
m_merged_polygons = m_deep_layer.derived ();
|
||||
m_merged_polygons = deep_layer ().derived ();
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
db::hier_clusters<db::PolygonRef> hc;
|
||||
db::Connectivity conn;
|
||||
conn.connect (m_deep_layer);
|
||||
conn.connect (deep_layer ());
|
||||
hc.set_base_verbosity (base_verbosity () + 10);
|
||||
hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn);
|
||||
hc.build (layout, deep_layer ().initial_cell (), conn);
|
||||
|
||||
// collect the clusters and merge them into big polygons
|
||||
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
|
||||
// hopefully more efficient that collecting everything and will lead to reuse of parts.
|
||||
|
||||
ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence (), report_progress (), progress_desc ());
|
||||
ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence (), report_progress (), progress_desc ());
|
||||
cm.set_base_verbosity (base_verbosity () + 10);
|
||||
|
||||
// TODO: iterate only over the called cells?
|
||||
|
|
@ -473,7 +495,7 @@ DeepRegion::set_is_merged (bool f)
|
|||
void
|
||||
DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
m_deep_layer.insert_into (layout, into_cell, into_layer);
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
|
|
@ -523,17 +545,17 @@ DeepRegion::not_with (const Region &other) const
|
|||
DeepLayer
|
||||
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
db::BoolAndOrNotLocalOperation op (and_op);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), m_deep_layer.breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
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 ());
|
||||
|
||||
proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
|
@ -648,10 +670,10 @@ DeepRegion::size () const
|
|||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size ();
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
@ -726,7 +748,7 @@ DeepRegion::perimeter (const db::Box &box) const
|
|||
Box
|
||||
DeepRegion::bbox () const
|
||||
{
|
||||
return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ());
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
@ -933,163 +955,37 @@ DeepRegion::process_in_place (const PolygonProcessorBase &filter)
|
|||
EdgesDelegate *
|
||||
DeepRegion::processed_to_edges (const PolygonToEdgeProcessorBase &filter) const
|
||||
{
|
||||
return processed_impl<db::Edge, db::DeepEdges> (filter);
|
||||
return shape_collection_processed_impl<db::Polygon, db::Edge, db::DeepEdges> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
DeepRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &filter) const
|
||||
{
|
||||
return processed_impl<db::EdgePair, db::DeepEdgePairs> (filter);
|
||||
return shape_collection_processed_impl<db::Polygon, db::EdgePair, db::DeepEdgePairs> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::processed (const PolygonProcessorBase &filter) const
|
||||
{
|
||||
return processed_impl<db::Polygon, db::DeepRegion> (filter);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class Result> struct delivery;
|
||||
|
||||
template <>
|
||||
struct delivery<db::Polygon>
|
||||
{
|
||||
delivery (db::Layout *layout, db::Shapes *shapes)
|
||||
: mp_layout (layout), mp_shapes (shapes)
|
||||
{ }
|
||||
|
||||
void put (const db::Polygon &result)
|
||||
{
|
||||
tl::MutexLocker locker (&mp_layout->lock ());
|
||||
mp_shapes->insert (db::PolygonRef (result, mp_layout->shape_repository ()));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
db::Shapes *mp_shapes;
|
||||
};
|
||||
|
||||
template <class Result>
|
||||
struct delivery
|
||||
{
|
||||
delivery (db::Layout *, db::Shapes *shapes)
|
||||
: mp_shapes (shapes)
|
||||
{ }
|
||||
|
||||
void put (const Result &result)
|
||||
{
|
||||
mp_shapes->insert (result);
|
||||
}
|
||||
|
||||
private:
|
||||
db::Shapes *mp_shapes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class Result, class OutputContainer>
|
||||
OutputContainer *
|
||||
DeepRegion::processed_impl (const polygon_processor<Result> &filter) const
|
||||
{
|
||||
const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
|
||||
|
||||
std::auto_ptr<VariantsCollectorBase> vars;
|
||||
if (filter.vars ()) {
|
||||
|
||||
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
|
||||
|
||||
vars->collect (polygons.layout (), polygons.initial_cell ());
|
||||
|
||||
if (filter.wants_variants ()) {
|
||||
const_cast<db::DeepLayer &> (polygons).separate_variants (*vars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (polygons.layout ());
|
||||
|
||||
std::vector<Result> heap;
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
|
||||
std::auto_ptr<OutputContainer> res (new OutputContainer (polygons.derived ()));
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
res->set_merged_semantics (false);
|
||||
}
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (polygons.layer ());
|
||||
|
||||
if (vars.get ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes *st;
|
||||
if (vv.size () == 1) {
|
||||
st = & c->shapes (res->deep_layer ().layer ());
|
||||
} else {
|
||||
st = & to_commit [c->cell_index ()] [v->first];
|
||||
}
|
||||
|
||||
delivery<Result> delivery (&layout, st);
|
||||
|
||||
const db::ICplxTrans &tr = v->first;
|
||||
db::ICplxTrans trinv = tr.inverted ();
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
poly.transform (tr);
|
||||
heap.clear ();
|
||||
filter.process (poly, heap);
|
||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||
delivery.put (i->transformed (trinv));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
delivery<Result> delivery (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
heap.clear ();
|
||||
filter.process (poly, heap);
|
||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||
delivery.put (*i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! to_commit.empty () && vars.get ()) {
|
||||
res->deep_layer ().commit_shapes (*vars, to_commit);
|
||||
}
|
||||
|
||||
if (filter.result_is_merged ()) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
return res.release ();
|
||||
return shape_collection_processed_impl<db::Polygon, db::Polygon, db::DeepRegion> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::filter_in_place (const PolygonFilterBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return filtered (filter);
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::filtered (const PolygonFilterBase &filter) const
|
||||
{
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
DeepRegion *
|
||||
DeepRegion::apply_filter (const PolygonFilterBase &filter) const
|
||||
{
|
||||
const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
|
||||
|
||||
|
|
@ -1170,7 +1066,7 @@ DeepRegion::merged_in_place ()
|
|||
ensure_merged_polygons_valid ();
|
||||
|
||||
// NOTE: this makes both layers share the same resource
|
||||
m_deep_layer = m_merged_polygons;
|
||||
set_deep_layer (m_merged_polygons);
|
||||
|
||||
set_is_merged (true);
|
||||
return this;
|
||||
|
|
@ -1205,21 +1101,21 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
db::hier_clusters<db::PolygonRef> hc;
|
||||
db::Connectivity conn;
|
||||
conn.connect (m_deep_layer);
|
||||
conn.connect (deep_layer ());
|
||||
hc.set_base_verbosity (base_verbosity () + 10);
|
||||
hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn);
|
||||
hc.build (layout, deep_layer ().initial_cell (), conn);
|
||||
|
||||
// collect the clusters and merge them into big polygons
|
||||
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
|
||||
// hopefully more efficient that collecting everything and will lead to reuse of parts.
|
||||
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence, report_progress (), progress_desc ());
|
||||
ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence, report_progress (), progress_desc ());
|
||||
cm.set_base_verbosity (base_verbosity () + 10);
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
|
@ -1289,29 +1185,6 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct XYAnisotropyAndMagnificationReducer
|
||||
: public db::TransformationReducer
|
||||
{
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
double a = trans.angle ();
|
||||
if (a > 180.0 - db::epsilon) {
|
||||
a -= 180.0;
|
||||
}
|
||||
return db::ICplxTrans (trans.mag (), a, false, db::Vector ());
|
||||
}
|
||||
|
||||
db::Trans reduce (const db::Trans &trans) const
|
||||
{
|
||||
return db::Trans (trans.angle () % 2, false, db::Vector ());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
||||
{
|
||||
|
|
@ -1502,7 +1375,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
const_cast<db::Cell *> (&polygons.initial_cell ()),
|
||||
other_deep ? &other_deep->deep_layer ().layout () : const_cast<db::Layout *> (&polygons.layout ()),
|
||||
other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast<db::Cell *> (&polygons.initial_cell ()),
|
||||
m_deep_layer.breakout_cells (),
|
||||
deep_layer ().breakout_cells (),
|
||||
other_deep ? other_deep->deep_layer ().breakout_cells () : 0);
|
||||
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -1870,6 +1743,143 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct TextResultInserter
|
||||
{
|
||||
typedef db::TextRef value_type;
|
||||
|
||||
TextResultInserter (std::unordered_set<db::TextRef> &result)
|
||||
: mp_result (&result)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::TextRef &e)
|
||||
{
|
||||
(*mp_result).insert (e);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<db::TextRef> *mp_result;
|
||||
};
|
||||
|
||||
class PullWithTextLocalOperation
|
||||
: public local_operation<db::PolygonRef, db::TextRef, db::TextRef>
|
||||
{
|
||||
public:
|
||||
PullWithTextLocalOperation ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *, const shape_interactions<db::PolygonRef, db::TextRef> &interactions, std::unordered_set<db::TextRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Polygon, size_t, db::TextRef, size_t> scanner;
|
||||
|
||||
TextResultInserter inserter (result);
|
||||
region_to_text_interaction_filter<TextResultInserter, db::TextRef> filter (inserter, false);
|
||||
|
||||
for (shape_interactions<db::PolygonRef, db::TextRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::PolygonRef, db::TextRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
scanner.insert2 (& interactions.intruder_shape (*j), 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::PolygonRef &subject = interactions.subject_shape (i->first);
|
||||
heap.push_back (subject.obj ().transformed (subject.trans ()));
|
||||
|
||||
scanner.insert1 (&heap.back (), 0);
|
||||
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::TextRef> ());
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
return Drop;
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Pull texts from second by their geometric relation to first"));
|
||||
}
|
||||
};
|
||||
|
||||
class InteractingWithTextLocalOperation
|
||||
: public local_operation<db::PolygonRef, db::TextRef, db::PolygonRef>
|
||||
{
|
||||
public:
|
||||
InteractingWithTextLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::TextRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Polygon, size_t, db::TextRef, size_t> scanner;
|
||||
|
||||
ResultInserter inserter (layout, result);
|
||||
region_to_text_interaction_filter<ResultInserter, db::TextRef> filter (inserter, m_inverse);
|
||||
|
||||
for (shape_interactions<db::PolygonRef, db::Text>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::PolygonRef, db::Text>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
scanner.insert2 (& interactions.intruder_shape (*j), 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::PolygonRef &subject = interactions.subject_shape (i->first);
|
||||
heap.push_back (subject.obj ().transformed (subject.trans ()));
|
||||
|
||||
scanner.insert1 (&heap.back (), 0);
|
||||
if (m_inverse) {
|
||||
filter.preset (&heap.back ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::TextRef> ());
|
||||
if (m_inverse) {
|
||||
filter.fill_output ();
|
||||
}
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
if (!m_inverse) {
|
||||
return Drop;
|
||||
} else {
|
||||
return Copy;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select regions by their geometric relation to texts"));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
|
|
@ -2016,4 +2026,70 @@ DeepRegion::pull_generic (const Edges &other) const
|
|||
return res;
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
DeepRegion::pull_generic (const Texts &other) const
|
||||
{
|
||||
std::auto_ptr<db::DeepTexts> dr_holder;
|
||||
const db::DeepTexts *other_deep = dynamic_cast<const db::DeepTexts *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepTexts (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
// in "inside" mode, the first argument needs to be merged too
|
||||
const db::DeepLayer &polygons = deep_layer ();
|
||||
const db::DeepLayer &other_texts = other_deep->deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::PullWithTextLocalOperation op;
|
||||
|
||||
db::local_processor<db::PolygonRef, db::TextRef, db::TextRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ());
|
||||
|
||||
db::DeepTexts *res = new db::DeepTexts (dl_out);
|
||||
res->set_is_merged (is_merged ());
|
||||
return res;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) const
|
||||
{
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
||||
std::auto_ptr<db::DeepTexts> dr_holder;
|
||||
const db::DeepTexts *other_deep = dynamic_cast<const db::DeepTexts *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepTexts (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::InteractingWithTextLocalOperation op (inverse);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::TextRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
if (split_after) {
|
||||
proc.set_area_ratio (polygons.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after) {
|
||||
res->set_is_merged (merged_semantics () || is_merged ());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace db {
|
|||
* @brief A deep, polygon-set delegate
|
||||
*/
|
||||
class DB_PUBLIC DeepRegion
|
||||
: public AsIfFlatRegion
|
||||
: public AsIfFlatRegion, public DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::layer<db::Polygon, db::unstable_layer_tag> polygon_layer_type;
|
||||
|
|
@ -159,27 +159,23 @@ public:
|
|||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
const DeepLayer &deep_layer () const
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
return this;
|
||||
}
|
||||
|
||||
DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
void set_is_merged (bool f);
|
||||
|
||||
protected:
|
||||
virtual void merged_semantics_changed ();
|
||||
virtual void min_coherence_changed ();
|
||||
void set_is_merged (bool f);
|
||||
|
||||
private:
|
||||
friend class DeepEdges;
|
||||
friend class DeepTexts;
|
||||
|
||||
DeepRegion &operator= (const DeepRegion &other);
|
||||
|
||||
DeepLayer m_deep_layer;
|
||||
mutable DeepLayer m_merged_polygons;
|
||||
mutable bool m_merged_polygons_valid;
|
||||
bool m_is_merged;
|
||||
|
|
@ -192,8 +188,11 @@ private:
|
|||
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &other) const;
|
||||
virtual TextsDelegate *pull_generic (const Texts &other) const;
|
||||
DeepRegion *apply_filter (const PolygonFilterBase &filter) const;
|
||||
|
||||
template <class Result, class OutputContainer> OutputContainer *processed_impl (const polygon_processor<Result> &filter) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,14 @@
|
|||
#include "dbCellMapping.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepEdgePairs.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include "tlTimer.h"
|
||||
|
||||
|
|
@ -48,6 +55,30 @@ DeepLayer::DeepLayer (const Region ®ion)
|
|||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const Texts &texts)
|
||||
: mp_store (), m_layout (0), m_layer (0)
|
||||
{
|
||||
const db::DeepTexts *dr = dynamic_cast<db::DeepTexts *> (texts.delegate ());
|
||||
tl_assert (dr != 0);
|
||||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const Edges &edges)
|
||||
: mp_store (), m_layout (0), m_layer (0)
|
||||
{
|
||||
const db::DeepEdges *dr = dynamic_cast<db::DeepEdges *> (edges.delegate ());
|
||||
tl_assert (dr != 0);
|
||||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const EdgePairs &edge_pairs)
|
||||
: mp_store (), m_layout (0), m_layer (0)
|
||||
{
|
||||
const db::DeepEdgePairs *dr = dynamic_cast<db::DeepEdgePairs *> (edge_pairs.delegate ());
|
||||
tl_assert (dr != 0);
|
||||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const DeepLayer &x)
|
||||
: mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer)
|
||||
{
|
||||
|
|
@ -459,9 +490,39 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC
|
|||
return dl;
|
||||
}
|
||||
|
||||
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (const db::Region ®ion) const
|
||||
DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans)
|
||||
{
|
||||
return layer_for_flat (tl::id_of (region.delegate ()));
|
||||
// reuse existing layer
|
||||
std::pair<bool, DeepLayer> lff = layer_for_flat (tl::id_of (texts.delegate ()));
|
||||
if (lff.first) {
|
||||
return lff.second;
|
||||
}
|
||||
|
||||
require_singular ();
|
||||
|
||||
unsigned int layer = layout ().insert_layer ();
|
||||
|
||||
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
||||
db::Box world = db::Box::world ();
|
||||
|
||||
db::TextBuildingHierarchyBuilderShapeReceiver tb (&layout ());
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> ii = texts.begin_iter ();
|
||||
db::ICplxTrans ttop = trans * ii.second;
|
||||
while (! ii.first.at_end ()) {
|
||||
tb.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes);
|
||||
++ii.first;
|
||||
}
|
||||
|
||||
DeepLayer dl (this, 0 /*singular layout index*/, layer);
|
||||
m_layers_for_flat [tl::id_of (texts.delegate ())] = std::make_pair (dl.layout_index (), dl.layer ());
|
||||
m_flat_region_id [std::make_pair (dl.layout_index (), dl.layer ())] = tl::id_of (texts.delegate ());
|
||||
return dl;
|
||||
}
|
||||
|
||||
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (const ShapeCollection &coll) const
|
||||
{
|
||||
return layer_for_flat (tl::id_of (coll.get_delegate ()));
|
||||
}
|
||||
|
||||
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (size_t region_id) const
|
||||
|
|
@ -807,64 +868,23 @@ DeepLayer DeepShapeStore::create_copy (const DeepLayer &source, HierarchyBuilder
|
|||
|
||||
DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &si, bool as_edges, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
||||
// The chain of operators for producing edges
|
||||
db::EdgeBuildingHierarchyBuilderShapeReceiver refs (as_edges);
|
||||
|
||||
// Build the working hierarchy from the recursive shape iterator
|
||||
try {
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy")));
|
||||
db::LayoutLocker ll (&layout, true /*no update*/);
|
||||
|
||||
builder.set_shape_receiver (&refs);
|
||||
db::RecursiveShapeIterator (si).push (& builder);
|
||||
builder.set_shape_receiver (0);
|
||||
|
||||
} catch (...) {
|
||||
builder.set_shape_receiver (0);
|
||||
throw;
|
||||
}
|
||||
|
||||
return DeepLayer (this, layout_index, layer_index);
|
||||
return create_custom_layer (si, &refs, trans);
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_edge_pair_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
||||
// The chain of operators for producing the edge pairs
|
||||
db::EdgePairBuildingHierarchyBuilderShapeReceiver refs;
|
||||
return create_custom_layer (si, &refs, trans);
|
||||
}
|
||||
|
||||
// Build the working hierarchy from the recursive shape iterator
|
||||
try {
|
||||
DeepLayer DeepShapeStore::create_text_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy")));
|
||||
db::LayoutLocker ll (&layout, true /*no update*/);
|
||||
|
||||
builder.set_shape_receiver (&refs);
|
||||
db::RecursiveShapeIterator (si).push (& builder);
|
||||
builder.set_shape_receiver (0);
|
||||
|
||||
} catch (...) {
|
||||
builder.set_shape_receiver (0);
|
||||
throw;
|
||||
}
|
||||
|
||||
return DeepLayer (this, layout_index, layer_index);
|
||||
db::TextBuildingHierarchyBuilderShapeReceiver refs (&layout);
|
||||
return create_custom_layer (si, &refs, trans);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1123,6 +1143,12 @@ DeepShapeStore::insert_as_polygons (const DeepLayer &deep_layer, db::Layout *int
|
|||
s->polygon (poly);
|
||||
out.insert (poly);
|
||||
|
||||
} else if (s->is_text ()) {
|
||||
|
||||
db::Text t;
|
||||
s->text (t);
|
||||
out.insert (db::SimplePolygon (t.box ().enlarged (db::Vector (enl, enl))));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ class DeepShapeStore;
|
|||
class DeepShapeStoreState;
|
||||
class Region;
|
||||
class Edges;
|
||||
class EdgePairs;
|
||||
class Texts;
|
||||
class ShapeCollection;
|
||||
|
||||
/**
|
||||
* @brief Represents a shape collection from the deep shape store
|
||||
|
|
@ -75,6 +78,24 @@ public:
|
|||
*/
|
||||
DeepLayer (const Region ®ion);
|
||||
|
||||
/**
|
||||
* @brief Conversion operator from texts collection to DeepLayer
|
||||
* This requires the texts to be a DeepTexts. Otherwise, this constructor will assert
|
||||
*/
|
||||
DeepLayer (const Texts ®ion);
|
||||
|
||||
/**
|
||||
* @brief Conversion operator from edges collection to DeepLayer
|
||||
* This requires the edges to be a DeepEdges. Otherwise, this constructor will assert
|
||||
*/
|
||||
DeepLayer (const Edges ®ion);
|
||||
|
||||
/**
|
||||
* @brief Conversion operator from edge pairs collection to DeepLayer
|
||||
* This requires the edge pairs to be a DeepEdgePairs. Otherwise, this constructor will assert
|
||||
*/
|
||||
DeepLayer (const EdgePairs ®ion);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
|
|
@ -338,15 +359,26 @@ public:
|
|||
* After a flat layer has been created for a region, it can be retrieved
|
||||
* from the region later with layer_for_flat (region).
|
||||
*/
|
||||
DeepLayer create_from_flat (const db::Edges ®ion, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
DeepLayer create_from_flat (const db::Edges &edges, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Gets the layer for a given flat region.
|
||||
* @brief Creates a new layer from a flat text collection (or the text collection is made flat)
|
||||
*
|
||||
* This method is intended for use with singular-created DSS objects (see
|
||||
* singular constructor).
|
||||
*
|
||||
* After a flat layer has been created for a region, it can be retrieved
|
||||
* from the region later with layer_for_flat (region).
|
||||
*/
|
||||
DeepLayer create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Gets the layer for a given flat collection (Region, Edges, Texts, EdgePairs)
|
||||
*
|
||||
* If a layer has been created for a flat region with create_from_flat, it can be retrieved with this method.
|
||||
* The first return value is true in this case.
|
||||
*/
|
||||
std::pair<bool, DeepLayer> layer_for_flat (const db::Region ®ion) const;
|
||||
std::pair<bool, DeepLayer> layer_for_flat (const ShapeCollection &coll) const;
|
||||
|
||||
/**
|
||||
* @brief Same as layer_for_flat, but takes a region Id
|
||||
|
|
@ -395,6 +427,15 @@ public:
|
|||
*/
|
||||
DeepLayer create_edge_pair_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Inserts an text layer into the deep shape store
|
||||
*
|
||||
* This method will create a new layer inside the deep shape store as a
|
||||
* working copy of the original layer. This method creates a layer
|
||||
* for texts.
|
||||
*/
|
||||
DeepLayer create_text_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Inserts a polygon layer into the deep shape store using a custom preparation pipeline
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,619 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbDeepTexts.h"
|
||||
#include "dbCellGraphUtils.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbLocalOperation.h"
|
||||
#include "dbTextsUtils.h"
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An iterator delegate for the deep text collection
|
||||
* TODO: this is kind of redundant with OriginalLayerIterator ..
|
||||
*/
|
||||
class DB_PUBLIC DeepTextsIterator
|
||||
: public TextsIteratorDelegate
|
||||
{
|
||||
public:
|
||||
DeepTextsIterator (const db::RecursiveShapeIterator &iter)
|
||||
: m_iter (iter)
|
||||
{
|
||||
set ();
|
||||
}
|
||||
|
||||
virtual ~DeepTextsIterator () { }
|
||||
|
||||
virtual bool at_end () const
|
||||
{
|
||||
return m_iter.at_end ();
|
||||
}
|
||||
|
||||
virtual void increment ()
|
||||
{
|
||||
++m_iter;
|
||||
set ();
|
||||
}
|
||||
|
||||
virtual const value_type *get () const
|
||||
{
|
||||
return &m_text;
|
||||
}
|
||||
|
||||
virtual TextsIteratorDelegate *clone () const
|
||||
{
|
||||
return new DeepTextsIterator (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Texts;
|
||||
|
||||
db::RecursiveShapeIterator m_iter;
|
||||
mutable value_type m_text;
|
||||
|
||||
void set () const {
|
||||
if (! m_iter.at_end ()) {
|
||||
m_iter.shape ().text (m_text);
|
||||
m_text.transform (m_iter.trans ());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DeepTexts::DeepTexts ()
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_from_flat (other));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_text_layer (si));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_text_layer (si, trans));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const DeepTexts &other)
|
||||
: AsIfFlatTexts (other), DeepShapeCollectionDelegateBase (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepTexts &
|
||||
DeepTexts::operator= (const DeepTexts &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
AsIfFlatTexts::operator= (other);
|
||||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const DeepLayer &dl)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
}
|
||||
|
||||
DeepTexts::~DeepTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::clone () const
|
||||
{
|
||||
return new DeepTexts (*this);
|
||||
}
|
||||
|
||||
TextsIteratorDelegate *DeepTexts::begin () const
|
||||
{
|
||||
return new DeepTextsIterator (begin_iter ().first);
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> DeepTexts::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
||||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
size_t DeepTexts::size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string DeepTexts::to_string (size_t nmax) const
|
||||
{
|
||||
return db::AsIfFlatTexts::to_string (nmax);
|
||||
}
|
||||
|
||||
Box DeepTexts::bbox () const
|
||||
{
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
bool DeepTexts::empty () const
|
||||
{
|
||||
return begin_iter ().first.at_end ();
|
||||
}
|
||||
|
||||
const db::Text *DeepTexts::nth (size_t) const
|
||||
{
|
||||
throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat text collections")));
|
||||
}
|
||||
|
||||
bool DeepTexts::has_valid_texts () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator *DeepTexts::iter () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
DeepTexts::add_in_place (const Texts &other)
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const DeepTexts *other_deep = dynamic_cast <const DeepTexts *> (other.delegate ());
|
||||
if (other_deep) {
|
||||
|
||||
deep_layer ().add_from (other_deep->deep_layer ());
|
||||
|
||||
} else {
|
||||
|
||||
// non-deep to deep merge (flat)
|
||||
|
||||
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
|
||||
for (db::Texts::const_iterator p = other.begin (); ! p.at_end (); ++p) {
|
||||
shapes.insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::add (const Texts &other) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return clone ();
|
||||
} else if (empty ()) {
|
||||
return other.delegate ()->clone ();
|
||||
} else {
|
||||
DeepTexts *new_texts = dynamic_cast<DeepTexts *> (clone ());
|
||||
new_texts->add_in_place (other);
|
||||
return new_texts;
|
||||
}
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter)
|
||||
{
|
||||
// TODO: implement as really in place
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const
|
||||
{
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
|
||||
{
|
||||
const db::DeepLayer &texts = deep_layer ();
|
||||
|
||||
std::auto_ptr<VariantsCollectorBase> vars;
|
||||
if (filter.vars ()) {
|
||||
|
||||
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
|
||||
|
||||
vars->collect (texts.layout (), texts.initial_cell ());
|
||||
|
||||
if (filter.wants_variants ()) {
|
||||
const_cast<db::DeepLayer &> (texts).separate_variants (*vars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (texts.layout ());
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
|
||||
std::auto_ptr<db::DeepTexts> res (new db::DeepTexts (texts.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (texts.layer ());
|
||||
|
||||
if (vars.get ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes *st;
|
||||
if (vv.size () == 1) {
|
||||
st = & c->shapes (res->deep_layer ().layer ());
|
||||
} else {
|
||||
st = & to_commit [c->cell_index ()] [v->first];
|
||||
}
|
||||
|
||||
const db::ICplxTrans &tr = v->first;
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
|
||||
db::Text text;
|
||||
si->text (text);
|
||||
if (filter.selected (text.transformed (tr))) {
|
||||
st->insert (*si);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
|
||||
db::Text text;
|
||||
si->text (text);
|
||||
if (filter.selected (text)) {
|
||||
st.insert (*si);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! to_commit.empty () && vars.get ()) {
|
||||
res->deep_layer ().commit_shapes (*vars, to_commit);
|
||||
}
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter) const
|
||||
{
|
||||
return shape_collection_processed_impl<db::Text, db::Polygon, db::DeepRegion> (deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *DeepTexts::polygons (db::Coord e) const
|
||||
{
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) {
|
||||
db::Box box = s->bbox ();
|
||||
box.enlarge (db::Vector (e, e));
|
||||
db::Polygon poly (box);
|
||||
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
return new db::DeepRegion (new_layer);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepTexts::edges () const
|
||||
{
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) {
|
||||
db::Box box = s->bbox ();
|
||||
output.insert (db::Edge (box.p1 (), box.p2 ()));
|
||||
}
|
||||
}
|
||||
|
||||
return new db::DeepEdges (new_layer);
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::in (const Texts &other, bool invert) const
|
||||
{
|
||||
// TODO: implement
|
||||
return AsIfFlatTexts::in (other, invert);
|
||||
}
|
||||
|
||||
bool DeepTexts::equals (const Texts &other) const
|
||||
{
|
||||
const DeepTexts *other_delegate = dynamic_cast<const DeepTexts *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatTexts::equals (other);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeepTexts::less (const Texts &other) const
|
||||
{
|
||||
const DeepTexts *other_delegate = dynamic_cast<const DeepTexts *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatTexts::less (other);
|
||||
}
|
||||
}
|
||||
|
||||
void DeepTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class Text2PolygonInteractingLocalOperation
|
||||
: public local_operation<db::TextRef, db::PolygonRef, db::TextRef>
|
||||
{
|
||||
public:
|
||||
Text2PolygonInteractingLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::TextRef, db::PolygonRef> &interactions, std::unordered_set<db::TextRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::TextRef, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j));
|
||||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::TextRef &subject = interactions.subject_shape (i->first);
|
||||
scanner.insert1 (&subject, 0);
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
|
||||
heap.push_back (o->obj ().transformed (o->trans ()));
|
||||
scanner.insert2 (& heap.back (), 1);
|
||||
}
|
||||
|
||||
if (m_inverse) {
|
||||
|
||||
std::unordered_set<db::TextRef> interacting;
|
||||
text_to_region_interaction_filter<std::unordered_set<db::TextRef>, db::TextRef> filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::TextRef> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::TextRef &subject = interactions.subject_shape (i->first);
|
||||
if (interacting.find (subject) == interacting.end ()) {
|
||||
result.insert (subject);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
text_to_region_interaction_filter<std::unordered_set<db::TextRef>, db::TextRef> filter (result);
|
||||
scanner.process (filter, 1, db::box_convert<db::TextRef> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
if (m_inverse) {
|
||||
return Copy;
|
||||
} else {
|
||||
return Drop;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select interacting texts"));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
struct ResultInserter
|
||||
{
|
||||
typedef db::Polygon value_type;
|
||||
|
||||
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
|
||||
: mp_layout (layout), mp_result (&result)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Polygon &p)
|
||||
{
|
||||
(*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ()));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
std::unordered_set<db::PolygonRef> *mp_result;
|
||||
};
|
||||
|
||||
class Text2PolygonPullLocalOperation
|
||||
: public local_operation<db::TextRef, db::PolygonRef, db::PolygonRef>
|
||||
{
|
||||
public:
|
||||
Text2PolygonPullLocalOperation ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *layout, const shape_interactions<db::TextRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::TextRef, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j));
|
||||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::TextRef &subject = interactions.subject_shape (i->first);
|
||||
scanner.insert1 (&subject, 1);
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
|
||||
heap.push_back (o->obj ().transformed (o->trans ()));
|
||||
scanner.insert2 (& heap.back (), 0);
|
||||
}
|
||||
|
||||
ResultInserter inserter (layout, result);
|
||||
text_to_region_interaction_filter<ResultInserter, db::TextRef> filter (inserter);
|
||||
scanner.process (filter, 1, db::box_convert<db::TextRef> (), db::box_convert<db::Polygon> ());
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
return Drop;
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select interacting regions"));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
DeepTexts::selected_interacting_generic (const Region &other, bool inverse) const
|
||||
{
|
||||
std::auto_ptr<db::DeepRegion> dr_holder;
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepRegion (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &texts = deep_layer ();
|
||||
|
||||
DeepLayer dl_out (texts.derived ());
|
||||
|
||||
db::Text2PolygonInteractingLocalOperation op (inverse);
|
||||
|
||||
db::local_processor<db::TextRef, db::PolygonRef, db::TextRef> proc (const_cast<db::Layout *> (&texts.layout ()), const_cast<db::Cell *> (&texts.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (other.base_verbosity ());
|
||||
proc.set_threads (texts.store ()->threads ());
|
||||
|
||||
proc.run (&op, texts.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return new db::DeepTexts (dl_out);
|
||||
}
|
||||
|
||||
RegionDelegate *DeepTexts::pull_generic (const Region &other) const
|
||||
{
|
||||
std::auto_ptr<db::DeepRegion> dr_holder;
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepRegion (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &texts = deep_layer ();
|
||||
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (other_polygons.derived ());
|
||||
|
||||
db::Text2PolygonPullLocalOperation op;
|
||||
|
||||
db::local_processor<db::TextRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&texts.layout ()), const_cast<db::Cell *> (&texts.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ());
|
||||
proc.set_base_verbosity (other.base_verbosity ());
|
||||
proc.set_threads (texts.store ()->threads ());
|
||||
|
||||
proc.run (&op, texts.layer (), other_polygons.layer (), dl_out.layer ());
|
||||
|
||||
return new db::DeepRegion (dl_out);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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_dbDeepTexts
|
||||
#define HDR_dbDeepTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatTexts.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepTexts
|
||||
: public db::AsIfFlatTexts, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepTexts ();
|
||||
DeepTexts (const db::Texts &other, DeepShapeStore &dss);
|
||||
DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss);
|
||||
DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
DeepTexts (const DeepTexts &other);
|
||||
DeepTexts (const DeepLayer &dl);
|
||||
|
||||
virtual ~DeepTexts ();
|
||||
|
||||
TextsDelegate *clone () const;
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
virtual size_t size () const;
|
||||
virtual std::string to_string (size_t) const;
|
||||
virtual Box bbox () const;
|
||||
virtual bool empty () const;
|
||||
virtual const db::Text *nth (size_t n) const;
|
||||
virtual bool has_valid_texts () const;
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &) const;
|
||||
|
||||
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &filter) const;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other);
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &, bool) const;
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
DeepTexts &operator= (const DeepTexts &other);
|
||||
|
||||
void init ();
|
||||
DeepTexts *apply_filter (const TextFilterBase &filter) const;
|
||||
|
||||
virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ EdgePairs::EdgePairs (EdgePairsDelegate *delegate)
|
|||
}
|
||||
|
||||
EdgePairs::EdgePairs (const EdgePairs &other)
|
||||
: gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ())
|
||||
: db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -143,6 +143,11 @@ EdgePairs::iter () const
|
|||
return *(i ? i : &def_iter);
|
||||
}
|
||||
|
||||
void EdgePairs::processed (Region &output, const EdgePairToPolygonProcessorBase &filter) const
|
||||
{
|
||||
output = Region (mp_delegate->processed_to_polygons (filter));
|
||||
}
|
||||
|
||||
void EdgePairs::polygons (Region &output, db::Coord e) const
|
||||
{
|
||||
output.set_delegate (mp_delegate->polygons (e));
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@
|
|||
#include "dbEdgePairsDelegate.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -230,7 +229,7 @@ public:
|
|||
* can be converted to polygons or to individual edges.
|
||||
*/
|
||||
class DB_PUBLIC EdgePairs
|
||||
: public gsi::ObjectBase
|
||||
: public db::ShapeCollection
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -339,6 +338,14 @@ public:
|
|||
*/
|
||||
explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
ShapeCollectionDelegateBase *get_delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying delegate object
|
||||
*/
|
||||
|
|
@ -458,6 +465,14 @@ public:
|
|||
return EdgePairs (mp_delegate->filtered (filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes the edge pairs into polygons
|
||||
*
|
||||
* This method will run the processor over all edge pairs and return a region
|
||||
* with the outputs of the processor.
|
||||
*/
|
||||
void processed (Region &output, const EdgePairToPolygonProcessorBase &filter) const;
|
||||
|
||||
/**
|
||||
* @brief Transforms the edge pair set
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ EdgePairsDelegate::EdgePairsDelegate ()
|
|||
}
|
||||
|
||||
EdgePairsDelegate::EdgePairsDelegate (const EdgePairsDelegate &other)
|
||||
: tl::UniqueId ()
|
||||
: ShapeCollectionDelegateBase ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
#define HDR_dbEdgePairsDelegate
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbEdgePair.h"
|
||||
#include "tlUniqueId.h"
|
||||
#include "dbShapeCollection.h"
|
||||
#include "dbShapeCollectionUtils.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -38,6 +38,8 @@ class RegionDelegate;
|
|||
class EdgesDelegate;
|
||||
class Layout;
|
||||
|
||||
typedef shape_collection_processor<db::EdgePair, db::Polygon> EdgePairToPolygonProcessorBase;
|
||||
|
||||
/**
|
||||
* @brief The edge pair set iterator delegate
|
||||
*/
|
||||
|
|
@ -59,7 +61,7 @@ public:
|
|||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC EdgePairsDelegate
|
||||
: public tl::UniqueId
|
||||
: public ShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -98,6 +100,7 @@ public:
|
|||
|
||||
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter) = 0;
|
||||
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &filter) const = 0;
|
||||
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const = 0;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const = 0;
|
||||
virtual EdgesDelegate *edges () const = 0;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Edges::Edges (EdgesDelegate *delegate)
|
|||
}
|
||||
|
||||
Edges::Edges (const Edges &other)
|
||||
: gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ())
|
||||
: db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@
|
|||
#include "dbEdgesDelegate.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbCellVariants.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -215,7 +214,7 @@ class Edges;
|
|||
*/
|
||||
|
||||
class DB_PUBLIC Edges
|
||||
: public gsi::ObjectBase
|
||||
: public db::ShapeCollection
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -359,6 +358,14 @@ public:
|
|||
*/
|
||||
explicit Edges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges = true, bool merged_semantics = true);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
ShapeCollectionDelegateBase *get_delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying delegate object
|
||||
*/
|
||||
|
|
@ -1301,6 +1308,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class EdgePairs;
|
||||
friend class Texts;
|
||||
|
||||
EdgesDelegate *mp_delegate;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ EdgesDelegate::EdgesDelegate ()
|
|||
}
|
||||
|
||||
EdgesDelegate::EdgesDelegate (const EdgesDelegate &other)
|
||||
: tl::UniqueId ()
|
||||
: ShapeCollectionDelegateBase ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@
|
|||
#include "dbEdge.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdgePairRelations.h"
|
||||
#include "tlUniqueId.h"
|
||||
#include "dbShapeCollection.h"
|
||||
#include "dbShapeCollectionUtils.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -128,32 +129,9 @@ public:
|
|||
virtual bool wants_variants () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A edge processor base class
|
||||
*/
|
||||
class DB_PUBLIC EdgeProcessorBase
|
||||
: public edge_processor<db::Edge>
|
||||
{
|
||||
// .. nothing yet ..
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An edge-to-polygon processor base class
|
||||
*/
|
||||
class DB_PUBLIC EdgeToPolygonProcessorBase
|
||||
: public edge_processor<db::Polygon>
|
||||
{
|
||||
// .. nothing yet ..
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An edge-to-edge pair processor base class
|
||||
*/
|
||||
class DB_PUBLIC EdgeToEdgePairProcessorBase
|
||||
: public edge_processor<db::EdgePair>
|
||||
{
|
||||
// .. nothing yet ..
|
||||
};
|
||||
typedef shape_collection_processor<db::Edge, db::Edge> EdgeProcessorBase;
|
||||
typedef shape_collection_processor<db::Edge, db::Polygon> EdgeToPolygonProcessorBase;
|
||||
typedef shape_collection_processor<db::Edge, db::EdgePair> EdgeToEdgePairProcessorBase;
|
||||
|
||||
class RecursiveShapeIterator;
|
||||
class EdgeFilterBase;
|
||||
|
|
@ -181,7 +159,7 @@ public:
|
|||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC EdgesDelegate
|
||||
: public tl::UniqueId
|
||||
: public ShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ EmptyEdgePairs::polygons (db::Coord) const
|
|||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
EmptyEdgePairs::edges () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public:
|
|||
|
||||
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &) { return this; }
|
||||
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const { return new EmptyEdgePairs (); }
|
||||
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbRegionDelegate.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -107,11 +108,14 @@ public:
|
|||
virtual RegionDelegate *selected_not_interacting (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_interacting (const Edges &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_interacting (const Texts &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); }
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual TextsDelegate *pull_interacting (const Texts &) const { return new EmptyTexts (); }
|
||||
virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbEmptyTexts.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
EmptyTexts::EmptyTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EmptyTexts::EmptyTexts (const EmptyTexts &other)
|
||||
: TextsDelegate (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::clone () const
|
||||
{
|
||||
return new EmptyTexts (*this);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyTexts::polygons (db::Coord) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyTexts::processed_to_polygons (const TextToPolygonProcessorBase &) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
EmptyTexts::edges () const
|
||||
{
|
||||
return new EmptyEdges ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::add_in_place (const Texts &other)
|
||||
{
|
||||
return add (other);
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::add (const Texts &other) const
|
||||
{
|
||||
return other.delegate ()->clone ();
|
||||
}
|
||||
|
||||
bool
|
||||
EmptyTexts::equals (const Texts &other) const
|
||||
{
|
||||
return other.empty ();
|
||||
}
|
||||
|
||||
bool
|
||||
EmptyTexts::less (const Texts &other) const
|
||||
{
|
||||
return other.empty () ? false : true;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyTexts::pull_interacting (const Region &) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::selected_interacting (const Region &) const
|
||||
{
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::selected_not_interacting (const Region &) const
|
||||
{
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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_dbEmptyTexts
|
||||
#define HDR_dbEmptyTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbTextsDelegate.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC EmptyTexts
|
||||
: public TextsDelegate
|
||||
{
|
||||
public:
|
||||
EmptyTexts ();
|
||||
EmptyTexts (const EmptyTexts &other);
|
||||
|
||||
virtual TextsDelegate *clone () const;
|
||||
|
||||
virtual std::string to_string (size_t) const { return std::string (); }
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const { return 0; }
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
|
||||
|
||||
virtual bool empty () const { return true; }
|
||||
virtual size_t size () const { return 0; }
|
||||
|
||||
virtual Box bbox () const { return Box (); }
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; }
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &) const { return new EmptyTexts (); }
|
||||
|
||||
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &) const;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other);
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); }
|
||||
|
||||
virtual const db::Text *nth (size_t) const { tl_assert (false); }
|
||||
virtual bool has_valid_texts () const { return true; }
|
||||
|
||||
virtual const db::RecursiveShapeIterator *iter () const { return 0; }
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { }
|
||||
virtual void insert_into_as_polygons (Layout *, db::cell_index_type, unsigned int, db::Coord) const { }
|
||||
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const;
|
||||
virtual TextsDelegate *selected_interacting (const Region &) const;
|
||||
virtual TextsDelegate *selected_not_interacting (const Region &) const;
|
||||
|
||||
private:
|
||||
EmptyTexts &operator= (const EmptyTexts &other);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbFlatTexts.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// FlatTexts implementation
|
||||
|
||||
FlatTexts::FlatTexts ()
|
||||
: AsIfFlatTexts (), m_texts (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
FlatTexts::~FlatTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
FlatTexts::FlatTexts (const FlatTexts &other)
|
||||
: AsIfFlatTexts (other), m_texts (false)
|
||||
{
|
||||
m_texts = other.m_texts;
|
||||
}
|
||||
|
||||
FlatTexts::FlatTexts (const db::Shapes &texts)
|
||||
: AsIfFlatTexts (), m_texts (texts)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void FlatTexts::invalidate_cache ()
|
||||
{
|
||||
invalidate_bbox ();
|
||||
}
|
||||
|
||||
void FlatTexts::reserve (size_t n)
|
||||
{
|
||||
m_texts.reserve (db::Text::tag (), n);
|
||||
}
|
||||
|
||||
TextsIteratorDelegate *FlatTexts::begin () const
|
||||
{
|
||||
return new FlatTextsIterator (m_texts.get_layer<db::Text, db::unstable_layer_tag> ().begin (), m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatTexts::begin_iter () const
|
||||
{
|
||||
return std::make_pair (db::RecursiveShapeIterator (m_texts), db::ICplxTrans ());
|
||||
}
|
||||
|
||||
bool FlatTexts::empty () const
|
||||
{
|
||||
return m_texts.empty ();
|
||||
}
|
||||
|
||||
size_t FlatTexts::size () const
|
||||
{
|
||||
return m_texts.size ();
|
||||
}
|
||||
|
||||
Box FlatTexts::compute_bbox () const
|
||||
{
|
||||
m_texts.update_bbox ();
|
||||
return m_texts.bbox ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
FlatTexts::filter_in_place (const TextFilterBase &filter)
|
||||
{
|
||||
text_iterator_type pw = m_texts.get_layer<db::Text, db::unstable_layer_tag> ().begin ();
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (filter.selected (*p)) {
|
||||
if (pw == m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ()) {
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().insert (*p);
|
||||
pw = m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ();
|
||||
} else {
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().replace (pw++, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().erase (pw, m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
TextsDelegate *FlatTexts::add (const Texts &other) const
|
||||
{
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts (*this));
|
||||
new_texts->invalidate_cache ();
|
||||
|
||||
FlatTexts *other_flat = dynamic_cast<FlatTexts *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
new_texts->raw_texts ().insert (other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().begin (), other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = new_texts->raw_texts ().size ();
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
new_texts->raw_texts ().reserve (db::Text::tag (), n);
|
||||
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
}
|
||||
|
||||
TextsDelegate *FlatTexts::add_in_place (const Texts &other)
|
||||
{
|
||||
invalidate_cache ();
|
||||
|
||||
FlatTexts *other_flat = dynamic_cast<FlatTexts *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
m_texts.insert (other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().begin (), other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = m_texts.size ();
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
m_texts.reserve (db::Text::tag (), n);
|
||||
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
m_texts.insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
const db::Text *FlatTexts::nth (size_t n) const
|
||||
{
|
||||
return n < m_texts.size () ? &m_texts.get_layer<db::Text, db::unstable_layer_tag> ().begin () [n] : 0;
|
||||
}
|
||||
|
||||
bool FlatTexts::has_valid_texts () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator *FlatTexts::iter () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
db::Shapes &out = layout->cell (into_cell).shapes (into_layer);
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
db::Box box = p->box ();
|
||||
box.enlarge (db::Vector (enl, enl));
|
||||
out.insert (db::SimplePolygon (box));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
layout->cell (into_cell).shapes (into_layer).insert (m_texts);
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert (const db::Text &t)
|
||||
{
|
||||
m_texts.insert (t);
|
||||
invalidate_cache ();
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert (const db::Shape &shape)
|
||||
{
|
||||
if (shape.is_text ()) {
|
||||
|
||||
db::Text t;
|
||||
shape.text (t);
|
||||
insert (t);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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_dbFlatTexts
|
||||
#define HDR_dbFlatTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatTexts.h"
|
||||
#include "dbShapes.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief An iterator delegate for the flat text set
|
||||
*/
|
||||
class DB_PUBLIC FlatTextsIterator
|
||||
: public TextsIteratorDelegate
|
||||
{
|
||||
public:
|
||||
typedef db::layer<db::Text, db::unstable_layer_tag> edge_pair_layer_type;
|
||||
typedef edge_pair_layer_type::iterator iterator_type;
|
||||
|
||||
FlatTextsIterator (iterator_type from, iterator_type to)
|
||||
: m_from (from), m_to (to)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual bool at_end () const
|
||||
{
|
||||
return m_from == m_to;
|
||||
}
|
||||
|
||||
virtual void increment ()
|
||||
{
|
||||
++m_from;
|
||||
}
|
||||
|
||||
virtual const value_type *get () const
|
||||
{
|
||||
return m_from.operator-> ();
|
||||
}
|
||||
|
||||
virtual TextsIteratorDelegate *clone () const
|
||||
{
|
||||
return new FlatTextsIterator (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Texts;
|
||||
|
||||
iterator_type m_from, m_to;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The delegate for the actual text set implementation
|
||||
*/
|
||||
class DB_PUBLIC FlatTexts
|
||||
: public AsIfFlatTexts
|
||||
{
|
||||
public:
|
||||
typedef db::Text value_type;
|
||||
|
||||
typedef db::layer<db::Text, db::unstable_layer_tag> text_layer_type;
|
||||
typedef text_layer_type::iterator text_iterator_type;
|
||||
|
||||
FlatTexts ();
|
||||
FlatTexts (const db::Shapes &texts);
|
||||
|
||||
FlatTexts (const FlatTexts &other);
|
||||
|
||||
virtual ~FlatTexts ();
|
||||
|
||||
TextsDelegate *clone () const
|
||||
{
|
||||
return new FlatTexts (*this);
|
||||
}
|
||||
|
||||
void reserve (size_t);
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
virtual bool empty () const;
|
||||
virtual size_t size () const;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other);
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual const db::Text *nth (size_t n) const;
|
||||
virtual bool has_valid_texts () const;
|
||||
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
void insert (const db::Text &text);
|
||||
void insert (const db::Shape &shape);
|
||||
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans)
|
||||
{
|
||||
if (shape.is_edge_pair ()) {
|
||||
|
||||
db::Text t;
|
||||
shape.text (t);
|
||||
t.transform (trans);
|
||||
insert (t);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert_seq (const Iter &seq)
|
||||
{
|
||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform (const Trans &trans)
|
||||
{
|
||||
if (! trans.is_unity ()) {
|
||||
for (text_iterator_type p = m_texts.template get_layer<db::Text, db::unstable_layer_tag> ().begin (); p != m_texts.template get_layer<db::Text, db::unstable_layer_tag> ().end (); ++p) {
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||
}
|
||||
invalidate_cache ();
|
||||
}
|
||||
}
|
||||
|
||||
db::Shapes &raw_texts () { return m_texts; }
|
||||
|
||||
protected:
|
||||
virtual Box compute_bbox () const;
|
||||
void invalidate_cache ();
|
||||
|
||||
private:
|
||||
friend class AsIfFlatTexts;
|
||||
|
||||
FlatTexts &operator= (const FlatTexts &other);
|
||||
|
||||
mutable db::Shapes m_texts;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -283,6 +283,12 @@ namespace std
|
|||
h = hfunc (b, h);
|
||||
h = hfunc (na, h);
|
||||
h = hfunc (nb, h);
|
||||
} else if (o.size () > 1) {
|
||||
// iterated array
|
||||
typename db::array <db::CellInst, db::simple_trans<C> >::iterator i = o.begin ();
|
||||
while (! (++i).at_end ()) {
|
||||
h = hfunc (*i, h);
|
||||
}
|
||||
}
|
||||
|
||||
if (o.is_complex ()) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbPolygonTools.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbNetShape.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlTimer.h"
|
||||
|
|
@ -43,9 +44,9 @@ namespace db
|
|||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class Shape, class Trans> void insert_transformed (db::Layout &layout, Container &shapes, const Shape &s, const Trans &t);
|
||||
template <class Shape, class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t);
|
||||
|
||||
template <class Container, class Trans> void insert_transformed (db::Layout &layout, Container &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
template <class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
{
|
||||
db::Polygon poly = s.obj ();
|
||||
poly.transform (s.trans ());
|
||||
|
|
@ -55,7 +56,32 @@ template <class Container, class Trans> void insert_transformed (db::Layout &lay
|
|||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
|
||||
template <class Container, class Trans> void insert_transformed (db::Layout & /*layout*/, Container &shapes, const db::Edge &s, const Trans &t)
|
||||
template <class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::NetShape &s, const Trans &t)
|
||||
{
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
db::Polygon poly = pr.obj ();
|
||||
poly.transform (pr.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
poly.transform (t);
|
||||
}
|
||||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
|
||||
} else if (s.type () == db::NetShape::Text) {
|
||||
|
||||
db::TextRef tr = s.text_ref ();
|
||||
db::Text text = tr.obj ();
|
||||
text.transform (tr.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
text.transform (t);
|
||||
}
|
||||
shapes.insert (db::TextRef (text, layout.shape_repository ()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Trans> void insert_transformed (db::Layout & /*layout*/, db::Shapes &shapes, const db::Edge &s, const Trans &t)
|
||||
{
|
||||
shapes.insert (s.transformed (t));
|
||||
}
|
||||
|
|
@ -237,6 +263,20 @@ interaction_test (const db::PolygonRef &a, const db::PolygonRef &b, const db::un
|
|||
}
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
static bool
|
||||
interaction_test (const db::NetShape &a, const db::NetShape &b, const Trans &trans, db::Connectivity::edge_connectivity_type)
|
||||
{
|
||||
return a.interacts_with_transformed (b, trans);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static bool
|
||||
interaction_test (const db::NetShape &a, const db::NetShape &b, const db::unit_trans<C> &, db::Connectivity::edge_connectivity_type)
|
||||
{
|
||||
return a.interacts_with (b);
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
static bool
|
||||
interaction_test (const db::Edge &a, const db::Edge &b, const Trans &trans, db::Connectivity::edge_connectivity_type ec)
|
||||
|
|
@ -272,6 +312,8 @@ bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::NetShape> (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::UnitTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::NetShape> (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::ICplxTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::Edge> (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans) const;
|
||||
|
|
@ -630,8 +672,10 @@ size_t local_cluster<T>::split (double max_area_ratio, Iter &output) const
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC local_cluster<db::NetShape>;
|
||||
template class DB_PUBLIC local_cluster<db::PolygonRef>;
|
||||
template class DB_PUBLIC local_cluster<db::Edge>;
|
||||
template DB_PUBLIC size_t local_cluster<db::NetShape>::split<std::back_insert_iterator<std::list<local_cluster<db::NetShape> > > > (double, std::back_insert_iterator<std::list<local_cluster<db::NetShape> > > &) const;
|
||||
template DB_PUBLIC size_t local_cluster<db::PolygonRef>::split<std::back_insert_iterator<std::list<local_cluster<db::PolygonRef> > > > (double, std::back_insert_iterator<std::list<local_cluster<db::PolygonRef> > > &) const;
|
||||
template DB_PUBLIC size_t local_cluster<db::Edge>::split<std::back_insert_iterator<std::list<local_cluster<db::Edge> > > > (double, std::back_insert_iterator<std::list<local_cluster<db::Edge> > > &) const;
|
||||
|
||||
|
|
@ -747,10 +791,10 @@ namespace
|
|||
|
||||
template <class T, class BoxTree>
|
||||
struct cluster_building_receiver
|
||||
: public db::box_scanner_receiver<T, std::pair<unsigned int, unsigned int> >
|
||||
: public db::box_scanner_receiver<T, std::pair<unsigned int, size_t> >
|
||||
{
|
||||
typedef typename local_cluster<T>::id_type id_type;
|
||||
typedef std::pair<const T *, std::pair<unsigned int, unsigned int> > shape_value;
|
||||
typedef std::pair<const T *, std::pair<unsigned int, size_t> > shape_value;
|
||||
typedef std::vector<shape_value> shape_vector;
|
||||
typedef std::set<size_t> global_nets;
|
||||
typedef std::pair<shape_vector, global_nets> cluster_value;
|
||||
|
|
@ -778,7 +822,7 @@ struct cluster_building_receiver
|
|||
}
|
||||
}
|
||||
|
||||
void add (const T *s1, std::pair<unsigned int, unsigned int> p1, const T *s2, std::pair<unsigned int, unsigned int> p2)
|
||||
void add (const T *s1, std::pair<unsigned int, size_t> p1, const T *s2, std::pair<unsigned int, size_t> p2)
|
||||
{
|
||||
if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first)) {
|
||||
return;
|
||||
|
|
@ -824,7 +868,7 @@ struct cluster_building_receiver
|
|||
}
|
||||
}
|
||||
|
||||
void finish (const T *s, std::pair<unsigned int, unsigned> p)
|
||||
void finish (const T *s, std::pair<unsigned int, size_t> p)
|
||||
{
|
||||
// if the shape has not been handled yet, insert a single cluster with only this shape
|
||||
typename std::map<const T *, typename std::list<cluster_value>::iterator>::iterator ic = m_shape_to_clusters.find (s);
|
||||
|
|
@ -886,22 +930,108 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct addressable_shape_delivery
|
||||
{
|
||||
const T *operator () (const db::Shape &shape)
|
||||
{
|
||||
typename T::tag object_tag;
|
||||
return shape.basic_ptr (object_tag);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct addressable_shape_delivery<db::NetShape>
|
||||
{
|
||||
const NetShape *operator () (const db::Shape &shape)
|
||||
{
|
||||
if (shape.type () == db::Shape::TextRef) {
|
||||
m_heap.push_back (db::NetShape (shape.text_ref ()));
|
||||
return &m_heap.back ();
|
||||
} else if (shape.type () == db::Shape::PolygonRef) {
|
||||
m_heap.push_back (db::NetShape (shape.polygon_ref ()));
|
||||
return &m_heap.back ();
|
||||
} else {
|
||||
tl_assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<NetShape> m_heap;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct attr_accessor
|
||||
{
|
||||
size_t operator() (const db::Shape &shape) const
|
||||
{
|
||||
return shape.prop_id ();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct attr_accessor<db::NetShape>
|
||||
{
|
||||
size_t operator() (const db::Shape &shape) const
|
||||
{
|
||||
// NOTE: the attribute is
|
||||
// * odd: a StringRef pointer's value
|
||||
// * even: a Property ID times 2
|
||||
if (shape.type () == db::Shape::TextRef) {
|
||||
return db::text_ref_to_attr (&shape.text_ref ().obj ());
|
||||
} else {
|
||||
return db::prop_id_to_attr (shape.prop_id ());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct get_shape_flags { };
|
||||
|
||||
template <>
|
||||
struct get_shape_flags<db::Edge>
|
||||
{
|
||||
db::ShapeIterator::flags_type operator() () const
|
||||
{
|
||||
return db::ShapeIterator::Edges;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_shape_flags<db::PolygonRef>
|
||||
{
|
||||
db::ShapeIterator::flags_type operator() () const
|
||||
{
|
||||
return db::ShapeIterator::Polygons;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_shape_flags<db::NetShape>
|
||||
{
|
||||
db::ShapeIterator::flags_type operator() () const
|
||||
{
|
||||
return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons | db::ShapeIterator::Texts);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
local_clusters<T>::build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence, bool report_progress)
|
||||
local_clusters<T>::build_clusters (const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence, bool report_progress)
|
||||
{
|
||||
static std::string desc = tl::to_string (tr ("Building local clusters"));
|
||||
|
||||
db::box_scanner<T, std::pair<unsigned int, unsigned int> > bs (report_progress, desc);
|
||||
typename T::tag object_tag;
|
||||
db::box_scanner<T, std::pair<unsigned int, size_t> > bs (report_progress, desc);
|
||||
db::box_convert<T> bc;
|
||||
addressable_shape_delivery<T> heap;
|
||||
attr_accessor<T> attr;
|
||||
db::ShapeIterator::flags_type shape_flags = get_shape_flags<T> () ();
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
const db::Shapes &shapes = cell.shapes (*l);
|
||||
for (db::Shapes::shape_iterator s = shapes.begin (shape_flags); ! s.at_end (); ++s) {
|
||||
bs.insert (s->basic_ptr (object_tag), std::make_pair (*l, (unsigned int) s->prop_id ()));
|
||||
bs.insert (heap (*s), std::make_pair (*l, attr (*s)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -916,9 +1046,9 @@ local_clusters<T>::build_clusters (const db::Cell &cell, db::ShapeIterator::flag
|
|||
|
||||
template <class T>
|
||||
void
|
||||
local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<unsigned int> &attr_equivalence)
|
||||
local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence)
|
||||
{
|
||||
tl::equivalence_clusters<unsigned int> eq;
|
||||
tl::equivalence_clusters<size_t> eq;
|
||||
|
||||
// collect all local attributes (the ones which are present in attr_equivalence) into "eq"
|
||||
// and form equivalences for multi-attribute clusters.
|
||||
|
|
@ -939,18 +1069,18 @@ local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<unsig
|
|||
|
||||
// identify the layout clusters joined into one attribute cluster and join them
|
||||
|
||||
std::map<tl::equivalence_clusters<unsigned int>::cluster_id_type, std::set<size_t> > c2c;
|
||||
std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> > c2c;
|
||||
|
||||
for (const_iterator c = begin (); c != end (); ++c) {
|
||||
for (typename local_cluster<T>::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) {
|
||||
tl::equivalence_clusters<unsigned int>::cluster_id_type cl = attr_equivalence.cluster_id (*a);
|
||||
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence.cluster_id (*a);
|
||||
if (cl > 0) {
|
||||
c2c [cl].insert (c->id ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<tl::equivalence_clusters<unsigned int>::cluster_id_type, std::set<size_t> >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) {
|
||||
for (std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) {
|
||||
if (c->second.size () > 1) {
|
||||
std::set<size_t>::const_iterator cl0 = c->second.begin ();
|
||||
std::set<size_t>::const_iterator cl = cl0;
|
||||
|
|
@ -962,6 +1092,7 @@ local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<unsig
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC local_clusters<db::NetShape>;
|
||||
template class DB_PUBLIC local_clusters<db::PolygonRef>;
|
||||
template class DB_PUBLIC local_clusters<db::Edge>;
|
||||
|
||||
|
|
@ -984,6 +1115,7 @@ connected_clusters_iterator<T>::connected_clusters_iterator (const connected_clu
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC connected_clusters_iterator<db::NetShape>;
|
||||
template class DB_PUBLIC connected_clusters_iterator<db::PolygonRef>;
|
||||
template class DB_PUBLIC connected_clusters_iterator<db::Edge>;
|
||||
|
||||
|
|
@ -1053,6 +1185,7 @@ connected_clusters<T>::find_cluster_with_connection (const ClusterInstance &inst
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC connected_clusters<db::NetShape>;
|
||||
template class DB_PUBLIC connected_clusters<db::PolygonRef>;
|
||||
template class DB_PUBLIC connected_clusters<db::Edge>;
|
||||
|
||||
|
|
@ -1133,11 +1266,11 @@ void hier_clusters<T>::clear ()
|
|||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
{
|
||||
clear ();
|
||||
cell_clusters_box_converter<T> cbc (layout, *this);
|
||||
do_build (cbc, layout, cell, shape_flags, conn, attr_equivalence, breakout_cells);
|
||||
do_build (cbc, layout, cell, conn, attr_equivalence, breakout_cells);
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
@ -1273,8 +1406,8 @@ private:
|
|||
struct InteractionKeyForClustersType
|
||||
: public InstanceToInstanceInteraction
|
||||
{
|
||||
InteractionKeyForClustersType (db::cell_index_type _ci1, db::cell_index_type _ci2, const db::ICplxTrans &_t21, const box_type &_box)
|
||||
: InstanceToInstanceInteraction (_ci1, 0, _ci2, 0, _t21), box (_box)
|
||||
InteractionKeyForClustersType (db::cell_index_type _ci1, db::cell_index_type _ci2, const db::ICplxTrans &_t1, const db::ICplxTrans &_t21, const box_type &_box)
|
||||
: InstanceToInstanceInteraction (_ci1, 0, _ci2, 0, _t1, _t21), box (_box)
|
||||
{ }
|
||||
|
||||
bool operator== (const InteractionKeyForClustersType &other) const
|
||||
|
|
@ -1349,18 +1482,22 @@ private:
|
|||
|
||||
InstanceToInstanceInteraction ii_key;
|
||||
db::ICplxTrans i1t, i2t;
|
||||
bool fill_cache = false;
|
||||
|
||||
// Cache is only used for single instances, non-iterated, simple or regular arrays.
|
||||
if ((! i1element.at_end () || i1.size () == 1 || ! i1.is_iterated_array ()) &&
|
||||
(! i2element.at_end () || i2.size () == 1 || ! i2.is_iterated_array ())) {
|
||||
|
||||
{
|
||||
i1t = i1element.at_end () ? i1.complex_trans () : i1.complex_trans (*i1element);
|
||||
db::ICplxTrans tt1 = t1 * i1t;
|
||||
|
||||
i2t = i2element.at_end () ? i2.complex_trans () : i2.complex_trans (*i2element);
|
||||
db::ICplxTrans tt2 = t2 * i2t;
|
||||
|
||||
db::ICplxTrans tt21 = tt1.inverted () * tt2;
|
||||
db::ICplxTrans cache_norm = tt1.inverted ();
|
||||
ii_key = InstanceToInstanceInteraction (i1.cell_index (), (! i1element.at_end () || i1.size () == 1) ? 0 : i1.cell_inst ().delegate (),
|
||||
i2.cell_index (), (! i2element.at_end () || i2.size () == 1) ? 0 : i2.cell_inst ().delegate (),
|
||||
tt21);
|
||||
cache_norm, cache_norm * tt2);
|
||||
|
||||
instance_interaction_cache_type::iterator ii = mp_instance_interaction_cache->find (ii_key);
|
||||
if (ii != mp_instance_interaction_cache->end ()) {
|
||||
|
|
@ -1378,6 +1515,9 @@ private:
|
|||
return;
|
||||
|
||||
}
|
||||
|
||||
fill_cache = true;
|
||||
|
||||
}
|
||||
|
||||
// array interactions
|
||||
|
|
@ -1478,15 +1618,19 @@ private:
|
|||
// return the list of unique interactions
|
||||
interacting_clusters.insert (interacting_clusters.end (), sorted_interactions.begin (), sorted_interactions.end ());
|
||||
|
||||
// normalize transformations in cache
|
||||
db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted ();
|
||||
for (std::vector<std::pair<ClusterInstance, ClusterInstance> >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) {
|
||||
i->first.transform (i1ti);
|
||||
i->second.transform (i2ti);
|
||||
}
|
||||
if (fill_cache) {
|
||||
|
||||
cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key];
|
||||
cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ());
|
||||
// normalize transformations for cache
|
||||
db::ICplxTrans i1ti = i1t.inverted (), i2ti = i2t.inverted ();
|
||||
for (std::vector<std::pair<ClusterInstance, ClusterInstance> >::iterator i = sorted_interactions.begin (); i != sorted_interactions.end (); ++i) {
|
||||
i->first.transform (i1ti);
|
||||
i->second.transform (i2ti);
|
||||
}
|
||||
|
||||
cluster_instance_pair_list_type &cached = (*mp_instance_interaction_cache) [ii_key];
|
||||
cached.insert (cached.end (), sorted_interactions.begin (), sorted_interactions.end ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1508,7 +1652,7 @@ private:
|
|||
|
||||
box_type common2 = common.transformed (t2i);
|
||||
|
||||
InteractionKeyForClustersType ikey (ci1, ci2, t21, common2);
|
||||
InteractionKeyForClustersType ikey (ci1, ci2, t1i, t21, common2);
|
||||
|
||||
typename std::map<InteractionKeyForClustersType, std::vector<std::pair<size_t, size_t> > >::const_iterator ici = m_interaction_cache_for_clusters.find (ikey);
|
||||
if (ici != m_interaction_cache_for_clusters.end ()) {
|
||||
|
|
@ -1939,7 +2083,7 @@ hier_clusters<T>::propagate_cluster_inst (const db::Layout &layout, const db::Ce
|
|||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity, tl::to_string (tr ("Computing shape clusters")));
|
||||
|
||||
|
|
@ -1957,8 +2101,8 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
|
||||
// look for the net label joining spec - for the top cell the "top_cell_index" entry is looked for.
|
||||
// If there is no such entry or the cell is not the top cell, look for the entry by cell index.
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> >::const_iterator ae;
|
||||
const tl::equivalence_clusters<unsigned int> *ec = 0;
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> >::const_iterator ae;
|
||||
const tl::equivalence_clusters<size_t> *ec = 0;
|
||||
if (attr_equivalence) {
|
||||
if (*c == cell.cell_index ()) {
|
||||
ae = attr_equivalence->find (top_cell_index);
|
||||
|
|
@ -1974,7 +2118,7 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
}
|
||||
}
|
||||
|
||||
build_local_cluster (layout, layout.cell (*c), shape_flags, conn, ec);
|
||||
build_local_cluster (layout, layout.cell (*c), conn, ec);
|
||||
|
||||
++progress;
|
||||
|
||||
|
|
@ -2021,7 +2165,7 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence)
|
||||
hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence)
|
||||
{
|
||||
std::string msg = tl::to_string (tr ("Computing local clusters for cell: ")) + std::string (layout.cell_name (cell.cell_index ()));
|
||||
if (tl::verbosity () >= m_base_verbosity + 20) {
|
||||
|
|
@ -2030,7 +2174,7 @@ hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell
|
|||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 20, msg);
|
||||
|
||||
connected_clusters<T> &local = m_per_cell_clusters [cell.cell_index ()];
|
||||
local.build_clusters (cell, shape_flags, conn, attr_equivalence, true);
|
||||
local.build_clusters (cell, conn, attr_equivalence, true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
|
@ -2336,6 +2480,7 @@ hier_clusters<T>::return_to_hierarchy (db::Layout &layout, const std::map<unsign
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC hier_clusters<db::NetShape>;
|
||||
template class DB_PUBLIC hier_clusters<db::PolygonRef>;
|
||||
template class DB_PUBLIC hier_clusters<db::Edge>;
|
||||
|
||||
|
|
@ -2460,6 +2605,7 @@ void recursive_cluster_shape_iterator<T>::down (db::cell_index_type ci, typename
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::NetShape>;
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::PolygonRef>;
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::Edge>;
|
||||
|
||||
|
|
@ -2533,6 +2679,7 @@ void recursive_cluster_iterator<T>::down (db::cell_index_type ci, typename db::l
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC recursive_cluster_iterator<db::NetShape>;
|
||||
template class DB_PUBLIC recursive_cluster_iterator<db::PolygonRef>;
|
||||
template class DB_PUBLIC recursive_cluster_iterator<db::Edge>;
|
||||
|
||||
|
|
@ -2614,6 +2761,7 @@ incoming_cluster_connections<T>::ensure_computed_parent (db::cell_index_type ci)
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC incoming_cluster_connections<db::NetShape>;
|
||||
template class DB_PUBLIC incoming_cluster_connections<db::PolygonRef>;
|
||||
template class DB_PUBLIC incoming_cluster_connections<db::Edge>;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "dbCell.h"
|
||||
#include "dbInstElement.h"
|
||||
#include "tlEquivalenceClusters.h"
|
||||
#include "tlAssert.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
|
@ -505,7 +506,7 @@ public:
|
|||
* cluster joining may happen in this case, because multi-attribute
|
||||
* assignment might create connections too.
|
||||
*/
|
||||
void build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence = 0, bool report_progress = false);
|
||||
void build_clusters (const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence = 0, bool report_progress = false);
|
||||
|
||||
/**
|
||||
* @brief Creates and inserts a new clusters
|
||||
|
|
@ -540,7 +541,7 @@ private:
|
|||
tree_type m_clusters;
|
||||
size_t m_next_dummy_id;
|
||||
|
||||
void apply_attr_equivalences (const tl::equivalence_clusters<unsigned int> &attr_equivalence);
|
||||
void apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -761,13 +762,71 @@ inline bool less_array_delegates (const db::ArrayBase *a, const db::ArrayBase *b
|
|||
*/
|
||||
struct InstanceToInstanceInteraction
|
||||
{
|
||||
InstanceToInstanceInteraction (db::cell_index_type _ci1, const db::ArrayBase *_array1, db::cell_index_type _ci2, const db::ArrayBase *_array2, const db::ICplxTrans &_t21)
|
||||
: ci1 (_ci1), ci2 (_ci2), array1 (_array1), array2 (_array2), t21 (_t21)
|
||||
{ }
|
||||
InstanceToInstanceInteraction (db::cell_index_type _ci1, const db::ArrayBase *_array1, db::cell_index_type _ci2, const db::ArrayBase *_array2, const db::ICplxTrans &_tn, const db::ICplxTrans &_t21)
|
||||
: ci1 (_ci1), ci2 (_ci2), array1 (0), array2 (0), t21 (_t21)
|
||||
{
|
||||
if (_array1) {
|
||||
array1 = _array1->basic_clone ();
|
||||
static_cast<db::basic_array<db::Coord> *> (array1)->transform (_tn);
|
||||
}
|
||||
|
||||
if (_array2) {
|
||||
array2 = _array2->basic_clone ();
|
||||
static_cast<db::basic_array<db::Coord> *> (array2)->transform (_tn);
|
||||
}
|
||||
}
|
||||
|
||||
InstanceToInstanceInteraction ()
|
||||
: ci1 (0), ci2 (0), array1 (0), array2 (0)
|
||||
{ }
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InstanceToInstanceInteraction (const InstanceToInstanceInteraction &other)
|
||||
: ci1 (other.ci1), ci2 (other.ci2),
|
||||
array1 (other.array1 ? other.array1->basic_clone () : 0),
|
||||
array2 (other.array2 ? other.array2->basic_clone () : 0),
|
||||
t21 (other.t21)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InstanceToInstanceInteraction &operator= (const InstanceToInstanceInteraction &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
ci1 = other.ci1;
|
||||
ci2 = other.ci2;
|
||||
|
||||
if (array1) {
|
||||
delete array1;
|
||||
}
|
||||
array1 = other.array1 ? other.array1->basic_clone () : 0;
|
||||
|
||||
if (array2) {
|
||||
delete array2;
|
||||
}
|
||||
array2 = other.array2 ? other.array2->basic_clone () : 0;
|
||||
|
||||
t21 = other.t21;
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~InstanceToInstanceInteraction ()
|
||||
{
|
||||
if (array1) {
|
||||
delete array1;
|
||||
}
|
||||
array1 = 0;
|
||||
|
||||
if (array2) {
|
||||
delete array2;
|
||||
}
|
||||
array2 = 0;
|
||||
}
|
||||
|
||||
bool operator== (const InstanceToInstanceInteraction &other) const
|
||||
{
|
||||
|
|
@ -796,7 +855,7 @@ struct InstanceToInstanceInteraction
|
|||
}
|
||||
|
||||
db::cell_index_type ci1, ci2;
|
||||
const db::ArrayBase *array1, *array2;
|
||||
db::ArrayBase *array1, *array2;
|
||||
db::ICplxTrans t21;
|
||||
};
|
||||
|
||||
|
|
@ -998,7 +1057,7 @@ public:
|
|||
/**
|
||||
* @brief Builds a hierarchy of clusters from a cell hierarchy and given connectivity
|
||||
*/
|
||||
void build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence = 0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||
void build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence = 0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||
|
||||
/**
|
||||
* @brief Gets the connected clusters for a given cell
|
||||
|
|
@ -1036,10 +1095,10 @@ public:
|
|||
size_t propagate_cluster_inst (const db::Layout &layout, const Cell &cell, const ClusterInstance &ci, db::cell_index_type parent_ci, bool with_self);
|
||||
|
||||
private:
|
||||
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence);
|
||||
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence);
|
||||
void build_hier_connections (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, instance_interaction_cache_type &instance_interaction_cache);
|
||||
void build_hier_connections_for_cells (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const std::vector<db::cell_index_type> &cells, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, tl::RelativeProgress &progress, instance_interaction_cache_type &instance_interaction_cache);
|
||||
void do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<cell_index_type> *breakout_cells);
|
||||
void do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence, const std::set<cell_index_type> *breakout_cells);
|
||||
|
||||
std::map<db::cell_index_type, connected_clusters<T> > m_per_cell_clusters;
|
||||
int m_base_verbosity;
|
||||
|
|
@ -1335,6 +1394,49 @@ private:
|
|||
void ensure_computed_parent (db::cell_index_type ci) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper function generating an attribute ID from a property ID
|
||||
* This function is used to provide a generic attribute wrapping a property ID and a text ID.
|
||||
*/
|
||||
inline size_t prop_id_to_attr (db::properties_id_type id)
|
||||
{
|
||||
return size_t (id) * 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the attribute is a property ID
|
||||
*/
|
||||
inline bool is_prop_id_attr (size_t attr)
|
||||
{
|
||||
return (attr & 1) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the property ID from an attribute
|
||||
*/
|
||||
inline db::properties_id_type prop_id_from_attr (size_t attr)
|
||||
{
|
||||
return attr / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A helper function generating an attribute from a StringRef
|
||||
*/
|
||||
inline size_t text_ref_to_attr (const db::Text *tr)
|
||||
{
|
||||
return size_t (tr) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the text value from an attribute ID
|
||||
*/
|
||||
inline const char *text_from_attr (size_t attr)
|
||||
{
|
||||
tl_assert ((attr & 1) != 0);
|
||||
const db::Text *t = reinterpret_cast<const db::Text *> (attr - 1);
|
||||
return t->string ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -633,8 +633,11 @@ shape_interactions<TS, TI>::intruder_shape (unsigned int id) const
|
|||
|
||||
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Edge>;
|
||||
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::TextRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::Edge, db::Edge>;
|
||||
template class DB_PUBLIC shape_interactions<db::Edge, db::PolygonRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::TextRef, db::TextRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::TextRef, db::PolygonRef>;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Helper classes for the LocalProcessor
|
||||
|
|
@ -656,6 +659,12 @@ inline unsigned int shape_flags<db::Edge> ()
|
|||
return db::ShapeIterator::Edges;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned int shape_flags<db::TextRef> ()
|
||||
{
|
||||
return db::ShapeIterator::Texts;
|
||||
}
|
||||
|
||||
template <class TS, class TI>
|
||||
struct interaction_registration_shape2shape
|
||||
: db::box_scanner_receiver2<TS, unsigned int, TI, unsigned int>
|
||||
|
|
@ -850,8 +859,11 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u
|
|||
|
||||
// not very strong, but already useful: the cells interact if there is a layer1 in cell1
|
||||
// in the common box and a layer2 in the cell2 in the common box
|
||||
if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, tni1 * cbox, true).at_end () &&
|
||||
! db::RecursiveShapeIterator (*layout2, cell2, layer2, tni2 * cbox, true).at_end ()) {
|
||||
// NOTE: don't use overlap mode for the RecursiveShapeIterator as this would not capture dot-like
|
||||
// objects like texts. Instead safe-shrink the search box and use touching mode ("false" for the last
|
||||
// argument)
|
||||
if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, safe_box_enlarged (tni1 * cbox, -1, -1), false).at_end () &&
|
||||
! db::RecursiveShapeIterator (*layout2, cell2, layer2, safe_box_enlarged (tni2 * cbox, -1, -1), false).at_end ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -929,7 +941,9 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins
|
|||
|
||||
// not very strong, but already useful: the cells interact if there is a layer in cell
|
||||
// in the common box
|
||||
if (! db::RecursiveShapeIterator (*layout, cell, layer, tni * cbox, true).at_end ()) {
|
||||
// NOTE: don't use overlapping mode here, because this will not select point-like objects as texts or
|
||||
// dot edges. Instead safe-shrink the search box and use touching mode.
|
||||
if (! db::RecursiveShapeIterator (*layout, cell, layer, safe_box_enlarged (tni * cbox, -1, -1), false).at_end ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1743,11 +1757,15 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
template class DB_PUBLIC local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::Edge, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::Edge, db::Edge>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::TextRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::TextRef, db::TextRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::PolygonRef, db::EdgePair>;
|
||||
template class DB_PUBLIC local_processor<db::Edge, db::Edge, db::Edge>;
|
||||
template class DB_PUBLIC local_processor<db::Edge, db::PolygonRef, db::Edge>;
|
||||
template class DB_PUBLIC local_processor<db::Edge, db::PolygonRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::Edge, db::Edge, db::EdgePair>;
|
||||
template class DB_PUBLIC local_processor<db::TextRef, db::PolygonRef, db::TextRef>;
|
||||
template class DB_PUBLIC local_processor<db::TextRef, db::PolygonRef, db::PolygonRef>;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ namespace db
|
|||
|
||||
static HierarchyBuilderShapeInserter def_inserter;
|
||||
|
||||
static HierarchyBuilder::cell_map_type null_map;
|
||||
static HierarchyBuilder::cell_map_type::const_iterator null_iterator = null_map.end ();
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
int
|
||||
|
|
@ -168,7 +171,7 @@ HierarchyBuilder::reset ()
|
|||
m_cell_map.clear ();
|
||||
m_cells_seen.clear ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = cell_map_type::const_iterator ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
|
|
@ -263,14 +266,14 @@ HierarchyBuilder::end (const RecursiveShapeIterator *iter)
|
|||
m_cells_seen.clear ();
|
||||
mp_initial_cell = m_cell_stack.empty () ? 0 : m_cell_stack.front ().second.front ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = cell_map_type::const_iterator ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != cell_map_type::const_iterator ());
|
||||
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != null_iterator);
|
||||
|
||||
m_cells_seen.insert (m_cm_entry->first);
|
||||
|
||||
|
|
@ -704,4 +707,22 @@ void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout)
|
||||
: mp_layout (layout)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target)
|
||||
{
|
||||
if (shape.is_text ()) {
|
||||
// NOTE: we intentionally skip all the text attributes (font etc.) here because in the context
|
||||
// of a text collections we're only interested in the locations.
|
||||
db::Text t (shape.text_string (), shape.text_trans ());
|
||||
target->insert (db::TextRef (t.transformed (trans), mp_layout->shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,23 @@ public:
|
|||
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An text-generating shape receiver that feeds a shapes array after turning the shapes into texts
|
||||
*/
|
||||
class DB_PUBLIC TextBuildingHierarchyBuilderShapeReceiver
|
||||
: public HierarchyBuilderShapeReceiver
|
||||
{
|
||||
public:
|
||||
TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout);
|
||||
|
||||
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
|
||||
virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class building a hierarchy from a recursive shape iterator in push mode
|
||||
*
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ void init (const std::vector<std::string> &_paths)
|
|||
try {
|
||||
s_plugins.push_back (load_plugin (imp));
|
||||
modules.insert (*im);
|
||||
} catch (tl::Exception (&ex)) {
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,16 +241,28 @@ Instance::to_string (bool resolve_cell_name) const
|
|||
r = "cell_index=" + tl::to_string (ci.object ().cell_index ());
|
||||
}
|
||||
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans ().to_string ();
|
||||
} else {
|
||||
r += " " + (*ci.begin ()).to_string ();
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans ().to_string ();
|
||||
} else {
|
||||
r += " " + (*ci.begin ()).to_string ();
|
||||
}
|
||||
|
||||
r += " array=(" + a.to_string () + "," + b.to_string () + " " + tl::to_string (amax) + "x" + tl::to_string (bmax) + ")";
|
||||
|
||||
} else {
|
||||
|
||||
for (db::CellInstArray::iterator i = ci.begin (); ! i.at_end (); ++i) {
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans (*i).to_string ();
|
||||
} else {
|
||||
r += " " + (*i).to_string ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (has_prop_id ()) {
|
||||
|
|
@ -640,13 +652,12 @@ OverlappingInstanceIteratorTraits::init (instance_iterator<OverlappingInstanceIt
|
|||
// ChildCellIterator implementation
|
||||
|
||||
ChildCellIterator::ChildCellIterator ()
|
||||
: m_iter (), m_end (), mp_insts (0)
|
||||
: m_iter (), m_end ()
|
||||
{ }
|
||||
|
||||
ChildCellIterator::ChildCellIterator (const instances_type *insts)
|
||||
: m_iter (insts->begin_sorted_insts ()),
|
||||
m_end (insts->end_sorted_insts ()),
|
||||
mp_insts (insts)
|
||||
m_end (insts->end_sorted_insts ())
|
||||
{ }
|
||||
|
||||
cell_index_type
|
||||
|
|
|
|||
|
|
@ -945,7 +945,6 @@ public:
|
|||
|
||||
private:
|
||||
inst_iterator_type m_iter, m_end;
|
||||
const instances_type *mp_insts;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbTexts.h"
|
||||
#include "tlTimer.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlInternational.h"
|
||||
|
|
@ -661,6 +664,12 @@ Layout::insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_p
|
|||
edge_pairs.insert_into (this, cell, layer);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::insert (db::cell_index_type cell, int layer, const db::Texts &texts)
|
||||
{
|
||||
texts.insert_into (this, cell, layer);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::ICplxTrans &t, int levels)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class LayerMapping;
|
|||
class Region;
|
||||
class Edges;
|
||||
class EdgePairs;
|
||||
class Texts;
|
||||
|
||||
template <class Coord> class generic_repository;
|
||||
typedef generic_repository<db::Coord> GenericRepository;
|
||||
|
|
@ -557,6 +558,14 @@ public:
|
|||
return m_string_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the string repository (const version)
|
||||
*/
|
||||
const StringRepository &string_repository () const
|
||||
{
|
||||
return m_string_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the shape repository
|
||||
*/
|
||||
|
|
@ -565,6 +574,14 @@ public:
|
|||
return m_shape_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the shape repository (const version)
|
||||
*/
|
||||
const GenericRepository &shape_repository () const
|
||||
{
|
||||
return m_shape_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the properties repository
|
||||
*/
|
||||
|
|
@ -1123,6 +1140,15 @@ public:
|
|||
*/
|
||||
void insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_pairs);
|
||||
|
||||
/**
|
||||
* @brief Inserts a text collection (potentially hierarchical) into the given cell and layer
|
||||
*
|
||||
* If the text collection is flat (conceptionally), it will be put into the cell.
|
||||
* If the text collection is hierarchical, a cell hierarchy will be built below the
|
||||
* given cell.
|
||||
*/
|
||||
void insert (db::cell_index_type cell, int layer, const db::Texts &texts);
|
||||
|
||||
/**
|
||||
* @brief Delete a cell plus all subcells
|
||||
*
|
||||
|
|
|
|||
|
|
@ -427,6 +427,9 @@ struct PathCompareOpWithTolerance
|
|||
db::Path::iterator ia = a.begin (), ib = b.begin ();
|
||||
while (ia != a.end () && ib != b.end ()) {
|
||||
c = compare_point (*ia, *ib, m_tolerance);
|
||||
if (c != 0) {
|
||||
return c < 0;
|
||||
}
|
||||
++ia;
|
||||
++ib;
|
||||
}
|
||||
|
|
@ -1186,6 +1189,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl;
|
||||
} else if (ci.size () > 1) {
|
||||
enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl;
|
||||
} else {
|
||||
enough (tl::info) << "" << tl::noendl;
|
||||
}
|
||||
|
|
@ -1205,6 +1210,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl;
|
||||
} else if (ci.size () > 1) {
|
||||
enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl;
|
||||
} else {
|
||||
enough (tl::info) << "" << tl::noendl;
|
||||
}
|
||||
|
|
@ -1256,7 +1263,7 @@ PrintingDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b)
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Database units differ " << dbu_a << " vs. " << dbu_b;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1266,7 +1273,7 @@ PrintingDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la)
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Layer " << la.to_string () << " is not present in layout b, but in a";
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1276,7 +1283,7 @@ PrintingDifferenceReceiver::layer_in_b_only (const db::LayerProperties &lb)
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Layer " << lb.to_string () << " is not present in layout a, but in b";
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1287,7 +1294,7 @@ PrintingDifferenceReceiver::layer_name_differs (const db::LayerProperties &la, c
|
|||
try {
|
||||
enough (tl::error) << "Layer names differ between layout a and b for layer " << la.layer << "/" << la.datatype << ": "
|
||||
<< la.name << " vs. " << lb.name;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1297,7 +1304,7 @@ PrintingDifferenceReceiver::cell_in_a_only (const std::string &cellname, db::cel
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Cell " << cellname << " is not present in layout b, but in a";
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1307,7 +1314,7 @@ PrintingDifferenceReceiver::cell_in_b_only (const std::string &cellname, db::cel
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Cell " << cellname << " is not present in layout a, but in b";
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1317,7 +1324,7 @@ PrintingDifferenceReceiver::cell_name_differs (const std::string &cellname_a, db
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Cell " << cellname_a << " in a is renamed to " << cellname_b << " in b";
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1327,7 +1334,7 @@ PrintingDifferenceReceiver::bbox_differs (const db::Box &ba, const db::Box &bb)
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Bounding boxes differ for cell " << m_cellname << ", " << ba.to_string () << " vs. " << bb.to_string ();
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1343,7 +1350,7 @@ PrintingDifferenceReceiver::begin_inst_differences ()
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Instances differ in cell " << m_cellname;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1366,7 +1373,7 @@ PrintingDifferenceReceiver::instances_in_a_only (const std::vector <db::CellInst
|
|||
for (std::vector <db::CellInstArrayWithProperties>::const_iterator s = anotb.begin (); s != anotb.end (); ++s) {
|
||||
print_cell_inst (*s, a);
|
||||
}
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1379,7 +1386,7 @@ PrintingDifferenceReceiver::instances_in_b_only (const std::vector <db::CellInst
|
|||
for (std::vector <db::CellInstArrayWithProperties>::const_iterator s = bnota.begin (); s != bnota.end (); ++s) {
|
||||
print_cell_inst (*s, b);
|
||||
}
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1401,7 +1408,7 @@ PrintingDifferenceReceiver::per_layer_bbox_differs (const db::Box &ba, const db:
|
|||
try {
|
||||
enough (tl::error) << "Per-layer bounding boxes differ for cell " << m_cellname << ", layer (" << m_layer.to_string () << "), "
|
||||
<< ba.to_string () << " vs. " << bb.to_string ();
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1411,7 +1418,7 @@ PrintingDifferenceReceiver::begin_polygon_differences ()
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Polygons differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1424,7 +1431,7 @@ PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, c
|
|||
print_diffs (pr, a, b);
|
||||
enough (tl::info) << "Not in a but in b:";
|
||||
print_diffs (pr, b, a);
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1439,7 +1446,7 @@ PrintingDifferenceReceiver::begin_path_differences ()
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Paths differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1452,7 +1459,7 @@ PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, c
|
|||
print_diffs (pr, a, b);
|
||||
enough (tl::info) << "Not in a but in b:";
|
||||
print_diffs (pr, b, a);
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1467,7 +1474,7 @@ PrintingDifferenceReceiver::begin_box_differences ()
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Boxes differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1480,7 +1487,7 @@ PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, c
|
|||
print_diffs (pr, a, b);
|
||||
enough (tl::info) << "Not in a but in b:";
|
||||
print_diffs (pr, b, a);
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1495,7 +1502,7 @@ PrintingDifferenceReceiver::begin_edge_differences ()
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Edges differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1508,7 +1515,7 @@ PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, c
|
|||
print_diffs (pr, a, b);
|
||||
enough (tl::info) << "Not in a but in b:";
|
||||
print_diffs (pr, b, a);
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1523,7 +1530,7 @@ PrintingDifferenceReceiver::begin_text_differences ()
|
|||
{
|
||||
try {
|
||||
enough (tl::error) << "Texts differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
@ -1536,7 +1543,7 @@ PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, c
|
|||
print_diffs (pr, a, b);
|
||||
enough (tl::info) << "Not in a but in b:";
|
||||
print_diffs (pr, b, a);
|
||||
} catch (tl::CancelException) {
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbLayoutToNetlistWriter.h"
|
||||
|
|
@ -172,17 +173,17 @@ db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::st
|
|||
return region.release ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n)
|
||||
db::Texts *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n)
|
||||
{
|
||||
db::RecursiveShapeIterator si (m_iter);
|
||||
si.set_layer (layer_index);
|
||||
si.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
std::auto_ptr <db::Region> region (new db::Region (si, dss ()));
|
||||
std::auto_ptr <db::Texts> texts (new db::Texts (si, dss ()));
|
||||
if (! n.empty ()) {
|
||||
register_layer (*region, n);
|
||||
register_layer (*texts, n);
|
||||
}
|
||||
return region.release ();
|
||||
return texts.release ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n)
|
||||
|
|
@ -206,7 +207,7 @@ void LayoutToNetlist::link_nets (const db::Net *net, const db::Net *with)
|
|||
return;
|
||||
}
|
||||
|
||||
connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||
connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||
clusters.join_cluster_with (net->cluster_id (), with->cluster_id ());
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +222,7 @@ size_t LayoutToNetlist::link_net_to_parent_circuit (const Net *subcircuit_net, C
|
|||
db::CplxTrans dbu_trans (internal_layout ()->dbu ());
|
||||
db::ICplxTrans trans = dbu_trans.inverted () * dtrans * dbu_trans;
|
||||
|
||||
connected_clusters<db::PolygonRef> &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ());
|
||||
connected_clusters<db::NetShape> &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ());
|
||||
|
||||
size_t id = parent_net_clusters.insert_dummy ();
|
||||
|
||||
|
|
@ -236,7 +237,7 @@ void LayoutToNetlist::ensure_netlist ()
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers)
|
||||
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::ShapeCollection *> &layers)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -262,7 +263,7 @@ void LayoutToNetlist::connect (const db::Region &l)
|
|||
m_conn.connect (dl.layer ());
|
||||
}
|
||||
|
||||
void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
|
||||
void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -283,7 +284,7 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
|
|||
m_conn.connect (dla.layer (), dlb.layer ());
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &gn)
|
||||
void LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const std::string &gn)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -296,7 +297,7 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &
|
|||
db::DeepLayer dl = deep_layer_of (l);
|
||||
m_dlrefs.insert (dl);
|
||||
|
||||
return m_conn.connect_global (dl.layer (), gn);
|
||||
m_conn.connect_global (dl.layer (), gn);
|
||||
}
|
||||
|
||||
const std::string &LayoutToNetlist::global_net_name (size_t id) const
|
||||
|
|
@ -393,42 +394,6 @@ void LayoutToNetlist::ensure_layout () const
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::register_layer (const db::Region ®ion, const std::string &n)
|
||||
{
|
||||
if (m_named_regions.find (n) != m_named_regions.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n);
|
||||
}
|
||||
|
||||
db::DeepLayer dl;
|
||||
|
||||
if (m_is_flat) {
|
||||
|
||||
dl = dss ().create_from_flat (region, true);
|
||||
|
||||
} else {
|
||||
|
||||
db::DeepRegion *delegate = dynamic_cast<db::DeepRegion *> (region.delegate());
|
||||
if (! delegate) {
|
||||
|
||||
dl = dss ().create_from_flat (region, true);
|
||||
|
||||
} else {
|
||||
|
||||
if (is_persisted (region)) {
|
||||
std::string prev_name = name (region);
|
||||
m_named_regions.erase (prev_name);
|
||||
}
|
||||
|
||||
dl = delegate->deep_layer ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_named_regions [n] = dl;
|
||||
m_name_of_layer [dl.layer ()] = n;
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::make_new_name (const std::string &stem)
|
||||
{
|
||||
int m = std::numeric_limits<int>::max () / 2 + 1;
|
||||
|
|
@ -452,16 +417,6 @@ std::string LayoutToNetlist::make_new_name (const std::string &stem)
|
|||
return name;
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::name (const db::Region ®ion) const
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (layer_of (region));
|
||||
if (n != m_name_of_layer.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::name (unsigned int l) const
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (l);
|
||||
|
|
@ -472,11 +427,6 @@ std::string LayoutToNetlist::name (unsigned int l) const
|
|||
}
|
||||
}
|
||||
|
||||
bool LayoutToNetlist::is_persisted (const db::Region ®ion) const
|
||||
{
|
||||
return m_name_of_layer.find (layer_of (region)) != m_name_of_layer.end ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::layer_by_name (const std::string &name)
|
||||
{
|
||||
std::map<std::string, db::DeepLayer>::const_iterator l = m_named_regions.find (name);
|
||||
|
|
@ -497,12 +447,71 @@ db::Region *LayoutToNetlist::layer_by_index (unsigned int index)
|
|||
}
|
||||
}
|
||||
|
||||
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const
|
||||
static db::DeepLayer dss_create_from_flat (db::DeepShapeStore &dss, const db::ShapeCollection &coll)
|
||||
{
|
||||
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (region.delegate ());
|
||||
const db::Region *region = dynamic_cast<const db::Region *> (&coll);
|
||||
const db::Texts *texts = dynamic_cast<const db::Texts *> (&coll);
|
||||
if (region) {
|
||||
return dss.create_from_flat (*region, true);
|
||||
} else if (texts) {
|
||||
return dss.create_from_flat (*texts);
|
||||
} else {
|
||||
tl_assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::name (const ShapeCollection &coll) const
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (layer_of (coll));
|
||||
if (n != m_name_of_layer.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n)
|
||||
{
|
||||
if (m_named_regions.find (n) != m_named_regions.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n);
|
||||
}
|
||||
|
||||
db::DeepLayer dl;
|
||||
|
||||
if (m_is_flat) {
|
||||
|
||||
dl = dss_create_from_flat (dss (), collection);
|
||||
|
||||
} else {
|
||||
|
||||
db::DeepShapeCollectionDelegateBase *delegate = collection.get_delegate ()->deep ();
|
||||
if (! delegate) {
|
||||
|
||||
dl = dss_create_from_flat (dss (), collection);
|
||||
|
||||
} else {
|
||||
|
||||
if (is_persisted (collection)) {
|
||||
std::string prev_name = name (collection);
|
||||
m_named_regions.erase (prev_name);
|
||||
}
|
||||
|
||||
dl = delegate->deep_layer ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_named_regions [n] = dl;
|
||||
m_name_of_layer [dl.layer ()] = n;
|
||||
}
|
||||
|
||||
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::ShapeCollection &coll) const
|
||||
{
|
||||
const db::DeepShapeCollectionDelegateBase *dr = coll.get_delegate ()->deep ();
|
||||
if (! dr) {
|
||||
|
||||
std::pair<bool, db::DeepLayer> lff = dss ().layer_for_flat (region);
|
||||
std::pair<bool, db::DeepLayer> lff = dss ().layer_for_flat (coll);
|
||||
if (lff.first) {
|
||||
return lff.second;
|
||||
} else {
|
||||
|
|
@ -514,11 +523,6 @@ db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const
|
||||
{
|
||||
return deep_layer_of (region).layer ();
|
||||
}
|
||||
|
||||
db::CellMapping LayoutToNetlist::make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells)
|
||||
{
|
||||
std::set<db::cell_index_type> device_cells;
|
||||
|
|
@ -613,49 +617,84 @@ namespace
|
|||
}
|
||||
|
||||
template <class Tr>
|
||||
static bool deliver_shape (const db::PolygonRef &, StopOnFirst, const Tr &, db::properties_id_type)
|
||||
static bool deliver_shape (const db::NetShape &, StopOnFirst, const Tr &, db::properties_id_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/)
|
||||
static bool deliver_shape (const db::NetShape &s, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/)
|
||||
{
|
||||
if (pr.obj ().is_box ()) {
|
||||
region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
} else {
|
||||
region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
|
||||
if (pr.obj ().is_box ()) {
|
||||
region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
} else {
|
||||
region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid)
|
||||
static bool deliver_shape (const db::NetShape &s, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid)
|
||||
{
|
||||
if (pr.obj ().is_box ()) {
|
||||
if (propid) {
|
||||
shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid));
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
|
||||
if (pr.obj ().is_box ()) {
|
||||
if (propid) {
|
||||
shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid));
|
||||
} else {
|
||||
shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
}
|
||||
} else {
|
||||
shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
db::Layout *layout = shapes.layout ();
|
||||
if (layout) {
|
||||
db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ());
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid));
|
||||
} else {
|
||||
shapes.insert (polygon_ref);
|
||||
}
|
||||
} else {
|
||||
db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonWithProperties (polygon, propid));
|
||||
} else {
|
||||
shapes.insert (polygon);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
} else if (s.type () == db::NetShape::Text) {
|
||||
|
||||
db::TextRef pr = s.text_ref ();
|
||||
|
||||
db::Layout *layout = shapes.layout ();
|
||||
if (layout) {
|
||||
db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ());
|
||||
db::TextRef text_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ());
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid));
|
||||
shapes.insert (db::TextRefWithProperties (text_ref, propid));
|
||||
} else {
|
||||
shapes.insert (polygon_ref);
|
||||
shapes.insert (text_ref);
|
||||
}
|
||||
} else {
|
||||
db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
db::Text text (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonWithProperties (polygon, propid));
|
||||
shapes.insert (db::TextWithProperties (text, propid));
|
||||
} else {
|
||||
shapes.insert (polygon);
|
||||
shapes.insert (text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -759,7 +798,7 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
|
|||
|
||||
if (net_cell_name_prefix) {
|
||||
|
||||
const db::connected_clusters<db::PolygonRef> &ccl = m_net_clusters.clusters_per_cell (ci);
|
||||
const db::connected_clusters<db::NetShape> &ccl = m_net_clusters.clusters_per_cell (ci);
|
||||
|
||||
bool any_connections = circuit_cell_name_prefix && ! ccl.connections_for_cluster (cid).empty ();
|
||||
if (! any_connections) {
|
||||
|
|
@ -805,8 +844,8 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
|
|||
db::ICplxTrans tr_wo_mag = tr * db::ICplxTrans (1.0 / tr.mag ());
|
||||
db::ICplxTrans tr_mag (tr.mag ());
|
||||
|
||||
const db::connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (ci);
|
||||
typedef db::connected_clusters<db::PolygonRef>::connections_type connections_type;
|
||||
const db::connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (ci);
|
||||
typedef db::connected_clusters<db::NetShape>::connections_type connections_type;
|
||||
const connections_type &connections = clusters.connections_for_cluster (cid);
|
||||
for (connections_type::const_iterator c = connections.begin (); c != connections.end (); ++c) {
|
||||
|
||||
|
|
@ -1002,18 +1041,18 @@ LayoutToNetlist::build_nets (const std::vector<const db::Net *> *nets, const db:
|
|||
}
|
||||
}
|
||||
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point)
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoint &point, std::vector<db::SubCircuit *> *sc_path_out, db::Circuit *initial_circuit)
|
||||
{
|
||||
return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point);
|
||||
return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point, sc_path_out, initial_circuit);
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path)
|
||||
size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path)
|
||||
{
|
||||
db::Box local_box = trans * test_cluster.bbox ();
|
||||
|
||||
const db::local_clusters<db::PolygonRef> &lcc = net_clusters ().clusters_per_cell (cell->cell_index ());
|
||||
for (db::local_clusters<db::PolygonRef>::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) {
|
||||
const db::local_cluster<db::PolygonRef> &lc = *i;
|
||||
const db::local_clusters<db::NetShape> &lcc = net_clusters ().clusters_per_cell (cell->cell_index ());
|
||||
for (db::local_clusters<db::NetShape>::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) {
|
||||
const db::local_cluster<db::NetShape> &lc = *i;
|
||||
if (lc.interacts (test_cluster, trans, m_conn)) {
|
||||
return lc.id ();
|
||||
}
|
||||
|
|
@ -1038,7 +1077,7 @@ size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell
|
|||
return 0;
|
||||
}
|
||||
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point)
|
||||
db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Point &point, std::vector<db::SubCircuit *> *sc_path_out, db::Circuit *initial_circuit)
|
||||
{
|
||||
if (! m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet")));
|
||||
|
|
@ -1050,15 +1089,23 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
unsigned int layer = layer_of (of_region);
|
||||
|
||||
const db::Cell *top_cell = internal_top_cell ();
|
||||
if (initial_circuit && internal_layout ()->is_valid_cell_index (initial_circuit->cell_index ())) {
|
||||
top_cell = &internal_layout ()->cell (initial_circuit->cell_index ());
|
||||
}
|
||||
if (! top_cell) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prepare a test cluster
|
||||
db::Box box (point - db::Vector (1, 1), point + db::Vector (1, 1));
|
||||
db::GenericRepository sr;
|
||||
db::local_cluster<db::PolygonRef> test_cluster;
|
||||
db::local_cluster<db::NetShape> test_cluster;
|
||||
test_cluster.add (db::PolygonRef (db::Polygon (box), sr), layer);
|
||||
|
||||
std::vector<db::InstElement> inst_path;
|
||||
|
||||
size_t cluster_id = search_net (db::ICplxTrans (), internal_top_cell (), test_cluster, inst_path);
|
||||
size_t cluster_id = search_net (db::ICplxTrans (), top_cell, test_cluster, inst_path);
|
||||
if (cluster_id > 0) {
|
||||
|
||||
// search_net delivers the path in reverse order
|
||||
|
|
@ -1066,7 +1113,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
std::vector<db::cell_index_type> cell_indexes;
|
||||
cell_indexes.reserve (inst_path.size () + 1);
|
||||
cell_indexes.push_back (internal_top_cell ()->cell_index ());
|
||||
cell_indexes.push_back (top_cell->cell_index ());
|
||||
for (std::vector<db::InstElement>::const_iterator i = inst_path.begin (); i != inst_path.end (); ++i) {
|
||||
cell_indexes.push_back (i->inst_ptr.cell_index ());
|
||||
}
|
||||
|
|
@ -1103,45 +1150,64 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
|
||||
}
|
||||
|
||||
std::vector<db::SubCircuit *> sc_path;
|
||||
|
||||
db::Net *topmost_net = net;
|
||||
|
||||
// follow the path up in the net hierarchy using the transformation and the upper cell index as the
|
||||
// guide line
|
||||
while (! inst_path.empty () && net->pin_count () > 0) {
|
||||
while (circuit && ! inst_path.empty ()) {
|
||||
|
||||
cell_indexes.pop_back ();
|
||||
|
||||
const db::Pin *pin = circuit->pin_by_id (net->begin_pins ()->pin_id ());
|
||||
tl_assert (pin != 0);
|
||||
const db::Pin *pin = 0;
|
||||
if (net && net->pin_count () > 0) {
|
||||
pin = circuit->pin_by_id (net->begin_pins ()->pin_id ());
|
||||
tl_assert (pin != 0);
|
||||
}
|
||||
|
||||
db::DCplxTrans dtrans = dbu_trans * inst_path.back ().complex_trans () * dbu_trans_inv;
|
||||
|
||||
// try to find a parent circuit which connects to this net
|
||||
db::Circuit *upper_circuit = 0;
|
||||
db::SubCircuit *subcircuit = 0;
|
||||
db::Net *upper_net = 0;
|
||||
for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_net; ++r) {
|
||||
for (db::Circuit::refs_iterator r = circuit->begin_refs (); r != circuit->end_refs () && ! upper_circuit; ++r) {
|
||||
if (r->trans ().equal (dtrans) && r->circuit () && r->circuit ()->cell_index () == cell_indexes.back ()) {
|
||||
upper_net = r->net_for_pin (pin->id ());
|
||||
upper_circuit = r->circuit ();
|
||||
subcircuit = r.operator-> ();
|
||||
if (pin) {
|
||||
upper_net = subcircuit->net_for_pin (pin->id ());
|
||||
}
|
||||
upper_circuit = subcircuit->circuit ();
|
||||
}
|
||||
}
|
||||
|
||||
net = upper_net;
|
||||
|
||||
if (upper_net) {
|
||||
circuit = upper_circuit;
|
||||
net = upper_net;
|
||||
inst_path.pop_back ();
|
||||
topmost_net = upper_net;
|
||||
} else {
|
||||
break;
|
||||
sc_path.push_back (subcircuit);
|
||||
}
|
||||
|
||||
circuit = upper_circuit;
|
||||
inst_path.pop_back ();
|
||||
|
||||
}
|
||||
|
||||
return net;
|
||||
if (sc_path_out) {
|
||||
std::reverse (sc_path.begin (), sc_path.end ());
|
||||
*sc_path_out = sc_path;
|
||||
}
|
||||
|
||||
return topmost_net;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes)
|
||||
db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes)
|
||||
{
|
||||
// TODO: that's basically too much .. we only need the clusters
|
||||
if (! m_netlist_extracted) {
|
||||
|
|
@ -1155,12 +1221,12 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg
|
|||
|
||||
for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) {
|
||||
|
||||
const connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
const connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (connected_clusters<db::PolygonRef>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
for (connected_clusters<db::NetShape>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
continue;
|
||||
|
|
@ -1171,8 +1237,21 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg
|
|||
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (gate), db::ICplxTrans (), rgate, 0);
|
||||
deliver_shapes_of_net_recursive (0, m_net_clusters, *cid, *c, layer_of (metal), db::ICplxTrans (), rmetal, 0);
|
||||
|
||||
double agate = rgate.area () * dbu * dbu;
|
||||
double ametal = rmetal.area () * dbu * dbu;
|
||||
double agate = 0.0;
|
||||
if (fabs (gate_area_factor) > 1e-6) {
|
||||
agate += rgate.area () * dbu * dbu * gate_area_factor;
|
||||
}
|
||||
if (fabs (gate_perimeter_factor) > 1e-6) {
|
||||
agate += rgate.perimeter () * dbu * gate_perimeter_factor;
|
||||
}
|
||||
|
||||
double ametal = 0.0;
|
||||
if (fabs (metal_area_factor) > 1e-6) {
|
||||
ametal += rmetal.area () * dbu * dbu * metal_area_factor;
|
||||
}
|
||||
if (fabs (metal_perimeter_factor) > 1e-6) {
|
||||
ametal += rmetal.perimeter () * dbu * metal_perimeter_factor;
|
||||
}
|
||||
|
||||
double r = ratio;
|
||||
bool skip = false;
|
||||
|
|
|
|||
|
|
@ -240,13 +240,13 @@ public:
|
|||
* derived by boolean operations for example.
|
||||
* Named regions are persisted inside the LayoutToNetlist object.
|
||||
*/
|
||||
void register_layer (const db::Region ®ion, const std::string &name);
|
||||
void register_layer (const ShapeCollection &collection, const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the given region
|
||||
* Returns an empty string if the region does not have a name.
|
||||
* @brief Gets the name of the given collection
|
||||
* Returns an empty string if the collection does not have a name.
|
||||
*/
|
||||
std::string name (const db::Region ®ion) const;
|
||||
std::string name (const ShapeCollection &coll) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the given layer by index
|
||||
|
|
@ -272,7 +272,11 @@ public:
|
|||
* Persisted regions have a name and are kept inside the LayoutToNetlist
|
||||
* object.
|
||||
*/
|
||||
bool is_persisted (const db::Region ®ion) const;
|
||||
template <class Collection>
|
||||
bool is_persisted (const Collection &coll) const
|
||||
{
|
||||
return m_name_of_layer.find (layer_of (coll)) != m_name_of_layer.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the region (layer) with the given name
|
||||
|
|
@ -329,10 +333,10 @@ public:
|
|||
db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Creates a new region representing an original layer taking texts only
|
||||
* @brief Creates a new text collection representing an original layer taking texts only
|
||||
* See "make_layer" for details.
|
||||
*/
|
||||
db::Region *make_text_layer (unsigned int layer_index, const std::string &name = std::string ());
|
||||
db::Texts *make_text_layer (unsigned int layer_index, const std::string &name = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Creates a new region representing an original layer taking polygons and texts
|
||||
|
|
@ -346,13 +350,13 @@ public:
|
|||
* This method will run device extraction for the given extractor. The layer map is specific
|
||||
* for the extractor and uses the region objects derived with "make_layer" and it's variants.
|
||||
*
|
||||
* In addition, derived regions can be passed too. Certain limitations apply. It's safe to use
|
||||
* In addition, derived regions/text collections can be passed too. Certain limitations apply. It's safe to use
|
||||
* boolean operations for deriving layers. Other operations are applicable as long as they are
|
||||
* capable of delivering hierarchical layers.
|
||||
*
|
||||
* If errors occur, the device extractor will contain theses errors.
|
||||
*/
|
||||
void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers);
|
||||
void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::ShapeCollection *> &layers);
|
||||
|
||||
/**
|
||||
* @brief Defines an intra-layer connection for the given layer.
|
||||
|
|
@ -367,13 +371,46 @@ public:
|
|||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* The conditions mentioned with intra-layer "connect" apply for this method too.
|
||||
*/
|
||||
void connect (const db::Region &a, const db::Region &b);
|
||||
void connect (const db::Region &a, const db::Region &b)
|
||||
{
|
||||
connect_impl (a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* As one layer is a texts layer, this connection will basically add net labels.
|
||||
*/
|
||||
void connect (const db::Region &a, const db::Texts &b)
|
||||
{
|
||||
connect_impl (a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* As one layer is a texts layer, this connection will basically add net labels.
|
||||
*/
|
||||
void connect (const db::Texts &a, const db::Region &b)
|
||||
{
|
||||
connect_impl (b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects the given layer with a global net with the given name
|
||||
* Returns the global net ID
|
||||
*/
|
||||
size_t connect_global (const db::Region &l, const std::string &gn);
|
||||
void connect_global (const db::Region &l, const std::string &gn)
|
||||
{
|
||||
connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects the given text layer with a global net with the given name
|
||||
* Returns the global net ID
|
||||
*/
|
||||
void connect_global (const db::Texts &l, const std::string &gn)
|
||||
{
|
||||
connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the global net name for a given global net ID
|
||||
|
|
@ -470,7 +507,11 @@ public:
|
|||
* This method is required to derive the internal layer index - for example for
|
||||
* investigating the cluster tree.
|
||||
*/
|
||||
unsigned int layer_of (const db::Region ®ion) const;
|
||||
template <class Collection>
|
||||
unsigned int layer_of (const Collection &coll) const
|
||||
{
|
||||
return deep_layer_of (coll).layer ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.
|
||||
|
|
@ -522,7 +563,7 @@ public:
|
|||
* NOTE: the layer and cell indexes used inside this structure refer to the
|
||||
* internal layout.
|
||||
*/
|
||||
const db::hier_clusters<db::PolygonRef> &net_clusters () const
|
||||
const db::hier_clusters<db::NetShape> &net_clusters () const
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
|
@ -530,7 +571,7 @@ public:
|
|||
/**
|
||||
* @brief Gets the hierarchical shape clusters derived in the net extraction (non-conver version)
|
||||
*/
|
||||
db::hier_clusters<db::PolygonRef> &net_clusters ()
|
||||
db::hier_clusters<db::NetShape> &net_clusters ()
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
|
@ -668,8 +709,11 @@ public:
|
|||
*
|
||||
* This variant accepts a micrometer-unit location. The location is given in the
|
||||
* coordinate space of the initial cell.
|
||||
*
|
||||
* The subcircuit path leading to the topmost net is stored in *sc_path_out if this
|
||||
* pointer is non-null.
|
||||
*/
|
||||
db::Net *probe_net (const db::Region &of_region, const db::DPoint &point);
|
||||
db::Net *probe_net (const db::Region &of_region, const db::DPoint &point, std::vector<SubCircuit *> *sc_path_out = 0, Circuit *initial_circuit = 0);
|
||||
|
||||
/**
|
||||
* @brief Finds the net by probing a specific location on the given layer
|
||||
|
|
@ -677,7 +721,7 @@ public:
|
|||
* This variant accepts a database-unit location. The location is given in the
|
||||
* coordinate space of the initial cell.
|
||||
*/
|
||||
db::Net *probe_net (const db::Region &of_region, const db::Point &point);
|
||||
db::Net *probe_net (const db::Region &of_region, const db::Point &point, std::vector<SubCircuit *> *sc_path_out = 0, Circuit *initial_circuit = 0);
|
||||
|
||||
/**
|
||||
* @brief Runs an antenna check on the extracted clusters
|
||||
|
|
@ -689,6 +733,14 @@ public:
|
|||
* the limit ratio all metal shapes are copied to the output region as
|
||||
* error markers.
|
||||
*
|
||||
* The area computation of gate and metal happens by taking the polygon
|
||||
* area (A) and perimeter (P) into account:
|
||||
*
|
||||
* A(antenna) = A + P * t
|
||||
*
|
||||
* where t is the perimeter factor. The unit of this area factor is
|
||||
* micrometers.
|
||||
*
|
||||
* The limit ratio can be modified by the presence of connections to
|
||||
* other layers (specifically designating diodes for charge removal).
|
||||
* Each of these layers will modify the ratio by adding a value of
|
||||
|
|
@ -701,7 +753,31 @@ public:
|
|||
* regardless of the diode's area.
|
||||
* In other words: any diode will make the net safe against antenna discharge.
|
||||
*/
|
||||
db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ());
|
||||
db::Region antenna_check (const db::Region &gate, double gate_perimeter_factor, const db::Region &metal, double metal_perimeter_factor, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ())
|
||||
{
|
||||
return antenna_check (gate, 1.0, gate_perimeter_factor, metal, 1.0, metal_perimeter_factor, ratio, diodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Variant of the antennna check not using the perimeter
|
||||
* This version uses 0 for the perimeter factor hence not taking into account the perimeter at all.
|
||||
*/
|
||||
db::Region antenna_check (const db::Region &gate, const db::Region &metal, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ())
|
||||
{
|
||||
return antenna_check (gate, 1.0, 0.0, metal, 1.0, 0.0, ratio, diodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Variant of the antenna check providing an area scale factor
|
||||
*
|
||||
* This version provides an additional area scale factor f, so the effective area becomes
|
||||
*
|
||||
* A(antenna) = A * f + P * t
|
||||
*
|
||||
* where f is the area scale factor and t the perimeter scale factor. This version allows to ignore the
|
||||
* area contribution entirely and switch to a perimeter-based antenna check by setting f to zero.
|
||||
*/
|
||||
db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > ());
|
||||
|
||||
/**
|
||||
* @brief Saves the database to the given path
|
||||
|
|
@ -744,7 +820,7 @@ private:
|
|||
tl::weak_ptr<db::DeepShapeStore> mp_dss;
|
||||
unsigned int m_layout_index;
|
||||
db::Connectivity m_conn;
|
||||
db::hier_clusters<db::PolygonRef> m_net_clusters;
|
||||
db::hier_clusters<db::NetShape> m_net_clusters;
|
||||
std::auto_ptr<db::Netlist> mp_netlist;
|
||||
std::set<db::DeepLayer> m_dlrefs;
|
||||
std::map<std::string, db::DeepLayer> m_named_regions;
|
||||
|
|
@ -786,15 +862,17 @@ private:
|
|||
|
||||
void init ();
|
||||
void ensure_netlist ();
|
||||
size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
|
||||
size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
|
||||
void build_net_rec (const db::Net &net, db::Layout &target, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const Net *net, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
db::DeepLayer deep_layer_of (const db::Region ®ion) const;
|
||||
db::DeepLayer deep_layer_of (const ShapeCollection &coll) const;
|
||||
void ensure_layout () const;
|
||||
std::string make_new_name (const std::string &stem = std::string ());
|
||||
db::properties_id_type make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const;
|
||||
db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells);
|
||||
void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
||||
void connect_global_impl (const db::ShapeCollection &l, const std::string &gn);
|
||||
|
||||
// implementation of NetlistManipulationCallbacks
|
||||
virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::device_key ("device");
|
||||
DB_PUBLIC std::string LongKeys::polygon_key ("polygon");
|
||||
DB_PUBLIC std::string LongKeys::rect_key ("rect");
|
||||
DB_PUBLIC std::string LongKeys::text_key ("text");
|
||||
DB_PUBLIC std::string LongKeys::terminal_key ("terminal");
|
||||
DB_PUBLIC std::string LongKeys::abstract_key ("abstract");
|
||||
DB_PUBLIC std::string LongKeys::param_key ("param");
|
||||
|
|
@ -56,7 +57,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::scale_key ("scale");
|
||||
DB_PUBLIC std::string LongKeys::pin_key ("pin");
|
||||
|
||||
// A, B, C, D, E, F, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
// A, B, C, D, E, F, G, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
DB_PUBLIC std::string ShortKeys::version_key ("V");
|
||||
DB_PUBLIC std::string ShortKeys::description_key ("B");
|
||||
DB_PUBLIC std::string ShortKeys::top_key ("W");
|
||||
|
|
@ -72,6 +73,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string ShortKeys::device_key ("D");
|
||||
DB_PUBLIC std::string ShortKeys::polygon_key ("Q");
|
||||
DB_PUBLIC std::string ShortKeys::rect_key ("R");
|
||||
DB_PUBLIC std::string ShortKeys::text_key ("J");
|
||||
DB_PUBLIC std::string ShortKeys::terminal_key ("T");
|
||||
DB_PUBLIC std::string ShortKeys::abstract_key ("A");
|
||||
DB_PUBLIC std::string ShortKeys::param_key ("E");
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ namespace db
|
|||
* "*" for <x> or <y> means take previous
|
||||
* rect(<layer> [coord] [coord]) - defines a rectangle [short key: R]
|
||||
* coordinates are bottom/left and top/right
|
||||
* text(<layer> [text] [coord]) - defines a rectangle [short key: J]
|
||||
*
|
||||
* [coord]
|
||||
*
|
||||
|
|
@ -177,6 +178,7 @@ namespace l2n_std_format
|
|||
static std::string subcircuit_key;
|
||||
static std::string polygon_key;
|
||||
static std::string rect_key;
|
||||
static std::string text_key;
|
||||
static std::string terminal_key;
|
||||
static std::string abstract_key;
|
||||
static std::string param_key;
|
||||
|
|
@ -209,6 +211,7 @@ namespace l2n_std_format
|
|||
static std::string subcircuit_key;
|
||||
static std::string polygon_key;
|
||||
static std::string rect_key;
|
||||
static std::string text_key;
|
||||
static std::string terminal_key;
|
||||
static std::string abstract_key;
|
||||
static std::string param_key;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ LayoutToNetlistStandardReader::skip ()
|
|||
|
||||
void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read")));
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_path);
|
||||
|
||||
try {
|
||||
read_netlist (0, l2n);
|
||||
|
|
@ -358,8 +358,10 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
|
|||
dm->set_name (name);
|
||||
netlist->add_device_abstract (dm);
|
||||
|
||||
db::cell_index_type ci = l2n->internal_layout ()->add_cell (name.c_str ());
|
||||
dm->set_cell_index (ci);
|
||||
if (l2n) {
|
||||
db::cell_index_type ci = l2n->internal_layout ()->add_cell (name.c_str ());
|
||||
dm->set_cell_index (ci);
|
||||
}
|
||||
|
||||
std::string cls;
|
||||
read_word_or_quoted (cls);
|
||||
|
|
@ -443,8 +445,7 @@ LayoutToNetlistStandardReader::read_property (db::NetlistObject *obj)
|
|||
br.done ();
|
||||
}
|
||||
|
||||
std::pair<unsigned int, db::PolygonRef>
|
||||
LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
|
||||
std::pair<unsigned int, NetShape> LayoutToNetlistStandardReader::read_geometry(db::LayoutToNetlist *l2n)
|
||||
{
|
||||
std::string lname;
|
||||
|
||||
|
|
@ -480,6 +481,22 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
|
|||
poly.assign_hull (pt.begin (), pt.end ());
|
||||
return std::make_pair (lid, db::PolygonRef (poly, l2n->internal_layout ()->shape_repository ()));
|
||||
|
||||
} else if (test (skeys::text_key) || test (lkeys::text_key)) {
|
||||
|
||||
Brace br (this);
|
||||
|
||||
read_word_or_quoted (lname);
|
||||
unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname));
|
||||
|
||||
std::string text;
|
||||
read_word_or_quoted (text);
|
||||
|
||||
db::Point pt = read_point ();
|
||||
|
||||
br.done ();
|
||||
|
||||
return std::make_pair (lid, db::TextRef (db::Text (text, db::Trans (pt - db::Point ())), l2n->internal_layout ()->shape_repository ()));
|
||||
|
||||
} else if (at_end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Unexpected end of file (polygon or rect expected)")));
|
||||
} else {
|
||||
|
|
@ -522,7 +539,7 @@ LayoutToNetlistStandardReader::read_polygon ()
|
|||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell)
|
||||
LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::NetShape> &lc, db::Cell &cell)
|
||||
{
|
||||
m_ref = db::Point ();
|
||||
|
||||
|
|
@ -530,9 +547,9 @@ LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &b
|
|||
if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
read_property (obj);
|
||||
} else {
|
||||
std::pair<unsigned int, db::PolygonRef> pr = read_geometry (l2n);
|
||||
std::pair<unsigned int, db::NetShape> pr = read_geometry (l2n);
|
||||
lc.add (pr.second, pr.first);
|
||||
cell.shapes (pr.first).insert (pr.second);
|
||||
pr.second.insert_into (cell.shapes (pr.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -559,8 +576,8 @@ LayoutToNetlistStandardReader::read_net (db::Netlist * /*netlist*/, db::LayoutTo
|
|||
|
||||
if (l2n) {
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
db::connected_clusters<db::NetShape> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::NetShape> &lc = *cc.insert ();
|
||||
net->set_cluster_id (lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
|
|
@ -1023,8 +1040,8 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n,
|
|||
|
||||
if (l2n) {
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
db::connected_clusters<db::NetShape> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::NetShape> &lc = *cc.insert ();
|
||||
dm->set_cluster_id_for_terminal (tid, lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ());
|
||||
|
|
|
|||
|
|
@ -139,11 +139,11 @@ protected:
|
|||
void read_subcircuit (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map<db::CellInstArray, std::list<Connections> > &connections);
|
||||
bool read_trans_part (db::DCplxTrans &tr);
|
||||
void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc);
|
||||
std::pair<unsigned int, db::PolygonRef> read_geometry (db::LayoutToNetlist *l2n);
|
||||
std::pair<unsigned int, db::NetShape> read_geometry(db::LayoutToNetlist *l2n);
|
||||
void read_property (db::NetlistObject *obj);
|
||||
db::Polygon read_polygon ();
|
||||
db::Box read_rect ();
|
||||
void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell);
|
||||
void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<NetShape> &lc, db::Cell &cell);
|
||||
db::Point read_point ();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -397,30 +397,49 @@ void std_writer_impl<Keys>::reset_geometry_ref ()
|
|||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
|
||||
void std_writer_impl<Keys>::write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
|
||||
{
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (s->trans ());
|
||||
if (s->type () == db::NetShape::Polygon) {
|
||||
|
||||
const db::Polygon &poly = s->obj ();
|
||||
if (poly.is_box ()) {
|
||||
db::PolygonRef pr = s->polygon_ref ();
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (pr.trans ());
|
||||
|
||||
db::Box box = t * poly.box ();
|
||||
*mp_stream << Keys::rect_key << "(" << lname;
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p1 (), m_ref, relative);
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p2 (), m_ref, relative);
|
||||
*mp_stream << ")";
|
||||
const db::Polygon &poly = pr.obj ();
|
||||
if (poly.is_box ()) {
|
||||
|
||||
} else {
|
||||
db::Box box = t * poly.box ();
|
||||
*mp_stream << Keys::rect_key << "(" << lname;
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p1 (), m_ref, relative);
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p2 (), m_ref, relative);
|
||||
*mp_stream << ")";
|
||||
|
||||
*mp_stream << Keys::polygon_key << "(" << lname;
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp = db::polygon_to_simple_polygon (poly);
|
||||
write_points (*mp_stream, sp, t, m_ref, relative);
|
||||
} else {
|
||||
write_points (*mp_stream, poly, t, m_ref, relative);
|
||||
|
||||
*mp_stream << Keys::polygon_key << "(" << lname;
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp = db::polygon_to_simple_polygon (poly);
|
||||
write_points (*mp_stream, sp, t, m_ref, relative);
|
||||
} else {
|
||||
write_points (*mp_stream, poly, t, m_ref, relative);
|
||||
}
|
||||
*mp_stream << ")";
|
||||
|
||||
}
|
||||
|
||||
} else if (s->type () == db::NetShape::Text) {
|
||||
|
||||
*mp_stream << Keys::text_key << "(" << lname;
|
||||
|
||||
db::TextRef txtr = s->text_ref ();
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (txtr.trans ());
|
||||
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (txtr.obj ().string ()) << " ";
|
||||
|
||||
db::Point pt = t * (db::Point () + txtr.obj ().trans ().disp ());
|
||||
write_point (*mp_stream, pt, m_ref, relative);
|
||||
|
||||
*mp_stream << ")";
|
||||
|
||||
}
|
||||
|
|
@ -435,7 +454,7 @@ bool std_writer_impl<Keys>::new_cell (cell_index_type ci) const
|
|||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const std::string &indent)
|
||||
{
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = mp_l2n->net_clusters ();
|
||||
const db::hier_clusters<db::NetShape> &clusters = mp_l2n->net_clusters ();
|
||||
const db::Circuit *circuit = net.circuit ();
|
||||
const db::Connectivity &conn = mp_l2n->connectivity ();
|
||||
|
||||
|
|
@ -450,7 +469,7 @@ void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const st
|
|||
db::cell_index_type cci = circuit->cell_index ();
|
||||
db::cell_index_type prev_ci = cci;
|
||||
|
||||
for (db::recursive_cluster_shape_iterator<db::PolygonRef> si (clusters, *l, cci, net.cluster_id (), this); ! si.at_end (); ) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> si (clusters, *l, cci, net.cluster_id (), this); ! si.at_end (); ) {
|
||||
|
||||
// NOTE: we don't recursive into circuits which will later be output. However, as circuits may
|
||||
// vanish in "purge" but the clusters will still be there we need to recursive into clusters from
|
||||
|
|
@ -570,7 +589,7 @@ void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, co
|
|||
{
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = device_abstract.device_class ()->terminal_definitions ();
|
||||
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = mp_l2n->net_clusters ();
|
||||
const db::hier_clusters<db::NetShape> &clusters = mp_l2n->net_clusters ();
|
||||
const db::Connectivity &conn = mp_l2n->connectivity ();
|
||||
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
|
@ -587,8 +606,8 @@ void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, co
|
|||
continue;
|
||||
}
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid);
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
const db::local_cluster<db::NetShape> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid);
|
||||
for (db::local_cluster<db::NetShape>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
|
||||
*mp_stream << indent << indent2;
|
||||
write (s.operator-> (), db::ICplxTrans (), name_for_layer (mp_l2n, *l), true);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class DeviceAbstract;
|
|||
class Net;
|
||||
class Netlist;
|
||||
class LayoutToNetlist;
|
||||
class NetShape;
|
||||
|
||||
namespace l2n_std_format
|
||||
{
|
||||
|
|
@ -75,7 +76,7 @@ private:
|
|||
void write (const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
|
||||
void write (const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
|
||||
void write (const db::DeviceAbstract &device_abstract, const std::string &indent);
|
||||
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void write (const db::DCplxTrans &trans);
|
||||
void reset_geometry_ref ();
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,39 @@ Library::~Library ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
Library::is_for_technology (const std::string &name) const
|
||||
{
|
||||
return m_technologies.find (name) != m_technologies.end ();
|
||||
}
|
||||
|
||||
bool
|
||||
Library::for_technologies () const
|
||||
{
|
||||
return ! m_technologies.empty ();
|
||||
}
|
||||
|
||||
void
|
||||
Library::set_technology (const std::string &t)
|
||||
{
|
||||
m_technologies.clear ();
|
||||
if (! t.empty ()) {
|
||||
m_technologies.insert (t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Library::clear_technologies ()
|
||||
{
|
||||
m_technologies.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
Library::add_technology (const std::string &tech)
|
||||
{
|
||||
m_technologies.insert (tech);
|
||||
}
|
||||
|
||||
void
|
||||
Library::register_proxy (db::LibraryProxy *lib_proxy, db::Layout *ly)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "tlObject.h"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -108,18 +109,38 @@ public:
|
|||
* If this attribute is non-empty, the library is selected only when the given technology is
|
||||
* used for the layout.
|
||||
*/
|
||||
const std::string &get_technology () const
|
||||
const std::set<std::string> &get_technologies () const
|
||||
{
|
||||
return m_technology;
|
||||
return m_technologies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the technology name this library is associated with
|
||||
* @brief Gets a value indicating whether this library is associated with the given technology
|
||||
*/
|
||||
void set_technology (const std::string &t)
|
||||
{
|
||||
m_technology = t;
|
||||
}
|
||||
bool is_for_technology (const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the library is associated with any technology
|
||||
*/
|
||||
bool for_technologies () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the technology name this library is associated with
|
||||
*
|
||||
* This will reset the list of technologies to this one.
|
||||
* If the given technology string is empty, the list of technologies will be cleared.
|
||||
*/
|
||||
void set_technology (const std::string &t);
|
||||
|
||||
/**
|
||||
* @brief Clears the list of technologies this library is associated with
|
||||
*/
|
||||
void clear_technologies ();
|
||||
|
||||
/**
|
||||
* @brief Additionally associate the library with the given technology
|
||||
*/
|
||||
void add_technology (const std::string &tech);
|
||||
|
||||
/**
|
||||
* @brief Getter for the description property
|
||||
|
|
@ -198,7 +219,7 @@ public:
|
|||
private:
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
std::string m_technology;
|
||||
std::set<std::string> m_technologies;
|
||||
lib_id_type m_id;
|
||||
db::Layout m_layout;
|
||||
std::map<db::Layout *, int> m_referrers;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ LibraryManager::delete_lib (Library *library)
|
|||
library->remap_to (0);
|
||||
delete library;
|
||||
m_libs [id] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,14 +97,6 @@ public:
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy ctor
|
||||
*/
|
||||
Matrix2d (const Matrix2d &d)
|
||||
{
|
||||
*this = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a matrix from a transformation
|
||||
*/
|
||||
|
|
@ -522,14 +514,6 @@ public:
|
|||
set (d, 0.0, 0.0, 0.0, d, 0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy ctor
|
||||
*/
|
||||
Matrix3d (const Matrix3d &d)
|
||||
{
|
||||
*this = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add operator
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbNetShape.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbPolygonTools.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
NetShape::NetShape ()
|
||||
: m_ptr (0), m_dx (0), m_dy (0)
|
||||
{ }
|
||||
|
||||
NetShape::NetShape (const db::PolygonRef &pr)
|
||||
{
|
||||
m_ptr = size_t (&pr.obj ()) + 1;
|
||||
m_dx = pr.trans ().disp ().x ();
|
||||
m_dy = pr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::NetShape (const db::Polygon &poly, db::GenericRepository &repo)
|
||||
{
|
||||
db::PolygonRef pr (poly, repo);
|
||||
m_ptr = size_t (&pr.obj ()) + 1;
|
||||
m_dx = pr.trans ().disp ().x ();
|
||||
m_dy = pr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::NetShape (const db::TextRef &tr)
|
||||
{
|
||||
m_ptr = size_t (&tr.obj ());
|
||||
m_dx = tr.trans ().disp ().x ();
|
||||
m_dy = tr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::NetShape (const db::Text &text, db::GenericRepository &repo)
|
||||
{
|
||||
db::TextRef tr (text, repo);
|
||||
m_ptr = size_t (&tr.obj ());
|
||||
m_dx = tr.trans ().disp ().x ();
|
||||
m_dy = tr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::shape_type NetShape::type () const
|
||||
{
|
||||
if (m_ptr == 0) {
|
||||
return None;
|
||||
} else if ((m_ptr & 1) != 0) {
|
||||
return Polygon;
|
||||
} else {
|
||||
return Text;
|
||||
}
|
||||
}
|
||||
|
||||
db::PolygonRef NetShape::polygon_ref () const
|
||||
{
|
||||
if ((size_t (m_ptr) & 1) != 0) {
|
||||
return db::PolygonRef (reinterpret_cast<db::Polygon *> (m_ptr - 1), db::Disp (db::Vector (m_dx, m_dy)));
|
||||
}
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
db::TextRef NetShape::text_ref () const
|
||||
{
|
||||
if ((size_t (m_ptr) & 1) == 0) {
|
||||
return db::TextRef (reinterpret_cast<db::Text *> (m_ptr), db::Disp (db::Vector (m_dx, m_dy)));
|
||||
}
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
void NetShape::transform (const db::Disp &tr)
|
||||
{
|
||||
m_dx += tr.disp ().x ();
|
||||
m_dy += tr.disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::box_type NetShape::bbox () const
|
||||
{
|
||||
if ((m_ptr & 1) != 0) {
|
||||
return polygon_ref ().box ();
|
||||
} else if (m_ptr != 0) {
|
||||
return text_ref ().box ();
|
||||
} else {
|
||||
return box_type ();
|
||||
}
|
||||
}
|
||||
|
||||
void NetShape::insert_into (db::Shapes &shapes) const
|
||||
{
|
||||
if ((m_ptr & 1) != 0) {
|
||||
shapes.insert (polygon_ref ());
|
||||
} else if (m_ptr != 0) {
|
||||
shapes.insert (text_ref ());
|
||||
}
|
||||
}
|
||||
|
||||
void NetShape::insert_into (db::Shapes &shapes, db::properties_id_type pi) const
|
||||
{
|
||||
if ((m_ptr & 1) != 0) {
|
||||
shapes.insert (db::PolygonRefWithProperties (polygon_ref (), pi));
|
||||
} else if (m_ptr != 0) {
|
||||
shapes.insert (db::TextRefWithProperties (text_ref (), pi));
|
||||
}
|
||||
}
|
||||
|
||||
bool NetShape::interacts_with (const db::NetShape &other) const
|
||||
{
|
||||
if (m_ptr == 0 || other.m_ptr == 0 || ! bbox ().touches (other.bbox ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_ptr & 1) != 0) {
|
||||
|
||||
if ((other.m_ptr & 1) != 0) {
|
||||
|
||||
// Polygon vs. polygon
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Polygon p = pr_other.obj ().transformed (pr.trans ().inverted () * pr_other.trans ());
|
||||
return db::interact_pp (pr.obj (), p);
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Point pt = db::Point (other.m_dx, other.m_dy) - pr.trans ().disp ();
|
||||
return db::inside_poly (pr.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ((other.m_ptr & 1) == 0) {
|
||||
|
||||
// Text vs. text
|
||||
return m_dx == other.m_dx && m_dy == other.m_dy;
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::Point pt = db::Point (m_dx, m_dy) - pr_other.trans ().disp ();
|
||||
return db::inside_poly (pr_other.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
bool NetShape::interacts_with_transformed (const db::NetShape &other, const Tr &trans) const
|
||||
{
|
||||
if (m_ptr == 0 || other.m_ptr == 0 || ! bbox ().touches (other.bbox ().transformed (trans))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_ptr & 1) != 0) {
|
||||
|
||||
if ((other.m_ptr & 1) != 0) {
|
||||
|
||||
// Polygon vs. polygon
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Polygon p = pr_other.obj ().transformed (Tr (pr.trans ().inverted ()) * trans * Tr (pr_other.trans ()));
|
||||
return db::interact_pp (pr.obj (), p);
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Point pt = trans * db::Point (other.m_dx, other.m_dy) - pr.trans ().disp ();
|
||||
return db::inside_poly (pr.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ((other.m_ptr & 1) == 0) {
|
||||
|
||||
// Text vs. text
|
||||
db::Point pt = trans * db::Point (other.m_dx, other.m_dy);
|
||||
return db::Point (m_dx, m_dy) == pt;
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::Point pt = trans.inverted () * db::Point (m_dx, m_dy) - pr_other.trans ().disp ();
|
||||
return db::inside_poly (pr_other.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template DB_PUBLIC bool NetShape::interacts_with_transformed<db::ICplxTrans> (const db::NetShape &other, const db::ICplxTrans &trans) const;
|
||||
template DB_PUBLIC bool NetShape::interacts_with_transformed<db::Trans> (const db::NetShape &other, const db::Trans &trans) const;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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_dbNetShape
|
||||
#define HDR_dbNetShape
|
||||
|
||||
#include "dbPolygon.h"
|
||||
#include "dbText.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "dbBoxConvert.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
class Shapes;
|
||||
|
||||
/**
|
||||
* @brief Provides a union of a PolygonRef and a TextRef
|
||||
*
|
||||
* This object is used in the netlist extractor and represents either a polygon or a text.
|
||||
* The TextRef shall utilize a StringRef to represent the string.
|
||||
*/
|
||||
class DB_PUBLIC NetShape
|
||||
{
|
||||
public:
|
||||
enum shape_type { None, Text, Polygon };
|
||||
|
||||
typedef db::Point point_type;
|
||||
typedef db::Box box_type;
|
||||
typedef db::Coord coord_type;
|
||||
typedef db::Disp trans_type;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
NetShape ();
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a PolygonRef
|
||||
*/
|
||||
NetShape (const db::PolygonRef &pr);
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a Polygon from the given shape repository
|
||||
*/
|
||||
NetShape (const db::Polygon &poly, db::GenericRepository &repo);
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a TextRef
|
||||
*/
|
||||
NetShape (const db::TextRef &tr);
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a Text from the given shape repository
|
||||
*/
|
||||
NetShape (const db::Text &text, db::GenericRepository &repo);
|
||||
|
||||
/**
|
||||
* @brief Gets a code indicating the type of object stored herein
|
||||
*/
|
||||
shape_type type () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the PolygonRef object
|
||||
* Asserts if the object stored is not a polygon.
|
||||
*/
|
||||
db::PolygonRef polygon_ref () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the TextRef object
|
||||
* Asserts if the object stored is not a text.
|
||||
*/
|
||||
db::TextRef text_ref () const;
|
||||
|
||||
/**
|
||||
* @brief In-place transformation
|
||||
*/
|
||||
void transform (const db::Disp &tr);
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const NetShape &net_shape) const
|
||||
{
|
||||
return m_ptr == net_shape.m_ptr && m_dx == net_shape.m_dx && m_dy == net_shape.m_dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const NetShape &net_shape) const
|
||||
{
|
||||
return ! operator== (net_shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const NetShape &net_shape) const
|
||||
{
|
||||
if (m_ptr != net_shape.m_ptr) {
|
||||
return m_ptr < net_shape.m_ptr;
|
||||
}
|
||||
if (m_dx != net_shape.m_dx) {
|
||||
return m_dx < net_shape.m_dx;
|
||||
}
|
||||
return m_dy < net_shape.m_dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box of the object
|
||||
*/
|
||||
box_type bbox () const;
|
||||
|
||||
/**
|
||||
* @brief Inserts the object into a Shapes collection
|
||||
*/
|
||||
void insert_into (db::Shapes &shapes) const;
|
||||
|
||||
/**
|
||||
* @brief Inserts the object into a Shapes collection with the given properties ID
|
||||
*/
|
||||
void insert_into (db::Shapes &shapes, db::properties_id_type pi) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the object interacts with another NetShape object
|
||||
*/
|
||||
bool interacts_with (const db::NetShape &other) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the object interacts with another NetShape object after transforming it
|
||||
*/
|
||||
template <class Tr>
|
||||
bool interacts_with_transformed (const db::NetShape &other, const Tr &trans) const;
|
||||
|
||||
public:
|
||||
size_t m_ptr;
|
||||
coord_type m_dx, m_dy;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A box converter implementation for NetShape
|
||||
*/
|
||||
template <>
|
||||
struct box_convert<db::NetShape>
|
||||
{
|
||||
typedef db::NetShape::box_type box_type;
|
||||
typedef db::NetShape::coord_type coord_type;
|
||||
typedef db::complex_bbox_tag complexity;
|
||||
|
||||
box_type operator() (const db::NetShape &net_shape) const
|
||||
{
|
||||
return net_shape.bbox ();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -265,6 +265,10 @@ void Netlist::unlock ()
|
|||
|
||||
const tl::vector<Circuit *> &Netlist::child_circuits (Circuit *circuit)
|
||||
{
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
if (! m_valid_topology) {
|
||||
validate_topology ();
|
||||
}
|
||||
|
|
@ -275,6 +279,10 @@ const tl::vector<Circuit *> &Netlist::child_circuits (Circuit *circuit)
|
|||
|
||||
const tl::vector<Circuit *> &Netlist::parent_circuits (Circuit *circuit)
|
||||
{
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
if (! m_valid_topology) {
|
||||
validate_topology ();
|
||||
}
|
||||
|
|
@ -364,18 +372,39 @@ void Netlist::clear ()
|
|||
|
||||
void Netlist::add_circuit (Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit already contained in a netlist")));
|
||||
}
|
||||
|
||||
m_circuits.push_back (circuit);
|
||||
circuit->set_netlist (this);
|
||||
}
|
||||
|
||||
void Netlist::remove_circuit (Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
circuit->set_netlist (0);
|
||||
m_circuits.erase (circuit);
|
||||
}
|
||||
|
||||
void Netlist::purge_circuit (Circuit *circuit)
|
||||
{
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
circuit->blank ();
|
||||
remove_circuit (circuit);
|
||||
}
|
||||
|
|
@ -406,7 +435,12 @@ void Netlist::flatten_circuits (const std::vector<Circuit *> &circuits)
|
|||
|
||||
void Netlist::flatten_circuit (Circuit *circuit)
|
||||
{
|
||||
tl_assert (circuit != 0);
|
||||
if (! circuit) {
|
||||
return;
|
||||
}
|
||||
if (circuit->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Circuit not within given netlist")));
|
||||
}
|
||||
|
||||
std::vector<db::SubCircuit *> refs;
|
||||
for (db::Circuit::refs_iterator sc = circuit->begin_refs (); sc != circuit->end_refs (); ++sc) {
|
||||
|
|
@ -448,24 +482,52 @@ DeviceClass *Netlist::device_class_by_name (const std::string &name)
|
|||
|
||||
void Netlist::add_device_class (DeviceClass *device_class)
|
||||
{
|
||||
if (! device_class) {
|
||||
return;
|
||||
}
|
||||
if (device_class->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device class already contained in a netlist")));
|
||||
}
|
||||
|
||||
m_device_classes.push_back (device_class);
|
||||
device_class->set_netlist (this);
|
||||
}
|
||||
|
||||
void Netlist::remove_device_class (DeviceClass *device_class)
|
||||
{
|
||||
if (! device_class) {
|
||||
return;
|
||||
}
|
||||
if (device_class->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device class not within given netlist")));
|
||||
}
|
||||
|
||||
device_class->set_netlist (0);
|
||||
m_device_classes.erase (device_class);
|
||||
}
|
||||
|
||||
void Netlist::add_device_abstract (DeviceAbstract *device_abstract)
|
||||
{
|
||||
if (! device_abstract) {
|
||||
return;
|
||||
}
|
||||
if (device_abstract->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device abstract already contained in a netlist")));
|
||||
}
|
||||
|
||||
m_device_abstracts.push_back (device_abstract);
|
||||
device_abstract->set_netlist (this);
|
||||
}
|
||||
|
||||
void Netlist::remove_device_abstract (DeviceAbstract *device_abstract)
|
||||
{
|
||||
if (! device_abstract) {
|
||||
return;
|
||||
}
|
||||
if (device_abstract->netlist () != this) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device abstract not within given netlist")));
|
||||
}
|
||||
|
||||
device_abstract->set_netlist (0);
|
||||
m_device_abstracts.erase (device_abstract);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -38,6 +38,8 @@ class DeviceCategorizer;
|
|||
class CircuitCategorizer;
|
||||
class CircuitMapper;
|
||||
class NetGraph;
|
||||
class SubCircuitEquivalenceTracker;
|
||||
class DeviceEquivalenceTracker;
|
||||
|
||||
/**
|
||||
* @brief A receiver for netlist compare events
|
||||
|
|
@ -285,6 +287,26 @@ public:
|
|||
return m_max_n_branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating depth-first traversal
|
||||
*
|
||||
* With depth first (the default), the algorithm looks for further identities before moving to another
|
||||
* node. With breadth first (false), the algorithm will work in "waves" rather than digging deerly
|
||||
* into the direction of a node.
|
||||
*/
|
||||
void set_depth_first (bool df)
|
||||
{
|
||||
m_depth_first = df;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating depth-first traversal
|
||||
*/
|
||||
bool depth_first () const
|
||||
{
|
||||
return m_depth_first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the list of circuits without matching circuit in the other netlist
|
||||
* The result can be used to flatten these circuits prior to compare.
|
||||
|
|
@ -326,8 +348,8 @@ protected:
|
|||
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
|
||||
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
|
||||
void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const;
|
||||
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, bool &good) const;
|
||||
void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &good) const;
|
||||
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const;
|
||||
void do_subcircuit_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, CircuitCategorizer &circuit_categorizer, const db::CircuitPinMapper &circuit_pin_mapper, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, db::SubCircuitEquivalenceTracker &subcircuit_eq, bool &good) const;
|
||||
bool handle_pin_mismatch (const NetGraph &g1, const db::Circuit *c1, const db::Pin *pin1, const NetGraph &g2, const db::Circuit *c2, const db::Pin *p2) const;
|
||||
|
||||
mutable NetlistCompareLogger *mp_logger;
|
||||
|
|
@ -339,6 +361,7 @@ protected:
|
|||
double m_res_threshold;
|
||||
size_t m_max_n_branch;
|
||||
size_t m_max_depth;
|
||||
bool m_depth_first;
|
||||
bool m_dont_consider_net_names;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,39 @@ NetlistCrossReference::per_circuit_data_for (const std::pair<const db::Circuit *
|
|||
return 0;
|
||||
}
|
||||
|
||||
const db::Pin *
|
||||
NetlistCrossReference::other_pin_for (const db::Pin *pin) const
|
||||
{
|
||||
std::map<const db::Pin *, const db::Pin *>::const_iterator i = m_other_pin.find (pin);
|
||||
if (i != m_other_pin.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const db::Device *
|
||||
NetlistCrossReference::other_device_for (const db::Device *device) const
|
||||
{
|
||||
std::map<const db::Device *, const db::Device *>::const_iterator i = m_other_device.find (device);
|
||||
if (i != m_other_device.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const db::SubCircuit *
|
||||
NetlistCrossReference::other_subcircuit_for (const db::SubCircuit *subcircuit) const
|
||||
{
|
||||
std::map<const db::SubCircuit *, const db::SubCircuit *>::const_iterator i = m_other_subcircuit.find (subcircuit);
|
||||
if (i != m_other_subcircuit.end ()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const db::Circuit *
|
||||
NetlistCrossReference::other_circuit_for (const db::Circuit *circuit) const
|
||||
{
|
||||
|
|
@ -568,6 +601,16 @@ NetlistCrossReference::build_subcircuit_pin_refs (const std::pair<const db::Net
|
|||
|
||||
}
|
||||
|
||||
// Fallback for swappable pins: match based on the subcircuit alone
|
||||
if (! pb) {
|
||||
std::map<std::pair<const db::SubCircuit *, size_t>, const db::NetSubcircuitPinRef *>::iterator b = s2t_b.lower_bound (std::make_pair (sb, 0));
|
||||
if (b != s2t_b.end () && b->first.first == sb) {
|
||||
pb = b->second;
|
||||
// remove the entry so we won't find it again
|
||||
s2t_b.erase (b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data.subcircuit_pins.push_back (std::make_pair (a->second, pb));
|
||||
|
|
|
|||
|
|
@ -256,6 +256,9 @@ public:
|
|||
return m_circuits.end ();
|
||||
}
|
||||
|
||||
const db::Pin *other_pin_for (const db::Pin *pin) const;
|
||||
const db::Device *other_device_for (const db::Device *device) const;
|
||||
const db::SubCircuit *other_subcircuit_for (const db::SubCircuit *subcircuit) const;
|
||||
const db::Circuit *other_circuit_for (const db::Circuit *circuit) const;
|
||||
const db::Net *other_net_for (const db::Net *net) const;
|
||||
const PerNetData *per_net_data_for (const std::pair<const db::Net *, const db::Net *> &nets) const;
|
||||
|
|
|
|||
|
|
@ -119,9 +119,12 @@ void NetlistDeviceExtractor::initialize (db::Netlist *nl)
|
|||
setup ();
|
||||
}
|
||||
|
||||
static void insert_into_region (const db::PolygonRef &s, const db::ICplxTrans &tr, db::Region ®ion)
|
||||
static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, db::Region ®ion)
|
||||
{
|
||||
region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ())));
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
region.insert (pr.obj ().transformed (tr * db::ICplxTrans (pr.trans ())));
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters, double device_scaling)
|
||||
|
|
@ -161,10 +164,10 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
|
|||
}
|
||||
|
||||
tl_assert (l->second != 0);
|
||||
db::DeepRegion *dr = dynamic_cast<db::DeepRegion *> (l->second->delegate ());
|
||||
db::DeepShapeCollectionDelegateBase *dr = l->second->get_delegate ()->deep ();
|
||||
if (dr == 0) {
|
||||
|
||||
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->delegate ()));
|
||||
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->get_delegate ()));
|
||||
if (alias.first) {
|
||||
// use deep layer alias for a given flat one (if found)
|
||||
layers.push_back (alias.second.layer ());
|
||||
|
|
@ -207,8 +210,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
{
|
||||
tl_assert (layers.size () == m_layer_definitions.size ());
|
||||
|
||||
typedef db::PolygonRef shape_type;
|
||||
db::ShapeIterator::flags_type shape_iter_flags = db::ShapeIterator::Polygons;
|
||||
typedef db::NetShape shape_type;
|
||||
|
||||
mp_layout = &layout;
|
||||
m_layers = layers;
|
||||
|
|
@ -247,7 +249,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
|
||||
db::Connectivity device_conn = get_connectivity (layout, layers);
|
||||
db::hier_clusters<shape_type> device_clusters;
|
||||
device_clusters.build (layout, cell, shape_iter_flags, device_conn, 0, breakout_cells);
|
||||
device_clusters.build (layout, cell, device_conn, 0, breakout_cells);
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Extracting devices")));
|
||||
|
||||
|
|
@ -365,12 +367,12 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
|
|||
DeviceCellKey key;
|
||||
|
||||
for (geometry_per_terminal_type::const_iterator t = d->second.second.begin (); t != d->second.second.end (); ++t) {
|
||||
std::map<unsigned int, std::set<db::PolygonRef> > > = key.geometry [t->first];
|
||||
std::map<unsigned int, std::set<db::NetShape> > > = key.geometry [t->first];
|
||||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
std::set<db::PolygonRef> &gl = gt [l->first];
|
||||
for (std::vector<db::PolygonRef>::const_iterator p = l->second.begin (); p != l->second.end (); ++p) {
|
||||
db::PolygonRef pr = *p;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
std::set<db::NetShape> &gl = gt [l->first];
|
||||
for (std::vector<db::NetShape>::const_iterator p = l->second.begin (); p != l->second.end (); ++p) {
|
||||
db::NetShape pr = *p;
|
||||
pr.transform (db::NetShape::trans_type (-disp));
|
||||
gl.insert (pr);
|
||||
}
|
||||
}
|
||||
|
|
@ -411,10 +413,10 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
|
|||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
|
||||
db::Shapes &shapes = device_cell.shapes (l->first);
|
||||
for (std::vector<db::PolygonRef>::const_iterator s = l->second.begin (); s != l->second.end (); ++s) {
|
||||
db::PolygonRef pr = *s;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
shapes.insert (db::PolygonRefWithProperties (pr, pi));
|
||||
for (std::vector<db::NetShape>::const_iterator s = l->second.begin (); s != l->second.end (); ++s) {
|
||||
db::NetShape pr = *s;
|
||||
pr.transform (db::NetShape::trans_type (-disp));
|
||||
pr.insert_into (shapes, pi);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -542,10 +544,10 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id
|
|||
|
||||
std::pair<db::Device *, geometry_per_terminal_type> &dd = m_new_devices[device->id ()];
|
||||
dd.first = device;
|
||||
std::vector<db::PolygonRef> &geo = dd.second[terminal_id][layer_index];
|
||||
std::vector<db::NetShape> &geo = dd.second[terminal_id][layer_index];
|
||||
|
||||
for (db::Region::const_iterator p = region.begin_merged (); !p.at_end (); ++p) {
|
||||
geo.push_back (db::PolygonRef (*p, mp_layout->shape_repository ()));
|
||||
geo.push_back (db::NetShape (*p, mp_layout->shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -555,7 +557,7 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id
|
|||
tl_assert (geometry_index < m_layers.size ());
|
||||
unsigned int layer_index = m_layers [geometry_index];
|
||||
|
||||
db::PolygonRef pr (polygon, mp_layout->shape_repository ());
|
||||
db::NetShape pr (polygon, mp_layout->shape_repository ());
|
||||
std::pair<db::Device *, geometry_per_terminal_type> &dd = m_new_devices[device->id ()];
|
||||
dd.first = device;
|
||||
dd.second[terminal_id][layer_index].push_back (pr);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbNetShape.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
|
||||
|
|
@ -204,8 +205,8 @@ public:
|
|||
typedef error_list::const_iterator error_iterator;
|
||||
typedef std::vector<db::NetlistDeviceExtractorLayerDefinition> layer_definitions;
|
||||
typedef layer_definitions::const_iterator layer_definitions_iterator;
|
||||
typedef std::map<std::string, db::Region *> input_layers;
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
typedef std::map<std::string, db::ShapeCollection *> input_layers;
|
||||
typedef db::hier_clusters<db::NetShape> hier_clusters_type;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -260,8 +261,6 @@ public:
|
|||
* the nets later to associate nets with device terminals.
|
||||
*
|
||||
* The definition of the input layers is device class specific.
|
||||
*
|
||||
* NOTE: The extractor expects "PolygonRef" type layers.
|
||||
*/
|
||||
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||
|
||||
|
|
@ -521,11 +520,11 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
std::map<size_t, std::map<unsigned int, std::set<db::PolygonRef> > > geometry;
|
||||
std::map<size_t, std::map<unsigned int, std::set<db::NetShape> > > geometry;
|
||||
std::map<size_t, double> parameters;
|
||||
};
|
||||
|
||||
typedef std::map<unsigned int, std::vector<db::PolygonRef> > geometry_per_layer_type;
|
||||
typedef std::map<unsigned int, std::vector<db::NetShape> > geometry_per_layer_type;
|
||||
typedef std::map<size_t, geometry_per_layer_type> geometry_per_terminal_type;
|
||||
|
||||
tl::weak_ptr<db::Netlist> m_netlist;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "dbNetlistExtractor.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbNetlistDeviceExtractor.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
|
|
@ -50,9 +51,9 @@ void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
|||
}
|
||||
|
||||
static void
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<unsigned int> &eq)
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
|
||||
{
|
||||
std::map<std::string, std::set<unsigned int> > prop_by_name;
|
||||
std::map<std::string, std::set<size_t> > prop_by_name;
|
||||
tl::GlobPattern jn_pattern (joined_net_names);
|
||||
|
||||
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
|
||||
|
|
@ -60,15 +61,23 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type
|
|||
if (p->first == net_name_id) {
|
||||
std::string nn = p->second.to_string ();
|
||||
if (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (i->first);
|
||||
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::set<unsigned int> >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) {
|
||||
std::set<unsigned int>::const_iterator p = pn->second.begin ();
|
||||
std::set<unsigned int>::const_iterator p0 = p;
|
||||
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
|
||||
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
||||
std::string nn = t->string ();
|
||||
if (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::set<size_t> >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) {
|
||||
std::set<size_t>::const_iterator p = pn->second.begin ();
|
||||
std::set<size_t>::const_iterator p0 = p;
|
||||
while (p != pn->second.end ()) {
|
||||
eq.same (*p0, *p);
|
||||
++p;
|
||||
|
|
@ -93,9 +102,9 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
m_terminal_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::terminal_id_property_name ());
|
||||
m_device_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::device_id_property_name ());
|
||||
|
||||
// the big part: actually extract the nets
|
||||
// build an attribute equivalence map which lists the "attribute IDs" which are identical in terms of net names
|
||||
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > net_name_equivalence;
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
|
||||
if (m_text_annot_name_id.first) {
|
||||
if (! m_joined_net_names.empty ()) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||
|
|
@ -107,7 +116,10 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
}
|
||||
}
|
||||
}
|
||||
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence);
|
||||
|
||||
// the big part: actually extract the nets
|
||||
|
||||
mp_clusters->build (*mp_layout, *mp_cell, conn, &net_name_equivalence);
|
||||
|
||||
// reverse lookup for Circuit vs. cell index
|
||||
std::map<db::cell_index_type, db::Circuit *> circuits;
|
||||
|
|
@ -181,7 +193,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (*c);
|
||||
const db::local_cluster<db::NetShape> &lc = clusters.cluster_by_id (*c);
|
||||
if (clusters.connections_for_cluster (*c).empty () && lc.empty ()) {
|
||||
// this is an entirely empty cluster so we skip it.
|
||||
// Such clusters are left over when joining clusters.
|
||||
|
|
@ -204,8 +216,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
// add the global names as second priority
|
||||
if (net_names.empty ()) {
|
||||
const db::local_cluster<db::PolygonRef>::global_nets &gn = lc.get_global_nets ();
|
||||
for (db::local_cluster<db::PolygonRef>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
|
||||
const db::local_cluster<db::NetShape>::global_nets &gn = lc.get_global_nets ();
|
||||
for (db::local_cluster<db::NetShape>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
|
||||
net_names.insert (conn.global_net_name (*g));
|
||||
}
|
||||
}
|
||||
|
|
@ -250,7 +262,13 @@ NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, cons
|
|||
|
||||
for (local_cluster_type::attr_iterator a = dc->begin_attr (); a != dc->end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
if (! db::is_prop_id_attr (*a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_terminal_annot_name_id.second) {
|
||||
dm->set_cluster_id_for_terminal (j->second.to<size_t> (), dc->id ());
|
||||
|
|
@ -282,13 +300,23 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters,
|
|||
const local_cluster_type &lc = clusters.cluster_by_id (cid);
|
||||
for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (db::is_prop_id_attr (*a)) {
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) {
|
||||
net_names.insert (j->second.to_string ());
|
||||
}
|
||||
|
||||
if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) {
|
||||
net_names.insert (j->second.to_string ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
net_names.insert (db::text_from_attr (*a));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -343,13 +371,19 @@ void NetlistExtractor::connect_devices (db::Circuit *circuit,
|
|||
continue;
|
||||
}
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &dc = mp_clusters->clusters_per_cell (inst_cell_index).cluster_by_id (i->id ());
|
||||
const db::local_cluster<db::NetShape> &dc = mp_clusters->clusters_per_cell (inst_cell_index).cluster_by_id (i->id ());
|
||||
|
||||
// connect the net to the terminal of the device: take the terminal ID from the properties on the
|
||||
// device cluster
|
||||
for (local_cluster_type::attr_iterator a = dc.begin_attr (); a != dc.end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
if (! db::is_prop_id_attr (*a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (m_terminal_annot_name_id.first && j->first == m_terminal_annot_name_id.second) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbNetShape.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -71,9 +72,9 @@ class DeviceAbstract;
|
|||
class DB_PUBLIC NetlistExtractor
|
||||
{
|
||||
public:
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
typedef db::connected_clusters<db::PolygonRef> connected_clusters_type;
|
||||
typedef db::local_cluster<db::PolygonRef> local_cluster_type;
|
||||
typedef db::hier_clusters<db::NetShape> hier_clusters_type;
|
||||
typedef db::connected_clusters<db::NetShape> connected_clusters_type;
|
||||
typedef db::local_cluster<db::NetShape> local_cluster_type;
|
||||
|
||||
/**
|
||||
* @brief NetExtractor constructor
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
|
|||
mp_stream.reset (new tl::TextInputStream (stream));
|
||||
mp_netlist = &netlist;
|
||||
mp_circuit = 0;
|
||||
mp_anonymous_top_circuit = 0;
|
||||
mp_nets_by_name.reset (0);
|
||||
m_global_nets.clear ();
|
||||
m_circuits_read.clear ();
|
||||
|
|
@ -268,6 +269,8 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
|
|||
read_card ();
|
||||
}
|
||||
|
||||
build_global_nets ();
|
||||
|
||||
mp_delegate->finish (&netlist);
|
||||
finish ();
|
||||
|
||||
|
|
@ -287,6 +290,48 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist)
|
|||
}
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::build_global_nets ()
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
|
||||
|
||||
for (db::Netlist::bottom_up_circuit_iterator c = mp_netlist->begin_bottom_up (); c != mp_netlist->end_bottom_up (); ++c) {
|
||||
|
||||
if (c.operator-> () == mp_anonymous_top_circuit) {
|
||||
// no pins for the anonymous top circuit
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Net *net = c->net_by_name (*gn);
|
||||
if (! net || net->pin_count () > 0) {
|
||||
// only add a pin for a global net if there is a net with this name
|
||||
// don't add a pin if it already has one
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::Pin &pin = c->add_pin (*gn);
|
||||
c->connect_pin (pin.id (), net);
|
||||
|
||||
for (db::Circuit::refs_iterator r = c->begin_refs (); r != c->end_refs (); ++r) {
|
||||
|
||||
db::SubCircuit &sc = *r;
|
||||
|
||||
db::Net *pnet = sc.circuit ()->net_by_name (*gn);
|
||||
if (! pnet) {
|
||||
pnet = new db::Net ();
|
||||
pnet->set_name (*gn);
|
||||
sc.circuit ()->add_net (pnet);
|
||||
}
|
||||
|
||||
sc.connect_pin (pin.id (), pnet);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NetlistSpiceReader::finish ()
|
||||
{
|
||||
while (! m_streams.empty ()) {
|
||||
|
|
@ -419,7 +464,10 @@ bool NetlistSpiceReader::read_card ()
|
|||
|
||||
while (! ex.at_end ()) {
|
||||
std::string n = read_name (ex);
|
||||
m_global_nets.push_back (n);
|
||||
if (m_global_net_names.find (n) == m_global_net_names.end ()) {
|
||||
m_global_nets.push_back (n);
|
||||
m_global_net_names.insert (n);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ex.test_without_case ("subckt")) {
|
||||
|
|
@ -574,12 +622,9 @@ void NetlistSpiceReader::ensure_circuit ()
|
|||
mp_circuit = new db::Circuit ();
|
||||
// TODO: make top name configurable
|
||||
mp_circuit->set_name (".TOP");
|
||||
mp_anonymous_top_circuit = mp_circuit;
|
||||
mp_netlist->add_circuit (mp_circuit);
|
||||
|
||||
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
|
||||
make_net (*gn);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -825,13 +870,10 @@ void NetlistSpiceReader::read_subcircuit (const std::string &sc_name, const std:
|
|||
for (std::vector<db::Net *>::const_iterator i = nets.begin (); i != nets.end (); ++i) {
|
||||
cc->add_pin (std::string ());
|
||||
}
|
||||
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
|
||||
cc->add_pin (std::string ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (cc->pin_count () != nets.size () + m_global_nets.size ()) {
|
||||
if (cc->pin_count () != nets.size ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between circuit definition and circuit call: %d expected, got %d")), int (cc->pin_count ()), int (nets.size ())));
|
||||
}
|
||||
|
||||
|
|
@ -843,11 +885,6 @@ void NetlistSpiceReader::read_subcircuit (const std::string &sc_name, const std:
|
|||
for (std::vector<db::Net *>::const_iterator i = nets.begin (); i != nets.end (); ++i) {
|
||||
sc->connect_pin (i - nets.begin (), *i);
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
|
||||
db::Net *net = make_net (*gn);
|
||||
sc->connect_pin (gn - m_global_nets.begin () + nets.size (), net);
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistSpiceReader::skip_circuit (tl::Extractor & /*ex*/)
|
||||
|
|
@ -889,13 +926,10 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
|
|||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
cc->add_pin (std::string ());
|
||||
}
|
||||
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
|
||||
cc->add_pin (std::string ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (cc->pin_count () != nn.size () + m_global_nets.size ()) {
|
||||
if (cc->pin_count () != nn.size ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d in circuit %s")), int (cc->pin_count ()), int (nn.size ()), nc));
|
||||
}
|
||||
|
||||
|
|
@ -922,14 +956,6 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
|
|||
mp_circuit->connect_pin (pin_id, net);
|
||||
}
|
||||
|
||||
// produce pins for the global nets
|
||||
for (std::vector<std::string>::const_iterator gn = m_global_nets.begin (); gn != m_global_nets.end (); ++gn) {
|
||||
db::Net *net = make_net (*gn);
|
||||
size_t pin_id = gn - m_global_nets.begin () + nn.size ();
|
||||
mp_circuit->rename_pin (pin_id, net->name ());
|
||||
mp_circuit->connect_pin (pin_id, net);
|
||||
}
|
||||
|
||||
while (! at_end ()) {
|
||||
if (read_card ()) {
|
||||
break;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue