klayout/src/db/dbShapes.cc

1273 lines
51 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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 "dbShape.h"
#include "dbShapeRepository.h"
#include "dbShapes.h"
#include "dbShapes2.h"
#include "dbTrans.h"
#include "dbUserObject.h"
#include "dbLayout.h"
#include <limits>
namespace db
{
// -------------------------------------------------------------------------------
// some utilities
template <class Sh>
inline typename layer<Sh, db::stable_layer_tag>::iterator
iterator_from_shape (const db::layer<Sh, db::stable_layer_tag> & /*layer*/, const db::Shape &shape)
{
return shape.basic_iter (typename Sh::tag ());
}
template <class Sh>
inline typename layer<Sh, db::unstable_layer_tag>::iterator
iterator_from_shape (const db::layer<Sh, db::unstable_layer_tag> &layer, const db::Shape &shape)
{
// compute the iterator by some pointer arithmetics assuming that layer uses an contiguous container
// in unstable mode ...
return layer.begin () + (shape.basic_ptr (typename Sh::tag ()) - &*layer.begin ());
}
/**
* @brief A predicate returning true if the shape needs translation through translate ()
*/
template <class Sh>
inline bool needs_translate (object_tag<Sh> /*tag*/)
{
return tl::is_equal_type<typename shape_traits<Sh>::can_deref, tl::True> () || tl::is_equal_type<typename shape_traits<Sh>::is_array, tl::True> ();
}
// ---------------------------------------------------------------------------------------
// layer_op implementation
template <class Sh, class StableTag>
void
layer_op<Sh, StableTag>::insert (Shapes *shapes)
{
shapes->insert (m_shapes.begin (), m_shapes.end ());
}
template <class Sh, class StableTag>
void
layer_op<Sh, StableTag>::erase (Shapes *shapes)
{
if (shapes->size (typename Sh::tag (), StableTag ()) <= m_shapes.size ()) {
// If all shapes are to be removed, just clear the shapes
shapes->erase (typename Sh::tag (), StableTag (), shapes->begin (typename Sh::tag (), StableTag ()), shapes->end (typename Sh::tag (), StableTag ()));
} else {
// look up the shapes to delete and collect them in a sorted list. Then pass this to
// the erase method of the shapes object
std::vector<bool> done;
done.resize (m_shapes.size (), false);
std::sort (m_shapes.begin (), m_shapes.end ());
typename std::vector<Sh>::const_iterator s_begin = m_shapes.begin ();
typename std::vector<Sh>::const_iterator s_end = m_shapes.end ();
std::vector<typename db::layer<Sh, StableTag>::iterator> to_erase;
to_erase.reserve (m_shapes.size ());
// This is not quite effective but seems to be the simpliest way
// of implementing this: search for each element and erase these.
for (typename db::layer<Sh, StableTag>::iterator lsh = shapes->begin (typename Sh::tag (), StableTag ()); lsh != shapes->end (typename Sh::tag (), StableTag ()); ++lsh) {
typename std::vector<Sh>::const_iterator s = std::lower_bound (s_begin, s_end, *lsh);
while (s != s_end && done [std::distance(s_begin, s)] && *s == *lsh) {
++s;
}
if (s != s_end && *s == *lsh) {
done [std::distance(s_begin, s)] = true;
to_erase.push_back (lsh);
}
}
shapes->erase_positions (typename Sh::tag (), StableTag (), to_erase.begin (), to_erase.end ());
}
}
// ---------------------------------------------------------------------------------------
// Shapes implementation
Shapes &
Shapes::operator= (const Shapes &d)
{
if (&d != this) {
clear ();
do_insert (d);
}
return *this;
}
db::Layout *
Shapes::layout () const
{
db::Cell *c = cell ();
return c ? c->layout () : 0;
}
void
Shapes::insert (const Shapes &d)
{
// no undo support for this currently
tl_assert (! manager () || ! manager ()->transacting ());
do_insert (d);
}
void
Shapes::do_insert (const Shapes &d)
{
// shortcut for "nothing to do"
if (d.empty ()) {
return;
}
if (layout () == d.layout ()) {
// both shape containers reside in the same repository space - simply copy
m_layers.reserve (d.m_layers.size ());
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
m_layers.push_back ((*l)->clone (this, manager ()));
}
} else if (layout () == 0) {
// the target is standalone - dereference
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
(*l)->deref_into (this);
}
} else {
// both shape containers are in separate spaces - translate
for (tl::vector<LayerBase *>::const_iterator l = d.m_layers.begin (); l != d.m_layers.end (); ++l) {
(*l)->translate_into (this, shape_repository (), array_repository ());
}
}
}
// get the shape repository associated with this container
db::GenericRepository &
Shapes::shape_repository () const
{
return layout ()->shape_repository ();
}
// get the array repository associated with this container
db::ArrayRepository &
Shapes::array_repository () const
{
return layout ()->array_repository ();
}
void
Shapes::invalidate_state ()
{
if (! is_dirty ()) {
set_dirty (true);
if (layout () && cell ()) {
unsigned int index = cell ()->index_of_shapes (this);
if (index != std::numeric_limits<unsigned int>::max ()) {
layout ()->invalidate_bboxes (index);
}
}
}
}
void
Shapes::swap (Shapes &d)
{
// HINT: undo support for swap is implemented one level above (i.e. in the cell) since
// two Shapes objects are involved.
d.invalidate_state (); // HINT: must come before the change is done!
invalidate_state ();
m_layers.swap (d.m_layers);
}
Shapes::shape_type
Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_type & /*t*/, tl::func_delegate_base <db::properties_id_type> &pm)
{
switch (shape.m_type) {
case shape_type::Null:
default:
return shape_type ();
case shape_type::Polygon:
return shape_type (insert_by_tag (shape_type::polygon_type::tag (), shape, pm));
case shape_type::PolygonRef:
case shape_type::PolygonPtrArrayMember:
if (! layout ()) {
shape_type::polygon_type p;
shape.polygon (p);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::polygon_type> (p, pm (shape.prop_id ())));
}
} else if (shape.m_type == shape_type::PolygonRef) {
return shape_type (insert_by_tag (shape_type::polygon_ref_type::tag (), shape, shape_repository (), pm));
} else {
shape_type::polygon_ref_type s (shape.polygon_ref ());
if (! shape.has_prop_id ()) {
return insert (shape_type::polygon_ref_type (s, shape_repository ()));
} else {
typedef db::object_with_properties<shape_type::polygon_ref_type> swp_type;
return insert (swp_type (shape_type::polygon_ref_type (s, shape_repository ()), pm (shape.prop_id ())));
}
}
case shape_type::PolygonPtrArray:
tl_assert (layout () != 0); // cannot translate the array members
return shape_type (insert_array_by_tag (shape_type::polygon_ptr_array_type::tag (), shape, shape_repository (), pm));
case shape_type::SimplePolygon:
return (insert_by_tag (shape_type::simple_polygon_type::tag (), shape, pm));
case shape_type::SimplePolygonRef:
case shape_type::SimplePolygonPtrArrayMember:
if (! layout ()) {
shape_type::simple_polygon_type p;
shape.simple_polygon (p);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::simple_polygon_type> (p, pm (shape.prop_id ())));
}
} else if (shape.m_type == shape_type::SimplePolygonRef) {
return (insert_by_tag (shape_type::simple_polygon_ref_type::tag (), shape, shape_repository (), pm));
} else {
shape_type::simple_polygon_ref_type s (shape.simple_polygon_ref ());
if (! shape.has_prop_id ()) {
return insert (shape_type::simple_polygon_ref_type (s, shape_repository ()));
} else {
typedef db::object_with_properties<shape_type::simple_polygon_ref_type> swp_type;
return insert (swp_type (shape_type::simple_polygon_ref_type (s, shape_repository ()), pm (shape.prop_id ())));
}
}
case shape_type::SimplePolygonPtrArray:
tl_assert (layout () != 0); // cannot translate the array members
return (insert_array_by_tag (shape_type::simple_polygon_ptr_array_type::tag (), shape, shape_repository (), pm));
case shape_type::Edge:
return (insert_by_tag (shape_type::edge_type::tag (), shape, pm));
case shape_type::Path:
return (insert_by_tag (shape_type::path_type::tag (), shape, pm));
case shape_type::PathRef:
case shape_type::PathPtrArrayMember:
if (! layout ()) {
shape_type::path_type p;
shape.path (p);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::path_type> (p, pm (shape.prop_id ())));
}
} else if (shape.m_type == shape_type::PathRef) {
return (insert_by_tag (shape_type::path_ref_type::tag (), shape, shape_repository (), pm));
} else {
shape_type::path_ref_type s (shape.path_ref ());
if (! shape.has_prop_id ()) {
return insert (shape_type::path_ref_type (s, shape_repository ()));
} else {
typedef db::object_with_properties<shape_type::path_ref_type> swp_type;
return insert (swp_type (shape_type::path_ref_type (s, shape_repository ()), pm (shape.prop_id ())));
}
}
case shape_type::PathPtrArray:
tl_assert (layout () != 0); // cannot translate the array members
return (insert_array_by_tag (shape_type::path_ptr_array_type::tag (), shape, shape_repository (), pm));
case shape_type::Box:
return (insert_by_tag (shape_type::box_type::tag (), shape, pm));
case shape_type::BoxArrayMember:
{
shape_type::box_type s (shape.box ());
if (! shape.has_prop_id ()) {
return insert (s);
} else {
typedef db::object_with_properties<shape_type::box_type> swp_type;
return insert (swp_type (s, pm (shape.prop_id ())));
}
}
case shape_type::BoxArray:
return (insert_by_tag (shape_type::box_array_type::tag (), shape, pm));
case shape_type::ShortBox:
return (insert_by_tag (shape_type::short_box_type::tag (), shape, pm));
case shape_type::ShortBoxArrayMember:
{
shape_type::short_box_type s (shape.box ());
if (! shape.has_prop_id ()) {
return insert (s);
} else {
typedef db::object_with_properties<shape_type::short_box_type> swp_type;
return insert (swp_type (s, pm (shape.prop_id ())));
}
}
case shape_type::ShortBoxArray:
return (insert_by_tag (shape_type::short_box_array_type::tag (), shape, pm));
case shape_type::Text:
case shape_type::TextRef:
case shape_type::TextPtrArrayMember:
{
// because texts can refer to a string repository we go the safe way and
// simply instantiate and re-insert the text:
shape_type::text_type p;
shape.text (p);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::text_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::TextPtrArray:
tl_assert (layout () != 0); // cannot translate the array members
return insert_array_by_tag (shape_type::text_ptr_array_type::tag (), shape, shape_repository (), pm);
case shape_type::UserObject:
return insert_by_tag (shape_type::user_object_type::tag (), shape, pm);
};
}
template <class Trans>
Shapes::shape_type
Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_delegate_base <db::properties_id_type> &pm)
{
switch (shape.m_type) {
case shape_type::Null:
default:
return shape;
case shape_type::Polygon:
{
shape_type::polygon_type p (shape.polygon ());
// Hint: we don't compress so we don't loose information
p.transform (t, false);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::polygon_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::PolygonRef:
case shape_type::PolygonPtrArrayMember:
{
shape_type::polygon_type p;
shape.polygon (p);
// Hint: we don't compress so we don't loose information
p.transform (t, false);
// TODO: could create a reference again, but this is what a transform would to as well.
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::polygon_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::SimplePolygon:
{
shape_type::simple_polygon_type p (shape.simple_polygon ());
// Hint: we don't compress so we don't loose information
p.transform (t, false);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::simple_polygon_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::SimplePolygonRef:
case shape_type::SimplePolygonPtrArrayMember:
{
shape_type::simple_polygon_type p;
shape.simple_polygon (p);
// Hint: we don't compress so we don't loose information
p.transform (t, false);
// TODO: could create a reference again, but this is what a transform would to as well.
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::simple_polygon_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::Edge:
{
shape_type::edge_type p (shape.edge ());
p.transform (t);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::edge_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::Path:
{
shape_type::path_type p (shape.path ());
p.transform (t);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::path_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::PathRef:
case shape_type::PathPtrArrayMember:
{
shape_type::path_type p;
shape.path (p);
p.transform (t);
// TODO: could create a reference again, but this is what a transform would to as well.
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::path_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::Box:
case shape_type::BoxArrayMember:
case shape_type::ShortBox:
case shape_type::ShortBoxArrayMember:
{
if (t.is_ortho ()) {
shape_type::box_type p (shape.box ());
p.transform (t);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::box_type> (p, pm (shape.prop_id ())));
}
} else {
// A box cannot stay a box in this case ...
shape_type::simple_polygon_type p (shape.box ());
p.transform (t);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::simple_polygon_type> (p, pm (shape.prop_id ())));
}
}
}
case shape_type::Text:
{
shape_type::text_type p (shape.text ());
p.transform (t);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::text_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::TextRef:
case shape_type::TextPtrArrayMember:
{
shape_type::text_type p;
shape.text (p);
p.transform (t);
// TODO: could create a reference again, but this is what a transform would to as well.
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::text_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::UserObject:
{
shape_type::user_object_type p (shape.user_object ());
p.transform (t);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::user_object_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::PolygonPtrArray:
case shape_type::SimplePolygonPtrArray:
case shape_type::PathPtrArray:
case shape_type::BoxArray:
case shape_type::ShortBoxArray:
case shape_type::TextPtrArray:
// Arrays are not supported yet
// TODO: implement
throw tl::Exception (tl::to_string (QObject::tr ("Function 'insert' with transformation does not support shape arrays")));
};
}
Shapes::shape_type
Shapes::find (const Shapes::shape_type &shape) const
{
switch (shape.m_type) {
case shape_type::Null:
default:
return shape_type ();
case shape_type::Polygon:
return find_shape_by_tag (shape_type::polygon_type::tag (), shape);
case shape_type::PolygonRef:
return find_shape_by_tag (shape_type::polygon_ref_type::tag (), shape);
case shape_type::PolygonPtrArrayMember:
case shape_type::PolygonPtrArray:
return find_shape_by_tag (shape_type::polygon_ptr_array_type::tag (), shape);
case shape_type::SimplePolygon:
return find_shape_by_tag (shape_type::simple_polygon_type::tag (), shape);
case shape_type::SimplePolygonRef:
return find_shape_by_tag (shape_type::simple_polygon_ref_type::tag (), shape);
case shape_type::SimplePolygonPtrArrayMember:
case shape_type::SimplePolygonPtrArray:
return find_shape_by_tag (shape_type::simple_polygon_ptr_array_type::tag (), shape);
case shape_type::Edge:
return find_shape_by_tag (shape_type::edge_type::tag (), shape);
case shape_type::Path:
return find_shape_by_tag (shape_type::path_type::tag (), shape);
case shape_type::PathRef:
return find_shape_by_tag (shape_type::path_ref_type::tag (), shape);
case shape_type::PathPtrArrayMember:
case shape_type::PathPtrArray:
return find_shape_by_tag (shape_type::path_ptr_array_type::tag (), shape);
case shape_type::Box:
return find_shape_by_tag (shape_type::box_type::tag (), shape);
case shape_type::BoxArrayMember:
case shape_type::BoxArray:
return find_shape_by_tag (shape_type::box_array_type::tag (), shape);
case shape_type::ShortBox:
return find_shape_by_tag (shape_type::short_box_type::tag (), shape);
case shape_type::ShortBoxArrayMember:
case shape_type::ShortBoxArray:
return find_shape_by_tag (shape_type::short_box_array_type::tag (), shape);
case shape_type::Text:
return find_shape_by_tag (shape_type::text_type::tag (), shape);
case shape_type::TextRef:
return find_shape_by_tag (shape_type::text_ref_type::tag (), shape);
case shape_type::TextPtrArrayMember:
case shape_type::TextPtrArray:
return find_shape_by_tag (shape_type::text_ptr_array_type::tag (), shape);
case shape_type::UserObject:
return find_shape_by_tag (shape_type::user_object_type::tag (), shape);
};
}
Shapes::shape_type
Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type prop_id)
{
tl_assert (! ref.is_array_member ());
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace_prop_id' is permitted only in editable mode")));
}
if (ref.with_props ()) {
// this assumes we can simply patch the properties ID ..
switch (ref.m_type) {
case shape_type::Null:
break;
case shape_type::Polygon:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::polygon_type>::tag ()), prop_id);
break;
case shape_type::PolygonRef:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::polygon_ref_type>::tag ()), prop_id);
break;
case shape_type::PolygonPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::polygon_ptr_array_type>::tag ()), prop_id);
break;
case shape_type::SimplePolygon:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::simple_polygon_type>::tag ()), prop_id);
break;
case shape_type::SimplePolygonRef:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::simple_polygon_ref_type>::tag ()), prop_id);
break;
case shape_type::SimplePolygonPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::simple_polygon_ptr_array_type>::tag ()), prop_id);
break;
case shape_type::Edge:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::edge_type>::tag ()), prop_id);
break;
case shape_type::Path:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::path_type>::tag ()), prop_id);
break;
case shape_type::PathRef:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::path_ref_type>::tag ()), prop_id);
break;
case shape_type::PathPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::path_ptr_array_type>::tag ()), prop_id);
break;
case shape_type::Box:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::box_type>::tag ()), prop_id);
break;
case shape_type::BoxArray:
// HINT: since we are in editing mode, this type should not appear ..
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::box_array_type>::tag ()), prop_id);
break;
case shape_type::ShortBox:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::short_box_type>::tag ()), prop_id);
break;
case shape_type::ShortBoxArray:
// HINT: since we are in editing mode, this type should not appear ..
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::short_box_array_type>::tag ()), prop_id);
break;
case shape_type::Text:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::text_type>::tag ()), prop_id);
break;
case shape_type::TextRef:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::text_ref_type>::tag ()), prop_id);
break;
case shape_type::TextPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::text_ptr_array_type>::tag ()), prop_id);
break;
case shape_type::UserObject:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::user_object_type>::tag ()), prop_id);
default:
break;
};
return ref;
} else {
switch (ref.m_type) {
case shape_type::Null:
return ref;
case shape_type::Polygon:
return replace_prop_id_iter (shape_type::polygon_type::tag (), ref.basic_iter (shape_type::polygon_type::tag ()), prop_id);
case shape_type::PolygonRef:
return replace_prop_id_iter (shape_type::polygon_ref_type::tag (), ref.basic_iter (shape_type::polygon_ref_type::tag ()), prop_id);
case shape_type::PolygonPtrArray:
return replace_prop_id_iter (shape_type::polygon_ptr_array_type::tag (), ref.basic_iter (shape_type::polygon_ptr_array_type::tag ()), prop_id);
case shape_type::SimplePolygon:
return replace_prop_id_iter (shape_type::simple_polygon_type::tag (), ref.basic_iter (shape_type::simple_polygon_type::tag ()), prop_id);
case shape_type::SimplePolygonRef:
return replace_prop_id_iter (shape_type::simple_polygon_ref_type::tag (), ref.basic_iter (shape_type::simple_polygon_ref_type::tag ()), prop_id);
case shape_type::SimplePolygonPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_prop_id_iter (shape_type::simple_polygon_ptr_array_type::tag (), ref.basic_iter (shape_type::simple_polygon_ptr_array_type::tag ()), prop_id);
case shape_type::Edge:
return replace_prop_id_iter (shape_type::edge_type::tag (), ref.basic_iter (shape_type::edge_type::tag ()), prop_id);
case shape_type::Path:
return replace_prop_id_iter (shape_type::path_type::tag (), ref.basic_iter (shape_type::path_type::tag ()), prop_id);
case shape_type::PathRef:
return replace_prop_id_iter (shape_type::path_ref_type::tag (), ref.basic_iter (shape_type::path_ref_type::tag ()), prop_id);
case shape_type::PathPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_prop_id_iter (shape_type::path_ptr_array_type::tag (), ref.basic_iter (shape_type::path_ptr_array_type::tag ()), prop_id);
case shape_type::Box:
return replace_prop_id_iter (shape_type::box_type::tag (), ref.basic_iter (shape_type::box_type::tag ()), prop_id);
case shape_type::BoxArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_prop_id_iter (shape_type::box_array_type::tag (), ref.basic_iter (shape_type::box_array_type::tag ()), prop_id);
case shape_type::ShortBox:
return replace_prop_id_iter (shape_type::short_box_type::tag (), ref.basic_iter (shape_type::short_box_type::tag ()), prop_id);
case shape_type::ShortBoxArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_prop_id_iter (shape_type::short_box_array_type::tag (), ref.basic_iter (shape_type::short_box_array_type::tag ()), prop_id);
case shape_type::Text:
return replace_prop_id_iter (shape_type::text_type::tag (), ref.basic_iter (shape_type::text_type::tag ()), prop_id);
case shape_type::TextRef:
return replace_prop_id_iter (shape_type::text_ref_type::tag (), ref.basic_iter (shape_type::text_ref_type::tag ()), prop_id);
case shape_type::TextPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_prop_id_iter (shape_type::text_ptr_array_type::tag (), ref.basic_iter (shape_type::text_ptr_array_type::tag ()), prop_id);
case shape_type::UserObject:
return replace_prop_id_iter (shape_type::user_object_type::tag (), ref.basic_iter (shape_type::user_object_type::tag ()), prop_id);
default:
return ref;
};
}
}
template <class Trans>
Shapes::shape_type
Shapes::transform (const Shapes::shape_type &ref, const Trans &t)
{
tl_assert (! ref.is_array_member ());
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'transform' is permitted only in editable mode")));
}
switch (ref.m_type) {
case shape_type::Null:
return ref;
case shape_type::Polygon:
{
shape_type::polygon_type p (ref.polygon ());
p.transform (t);
return replace_member_with_props (shape_type::polygon_type::tag (), ref, p);
}
case shape_type::PolygonRef:
{
shape_type::polygon_type p;
ref.polygon (p);
p.transform (t);
return replace_member_with_props (shape_type::polygon_ref_type::tag (), ref, p);
}
case shape_type::SimplePolygon:
{
shape_type::simple_polygon_type p (ref.simple_polygon ());
p.transform (t);
return replace_member_with_props (shape_type::simple_polygon_type::tag (), ref, p);
}
case shape_type::SimplePolygonRef:
{
shape_type::simple_polygon_type p;
ref.simple_polygon (p);
p.transform (t);
return replace_member_with_props (shape_type::simple_polygon_ref_type::tag (), ref, p);
}
case shape_type::Edge:
{
shape_type::edge_type p (ref.edge ());
p.transform (t);
return replace_member_with_props (shape_type::edge_type::tag (), ref, p);
}
case shape_type::Path:
{
shape_type::path_type p (ref.path ());
p.transform (t);
return replace_member_with_props (shape_type::path_type::tag (), ref, p);
}
case shape_type::PathRef:
{
shape_type::path_type p;
ref.path (p);
p.transform (t);
return replace_member_with_props (shape_type::path_ref_type::tag (), ref, p);
}
case shape_type::Box:
case shape_type::ShortBox:
{
if (t.is_ortho ()) {
shape_type::box_type p (ref.box ());
p.transform (t);
return replace_member_with_props (shape_type::box_type::tag (), ref, p);
} else {
// A box cannot stay a box in this case ...
shape_type::simple_polygon_type p (ref.box ());
p.transform (t);
return replace_member_with_props (shape_type::box_type::tag (), ref, p);
}
}
case shape_type::Text:
{
shape_type::text_type p (ref.text ());
p.transform (t);
return replace_member_with_props (shape_type::text_type::tag (), ref, p);
}
case shape_type::TextRef:
{
shape_type::text_type p;
ref.text (p);
p.transform (t);
return replace_member_with_props (shape_type::text_ref_type::tag (), ref, p);
}
case shape_type::UserObject:
{
shape_type::user_object_type p (ref.user_object ());
p.transform (t);
return replace_member_with_props (shape_type::user_object_type::tag (), ref, p);
}
case shape_type::PolygonPtrArray:
case shape_type::SimplePolygonPtrArray:
case shape_type::PathPtrArray:
case shape_type::BoxArray:
case shape_type::ShortBoxArray:
case shape_type::TextPtrArray:
tl_assert (false); // TODO: not supported yet
default:
return ref;
};
}
template <class Sh>
Shapes::shape_type
Shapes::replace (const Shapes::shape_type &ref, const Sh &sh)
{
tl_assert (! ref.is_array_member ());
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace' is permitted only in editable mode")));
}
switch (ref.m_type) {
case shape_type::Null:
return ref;
case shape_type::Polygon:
return replace_member_with_props (shape_type::polygon_type::tag (), ref, sh);
case shape_type::PolygonRef:
return replace_member_with_props (shape_type::polygon_ref_type::tag (), ref, sh);
case shape_type::PolygonPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_member_with_props (shape_type::polygon_ptr_array_type::tag (), ref, sh);
case shape_type::SimplePolygon:
return replace_member_with_props (shape_type::simple_polygon_type::tag (), ref, sh);
case shape_type::SimplePolygonRef:
return replace_member_with_props (shape_type::simple_polygon_ref_type::tag (), ref, sh);
case shape_type::SimplePolygonPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_member_with_props (shape_type::simple_polygon_ptr_array_type::tag (), ref, sh);
case shape_type::Edge:
return replace_member_with_props (shape_type::edge_type::tag (), ref, sh);
case shape_type::Path:
return replace_member_with_props (shape_type::path_type::tag (), ref, sh);
case shape_type::PathRef:
return replace_member_with_props (shape_type::path_ref_type::tag (), ref, sh);
case shape_type::PathPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_member_with_props (shape_type::path_ptr_array_type::tag (), ref, sh);
case shape_type::Box:
return replace_member_with_props (shape_type::box_type::tag (), ref, sh);
case shape_type::BoxArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_member_with_props (shape_type::box_array_type::tag (), ref, sh);
case shape_type::ShortBox:
return replace_member_with_props (shape_type::short_box_type::tag (), ref, sh);
case shape_type::ShortBoxArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_member_with_props (shape_type::short_box_array_type::tag (), ref, sh);
case shape_type::Text:
return replace_member_with_props (shape_type::text_type::tag (), ref, sh);
case shape_type::TextRef:
return replace_member_with_props (shape_type::text_ref_type::tag (), ref, sh);
case shape_type::TextPtrArray:
// HINT: since we are in editing mode, this type should not appear ..
return replace_member_with_props (shape_type::text_ptr_array_type::tag (), ref, sh);
case shape_type::UserObject:
return replace_member_with_props (shape_type::user_object_type::tag (), ref, sh);
default:
return ref;
};
}
void
Shapes::clear ()
{
if (!m_layers.empty ()) {
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
(*l)->clear (this, manager ());
delete *l;
}
invalidate_state (); // HINT: must come before the change is done!
m_layers.clear ();
}
}
void Shapes::update_bbox ()
{
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
(*l)->update_bbox ();
}
set_dirty (false);
}
void Shapes::update ()
{
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
(*l)->sort ();
(*l)->update_bbox ();
}
set_dirty (false);
}
bool Shapes::is_bbox_dirty () const
{
if (is_dirty ()) {
return true;
}
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
if ((*l)->is_bbox_dirty ()) {
return true;
}
}
return false;
}
Shapes::box_type Shapes::bbox () const
{
box_type box;
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
box += (*l)->bbox ();
}
return box;
}
void Shapes::sort ()
{
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
(*l)->sort ();
}
}
void
Shapes::redo (db::Op *op)
{
db::LayerOpBase *layop = dynamic_cast<db::LayerOpBase *> (op);
if (layop) {
layop->redo (this);
}
}
void
Shapes::undo (db::Op *op)
{
db::LayerOpBase *layop = dynamic_cast<db::LayerOpBase *> (op);
if (layop) {
layop->undo (this);
}
}
void
Shapes::collect_mem_stat (db::MemStatistics &m) const
{
m.cell_info (m_layers);
m.cell_info (mp_cell);
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
(*l)->collect_mem_stat (m);
}
}
template <class Tag, class PropIdMap>
Shapes::shape_type
Shapes::insert_array_by_tag (Tag tag, const shape_type &shape, repository_type &rep, PropIdMap &pm)
{
if (! shape.has_prop_id ()) {
typename Tag::object_type n (*shape.basic_ptr (tag));
n.object ().translate (rep);
return insert (n);
} else {
db::object_with_properties<typename Tag::object_type> n (*shape.basic_ptr (tag), pm (shape.prop_id ()));
n.object ().translate (rep);
return insert (n);
}
}
/**
* @brief (Internal) Insert from a generic pointer
*/
template <class Tag, class PropIdMap>
Shapes::shape_type
Shapes::insert_by_tag (Tag tag, const shape_type &shape, repository_type &rep, PropIdMap &pm)
{
if (! shape.has_prop_id ()) {
return insert (typename Tag::object_type (*shape.basic_ptr (tag), rep));
} else {
typedef db::object_with_properties<typename Tag::object_type> swp_type;
return insert (swp_type (typename Tag::object_type (*shape.basic_ptr (tag), rep), pm (shape.prop_id ())));
}
}
/**
* @brief (Internal) Insert from a generic pointer
*/
template <class Tag, class PropIdMap>
Shapes::shape_type
Shapes::insert_by_tag (Tag tag, const shape_type &shape, PropIdMap &pm)
{
if (! shape.has_prop_id ()) {
return insert (*shape.basic_ptr (tag));
} else {
typedef db::object_with_properties<typename Tag::object_type> swp_type;
return insert (swp_type (*shape.basic_ptr (tag), pm (shape.prop_id ())));
}
}
template <class Tag>
Shapes::shape_type
Shapes::find_shape_by_tag (Tag tag, const shape_type &shape) const
{
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'find' is permitted only in editable mode")));
}
if (! shape.has_prop_id ()) {
typename db::layer<typename Tag::object_type, db::stable_layer_tag>::iterator i = get_layer<typename Tag::object_type, db::stable_layer_tag> ().find (*shape.basic_ptr (tag));
if (i == get_layer<typename Tag::object_type, db::stable_layer_tag> ().end ()) {
return shape_type ();
} else {
return shape_type (this, i);
}
} else {
typedef db::object_with_properties<typename Tag::object_type> swp_type;
typename db::layer<swp_type, db::stable_layer_tag>::iterator i = get_layer<swp_type, db::stable_layer_tag> ().find (*shape.basic_ptr (typename swp_type::tag ()));
if (i == get_layer<swp_type, db::stable_layer_tag> ().end ()) {
return shape_type ();
} else {
return shape_type (this, i);
}
}
}
template <class Sh>
void
Shapes::replace_prop_id (const Sh *pos, db::properties_id_type prop_id)
{
if (pos->properties_id () != prop_id) {
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace' is permitted only in editable mode")));
}
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *pos);
}
invalidate_state (); // HINT: must come before the change is done!
((Sh *) pos)->properties_id (prop_id);
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, *pos);
}
}
}
template <class Sh, class Iter>
Shapes::shape_type
Shapes::replace_prop_id_iter (typename db::object_tag<Sh>, const Iter &iter, db::properties_id_type prop_id)
{
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace' is permitted only in editable mode")));
}
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *iter);
}
db::object_with_properties <Sh> wp (*iter, prop_id);
invalidate_state (); // HINT: must come before the change is done!
get_layer<Sh, db::stable_layer_tag> ().erase (iter);
if (manager () && manager ()->transacting ()) {
db::layer_op<db::object_with_properties <Sh>, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, wp);
}
return shape_type (this, get_layer <db::object_with_properties <Sh>, db::stable_layer_tag> ().insert (wp));
}
template <class Sh1, class Sh2>
Shapes::shape_type
Shapes::reinsert_member_with_props (typename db::object_tag<Sh1>, const shape_type &ref, const Sh2 &sh)
{
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace' is permitted only in editable mode")));
}
// the shape types are not equal - resolve into erase and insert (of new)
if (! ref.with_props ()) {
erase_shape (ref);
return insert (sh);
} else {
db::properties_id_type pid = ref.prop_id ();
erase_shape (ref);
return insert (db::object_with_properties<Sh2> (sh, pid));
}
}
template <class Sh1, class Sh2>
Shapes::shape_type
Shapes::replace_member_with_props (typename db::object_tag<Sh1>, const shape_type &ref, const Sh2 &sh)
{
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace' is permitted only in editable mode")));
}
// the shape types are not equal - resolve into erase and insert (of new)
if (! ref.with_props ()) {
erase_shape (ref);
return insert (sh);
} else {
db::properties_id_type pid = ref.prop_id ();
erase_shape (ref);
return insert (db::object_with_properties<Sh2> (sh, pid));
}
}
template <class Sh>
Shapes::shape_type
Shapes::replace_member_with_props (typename db::object_tag<Sh> tag, const shape_type &ref, const Sh &sh)
{
// avoid creating a undo entry if the shape is equal to the current one
if (*ref.basic_ptr (tag) == sh) {
return ref;
}
if (! layout ()) {
if (needs_translate (tag)) {
return reinsert_member_with_props (tag, ref, sh);
} else {
// simple replace case
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (tag));
}
invalidate_state (); // HINT: must come before the change is done!
get_layer<Sh, db::stable_layer_tag> ().replace (ref.basic_iter (tag), sh);
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, sh);
}
return ref;
}
} else {
if (! is_editable ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Function 'replace' is permitted only in editable mode")));
}
if (! ref.with_props ()) {
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (tag));
}
invalidate_state (); // HINT: must come before the change is done!
if (needs_translate (tag)) {
Sh sh_trans;
sh_trans.translate (sh, shape_repository (), array_repository ());
get_layer<Sh, db::stable_layer_tag> ().replace (ref.basic_iter (tag), sh_trans);
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, sh_trans);
}
} else {
get_layer<Sh, db::stable_layer_tag> ().replace (ref.basic_iter (tag), sh);
if (manager () && manager ()->transacting ()) {
db::layer_op<Sh, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, sh);
}
}
} else {
if (manager () && manager ()->transacting ()) {
db::layer_op<db::object_with_properties<Sh>, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (typename db::object_with_properties<Sh>::tag ()));
}
invalidate_state (); // HINT: must come before the change is done!
db::object_with_properties<Sh> swp;
swp.translate (db::object_with_properties<Sh> (sh, ref.prop_id ()), shape_repository (), array_repository ());
get_layer<db::object_with_properties<Sh>, db::stable_layer_tag> ().replace (ref.basic_iter (typename db::object_with_properties<Sh>::tag ()), swp);
if (manager () && manager ()->transacting ()) {
db::layer_op<db::object_with_properties<Sh>, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, swp);
}
}
return ref;
}
}
// explicit instantiations
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Box &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const ShortBox &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Path &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Polygon &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const SimplePolygon &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Text &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Edge &);
template DB_PUBLIC Shape Shapes::transform<> (const Shape &, const ICplxTrans &);
template DB_PUBLIC Shape Shapes::transform<> (const Shape &, const Trans &);
template DB_PUBLIC Shape Shapes::do_insert<> (const Shape &, const ICplxTrans &, tl::func_delegate_base <db::properties_id_type> &);
template DB_PUBLIC Shape Shapes::do_insert<> (const Shape &, const Trans &, tl::func_delegate_base <db::properties_id_type> &);
template class DB_PUBLIC layer_op<db::Shape::polygon_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::polygon_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::simple_polygon_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::simple_polygon_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::polygon_ref_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::polygon_ref_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::simple_polygon_ref_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::simple_polygon_ref_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::polygon_ptr_array_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::polygon_ptr_array_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::simple_polygon_ptr_array_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::simple_polygon_ptr_array_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::path_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::path_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::path_ref_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::path_ref_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::path_ptr_array_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::path_ptr_array_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::edge_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_ref_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_ref_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_ptr_array_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_ptr_array_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::box_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::box_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::box_array_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::box_array_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::short_box_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::short_box_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::short_box_array_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::short_box_array_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::user_object_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::user_object_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::polygon_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::polygon_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::simple_polygon_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::simple_polygon_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::polygon_ref_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::polygon_ref_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::simple_polygon_ref_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::simple_polygon_ref_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::polygon_ptr_array_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::polygon_ptr_array_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::simple_polygon_ptr_array_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::simple_polygon_ptr_array_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::path_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::path_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::path_ref_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::path_ref_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::path_ptr_array_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::path_ptr_array_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::edge_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_ref_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_ref_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_ptr_array_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_ptr_array_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::box_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::box_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::box_array_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::box_array_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::short_box_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::short_box_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::short_box_array_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::short_box_array_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::user_object_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::user_object_type>, db::unstable_layer_tag>;
}