mirror of https://github.com/KLayout/klayout.git
931 lines
29 KiB
C++
931 lines
29 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2022 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"
|
|
|
|
namespace db
|
|
{
|
|
|
|
// -------------------------------------------------------------------------------
|
|
|
|
template <class Sh, class Iter>
|
|
inline db::Shape
|
|
iterator_to_shape (db::Shapes *shapes, const db::layer<Sh, db::unstable_layer_tag> & /*l*/, const Iter &iter)
|
|
{
|
|
// for unstable containers, we simply use the pointer as a reference
|
|
return db::Shape (shapes, *iter);
|
|
}
|
|
|
|
template <class Sh, class Iter>
|
|
inline db::Shape
|
|
iterator_to_shape (db::Shapes *shapes, const db::layer<Sh, db::stable_layer_tag> &l, const Iter &iter)
|
|
{
|
|
// for stable containers, we derive the primitive iterator via the pointer
|
|
return db::Shape (shapes, l.iterator_from_pointer (&*iter));
|
|
}
|
|
|
|
template <class Sh, class Iter>
|
|
inline db::Shape
|
|
iterator_to_shape (const db::Shapes *shapes, const db::layer<Sh, db::unstable_layer_tag> & /*l*/, const Iter &iter)
|
|
{
|
|
// for unstable containers, we simply use the pointer as a reference
|
|
return db::Shape (shapes, *iter);
|
|
}
|
|
|
|
template <class Sh, class Iter>
|
|
inline db::Shape
|
|
iterator_to_shape (const db::Shapes *shapes, const db::layer<Sh, db::stable_layer_tag> &l, const Iter &iter)
|
|
{
|
|
// for stable containers, we derive the primitive iterator via the pointer
|
|
return db::Shape (shapes, l.iterator_from_pointer (&*iter));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------
|
|
// ShapeIterator implementation
|
|
|
|
ShapeIterator::ShapeIterator ()
|
|
: m_region_mode (None),
|
|
m_type (Null),
|
|
m_box (),
|
|
m_flags (0),
|
|
mp_shapes (0),
|
|
mp_prop_sel (0),
|
|
m_inv_prop_sel (false),
|
|
m_array_iterator_valid (false),
|
|
m_editable (false),
|
|
m_quad_id (0)
|
|
{
|
|
m_valid = false;
|
|
m_with_props = false;
|
|
}
|
|
|
|
ShapeIterator::ShapeIterator (const ShapeIterator &d)
|
|
: m_region_mode (None),
|
|
m_type (Null),
|
|
m_box (),
|
|
m_flags (0),
|
|
mp_shapes (0),
|
|
mp_prop_sel (0),
|
|
m_inv_prop_sel (false),
|
|
m_array_iterator_valid (false),
|
|
m_editable (false),
|
|
m_quad_id (0)
|
|
{
|
|
m_valid = false;
|
|
m_with_props = false;
|
|
operator= (d);
|
|
}
|
|
|
|
ShapeIterator::ShapeIterator (const shapes_type &shapes, unsigned int flags, const property_selector *prop_sel, bool inv_prop_sel)
|
|
: m_region_mode (None),
|
|
m_type (object_type (0)),
|
|
m_box (),
|
|
m_flags (flags),
|
|
mp_shapes (&shapes),
|
|
mp_prop_sel (prop_sel),
|
|
m_inv_prop_sel (inv_prop_sel),
|
|
m_array_iterator_valid (false),
|
|
m_editable (shapes.is_editable ()),
|
|
m_quad_id (0)
|
|
{
|
|
// optimize: empty property selection plus inverse = no property selection at all
|
|
// any property selection and not inverse = only shapes with properties
|
|
if (mp_prop_sel) {
|
|
if (mp_prop_sel->empty () && m_inv_prop_sel) {
|
|
mp_prop_sel = 0;
|
|
m_inv_prop_sel = false;
|
|
} else if (! m_inv_prop_sel) {
|
|
m_flags |= Properties;
|
|
}
|
|
}
|
|
m_valid = false;
|
|
m_with_props = false;
|
|
|
|
// look for the first type selected
|
|
for (unsigned int m = 1; m_type != Null && (m_flags & m) == 0; m <<= 1) {
|
|
m_type = object_type ((unsigned int) m_type + 1);
|
|
}
|
|
|
|
advance (0); // validate
|
|
}
|
|
|
|
ShapeIterator::ShapeIterator (const shapes_type &shapes, const box_type &box, region_mode mode, unsigned int flags, const property_selector *prop_sel, bool inv_prop_sel)
|
|
: m_region_mode (mode),
|
|
m_type (object_type (0)),
|
|
m_box (box),
|
|
m_flags (flags),
|
|
mp_shapes (&shapes),
|
|
mp_prop_sel (prop_sel),
|
|
m_inv_prop_sel (inv_prop_sel),
|
|
m_array_iterator_valid (false),
|
|
m_editable (shapes.is_editable ()),
|
|
m_quad_id (0)
|
|
{
|
|
// optimize: empty property selection plus inverse = no property selection at all
|
|
// any property selection and not inverse = only shapes with properties
|
|
if (mp_prop_sel) {
|
|
if (mp_prop_sel->empty () && m_inv_prop_sel) {
|
|
mp_prop_sel = 0;
|
|
m_inv_prop_sel = false;
|
|
} else if (! m_inv_prop_sel) {
|
|
m_flags |= Properties;
|
|
}
|
|
}
|
|
m_valid = false;
|
|
m_with_props = false;
|
|
|
|
// look for the first type selected
|
|
for (unsigned int m = 1; m_type != Null && (m_flags & m) == 0; m <<= 1) {
|
|
m_type = object_type ((unsigned int) m_type + 1);
|
|
}
|
|
|
|
advance (0); // validate
|
|
}
|
|
|
|
ShapeIterator &
|
|
ShapeIterator::operator= (const ShapeIterator &d)
|
|
{
|
|
if (&d != this) {
|
|
|
|
cleanup ();
|
|
|
|
m_d = d.m_d;
|
|
m_valid = d.m_valid;
|
|
m_with_props = d.m_with_props;
|
|
m_region_mode = d.m_region_mode;
|
|
m_type = d.m_type;
|
|
m_box = d.m_box;
|
|
m_shape = d.m_shape;
|
|
m_array = d.m_array;
|
|
m_flags = d.m_flags;
|
|
mp_shapes = d.mp_shapes;
|
|
mp_prop_sel = d.mp_prop_sel;
|
|
m_inv_prop_sel = d.m_inv_prop_sel;
|
|
m_array_iterator_valid = d.m_array_iterator_valid;
|
|
m_editable = d.m_editable;
|
|
m_quad_id = d.m_quad_id;
|
|
|
|
if (m_type != Null) {
|
|
|
|
if (m_array_iterator_valid) {
|
|
|
|
if (m_type == PolygonPtrArray) {
|
|
|
|
polygon_ptr_array_iterator_type *d_arr_iter = (polygon_ptr_array_iterator_type *) d.m_ad.iter;
|
|
polygon_ptr_array_iterator_type *arr_iter = (polygon_ptr_array_iterator_type *) m_ad.iter;
|
|
new (arr_iter) polygon_ptr_array_iterator_type (*d_arr_iter);
|
|
|
|
} else if (m_type == SimplePolygonPtrArray) {
|
|
|
|
simple_polygon_ptr_array_iterator_type *d_arr_iter = (simple_polygon_ptr_array_iterator_type *) d.m_ad.iter;
|
|
simple_polygon_ptr_array_iterator_type *arr_iter = (simple_polygon_ptr_array_iterator_type *) m_ad.iter;
|
|
new (arr_iter) simple_polygon_ptr_array_iterator_type (*d_arr_iter);
|
|
|
|
} else if (m_type == PathPtrArray) {
|
|
|
|
path_ptr_array_iterator_type *d_arr_iter = (path_ptr_array_iterator_type *) d.m_ad.iter;
|
|
path_ptr_array_iterator_type *arr_iter = (path_ptr_array_iterator_type *) m_ad.iter;
|
|
new (arr_iter) path_ptr_array_iterator_type (*d_arr_iter);
|
|
|
|
} else if (m_type == TextPtrArray) {
|
|
|
|
text_ptr_array_iterator_type *d_arr_iter = (text_ptr_array_iterator_type *) d.m_ad.iter;
|
|
text_ptr_array_iterator_type *arr_iter = (text_ptr_array_iterator_type *) m_ad.iter;
|
|
new (arr_iter) text_ptr_array_iterator_type (*d_arr_iter);
|
|
|
|
} else if (m_type == BoxArray) {
|
|
|
|
box_array_iterator_type *d_arr_iter = (box_array_iterator_type *) d.m_ad.iter;
|
|
box_array_iterator_type *arr_iter = (box_array_iterator_type *) m_ad.iter;
|
|
new (arr_iter) box_array_iterator_type (*d_arr_iter);
|
|
|
|
} else if (m_type == ShortBoxArray) {
|
|
|
|
short_box_array_iterator_type *d_arr_iter = (short_box_array_iterator_type *) d.m_ad.iter;
|
|
short_box_array_iterator_type *arr_iter = (short_box_array_iterator_type *) m_ad.iter;
|
|
new (arr_iter) short_box_array_iterator_type (*d_arr_iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <class Iter>
|
|
inline void
|
|
ShapeIterator::skip_array_iter ()
|
|
{
|
|
Iter *arr_iter = (Iter *) m_ad.iter;
|
|
arr_iter->~Iter ();
|
|
}
|
|
|
|
void
|
|
ShapeIterator::skip_array ()
|
|
{
|
|
if (m_array_iterator_valid) {
|
|
if (m_type == PolygonPtrArray) {
|
|
skip_array_iter<polygon_ptr_array_iterator_type> ();
|
|
} else if (m_type == SimplePolygonPtrArray) {
|
|
skip_array_iter<simple_polygon_ptr_array_iterator_type> ();
|
|
} else if (m_type == PathPtrArray) {
|
|
skip_array_iter<path_ptr_array_iterator_type> ();
|
|
} else if (m_type == TextPtrArray) {
|
|
skip_array_iter<text_ptr_array_iterator_type> ();
|
|
} else if (m_type == BoxArray) {
|
|
skip_array_iter<box_array_iterator_type> ();
|
|
} else if (m_type == ShortBoxArray) {
|
|
skip_array_iter<short_box_array_iterator_type> ();
|
|
}
|
|
m_array_iterator_valid = false;
|
|
}
|
|
}
|
|
|
|
template <class Sh, class StableTag, class RegionTag>
|
|
struct advance_algorithm_traits;
|
|
|
|
template <class Sh, class StableTag>
|
|
struct advance_algorithm_traits<Sh, StableTag, ShapeIterator::NoRegionTag>
|
|
{
|
|
typedef typename db::layer<Sh, StableTag>::flat_iterator iterator_type;
|
|
typedef typename db::layer<db::object_with_properties<Sh>, StableTag >::flat_iterator iterator_with_props_type;
|
|
|
|
inline static void advance (iterator_type *iter, int /*mode*/)
|
|
{
|
|
++*iter;
|
|
}
|
|
|
|
inline static void advance (iterator_with_props_type *iter, int /*mode*/)
|
|
{
|
|
++*iter;
|
|
}
|
|
|
|
inline static size_t quad_id (iterator_type * /*iter*/)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
inline static size_t quad_id (iterator_with_props_type * /*iter*/)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
inline static iterator_type begin (const db::Shapes *shapes, const db::Box & /*box*/)
|
|
{
|
|
// use get_layer().begin..() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
return shapes->template get_layer <Sh, StableTag> ().begin_flat ();
|
|
}
|
|
|
|
inline static iterator_with_props_type begin_with_props (const db::Shapes *shapes, const db::Box & /*box*/)
|
|
{
|
|
// use get_layer().begin..() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
return shapes->template get_layer <db::object_with_properties <Sh>, StableTag> ().begin_flat ();
|
|
}
|
|
};
|
|
|
|
template <class Sh, class StableTag>
|
|
struct advance_algorithm_traits<Sh, StableTag, ShapeIterator::TouchingRegionTag>
|
|
{
|
|
typedef typename db::layer<Sh, StableTag>::touching_iterator iterator_type;
|
|
typedef typename db::layer<db::object_with_properties<Sh>, StableTag >::touching_iterator iterator_with_props_type;
|
|
|
|
inline static void advance (iterator_type *iter, int mode)
|
|
{
|
|
if (mode > 0) {
|
|
++*iter;
|
|
} else {
|
|
iter->skip_quad ();
|
|
}
|
|
}
|
|
|
|
inline static void advance (iterator_with_props_type *iter, int mode)
|
|
{
|
|
if (mode > 0) {
|
|
++*iter;
|
|
} else {
|
|
iter->skip_quad ();
|
|
}
|
|
}
|
|
|
|
inline static size_t quad_id (iterator_type *iter)
|
|
{
|
|
return iter->quad_id ();
|
|
}
|
|
|
|
inline static size_t quad_id (iterator_with_props_type *iter)
|
|
{
|
|
return iter->quad_id ();
|
|
}
|
|
|
|
inline static iterator_type begin (const db::Shapes *shapes, const db::Box &box)
|
|
{
|
|
// use get_layer().begin..() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
return shapes->template get_layer <Sh, StableTag> ().begin_touching (box);
|
|
}
|
|
|
|
inline static iterator_with_props_type begin_with_props (const db::Shapes *shapes, const db::Box &box)
|
|
{
|
|
// use get_layer().begin..() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
return shapes->template get_layer <db::object_with_properties <Sh>, StableTag> ().begin_touching (box);
|
|
}
|
|
};
|
|
|
|
template <class Sh, class StableTag>
|
|
struct advance_algorithm_traits<Sh, StableTag, ShapeIterator::OverlappingRegionTag>
|
|
{
|
|
typedef typename db::layer<Sh, StableTag>::overlapping_iterator iterator_type;
|
|
typedef typename db::layer<db::object_with_properties<Sh>, StableTag >::overlapping_iterator iterator_with_props_type;
|
|
|
|
inline static void advance (iterator_type *iter, int mode)
|
|
{
|
|
if (mode > 0) {
|
|
++*iter;
|
|
} else {
|
|
iter->skip_quad ();
|
|
}
|
|
}
|
|
|
|
inline static void advance (iterator_with_props_type *iter, int mode)
|
|
{
|
|
if (mode > 0) {
|
|
++*iter;
|
|
} else {
|
|
iter->skip_quad ();
|
|
}
|
|
}
|
|
|
|
inline static size_t quad_id (iterator_type *iter)
|
|
{
|
|
return iter->quad_id ();
|
|
}
|
|
|
|
inline static size_t quad_id (iterator_with_props_type *iter)
|
|
{
|
|
return iter->quad_id ();
|
|
}
|
|
|
|
inline static iterator_type begin (const db::Shapes *shapes, const db::Box &box)
|
|
{
|
|
// use get_layer().begin..() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
return shapes->template get_layer <Sh, StableTag> ().begin_overlapping (box);
|
|
}
|
|
|
|
inline static iterator_with_props_type begin_with_props (const db::Shapes *shapes, const db::Box &box)
|
|
{
|
|
// use get_layer().begin..() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
return shapes->template get_layer <db::object_with_properties <Sh>, StableTag> ().begin_overlapping (box);
|
|
}
|
|
};
|
|
|
|
template <class Sh, class StableTag, class RegionTag>
|
|
bool
|
|
ShapeIterator::advance_shape (int &mode)
|
|
{
|
|
typedef advance_algorithm_traits<Sh, StableTag, RegionTag> algorithm_traits;
|
|
typedef typename algorithm_traits::iterator_type iterator_type;
|
|
typedef typename algorithm_traits::iterator_with_props_type iterator_with_props_type;
|
|
|
|
if (mode) {
|
|
|
|
tl_assert (m_valid);
|
|
|
|
if (! m_with_props) {
|
|
iterator_type *iter = (iterator_type *) m_d.iter;
|
|
algorithm_traits::advance (iter, mode);
|
|
} else {
|
|
iterator_with_props_type *iter = (iterator_with_props_type *) m_d.iter;
|
|
do {
|
|
algorithm_traits::advance (iter, mode);
|
|
} while (mp_prop_sel && ! iter->at_end () && (mp_prop_sel->find ((*iter)->properties_id ()) == mp_prop_sel->end ()) != m_inv_prop_sel);
|
|
}
|
|
|
|
// further steps are validation only
|
|
mode = 0;
|
|
|
|
}
|
|
|
|
bool sel = (m_flags & (1 << (unsigned int) m_type)) != 0;
|
|
bool props_only = (m_flags & Properties) != 0;
|
|
|
|
if (! m_with_props && ! props_only) {
|
|
|
|
iterator_type *iter = (iterator_type *) m_d.iter;
|
|
|
|
if (!m_valid && sel) {
|
|
iterator_type i = algorithm_traits::begin (mp_shapes, m_box);
|
|
if (! i.at_end ()) {
|
|
new (iter) iterator_type (i);
|
|
m_valid = true;
|
|
}
|
|
}
|
|
|
|
if (m_valid) {
|
|
if (!sel || iter->at_end ()) {
|
|
m_valid = false;
|
|
} else {
|
|
m_shape = iterator_to_shape (mp_shapes, mp_shapes->template get_layer<Sh, StableTag> (), *iter);
|
|
m_quad_id = algorithm_traits::quad_id (iter);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
m_with_props = true;
|
|
|
|
{
|
|
|
|
iterator_with_props_type *iter = (iterator_with_props_type *) m_d.iter;
|
|
|
|
if (!m_valid && sel) {
|
|
// use get_layer().begin_flat() in order to suppress update() - this might change the container
|
|
// while iterating.
|
|
iterator_with_props_type i = algorithm_traits::begin_with_props (mp_shapes, m_box);
|
|
if (mp_prop_sel) {
|
|
while (! i.at_end () && (mp_prop_sel->find (i->properties_id ()) == mp_prop_sel->end ()) != m_inv_prop_sel) {
|
|
++i;
|
|
}
|
|
}
|
|
if (! i.at_end ()) {
|
|
new (iter) iterator_with_props_type (i);
|
|
m_valid = true;
|
|
}
|
|
}
|
|
|
|
if (m_valid) {
|
|
if (!sel || iter->at_end ()) {
|
|
m_valid = false;
|
|
} else {
|
|
m_shape = iterator_to_shape (mp_shapes, mp_shapes->template get_layer<db::object_with_properties<Sh>, StableTag> (), *iter);
|
|
m_quad_id = algorithm_traits::quad_id (iter);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
m_with_props = false;
|
|
return false;
|
|
}
|
|
|
|
template <class Array>
|
|
void
|
|
ShapeIterator::init_array_iter (typename ShapeIterator::NoRegionTag)
|
|
{
|
|
typedef typename Array::iterator array_iterator;
|
|
|
|
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
|
if (m_with_props) {
|
|
new (arr_iter) array_iterator (m_array.basic_ptr (typename db::object_with_properties<Array>::tag ())->begin ());
|
|
} else {
|
|
new (arr_iter) array_iterator (m_array.basic_ptr (typename Array::tag ())->begin ());
|
|
}
|
|
}
|
|
|
|
template <class Array>
|
|
void
|
|
ShapeIterator::init_array_iter (typename ShapeIterator::TouchingRegionTag)
|
|
{
|
|
typedef typename Array::iterator array_iterator;
|
|
typedef typename Array::object_type shape_ptr_type;
|
|
|
|
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
|
db::box_convert<shape_ptr_type> bc;
|
|
new (arr_iter) array_iterator (m_array.basic_ptr (typename Array::tag ())->begin_touching (m_box, bc));
|
|
}
|
|
|
|
template <class Array>
|
|
void
|
|
ShapeIterator::init_array_iter (typename ShapeIterator::OverlappingRegionTag)
|
|
{
|
|
typedef typename Array::iterator array_iterator;
|
|
typedef typename Array::object_type shape_ptr_type;
|
|
|
|
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
|
db::box_convert<shape_ptr_type> bc;
|
|
box_type box (m_box);
|
|
box.enlarge (vector_type (-1, -1));
|
|
new (arr_iter) array_iterator (m_array.basic_ptr (typename Array::tag ())->begin_touching (m_box, bc));
|
|
}
|
|
|
|
template <class Array, class StableTag, class RegionTag>
|
|
bool
|
|
ShapeIterator::advance_aref (int &mode)
|
|
{
|
|
typedef typename Array::iterator array_iterator;
|
|
|
|
if (mode && m_array_iterator_valid) {
|
|
|
|
if (mode == 1) {
|
|
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
|
++*arr_iter;
|
|
} else if (mode == 2) {
|
|
// skip array quad -> skip rest of array quad and move to shape in the next quad or to end
|
|
do_skip_array_quad ();
|
|
mode = 1;
|
|
} else {
|
|
// skip quad -> skip rest of array and move to next shape array
|
|
skip_array (); // sets m_array_iterator_valid = false
|
|
}
|
|
|
|
}
|
|
|
|
while (true) {
|
|
|
|
if (m_array_iterator_valid) {
|
|
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
|
if (! arr_iter->at_end ()) {
|
|
break;
|
|
} else {
|
|
arr_iter->~array_iterator ();
|
|
m_array_iterator_valid = false;
|
|
mode = 1; // force move to next item in increment mode
|
|
}
|
|
}
|
|
|
|
// move to next item (increment on mode == 1, skip quad on mode == -1) or validate this one (if mode == 0)
|
|
if (! advance_shape<Array, StableTag, RegionTag> (mode)) {
|
|
return false;
|
|
}
|
|
|
|
m_array = m_shape;
|
|
RegionTag region_tag;
|
|
init_array_iter <Array> (region_tag);
|
|
m_array_iterator_valid = true;
|
|
|
|
}
|
|
|
|
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
|
typename array_iterator::result_type t = **arr_iter;
|
|
|
|
// HINT: since the array references store "pointers" without an intrinsic
|
|
// transformation, we can drop this:
|
|
// t = t * (*iter)->obj ().trans ();
|
|
|
|
// This creates a local reference object to reference an array member
|
|
if (m_editable) {
|
|
if (m_with_props) {
|
|
m_shape = shape_type (mp_shapes, m_array.basic_iter (typename db::object_with_properties<Array>::tag ()), t);
|
|
} else {
|
|
m_shape = shape_type (mp_shapes, m_array.basic_iter (typename Array::tag ()), t);
|
|
}
|
|
} else {
|
|
if (m_with_props) {
|
|
m_shape = shape_type (mp_shapes, *m_array.basic_ptr (typename db::object_with_properties<Array>::tag ()), t);
|
|
} else {
|
|
m_shape = shape_type (mp_shapes, *m_array.basic_ptr (typename Array::tag ()), t);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class RegionTag, class StableTag>
|
|
void
|
|
ShapeIterator::advance_generic (int mode)
|
|
{
|
|
while (m_type != Null) {
|
|
|
|
switch (m_type) {
|
|
case Polygon:
|
|
if (advance_shape<polygon_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case PolygonRef:
|
|
if (advance_shape<polygon_ref_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case PolygonPtrArray:
|
|
if (advance_aref<polygon_ptr_array_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case SimplePolygon:
|
|
if (advance_shape<simple_polygon_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case SimplePolygonRef:
|
|
if (advance_shape<simple_polygon_ref_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case SimplePolygonPtrArray:
|
|
if (advance_aref<simple_polygon_ptr_array_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case Edge:
|
|
if (advance_shape<edge_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case EdgePair:
|
|
if (advance_shape<edge_pair_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case Point:
|
|
if (advance_shape<point_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case Path:
|
|
if (advance_shape<path_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case PathRef:
|
|
if (advance_shape<path_ref_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case PathPtrArray:
|
|
if (advance_aref<path_ptr_array_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case Box:
|
|
if (advance_shape<box_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case BoxArray:
|
|
if (advance_aref<box_array_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case ShortBox:
|
|
if (advance_shape<short_box_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case ShortBoxArray:
|
|
if (advance_aref<short_box_array_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case Text:
|
|
if (advance_shape<text_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case TextRef:
|
|
if (advance_shape<text_ref_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case TextPtrArray:
|
|
if (advance_aref<text_ptr_array_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
case UserObject:
|
|
if (advance_shape<user_object_type, StableTag, RegionTag> (mode)) return;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// look for the next type selected
|
|
m_type = object_type ((unsigned int) m_type + 1);
|
|
for (unsigned int m = 1 << (unsigned int) m_type; m_type != Null && (m_flags & m) == 0; m <<= 1) {
|
|
m_type = object_type ((unsigned int) m_type + 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
ShapeIterator::finish_array ()
|
|
{
|
|
skip_array ();
|
|
advance (1);
|
|
}
|
|
|
|
void
|
|
ShapeIterator::advance (int mode)
|
|
{
|
|
if (m_editable) {
|
|
if (m_region_mode == None) {
|
|
advance_generic<NoRegionTag, db::stable_layer_tag> (mode);
|
|
} else if (m_region_mode == Touching) {
|
|
advance_generic<TouchingRegionTag, db::stable_layer_tag> (mode);
|
|
} else if (m_region_mode == Overlapping) {
|
|
advance_generic<OverlappingRegionTag, db::stable_layer_tag> (mode);
|
|
}
|
|
} else {
|
|
if (m_region_mode == None) {
|
|
advance_generic<NoRegionTag, db::unstable_layer_tag> (mode);
|
|
} else if (m_region_mode == Touching) {
|
|
advance_generic<TouchingRegionTag, db::unstable_layer_tag> (mode);
|
|
} else if (m_region_mode == Overlapping) {
|
|
advance_generic<OverlappingRegionTag, db::unstable_layer_tag> (mode);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Sh, class StableTag>
|
|
db::Box
|
|
ShapeIterator::quad_box_by_shape (typename ShapeIterator::TouchingRegionTag) const
|
|
{
|
|
tl_assert (m_valid);
|
|
if (! m_with_props) {
|
|
typename db::layer<Sh, StableTag>::touching_iterator *iter = (typename db::layer<Sh, StableTag>::touching_iterator *) m_d.iter;
|
|
return iter->quad_box ();
|
|
} else {
|
|
typename db::layer<db::object_with_properties<Sh>, StableTag >::touching_iterator *iter = (typename db::layer< db::object_with_properties<Sh>, StableTag>::touching_iterator *) m_d.iter;
|
|
return iter->quad_box ();
|
|
}
|
|
}
|
|
|
|
template <class Sh, class StableTag>
|
|
db::Box
|
|
ShapeIterator::quad_box_by_shape (typename ShapeIterator::OverlappingRegionTag) const
|
|
{
|
|
tl_assert (m_valid);
|
|
if (! m_with_props) {
|
|
typename db::layer<Sh, StableTag>::overlapping_iterator *iter = (typename db::layer<Sh, StableTag>::overlapping_iterator *) m_d.iter;
|
|
return iter->quad_box ();
|
|
} else {
|
|
typename db::layer<db::object_with_properties<Sh>, StableTag >::overlapping_iterator *iter = (typename db::layer< db::object_with_properties<Sh>, StableTag>::overlapping_iterator *) m_d.iter;
|
|
return iter->quad_box ();
|
|
}
|
|
}
|
|
|
|
template <class RegionTag, class StableTag>
|
|
db::Box
|
|
ShapeIterator::quad_box_generic () const
|
|
{
|
|
RegionTag region_tag = RegionTag ();
|
|
|
|
switch (m_type) {
|
|
case Polygon:
|
|
return (quad_box_by_shape<polygon_type, StableTag> (region_tag));
|
|
case PolygonRef:
|
|
return (quad_box_by_shape<polygon_ref_type, StableTag> (region_tag));
|
|
case PolygonPtrArray:
|
|
return (quad_box_by_shape<polygon_ptr_array_type, StableTag> (region_tag));
|
|
case SimplePolygon:
|
|
return (quad_box_by_shape<simple_polygon_type, StableTag> (region_tag));
|
|
case SimplePolygonRef:
|
|
return (quad_box_by_shape<simple_polygon_ref_type, StableTag> (region_tag));
|
|
case SimplePolygonPtrArray:
|
|
return (quad_box_by_shape<simple_polygon_ptr_array_type, StableTag> (region_tag));
|
|
case Edge:
|
|
return (quad_box_by_shape<edge_type, StableTag> (region_tag));
|
|
case EdgePair:
|
|
return (quad_box_by_shape<edge_pair_type, StableTag> (region_tag));
|
|
case Point:
|
|
return (quad_box_by_shape<point_type, StableTag> (region_tag));
|
|
case Path:
|
|
return (quad_box_by_shape<path_type, StableTag> (region_tag));
|
|
case PathRef:
|
|
return (quad_box_by_shape<path_ref_type, StableTag> (region_tag));
|
|
case PathPtrArray:
|
|
return (quad_box_by_shape<path_ptr_array_type, StableTag> (region_tag));
|
|
case Box:
|
|
return (quad_box_by_shape<box_type, StableTag> (region_tag));
|
|
case BoxArray:
|
|
return (quad_box_by_shape<box_array_type, StableTag> (region_tag));
|
|
case ShortBox:
|
|
return (quad_box_by_shape<short_box_type, StableTag> (region_tag));
|
|
case ShortBoxArray:
|
|
return (quad_box_by_shape<short_box_array_type, StableTag> (region_tag));
|
|
case Text:
|
|
return (quad_box_by_shape<text_type, StableTag> (region_tag));
|
|
case TextRef:
|
|
return (quad_box_by_shape<text_ref_type, StableTag> (region_tag));
|
|
case TextPtrArray:
|
|
return (quad_box_by_shape<text_ptr_array_type, StableTag> (region_tag));
|
|
case UserObject:
|
|
return (quad_box_by_shape<user_object_type, StableTag> (region_tag));
|
|
default:
|
|
return db::Box ();
|
|
}
|
|
}
|
|
|
|
db::Box
|
|
ShapeIterator::quad_box () const
|
|
{
|
|
if (m_editable) {
|
|
if (m_region_mode == None) {
|
|
return db::Box::world ();
|
|
} else if (m_region_mode == Touching) {
|
|
return quad_box_generic<TouchingRegionTag, db::stable_layer_tag> ();
|
|
} else if (m_region_mode == Overlapping) {
|
|
return quad_box_generic<OverlappingRegionTag, db::stable_layer_tag> ();
|
|
}
|
|
} else {
|
|
if (m_region_mode == None) {
|
|
return db::Box::world ();
|
|
} else if (m_region_mode == Touching) {
|
|
return quad_box_generic<TouchingRegionTag, db::unstable_layer_tag> ();
|
|
} else if (m_region_mode == Overlapping) {
|
|
return quad_box_generic<OverlappingRegionTag, db::unstable_layer_tag> ();
|
|
}
|
|
}
|
|
|
|
return db::Box ();
|
|
}
|
|
|
|
template <class Iter>
|
|
void
|
|
ShapeIterator::do_skip_array_quad_iter ()
|
|
{
|
|
Iter *arr_iter = (Iter *) m_ad.iter;
|
|
arr_iter->skip_quad ();
|
|
}
|
|
|
|
void
|
|
ShapeIterator::do_skip_array_quad ()
|
|
{
|
|
if (m_array_iterator_valid) {
|
|
if (m_type == PolygonPtrArray) {
|
|
do_skip_array_quad_iter<polygon_ptr_array_iterator_type> ();
|
|
} else if (m_type == SimplePolygonPtrArray) {
|
|
do_skip_array_quad_iter<simple_polygon_ptr_array_iterator_type> ();
|
|
} else if (m_type == PathPtrArray) {
|
|
do_skip_array_quad_iter<path_ptr_array_iterator_type> ();
|
|
} else if (m_type == TextPtrArray) {
|
|
do_skip_array_quad_iter<text_ptr_array_iterator_type> ();
|
|
} else if (m_type == BoxArray) {
|
|
do_skip_array_quad_iter<box_array_iterator_type> ();
|
|
} else if (m_type == ShortBoxArray) {
|
|
do_skip_array_quad_iter<short_box_array_iterator_type> ();
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Iter>
|
|
size_t
|
|
ShapeIterator::get_array_quad_id () const
|
|
{
|
|
Iter *arr_iter = (Iter *) m_ad.iter;
|
|
return arr_iter->quad_id ();
|
|
}
|
|
|
|
size_t
|
|
ShapeIterator::array_quad_id () const
|
|
{
|
|
if (m_array_iterator_valid) {
|
|
if (m_type == PolygonPtrArray) {
|
|
return get_array_quad_id<polygon_ptr_array_iterator_type> ();
|
|
} else if (m_type == SimplePolygonPtrArray) {
|
|
return get_array_quad_id<simple_polygon_ptr_array_iterator_type> ();
|
|
} else if (m_type == PathPtrArray) {
|
|
return get_array_quad_id<path_ptr_array_iterator_type> ();
|
|
} else if (m_type == TextPtrArray) {
|
|
return get_array_quad_id<text_ptr_array_iterator_type> ();
|
|
} else if (m_type == BoxArray) {
|
|
return get_array_quad_id<box_array_iterator_type> ();
|
|
} else if (m_type == ShortBoxArray) {
|
|
return get_array_quad_id<short_box_array_iterator_type> ();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <class Iter, class Array>
|
|
db::Box
|
|
ShapeIterator::get_array_quad_box () const
|
|
{
|
|
const Array *arr = m_array.basic_ptr (typename Array::tag ());
|
|
Iter *arr_iter = (Iter *) m_ad.iter;
|
|
db::box_convert<typename Array::object_type> bc;
|
|
return arr->quad_box (*arr_iter, bc);
|
|
}
|
|
|
|
db::Box
|
|
ShapeIterator::array_quad_box () const
|
|
{
|
|
if (m_array_iterator_valid) {
|
|
if (m_type == PolygonPtrArray) {
|
|
return get_array_quad_box<polygon_ptr_array_iterator_type, polygon_ptr_array_type> ();
|
|
} else if (m_type == SimplePolygonPtrArray) {
|
|
return get_array_quad_box<simple_polygon_ptr_array_iterator_type, simple_polygon_ptr_array_type> ();
|
|
} else if (m_type == PathPtrArray) {
|
|
return get_array_quad_box<path_ptr_array_iterator_type, path_ptr_array_type> ();
|
|
} else if (m_type == TextPtrArray) {
|
|
return get_array_quad_box<text_ptr_array_iterator_type, text_ptr_array_type> ();
|
|
} else if (m_type == BoxArray) {
|
|
return get_array_quad_box<box_array_iterator_type, box_array_type> ();
|
|
} else if (m_type == ShortBoxArray) {
|
|
return get_array_quad_box<short_box_array_iterator_type, short_box_array_type> ();
|
|
}
|
|
}
|
|
|
|
return db::Box::world ();
|
|
}
|
|
|
|
void
|
|
ShapeIterator::cleanup ()
|
|
{
|
|
// this trick destroys all iterators that have been allocated in the generic union
|
|
if (m_type != Null) {
|
|
|
|
skip_array ();
|
|
m_flags = 0;
|
|
advance (0);
|
|
tl_assert (m_type == Null);
|
|
|
|
}
|
|
}
|
|
|
|
}
|