diff --git a/etc/klayout.metainfo.xml b/etc/klayout.metainfo.xml new file mode 100644 index 000000000..27f21c37a --- /dev/null +++ b/etc/klayout.metainfo.xml @@ -0,0 +1,28 @@ + + + de.klayout.KLayout + + KLayout + KLayout, viewer and editor for mask layouts + + CC0-1.0 + GPL-3.0-or-later + + + + Mask layout viewer and editor for the chip design engineer. + + + + klayout.desktop + + + https://www.klayout.de/intro-image.png + + + + Matthias Köfferlein + + klayout + + diff --git a/macbuild/ReadMe.md b/macbuild/ReadMe.md index 1ca45ab36..4f87e9616 100644 --- a/macbuild/ReadMe.md +++ b/macbuild/ReadMe.md @@ -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. 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: -* **`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. diff --git a/macbuild/Resources/script-bundle-A.zip b/macbuild/Resources/script-bundle-A.zip new file mode 100644 index 000000000..6bf4a60df Binary files /dev/null and b/macbuild/Resources/script-bundle-A.zip differ diff --git a/macbuild/Resources/script-bundle-B.zip b/macbuild/Resources/script-bundle-B.zip new file mode 100644 index 000000000..c0c78ca14 Binary files /dev/null and b/macbuild/Resources/script-bundle-B.zip differ diff --git a/macbuild/Resources/script-bundles.zip b/macbuild/Resources/script-bundles.zip index 72ebeecef..bb82e0847 100644 Binary files a/macbuild/Resources/script-bundles.zip and b/macbuild/Resources/script-bundles.zip differ diff --git a/macbuild/Resources/template-KLayoutDMG.applescript b/macbuild/Resources/template-KLayoutDMG.applescript index a8672081e..78d5b00d7 100644 --- a/macbuild/Resources/template-KLayoutDMG.applescript +++ b/macbuild/Resources/template-KLayoutDMG.applescript @@ -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 diff --git a/macbuild/build4mac_env.py b/macbuild/build4mac_env.py index 621acd1ed..033e574d9 100755 --- a/macbuild/build4mac_env.py +++ b/macbuild/build4mac_env.py @@ -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 diff --git a/macbuild/makeDMG4mac.py b/macbuild/makeDMG4mac.py index 7fea13cd6..2bb2a22c5 100755 --- a/macbuild/makeDMG4mac.py +++ b/macbuild/makeDMG4mac.py @@ -17,6 +17,7 @@ import sys import os import re import shutil +import zipfile import glob import platform import optparse @@ -47,7 +48,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 +57,10 @@ 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 CatalinaAnaconda3 # True if 'Catalina with Anaconda3' + global CatalinaHomebrew # True if 'Catalina with Homebrew' + 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 - @@ -130,7 +135,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 +144,21 @@ def SetGlobals(): VolumeDMG = "KLayout" TargetDMG = "" RootApplications = "/Applications" + CatalinaAnaconda3 = False + CatalinaHomebrew = False + DicLightWeight = dict() + Item3AppleScript = "" + # Populate DicLightWeight + DicLightWeight[ "ana3" ] = dict() + DicLightWeight[ "brew" ] = dict() + 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}' + 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}' #------------------------------------------------------------------------------ ## To check the contents of the package directory @@ -156,11 +176,18 @@ def SetGlobals(): # on failure, -1 #------------------------------------------------------------------------------ def CheckPkgDirectory(): + global Platform + global OpClean + global OpMake global DefaultBundleName global BundleName global PackagePrefix global QtIdentification global RubyPythonID + global CatalinaAnaconda3 + global CatalinaHomebrew + global DicLightWeight + global Item3AppleScript #----------------------------------------------------------------------------- # [1] Check the contents of the package directory @@ -175,30 +202,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 +222,73 @@ def CheckPkgDirectory(): PackagePrefix = pkgdirComponents[0] QtIdentification = pkgdirComponents[2] RubyPythonID = pkgdirComponents[5] - return sizeApp + + #----------------------------------------------------------------------------- + # [3] Check if Catalina with Anaconda3 / Homebrew + #----------------------------------------------------------------------------- + CatalinaAnaconda3 = Platform == "Catalina" + CatalinaAnaconda3 &= PackagePrefix == "LW" + CatalinaAnaconda3 &= QtIdentification == "qt5Ana3" + CatalinaAnaconda3 &= RubyPythonID == "Rana3Pana3" + + CatalinaHomebrew = Platform == "Catalina" + CatalinaHomebrew &= PackagePrefix == "LW" + CatalinaHomebrew &= QtIdentification == "qt5Brew" + CatalinaHomebrew &= RubyPythonID == "Rhb27Phb37" + + if CatalinaAnaconda3: + 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"] + + if CatalinaHomebrew: + 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"] + + #------------------------------------------------------ + # [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 +306,7 @@ def ParseCommandLineArguments(): global PackagePrefix global QtIdentification global RubyPythonID - global Version + global KLVersion global OccupiedDS global TargetDMG @@ -290,7 +365,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 +382,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 #------------------------------------------------------------------------------ @@ -364,6 +439,7 @@ def MakeTargetDMGFile(msg=""): BACKGROUND_PNG_FILE=BackgroundPNG, ITEM_1='%s' % BundleName, X1='860', Y1='165', ITEM_2='Applications', X2='860', Y2='345', + ITEM_3=Item3AppleScript, CHECK_BASH='[ -f " & dotDSStore & " ]; echo $?' ) try: @@ -523,10 +599,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 ) diff --git a/scripts/create_drc_samples.rb b/scripts/create_drc_samples.rb index 962c026ac..b8ea6665a 100644 --- a/scripts/create_drc_samples.rb +++ b/scripts/create_drc_samples.rb @@ -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("") + @file.puts(" ") + end + + def <<(str) + @file.puts(str) + end + + def finish + @file.puts(" ") + @file.puts("") + @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 << " #{img_path}/#{out}" + 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 + diff --git a/scripts/mkqtdecl_common/produce.rb b/scripts/mkqtdecl_common/produce.rb index cd0fe496e..89484364c 100755 --- a/scripts/mkqtdecl_common/produce.rb +++ b/scripts/mkqtdecl_common/produce.rb @@ -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 diff --git a/src/buddies/src/bd/strmxor.cc b/src/buddies/src/bd/strmxor.cc index 8c4b03a33..211cef593 100644 --- a/src/buddies/src/bd/strmxor.cc +++ b/src/buddies/src/bd/strmxor.cc @@ -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; diff --git a/src/db/db/db.pro b/src/db/db/db.pro index ea36ff395..6ee1e93fd 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -184,7 +184,19 @@ SOURCES = \ dbLayoutVsSchematic.cc \ gsiDeclDbNetlistCrossReference.cc \ gsiDeclDbLayoutVsSchematic.cc \ - dbNetlistObject.cc + dbNetlistObject.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 HEADERS = \ dbArray.h \ @@ -331,7 +343,17 @@ HEADERS = \ dbLayoutVsSchematicReader.h \ dbLayoutVsSchematicFormatDefs.h \ dbLayoutVsSchematic.h \ - dbNetlistObject.h + dbNetlistObject.h \ + dbTexts.h \ + dbDeepTexts.h \ + dbAsIfFlatTexts.h \ + dbTextsDelegate.h \ + dbEmptyTexts.h \ + dbFlatTexts.h \ + dbTextsUtils.h \ + dbOriginalLayerTexts.h \ + dbNetShape.h \ + dbShapeCollection.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc index bac1a9495..4ed4ee3e9 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.cc +++ b/src/db/db/dbAsIfFlatEdgePairs.cc @@ -75,7 +75,7 @@ AsIfFlatEdgePairs::in (const EdgePairs &other, bool invert) const op.insert (*o); } - std::auto_ptr new_edge_pairs (new FlatEdgePairs (false)); + std::auto_ptr new_edge_pairs (new FlatEdgePairs ()); for (EdgePairsIterator o (begin ()); ! o.at_end (); ++o) { if ((op.find (*o) == op.end ()) == invert) { diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 26bfe7689..588eaf462 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -59,6 +59,16 @@ AsIfFlatEdges::~AsIfFlatEdges () // .. nothing yet .. } +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 +180,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const { db::box_scanner 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 +507,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co db::box_scanner 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) { diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h index 7a94c35c5..55c79ade0 100644 --- a/src/db/db/dbAsIfFlatEdges.h +++ b/src/db/db/dbAsIfFlatEdges.h @@ -185,10 +185,9 @@ protected: virtual RegionDelegate *pull_generic (const Region ®ion) const; virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const; virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const; - -private: AsIfFlatEdges &operator= (const AsIfFlatEdges &other); +private: mutable bool m_bbox_valid; mutable db::Box m_bbox; diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 0a9278df1..047137407 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -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,17 @@ AsIfFlatRegion::~AsIfFlatRegion () // .. nothing yet .. } +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 +376,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 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatRegion (true)); + region_to_text_interaction_filter 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::box_convert ()); + + 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 +496,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const std::auto_ptr output (new FlatEdges (false)); region_to_edge_interaction_filter 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 +513,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 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatTexts (false)); + region_to_text_interaction_filter 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::box_convert ()); + + return output.release (); +} + RegionDelegate * AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index ed232d858..631026f4d 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -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,17 +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 static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes); template 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); +private: + mutable bool m_bbox_valid; mutable db::Box m_bbox; diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc new file mode 100644 index 000000000..fe9c86da3 --- /dev/null +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -0,0 +1,384 @@ + +/* + + 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 + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// AsIfFlagTexts implementation + +AsIfFlatTexts::AsIfFlatTexts () + : TextsDelegate (), m_bbox_valid (false) +{ + // .. 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 op; + for (TextsIterator o (other.begin ()); ! o.at_end (); ++o) { + op.insert (*o); + } + + std::auto_ptr 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 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::polygons (db::Coord e) const +{ + std::auto_ptr 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 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 (other.delegate ()); + if (other_flat) { + + std::auto_ptr 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 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 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 output (new FlatTexts ()); + + if (! inverse) { + + text_to_region_interaction_filter filter (*output); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } else { + + std::set interacting; + text_to_region_interaction_filter, db::Text> filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + 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 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 output (new FlatRegion (true)); + + text_to_region_interaction_filter filter (*output); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + 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); +} + +} + diff --git a/src/db/db/dbAsIfFlatTexts.h b/src/db/db/dbAsIfFlatTexts.h new file mode 100644 index 000000000..b0f4611fe --- /dev/null +++ b/src/db/db/dbAsIfFlatTexts.h @@ -0,0 +1,96 @@ + +/* + + 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 (); + 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 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 + diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc index f0138a17c..95d105d91 100644 --- a/src/db/db/dbDeepEdgePairs.cc +++ b/src/db/db/dbDeepEdgePairs.cc @@ -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 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 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 @@ -243,12 +242,12 @@ EdgePairsDelegate *DeepEdgePairs::filtered (const EdgePairFilterBase &filter) co RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const { - db::DeepLayer new_layer = m_deep_layer.derived (); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (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 +260,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 (m_deep_layer.layout ()); + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (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 +303,8 @@ EdgePairsDelegate *DeepEdgePairs::in (const EdgePairs &other, bool invert) const bool DeepEdgePairs::equals (const EdgePairs &other) const { const DeepEdgePairs *other_delegate = dynamic_cast (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 +314,8 @@ bool DeepEdgePairs::equals (const EdgePairs &other) const bool DeepEdgePairs::less (const EdgePairs &other) const { const DeepEdgePairs *other_delegate = dynamic_cast (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 +323,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); } - } diff --git a/src/db/db/dbDeepEdgePairs.h b/src/db/db/dbDeepEdgePairs.h index a6d0732f1..c75355a35 100644 --- a/src/db/db/dbDeepEdgePairs.h +++ b/src/db/db/dbDeepEdgePairs.h @@ -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 (); @@ -80,21 +80,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; }; diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 4b9eec059..d9c3fe21c 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -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 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 (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 (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 (m_deep_layer.layout ()); + db::Layout &layout = const_cast (deep_layer ().layout ()); db::hier_clusters 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 @@ -650,11 +671,18 @@ 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 +758,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 +781,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 proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&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 +799,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 proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&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 +1079,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 +1306,7 @@ public: } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 0); } @@ -1295,7 +1323,7 @@ public: edge_to_region_interaction_filter > filter (interacting); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::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 +1402,7 @@ public: } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 1); } diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 662ac5cd1..8ed87c971 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -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,14 +144,9 @@ 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; - } - - DeepLayer &deep_layer () - { - return m_deep_layer; + return this; } protected: @@ -163,7 +158,6 @@ private: 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 +172,8 @@ private: virtual RegionDelegate *pull_generic (const Region ®ion) const; virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const; virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const; + DeepEdges *apply_filter (const EdgeFilterBase &filter) const; + template OutputContainer *processed_impl (const edge_processor &filter) const; }; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 078924859..e0ba85dc5 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -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 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 (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 (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 (m_deep_layer.layout ()); + db::Layout &layout = const_cast (deep_layer ().layout ()); db::hier_clusters 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 proc (const_cast (&m_deep_layer.layout ()), const_cast (&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 proc (const_cast (&deep_layer ().layout ()), const_cast (&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 @@ -1085,11 +1107,18 @@ 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 +1199,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 +1234,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 (m_deep_layer.layout ()); + db::Layout &layout = const_cast (deep_layer ().layout ()); db::hier_clusters 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) { @@ -1502,7 +1531,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons const_cast (&polygons.initial_cell ()), other_deep ? &other_deep->deep_layer ().layout () : const_cast (&polygons.layout ()), other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast (&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 +1899,143 @@ public: } }; +struct TextResultInserter +{ + typedef db::TextRef value_type; + + TextResultInserter (std::unordered_set &result) + : mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::TextRef &e) + { + (*mp_result).insert (e); + } + +private: + std::unordered_set *mp_result; +}; + +class PullWithTextLocalOperation + : public local_operation +{ +public: + PullWithTextLocalOperation () + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + TextResultInserter inserter (result); + region_to_text_interaction_filter filter (inserter, false); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j), 0); + } + } + + std::list heap; + for (shape_interactions::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::box_convert ()); + } + + 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 +{ +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 &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + ResultInserter inserter (layout, result); + region_to_text_interaction_filter filter (inserter, m_inverse); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j), 0); + } + } + + std::list heap; + for (shape_interactions::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::box_convert ()); + 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 +2182,70 @@ DeepRegion::pull_generic (const Edges &other) const return res; } +TextsDelegate * +DeepRegion::pull_generic (const Texts &other) const +{ + std::auto_ptr dr_holder; + const db::DeepTexts *other_deep = dynamic_cast (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 (*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 proc (const_cast (&polygons.layout ()), const_cast (&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 dr_holder; + const db::DeepTexts *other_deep = dynamic_cast (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 (*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 proc (const_cast (&polygons.layout ()), const_cast (&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; +} + } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index c1665d658..28dcdf0f8 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -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 polygon_layer_type; @@ -159,14 +159,9 @@ 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; - } - - DeepLayer &deep_layer () - { - return m_deep_layer; + return this; } protected: @@ -176,10 +171,10 @@ protected: 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 +187,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 OutputContainer *processed_impl (const polygon_processor &filter) const; }; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index c1fcb9009..a2e11a840 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -25,7 +25,14 @@ #include "dbCellMapping.h" #include "dbLayoutUtils.h" #include "dbRegion.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbTexts.h" #include "dbDeepRegion.h" +#include "dbDeepEdges.h" +#include "dbDeepEdgePairs.h" +#include "dbDeepTexts.h" +#include "dbShapeCollection.h" #include "tlTimer.h" @@ -48,6 +55,30 @@ DeepLayer::DeepLayer (const Region ®ion) *this = dr->deep_layer (); } +DeepLayer::DeepLayer (const Texts &texts) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepTexts *dr = dynamic_cast (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 (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 (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 DeepShapeStore::layer_for_flat (const db::Region ®ion) const +DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans) { - return layer_for_flat (tl::id_of (region.delegate ())); + // reuse existing layer + std::pair 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 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 DeepShapeStore::layer_for_flat (const ShapeCollection &coll) const +{ + return layer_for_flat (tl::id_of (coll.get_delegate ())); } std::pair 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)))); + } } diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 3290d5573..9e6d30dad 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -43,6 +43,9 @@ class DeepShapeStore; class DeepShapeStoreState; class Region; class Edges; +class EdgePairs; +class Texts; +class ShapeCollection; /** * @brief Represents a shape collection from the deep shape store @@ -75,6 +78,24 @@ public: */ DeepLayer (const Region ®ion); + /** + * @brief Conversion operator from texts collection to DeepLayer + * This requires the texts to be a DeepTexts. Otherwise, this constructor will assert + */ + DeepLayer (const Texts ®ion); + + /** + * @brief Conversion operator from edges collection to DeepLayer + * This requires the edges to be a DeepEdges. Otherwise, this constructor will assert + */ + DeepLayer (const Edges ®ion); + + /** + * @brief Conversion operator from edge pairs collection to DeepLayer + * This requires the edge pairs to be a DeepEdgePairs. Otherwise, this constructor will assert + */ + DeepLayer (const EdgePairs ®ion); + /** * @brief Copy constructor */ @@ -338,15 +359,26 @@ public: * After a flat layer has been created for a region, it can be retrieved * from the region later with layer_for_flat (region). */ - DeepLayer create_from_flat (const db::Edges ®ion, const db::ICplxTrans &trans = db::ICplxTrans ()); + DeepLayer create_from_flat (const db::Edges &edges, const db::ICplxTrans &trans = db::ICplxTrans ()); /** - * @brief Gets the layer for a given flat region. + * @brief Creates a new layer from a flat text collection (or the text collection is made flat) + * + * This method is intended for use with singular-created DSS objects (see + * singular constructor). + * + * After a flat layer has been created for a region, it can be retrieved + * from the region later with layer_for_flat (region). + */ + DeepLayer create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans = db::ICplxTrans ()); + + /** + * @brief Gets the layer for a given flat collection (Region, Edges, Texts, EdgePairs) * * If a layer has been created for a flat region with create_from_flat, it can be retrieved with this method. * The first return value is true in this case. */ - std::pair layer_for_flat (const db::Region ®ion) const; + std::pair 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 * diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc new file mode 100644 index 000000000..50f6e2623 --- /dev/null +++ b/src/db/db/dbDeepTexts.cc @@ -0,0 +1,613 @@ + +/* + + 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 +#include + +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 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 (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 (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 vars; + if (filter.vars ()) { + + vars.reset (new db::VariantsCollectorBase (filter.vars ())); + + vars->collect (texts.layout (), texts.initial_cell ()); + + if (filter.wants_variants ()) { + const_cast (texts).separate_variants (*vars); + } + + } + + db::Layout &layout = const_cast (texts.layout ()); + std::map > to_commit; + + std::auto_ptr 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 &vv = vars->variants (c->cell_index ()); + for (std::map::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::polygons (db::Coord e) const +{ + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (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 (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 (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 (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 +{ +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 &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + std::set others; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j)); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::TextRef &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 0); + } + + std::list heap; + for (std::set::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 interacting; + text_to_region_interaction_filter, db::TextRef> filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (shape_interactions::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, db::TextRef> filter (result); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } + } + + 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 &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 *mp_result; +}; + +class Text2PolygonPullLocalOperation + : public local_operation +{ +public: + Text2PolygonPullLocalOperation () + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + std::set others; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j)); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::TextRef &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 1); + } + + std::list heap; + for (std::set::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 filter (inserter); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + } + + 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 dr_holder; + const db::DeepRegion *other_deep = dynamic_cast (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 (*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 proc (const_cast (&texts.layout ()), const_cast (&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 dr_holder; + const db::DeepRegion *other_deep = dynamic_cast (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 (*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 proc (const_cast (&texts.layout ()), const_cast (&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); +} + +} diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h new file mode 100644 index 000000000..812582b0d --- /dev/null +++ b/src/db/db/dbDeepTexts.h @@ -0,0 +1,100 @@ + +/* + + 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 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 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 + diff --git a/src/db/db/dbEdgePairs.cc b/src/db/db/dbEdgePairs.cc index 5a6c97f4c..fbafdcdff 100644 --- a/src/db/db/dbEdgePairs.cc +++ b/src/db/db/dbEdgePairs.cc @@ -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 .. } diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index 2dac4e52c..07947deaf 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -27,8 +27,7 @@ #include "dbEdgePairsDelegate.h" #include "dbShape.h" #include "dbRecursiveShapeIterator.h" - -#include "gsiObject.h" +#include "dbShapeCollection.h" #include @@ -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 */ diff --git a/src/db/db/dbEdgePairsDelegate.cc b/src/db/db/dbEdgePairsDelegate.cc index d2b93d626..94e78bf38 100644 --- a/src/db/db/dbEdgePairsDelegate.cc +++ b/src/db/db/dbEdgePairsDelegate.cc @@ -34,7 +34,7 @@ EdgePairsDelegate::EdgePairsDelegate () } EdgePairsDelegate::EdgePairsDelegate (const EdgePairsDelegate &other) - : tl::UniqueId () + : ShapeCollectionDelegateBase () { operator= (other); } diff --git a/src/db/db/dbEdgePairsDelegate.h b/src/db/db/dbEdgePairsDelegate.h index 3eeb340ce..0cd9798b6 100644 --- a/src/db/db/dbEdgePairsDelegate.h +++ b/src/db/db/dbEdgePairsDelegate.h @@ -25,9 +25,8 @@ #define HDR_dbEdgePairsDelegate #include "dbCommon.h" - #include "dbEdgePair.h" -#include "tlUniqueId.h" +#include "dbShapeCollection.h" namespace db { @@ -59,7 +58,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; diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index a2b0fbdde..aebcbaf0e 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -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 .. } diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index 3634e5d4e..aa76642db 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -27,8 +27,7 @@ #include "dbEdgesDelegate.h" #include "dbRecursiveShapeIterator.h" #include "dbCellVariants.h" - -#include "gsiObject.h" +#include "dbShapeCollection.h" #include @@ -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; diff --git a/src/db/db/dbEdgesDelegate.cc b/src/db/db/dbEdgesDelegate.cc index ea9c7ff45..982d6350a 100644 --- a/src/db/db/dbEdgesDelegate.cc +++ b/src/db/db/dbEdgesDelegate.cc @@ -37,7 +37,7 @@ EdgesDelegate::EdgesDelegate () } EdgesDelegate::EdgesDelegate (const EdgesDelegate &other) - : tl::UniqueId () + : ShapeCollectionDelegateBase () { operator= (other); } diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index 18213bc58..7b2ff0b18 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -29,7 +29,7 @@ #include "dbEdge.h" #include "dbEdgePairs.h" #include "dbEdgePairRelations.h" -#include "tlUniqueId.h" +#include "dbShapeCollection.h" #include @@ -181,7 +181,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; diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 5ab62f825..ec40deffa 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -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 (); } diff --git a/src/db/db/dbEmptyTexts.cc b/src/db/db/dbEmptyTexts.cc new file mode 100644 index 000000000..9ef48abc2 --- /dev/null +++ b/src/db/db/dbEmptyTexts.cc @@ -0,0 +1,106 @@ + +/* + + 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 (); +} + +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 (); +} + +} + diff --git a/src/db/db/dbEmptyTexts.h b/src/db/db/dbEmptyTexts.h new file mode 100644 index 000000000..99b1623ac --- /dev/null +++ b/src/db/db/dbEmptyTexts.h @@ -0,0 +1,89 @@ + +/* + + 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 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 *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 + diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc new file mode 100644 index 000000000..96668a150 --- /dev/null +++ b/src/db/db/dbFlatTexts.cc @@ -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 ().begin (), m_texts.get_layer ().end ()); +} + +std::pair 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 ().begin (); + for (TextsIterator p (begin ()); ! p.at_end (); ++p) { + if (filter.selected (*p)) { + if (pw == m_texts.get_layer ().end ()) { + m_texts.get_layer ().insert (*p); + pw = m_texts.get_layer ().end (); + } else { + m_texts.get_layer ().replace (pw++, *p); + } + } + } + + m_texts.get_layer ().erase (pw, m_texts.get_layer ().end ()); + + return this; +} + +TextsDelegate *FlatTexts::add (const Texts &other) const +{ + std::auto_ptr new_texts (new FlatTexts (*this)); + new_texts->invalidate_cache (); + + FlatTexts *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + new_texts->raw_texts ().insert (other_flat->raw_texts ().get_layer ().begin (), other_flat->raw_texts ().get_layer ().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 (other.delegate ()); + if (other_flat) { + + m_texts.insert (other_flat->raw_texts ().get_layer ().begin (), other_flat->raw_texts ().get_layer ().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 ().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); + + } +} + +} + diff --git a/src/db/db/dbFlatTexts.h b/src/db/db/dbFlatTexts.h new file mode 100644 index 000000000..90b3e9b24 --- /dev/null +++ b/src/db/db/dbFlatTexts.h @@ -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 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 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 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 + 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 + void insert_seq (const Iter &seq) + { + for (Iter i = seq; ! i.at_end (); ++i) { + insert (*i); + } + } + + template + void transform (const Trans &trans) + { + if (! trans.is_unity ()) { + for (text_iterator_type p = m_texts.template get_layer ().begin (); p != m_texts.template get_layer ().end (); ++p) { + m_texts.get_layer ().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 + diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 08ca4d269..f2d4dd92e 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -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 void insert_transformed (db::Layout &layout, Container &shapes, const Shape &s, const Trans &t); +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t); -template void insert_transformed (db::Layout &layout, Container &shapes, const db::PolygonRef &s, const Trans &t) +template 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 void insert_transformed (db::Layout &lay shapes.insert (db::PolygonRef (poly, layout.shape_repository ())); } -template void insert_transformed (db::Layout & /*layout*/, Container &shapes, const db::Edge &s, const Trans &t) +template 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 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 +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 +static bool +interaction_test (const db::NetShape &a, const db::NetShape &b, const db::unit_trans &, db::Connectivity::edge_connectivity_type) +{ + return a.interacts_with (b); +} + template 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 (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 (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 (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 (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
+ Mask layout viewer and editor for the chip design engineer. +