Introducing PolygonWithProperties etc. in gsi

This commit is contained in:
Matthias Koefferlein 2024-12-29 17:07:56 +01:00
parent 1be436b764
commit 75e4282f01
11 changed files with 489 additions and 1 deletions

View File

@ -420,7 +420,8 @@ HEADERS = \
dbOriginalLayerTexts.h \
dbNetShape.h \
dbShapeCollection.h \
dbShapeCollectionUtils.h
dbShapeCollectionUtils.h \
gsiDeclDbPropertiesSupport.h
RESOURCES = \
dbResources.qrc \

View File

@ -187,6 +187,17 @@ public:
return object_with_properties<Obj> (Obj::transformed (tr), m_id);
}
/**
* @brief Returns a string describing the object
*/
std::string to_string () const
{
std::string s = Obj::to_string ();
s += " props=";
s += db::properties (properties_id ()).to_dict_var ().to_string ();
return s;
}
private:
properties_id_type m_id;
};
@ -225,6 +236,16 @@ typedef object_with_properties<DBox> DBoxWithProperties;
typedef object_with_properties<db::array<db::CellInst, db::Trans> > CellInstArrayWithProperties;
typedef object_with_properties<db::array<db::CellInst, db::DTrans> > DCellInstArrayWithProperties;
/**
* @brief Output stream insertion operator
*/
template <class T>
inline std::ostream &
operator<< (std::ostream &os, const object_with_properties<T> &p)
{
return (os << p.to_string ());
}
} // namespace db
#endif

View File

@ -22,6 +22,7 @@
#include "gsiDecl.h"
#include "gsiDeclDbPropertiesSupport.h"
#include "dbPoint.h"
#include "dbBox.h"
#include "dbHash.h"
@ -590,6 +591,25 @@ Class<db::Box> decl_Box ("db", "Box",
"database objects."
);
static db::BoxWithProperties *new_box_with_properties (const db::Box &poly, db::properties_id_type pid)
{
return new db::BoxWithProperties (poly, pid);
}
Class<db::BoxWithProperties> decl_BoxWithProperties (decl_Box, "db", "BoxWithProperties",
gsi::properties_support_methods<db::BoxWithProperties> () +
constructor ("new", &new_box_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A Box object with properties attached.\n"
"This class represents a combination of a Box object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
static db::DBox *dbox_from_ibox (const db::Box &b)
{
return new db::DBox (b);
@ -645,4 +665,23 @@ Class<db::DBox> decl_DBox ("db", "DBox",
"database objects."
);
static db::DBoxWithProperties *new_dbox_with_properties (const db::DBox &poly, db::properties_id_type pid)
{
return new db::DBoxWithProperties (poly, pid);
}
Class<db::DBoxWithProperties> decl_DBoxWithProperties (decl_DBox, "db", "DBoxWithProperties",
gsi::properties_support_methods<db::DBoxWithProperties> () +
constructor ("new", &new_dbox_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A DBox object with properties attached.\n"
"This class represents a combination of a DBox object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
}

View File

@ -22,6 +22,7 @@
#include "gsiDecl.h"
#include "gsiDeclDbPropertiesSupport.h"
#include "dbPoint.h"
#include "dbPath.h"
#include "dbHash.h"
@ -384,6 +385,25 @@ Class<db::Path> decl_Path ("db", "Path",
"database objects."
);
static db::PathWithProperties *new_path_with_properties (const db::Path &poly, db::properties_id_type pid)
{
return new db::PathWithProperties (poly, pid);
}
Class<db::PathWithProperties> decl_PathWithProperties (decl_Path, "db", "PathWithProperties",
gsi::properties_support_methods<db::PathWithProperties> () +
constructor ("new", &new_path_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A Path object with properties attached.\n"
"This class represents a combination of a Path object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
static db::DPath *dpath_from_ipath (const db::Path &p)
{
return new db::DPath (p);
@ -452,4 +472,23 @@ Class<db::DPath> decl_DPath ("db", "DPath",
"database objects."
);
static db::DPathWithProperties *new_dpath_with_properties (const db::DPath &poly, db::properties_id_type pid)
{
return new db::DPathWithProperties (poly, pid);
}
Class<db::DPathWithProperties> decl_DPathWithProperties (decl_DPath, "db", "DPathWithProperties",
gsi::properties_support_methods<db::DPathWithProperties> () +
constructor ("new", &new_dpath_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A DPath object with properties attached.\n"
"This class represents a combination of a DPath object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
}

View File

@ -22,6 +22,7 @@
#include "gsiDecl.h"
#include "gsiDeclDbPropertiesSupport.h"
#include "dbPoint.h"
#include "dbPolygon.h"
#include "dbPolygonTools.h"
@ -785,6 +786,25 @@ Class<db::SimplePolygon> decl_SimplePolygon ("db", "SimplePolygon",
"database objects."
);
static db::SimplePolygonWithProperties *new_simple_polygon_with_properties (const db::SimplePolygon &poly, db::properties_id_type pid)
{
return new db::SimplePolygonWithProperties (poly, pid);
}
Class<db::SimplePolygonWithProperties> decl_SimplePolygonWithProperties (decl_SimplePolygon, "db", "SimplePolygonWithProperties",
gsi::properties_support_methods<db::SimplePolygonWithProperties> () +
constructor ("new", &new_simple_polygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A SimplePolygon object with properties attached.\n"
"This class represents a combination of a SimplePolygon object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
static db::DSimplePolygon *dspolygon_from_ispolygon (const db::SimplePolygon &p)
{
return new db::DSimplePolygon (p, false);
@ -853,6 +873,25 @@ Class<db::DSimplePolygon> decl_DSimplePolygon ("db", "DSimplePolygon",
"database objects."
);
static db::DSimplePolygonWithProperties *new_dsimple_polygon_with_properties (const db::DSimplePolygon &poly, db::properties_id_type pid)
{
return new db::DSimplePolygonWithProperties (poly, pid);
}
Class<db::DSimplePolygonWithProperties> decl_DSimplePolygonWithProperties (decl_DSimplePolygon, "db", "DSimplePolygonWithProperties",
gsi::properties_support_methods<db::DSimplePolygonWithProperties> () +
constructor ("new", &new_dsimple_polygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A DSimplePolygon object with properties attached.\n"
"This class represents a combination of a DSimplePolygon object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
// ---------------------------------------------------------------
// polygon binding
@ -2026,6 +2065,25 @@ Class<db::Polygon> decl_Polygon ("db", "Polygon",
"database objects."
);
static db::PolygonWithProperties *new_polygon_with_properties (const db::Polygon &poly, db::properties_id_type pid)
{
return new db::PolygonWithProperties (poly, pid);
}
Class<db::PolygonWithProperties> decl_PolygonWithProperties (decl_Polygon, "db", "PolygonWithProperties",
gsi::properties_support_methods<db::PolygonWithProperties> () +
constructor ("new", &new_polygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A Polygon object with properties attached.\n"
"This class represents a combination of a Polygon object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
static db::DPolygon *dpolygon_from_ipolygon (const db::Polygon &p)
{
return new db::DPolygon (p, false);
@ -2121,4 +2179,23 @@ Class<db::DPolygon> decl_DPolygon ("db", "DPolygon",
"database objects."
);
static db::DPolygonWithProperties *new_dpolygon_with_properties (const db::DPolygon &poly, db::properties_id_type pid)
{
return new db::DPolygonWithProperties (poly, pid);
}
Class<db::DPolygonWithProperties> decl_DPolygonWithProperties (decl_DPolygon, "db", "DPolygonWithProperties",
gsi::properties_support_methods<db::DPolygonWithProperties> () +
constructor ("new", &new_dpolygon_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A DPolygon object with properties attached.\n"
"This class represents a combination of a DPolygon object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
}

View File

@ -0,0 +1,116 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2024 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_dbPropertiesSupport
#define HDR_dbPropertiesSupport
#include "gsiDecl.h"
#include "dbPropertiesRepository.h"
namespace gsi
{
template <class T>
static void delete_property_meth_impl (T *s, const tl::Variant &key)
{
db::properties_id_type id = s->properties_id ();
if (id == 0) {
return;
}
db::PropertiesSet props = db::properties (id);
props.erase (key);
s->properties_id (db::properties_id (props));
}
template <class T>
static void set_property_meth_impl (T *s, const tl::Variant &key, const tl::Variant &value)
{
db::properties_id_type id = s->properties_id ();
db::PropertiesSet props = db::properties (id);
props.erase (key);
props.insert (key, value);
s->properties_id (db::properties_id (props));
}
template <class T>
static tl::Variant get_property_meth_impl (const T *s, const tl::Variant &key)
{
db::properties_id_type id = s->properties_id ();
const db::PropertiesSet &props = db::properties (id);
return props.value (key);
}
template <class T>
static tl::Variant get_properties_meth_impl (const T *s)
{
db::properties_id_type id = s->properties_id ();
const db::PropertiesSet &props = db::properties (id);
return props.to_dict_var ();
}
template <class T>
static gsi::Methods properties_support_methods ()
{
return
gsi::method ("prop_id", (db::properties_id_type (T::*) () const) &T::properties_id,
"@brief Gets the properties ID associated with the object\n"
) +
gsi::method ("prop_id=", (void (T::*) (db::properties_id_type)) &T::properties_id, gsi::arg ("id"),
"@brief Sets the properties ID of the object\n"
) +
gsi::method_ext ("delete_property", &delete_property_meth_impl<T>, gsi::arg ("key"),
"@brief Deletes the user property with the given key\n"
"This method is a convenience method that deletes the property with the given key. "
"It does nothing if no property with that key exists. Using that method is more "
"convenient than creating a new property set with a new ID and assigning that properties ID.\n"
"This method may change the properties ID."
) +
gsi::method_ext ("set_property", &set_property_meth_impl<T>, gsi::arg ("key"), gsi::arg ("value"),
"@brief Sets the user property with the given key to the given value\n"
"This method is a convenience method that sets the user property with the given key to the given value. "
"If no property with that key exists, it will create one. Using that method is more "
"convenient than creating a new property set with a new ID and assigning that properties ID.\n"
"This method may change the properties ID. "
"Note: GDS only supports integer keys. OASIS supports numeric and string keys.\n"
) +
gsi::method_ext ("property", &get_property_meth_impl<T>, gsi::arg ("key"),
"@brief Gets the user property with the given key\n"
"This method is a convenience method that gets the user property with the given key. "
"If no property with that key does not exist, it will return nil. Using that method is more "
"convenient than using the layout object and the properties ID to retrieve the property value. "
) +
gsi::method ("to_s", (std::string (T::*) () const) &T::to_string,
"@brief Returns a string representing the polygon\n"
) +
gsi::method_ext ("properties", &get_properties_meth_impl<T>,
"@brief Gets the user properties\n"
"This method is a convenience method that gets the properties of the shape as a single hash.\n"
);
}
}
#endif

View File

@ -22,6 +22,7 @@
#include "gsiDecl.h"
#include "gsiDeclDbPropertiesSupport.h"
#include "gsiEnums.h"
#include "dbPoint.h"
#include "dbText.h"
@ -448,6 +449,25 @@ Class<db::Text> decl_Text ("db", "Text",
"database objects."
);
static db::TextWithProperties *new_text_with_properties (const db::Text &poly, db::properties_id_type pid)
{
return new db::TextWithProperties (poly, pid);
}
Class<db::TextWithProperties> decl_TextWithProperties (decl_Text, "db", "TextWithProperties",
gsi::properties_support_methods<db::TextWithProperties> () +
constructor ("new", &new_text_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A Text object with properties attached.\n"
"This class represents a combination of a Text object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
static db::DText *dtext_from_itext (const db::Text &t)
{
return new db::DText (t);
@ -497,6 +517,25 @@ Class<db::DText> decl_DText ("db", "DText",
"database objects."
);
static db::DTextWithProperties *new_dtext_with_properties (const db::DText &poly, db::properties_id_type pid)
{
return new db::DTextWithProperties (poly, pid);
}
Class<db::DTextWithProperties> decl_DTextWithProperties (decl_DText, "db", "DTextWithProperties",
gsi::properties_support_methods<db::DTextWithProperties> () +
constructor ("new", &new_dtext_with_properties, gsi::arg ("polygon"), gsi::arg ("properties_id"),
"@brief Creates a new object from a property-less object and a properties ID."
)
,
"@brief A DText object with properties attached.\n"
"This class represents a combination of a DText object an user properties. User properties are "
"stored in form of a properties ID. Convenience methods are provided to manipulate or retrieve "
"user properties directly.\n"
"\n"
"This class has been introduced in version 0.30."
);
gsi::Enum<db::HAlign> decl_HAlign ("db", "HAlign",
gsi::enum_const ("HAlignLeft", db::HAlignLeft,
"@brief Left horizontal alignment\n"

View File

@ -512,6 +512,38 @@ class DBBox_TestClass < TestBase
end
def test_boxWithProperties
s = RBA::BoxWithProperties::new
assert_equal(s.to_s, "() props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::BoxWithProperties::new(RBA::Box::new(0, 0, 100, 200), pid)
assert_equal(s.to_s, "(0,0;100,200) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;100,200) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;100,200) props={}")
assert_equal(s.property(1), nil)
s = RBA::DBoxWithProperties::new
assert_equal(s.to_s, "() props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::DBoxWithProperties::new(RBA::DBox::new(0, 0, 100, 200), pid)
assert_equal(s.to_s, "(0,0;100,200) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;100,200) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;100,200) props={}")
assert_equal(s.property(1), nil)
end
end
load("test_epilogue.rb")

View File

@ -329,6 +329,38 @@ class DBPath_TestClass < TestBase
end
def test_pathWithProperties
s = RBA::PathWithProperties::new
assert_equal(s.to_s, "() w=0 bx=0 ex=0 r=false props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::PathWithProperties::new(RBA::Path::new([ [0,0], [100, 0] ], 100), pid)
assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={}")
assert_equal(s.property(1), nil)
s = RBA::DPathWithProperties::new
assert_equal(s.to_s, "() w=0 bx=0 ex=0 r=false props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::DPathWithProperties::new(RBA::DPath::new([ [0,0], [100, 0] ], 100), pid)
assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;100,0) w=100 bx=0 ex=0 r=false props={}")
assert_equal(s.property(1), nil)
end
end
load("test_epilogue.rb")

View File

@ -894,6 +894,66 @@ class DBPolygon_TestClass < TestBase
end
def test_polygonWithProperties
s = RBA::PolygonWithProperties::new
assert_equal(s.to_s, "() props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::PolygonWithProperties::new(RBA::Polygon::new(RBA::Box::new(0, 0, 100, 200)), pid)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}")
assert_equal(s.property(1), nil)
s = RBA::DPolygonWithProperties::new
assert_equal(s.to_s, "() props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::DPolygonWithProperties::new(RBA::DPolygon::new(RBA::DBox::new(0, 0, 100, 200)), pid)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}")
assert_equal(s.property(1), nil)
s = RBA::SimplePolygonWithProperties::new
assert_equal(s.to_s, "() props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::SimplePolygonWithProperties::new(RBA::SimplePolygon::new(RBA::Box::new(0, 0, 100, 200)), pid)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}")
assert_equal(s.property(1), nil)
s = RBA::DSimplePolygonWithProperties::new
assert_equal(s.to_s, "() props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::DSimplePolygonWithProperties::new(RBA::DSimplePolygon::new(RBA::DBox::new(0, 0, 100, 200)), pid)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "(0,0;0,200;100,200;100,0) props={}")
assert_equal(s.property(1), nil)
end
end
load("test_epilogue.rb")

View File

@ -254,6 +254,38 @@ class DBText_TestClass < TestBase
end
def test_textWithProperties
s = RBA::TextWithProperties::new
assert_equal(s.to_s, "('',r0 0,0) props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::TextWithProperties::new(RBA::Text::new("text", RBA::Trans::R90), pid)
assert_equal(s.to_s, "('text',r90 0,0) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "('text',r90 0,0) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "('text',r90 0,0) props={}")
assert_equal(s.property(1), nil)
s = RBA::DTextWithProperties::new
assert_equal(s.to_s, "('',r0 0,0) props={}")
pid = RBA::Layout::properties_id({ 1 => "one" })
s = RBA::DTextWithProperties::new(RBA::DText::new("text", RBA::Trans::R90), pid)
assert_equal(s.to_s, "('text',r90 0,0) props={1=>one}")
assert_equal(s.property(1), "one")
assert_equal(s.properties, { 1 => "one" })
s.set_property(1, "xxx")
assert_equal(s.to_s, "('text',r90 0,0) props={1=>xxx}")
s.delete_property(1)
assert_equal(s.to_s, "('text',r90 0,0) props={}")
assert_equal(s.property(1), nil)
end
end
load("test_epilogue.rb")