mirror of https://github.com/KLayout/klayout.git
1273 lines
51 KiB
C++
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>;
|
|
|
|
}
|
|
|