/* 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 namespace db { // ------------------------------------------------------------------------------- // some utilities template inline typename layer::iterator iterator_from_shape (const db::layer & /*layer*/, const db::Shape &shape) { return shape.basic_iter (typename Sh::tag ()); } template inline typename layer::iterator iterator_from_shape (const db::layer &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 inline bool needs_translate (object_tag /*tag*/) { return tl::is_equal_type::can_deref, tl::True> () || tl::is_equal_type::is_array, tl::True> (); } // --------------------------------------------------------------------------------------- // layer_op implementation template void layer_op::insert (Shapes *shapes) { shapes->insert (m_shapes.begin (), m_shapes.end ()); } template void layer_op::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 done; done.resize (m_shapes.size (), false); std::sort (m_shapes.begin (), m_shapes.end ()); typename std::vector::const_iterator s_begin = m_shapes.begin (); typename std::vector::const_iterator s_end = m_shapes.end (); std::vector::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::iterator lsh = shapes->begin (typename Sh::tag (), StableTag ()); lsh != shapes->end (typename Sh::tag (), StableTag ()); ++lsh) { typename std::vector::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::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::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::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::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 &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 (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 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 (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 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 (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 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 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 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 (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 Shapes::shape_type Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_delegate_base &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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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::tag ()), prop_id); break; case shape_type::PolygonRef: replace_prop_id (ref.basic_ptr (object_with_properties::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::tag ()), prop_id); break; case shape_type::SimplePolygon: replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); break; case shape_type::SimplePolygonRef: replace_prop_id (ref.basic_ptr (object_with_properties::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::tag ()), prop_id); break; case shape_type::Edge: replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); break; case shape_type::Path: replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); break; case shape_type::PathRef: replace_prop_id (ref.basic_ptr (object_with_properties::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::tag ()), prop_id); break; case shape_type::Box: replace_prop_id (ref.basic_ptr (object_with_properties::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::tag ()), prop_id); break; case shape_type::ShortBox: replace_prop_id (ref.basic_ptr (object_with_properties::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::tag ()), prop_id); break; case shape_type::Text: replace_prop_id (ref.basic_ptr (object_with_properties::tag ()), prop_id); break; case shape_type::TextRef: replace_prop_id (ref.basic_ptr (object_with_properties::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::tag ()), prop_id); break; case shape_type::UserObject: replace_prop_id (ref.basic_ptr (object_with_properties::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 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 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::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::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { (*l)->update_bbox (); } set_dirty (false); } void Shapes::update () { for (tl::vector::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::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::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { box += (*l)->bbox (); } return box; } void Shapes::sort () { for (tl::vector::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { (*l)->sort (); } } void Shapes::redo (db::Op *op) { db::LayerOpBase *layop = dynamic_cast (op); if (layop) { layop->redo (this); } } void Shapes::undo (db::Op *op) { db::LayerOpBase *layop = dynamic_cast (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::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { (*l)->collect_mem_stat (m); } } template 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 n (*shape.basic_ptr (tag), pm (shape.prop_id ())); n.object ().translate (rep); return insert (n); } } /** * @brief (Internal) Insert from a generic pointer */ template 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 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 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 swp_type; return insert (swp_type (*shape.basic_ptr (tag), pm (shape.prop_id ()))); } } template 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::iterator i = get_layer ().find (*shape.basic_ptr (tag)); if (i == get_layer ().end ()) { return shape_type (); } else { return shape_type (this, i); } } else { typedef db::object_with_properties swp_type; typename db::layer::iterator i = get_layer ().find (*shape.basic_ptr (typename swp_type::tag ())); if (i == get_layer ().end ()) { return shape_type (); } else { return shape_type (this, i); } } } template 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::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::queue_or_append (manager (), this, true /*insert*/, *pos); } } } template Shapes::shape_type Shapes::replace_prop_id_iter (typename db::object_tag, 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::queue_or_append (manager (), this, false /*not insert*/, *iter); } db::object_with_properties wp (*iter, prop_id); invalidate_state (); // HINT: must come before the change is done! get_layer ().erase (iter); if (manager () && manager ()->transacting ()) { db::layer_op, db::stable_layer_tag>::queue_or_append (manager (), this, true /*insert*/, wp); } return shape_type (this, get_layer , db::stable_layer_tag> ().insert (wp)); } template Shapes::shape_type Shapes::reinsert_member_with_props (typename db::object_tag, 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 (sh, pid)); } } template Shapes::shape_type Shapes::replace_member_with_props (typename db::object_tag, 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 (sh, pid)); } } template Shapes::shape_type Shapes::replace_member_with_props (typename db::object_tag 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::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (tag)); } invalidate_state (); // HINT: must come before the change is done! get_layer ().replace (ref.basic_iter (tag), sh); if (manager () && manager ()->transacting ()) { db::layer_op::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::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 ().replace (ref.basic_iter (tag), sh_trans); if (manager () && manager ()->transacting ()) { db::layer_op::queue_or_append (manager (), this, true /*insert*/, sh_trans); } } else { get_layer ().replace (ref.basic_iter (tag), sh); if (manager () && manager ()->transacting ()) { db::layer_op::queue_or_append (manager (), this, true /*insert*/, sh); } } } else { if (manager () && manager ()->transacting ()) { db::layer_op, db::stable_layer_tag>::queue_or_append (manager (), this, false /*not insert*/, *ref.basic_ptr (typename db::object_with_properties::tag ())); } invalidate_state (); // HINT: must come before the change is done! db::object_with_properties swp; swp.translate (db::object_with_properties (sh, ref.prop_id ()), shape_repository (), array_repository ()); get_layer, db::stable_layer_tag> ().replace (ref.basic_iter (typename db::object_with_properties::tag ()), swp); if (manager () && manager ()->transacting ()) { db::layer_op, 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 &); template DB_PUBLIC Shape Shapes::do_insert<> (const Shape &, const Trans &, tl::func_delegate_base &); template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::stable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; template class DB_PUBLIC layer_op; template class DB_PUBLIC layer_op, db::unstable_layer_tag>; }