Merge branch 'master' into 2.5d-view-devel

This commit is contained in:
Matthias Koefferlein 2020-08-30 23:40:54 +02:00
commit 1dc9d11745
1156 changed files with 52326 additions and 35239 deletions

View File

@ -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):

1
Jenkinsfile vendored
View File

@ -16,6 +16,7 @@ node("master") {
stage("Checkout sources") {
checkout scm
checkout_private()
}

28
etc/klayout.metainfo.xml Normal file
View File

@ -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>

View File

@ -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.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 204 KiB

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.

View File

@ -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

View File

@ -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

View File

@ -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

90
macbuild/macQAT.sh Executable file
View File

@ -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
#--------------

View 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 )

251
macbuild/nightyCatalina.py Executable file
View File

@ -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
#---------------

View 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

View File

@ -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

View File

@ -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

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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") {

View File

@ -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);
}
}

View File

@ -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
{

View File

@ -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);

View File

@ -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) {

View File

@ -185,10 +185,10 @@ protected:
virtual RegionDelegate *pull_generic (const Region &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, 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;

View File

@ -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
{

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 &center, unsigned int quad)
: m_center (center)
box_tree_node (box_tree_node *parent, const point_type &center, 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 &center, const point_type &corner, unsigned int quad)
{
init (parent, center, corner, quad);
}
void init (box_tree_node *parent, const point_type &center, 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;
}

View File

@ -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.
*

View File

@ -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);

View File

@ -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
*

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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 &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, bool invert) const;
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
};

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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 &region)
*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 &region) 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))));
}
}

View File

@ -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 &region);
/**
* @brief Conversion operator from texts collection to DeepLayer
* This requires the texts to be a DeepTexts. Otherwise, this constructor will assert
*/
DeepLayer (const Texts &region);
/**
* @brief Conversion operator from edges collection to DeepLayer
* This requires the edges to be a DeepEdges. Otherwise, this constructor will assert
*/
DeepLayer (const Edges &region);
/**
* @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 &region);
/**
* @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 &region, 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 &region) 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
*

619
src/db/db/dbDeepTexts.cc Normal file
View File

@ -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);
}
}

102
src/db/db/dbDeepTexts.h Normal file
View File

@ -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

View File

@ -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));

View File

@ -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
*/

View File

@ -34,7 +34,7 @@ EdgePairsDelegate::EdgePairsDelegate ()
}
EdgePairsDelegate::EdgePairsDelegate (const EdgePairsDelegate &other)
: tl::UniqueId ()
: ShapeCollectionDelegateBase ()
{
operator= (other);
}

View File

@ -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;

View File

@ -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 ..
}

View File

@ -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;

View File

@ -37,7 +37,7 @@ EdgesDelegate::EdgesDelegate ()
}
EdgesDelegate::EdgesDelegate (const EdgesDelegate &other)
: tl::UniqueId ()
: ShapeCollectionDelegateBase ()
{
operator= (other);
}

View File

@ -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;

View File

@ -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
{

View File

@ -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;

View File

@ -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 (); }

112
src/db/db/dbEmptyTexts.cc Normal file
View File

@ -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 ();
}
}

91
src/db/db/dbEmptyTexts.h Normal file
View File

@ -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

220
src/db/db/dbFlatTexts.cc Normal file
View File

@ -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);
}
}
}

173
src/db/db/dbFlatTexts.h Normal file
View File

@ -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

View File

@ -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 ()) {

View File

@ -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>;

View File

@ -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

View File

@ -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>;
}

View File

@ -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 ()));
}
}
}

View File

@ -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
*

View File

@ -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 ();
}
}

View File

@ -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

View File

@ -945,7 +945,6 @@ public:
private:
inst_iterator_type m_iter, m_end;
const instances_type *mp_insts;
};
/**

View File

@ -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)
{

View File

@ -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
*

View File

@ -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
}
}

View File

@ -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 &region, 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 &region) 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 &region) 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 &region) 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 &region) const
}
}
unsigned int LayoutToNetlist::layer_of (const db::Region &region) 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 &region, const Tr &tr, db::properties_id_type /*propid*/)
static bool deliver_shape (const db::NetShape &s, db::Region &region, 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;

View File

@ -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 &region, 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 &region) 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 &region) 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 &region) 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 &region) 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);

View File

@ -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");

View File

@ -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;

View File

@ -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 ());

View File

@ -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:

View File

@ -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);

View File

@ -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 ();

View File

@ -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)
{

View File

@ -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;

View File

@ -90,6 +90,7 @@ LibraryManager::delete_lib (Library *library)
library->remap_to (0);
delete library;
m_libs [id] = 0;
break;
}
}
}

View File

@ -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
*/

218
src/db/db/dbNetShape.cc Normal file
View File

@ -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;
}

178
src/db/db/dbNetShape.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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));

View File

@ -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;

View File

@ -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 &region)
static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, db::Region &region)
{
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> > &gt = key.geometry [t->first];
std::map<unsigned int, std::set<db::NetShape> > &gt = 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);

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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