/* 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 */ #ifndef HDR_dbLayer #define HDR_dbLayer #include "dbBoxTree.h" #include "dbBoxConvert.h" #include "tlVector.h" #include namespace db { template class generic_repository; class ArrayRepository; struct stable_layer_tag { }; struct unstable_layer_tag { }; template struct box_tree_typedef { }; template struct box_tree_typedef { typedef db::box_tree box_tree_type; }; template struct box_tree_typedef { typedef db::unstable_box_tree box_tree_type; }; template void to_non_const_box_tree_iter (const ConstIter &ci, NonConstIter &nci, stable_layer_tag) { nci = ci.to_non_const (); } template void to_non_const_box_tree_iter (const ConstIter &ci, NonConstIter &nci, unstable_layer_tag) { // HACK: this assumes non-const and const iterators have the same memory layout ... nci = *reinterpret_cast ((void *) &ci); } /** * @brief A layer object * * A layer is basically a collection of shape objects * with a bounding box and the capability to do region queries * with a test box. */ template struct layer { typedef db::box_convert box_convert; typedef typename Sh::coord_type coord_type; typedef typename db::box box_type; typedef typename box_tree_typedef::box_tree_type box_tree_type; typedef typename box_tree_type::flat_iterator flat_iterator; typedef typename box_tree_type::const_iterator iterator; typedef typename box_tree_type::iterator non_const_iterator; typedef typename box_tree_type::touching_iterator touching_iterator; typedef typename box_tree_type::overlapping_iterator overlapping_iterator; /** * @brief Default ctor: creates an empty layer object */ layer () : m_bbox_dirty (false), m_tree_dirty (false) { // .. nothing else .. } /** * @brief The copy constructor */ layer (const layer &d) { operator= (d); } /** * @brief The assignment operator * * The manager attachement is not copied. */ layer &operator= (const layer &d) { if (&d != this) { m_box_tree = d.m_box_tree; m_bbox = d.m_bbox; m_bbox_dirty = d.m_bbox_dirty; m_tree_dirty = d.m_tree_dirty; } return *this; } /** * @brief Get the iterator for an object given by a pointer */ iterator iterator_from_pointer (const Sh *p) const { return m_box_tree.iterator_from_pointer (p); } /** * @brief The translation operator * * This operator is used to copy one layer to another repository space. * The current layer will be overwritten. * * @param src The source layer * @param rep The repository that is associated with *this and into which the * shapes will be copied */ void translate (const layer &d, db::generic_repository &rep, db::ArrayRepository &array_rep) { tl_assert (&d != this); clear (); reserve (d.size ()); for (typename layer::iterator s = d.begin (); s != d.end (); ++s) { m_box_tree.insert (Sh ())->translate (*s, rep, array_rep); } m_bbox = d.m_bbox; m_bbox_dirty = d.m_bbox_dirty; m_tree_dirty = true; } /** * @brief The translation operator * * This operator is used to copy one layer to another repository space with a transformation. * The current layer will be overwritten. * * @param src The source layer * @param trans The transformation to apply * @param rep The repository that is associated with *this and into which the * shapes will be copied */ template void translate (const layer &d, const T &trans, db::generic_repository &rep, db::ArrayRepository &array_rep) { tl_assert (&d != this); clear (); reserve (d.size ()); for (typename layer::iterator s = d.begin (); s != d.end (); ++s) { m_box_tree.insert (Sh ())->translate (*s, trans, rep, array_rep); } m_bbox = d.m_bbox; m_bbox_dirty = d.m_bbox_dirty; m_tree_dirty = true; } /** * @brief Insert a new shape object * * Insert a new shape object. This will invalidate the sorted * state and the bounding box. It will require a "update_bbox" * and a "sort" call to restore these states. * * @param sh The object (copy) to insert * * @return A reference to the object created. This reference * is only guaranteed to be valid until the next insert * or sort call. */ iterator insert (const Sh &sh) { // inserting will make the bbox and the tree "dirty" - i.e. // it will need to be updated. m_bbox_dirty = true; m_tree_dirty = true; return m_box_tree.insert (sh); } /** * @brief Replace the given element with a new one * * Replace the element at the position "pos" with the new * element "sh". * * @param pos The position at which to replace the element * @param sh The element to replace *pos * * @return A reference to the new element */ Sh &replace (iterator pos, const Sh &sh) { m_bbox_dirty = true; m_tree_dirty = true; non_const_iterator ncpos; to_non_const_box_tree_iter (pos, ncpos, StableTag ()); *ncpos = sh; return *ncpos; } /** * @brief Erasing of an element * * Erase the element at the given position. Invalidates sorting * and the bbox. */ void erase (iterator pos) { m_bbox_dirty = true; m_tree_dirty = true; non_const_iterator ncpos; to_non_const_box_tree_iter (pos, ncpos, StableTag ()); m_box_tree.erase (ncpos); } /** * @brief Erasing of elements * * Erase the elements at the given positions [from,to). * Invalidates sorting and the bbox. */ void erase (iterator from, iterator to) { m_bbox_dirty = true; m_tree_dirty = true; non_const_iterator ncfrom, ncto; to_non_const_box_tree_iter (from, ncfrom, StableTag ()); to_non_const_box_tree_iter (to, ncto, StableTag ()); m_box_tree.erase (ncfrom, ncto); } /** * @brief Erasing of multiple elements * * Erase a set of positions given by an iterator I: *(from,to). * *I must render an "iterator" object. * The iterators in the sequence from, to must be sorted in * "later" order. */ template void erase_positions (I first, I last) { if (first != last) { m_bbox_dirty = true; m_tree_dirty = true; m_box_tree.erase_positions (first, last); } } /** * @brief Insertion of a range [from,to) */ template void insert (I from, I to) { // inserting will make the bbox and the tree "dirty" - i.e. // it will need to be updated. m_bbox_dirty = true; m_tree_dirty = true; m_box_tree.insert (from, to); } /** * @brief update the bounding box if required */ void update_bbox () { // Only do so, if the bbox is dirty (needs update) if (m_bbox_dirty) { // determine the bounding box box_convert bc = box_convert (); m_bbox = box_type (); for (typename box_tree_type::const_iterator o = m_box_tree.begin (); o != m_box_tree.end (); ++o) { m_bbox += bc(*o); } m_bbox_dirty = false; } } /** * @brief Retrieve the bounding box */ const box_type &bbox () const { // update the bbox if required tl_assert (! m_bbox_dirty); return m_bbox; } /** * @brief Restore the sorted state */ void sort () { // only sort if not done already if (m_tree_dirty) { // and actually sort the tree box_convert bc = box_convert (); m_box_tree.sort (bc); m_tree_dirty = false; } } /** * @brief Clear the layer */ void clear () { m_bbox = box_type (); m_box_tree.clear (); m_bbox_dirty = false; m_tree_dirty = false; } /** * @brief A "flat" query (see box_tree::flat_iterator for a description) */ flat_iterator begin_flat () const { // we do not assert !is_dirty here for two reasons: first, in unstable mode, this is not necessary // and second, in stable mode, it might be by intention, if the shape iterator moves on to a // shape group that has been updated in between and should *not* iterate over the new set ... return m_box_tree.begin_flat (); } /** * @brief A "touching" region query */ touching_iterator begin_touching (const box_type &b) const { // sort the tree if required tl_assert (! m_tree_dirty); box_convert bc = box_convert (); return m_box_tree.begin_touching (b, bc); } /** * @brief A "overlapping" region query */ overlapping_iterator begin_overlapping (const box_type &b) const { // sort the tree if required tl_assert (! m_tree_dirty); box_convert bc = box_convert (); return m_box_tree.begin_overlapping (b, bc); } /** * @brief Find a shape in the layer * * This is a precise search. It returns end() if there is no * shape exactly matching the one provided. */ iterator find (const Sh &sh) const { // TODO: this could be done more efficiently with an exact region search // if we had a converter of a touching iterator to a normal iterator for (iterator s = begin (); s != end (); ++s) { if (*s == sh) { return s; } } return end (); } /** * @brief The normal begin iterator returning the begin of all elements */ iterator begin () const { return m_box_tree.begin (); } /** * @brief The normal end iterator returning the past-end position of all elements */ iterator end () const { return m_box_tree.end (); } /** * @brief Return true if the bounding box is "dirty" */ bool is_bbox_dirty () const { return m_bbox_dirty; } /** * @brief Reserve a certain number of elements */ void reserve (size_t n) { m_box_tree.reserve (n); } /** * @brief Reserve a certain number of elements */ size_t size () const { return m_box_tree.size (); } /** * @brief Reserve a certain number of elements */ bool empty () const { return m_box_tree.empty (); } void collect_mem_stat (db::MemStatistics &m) const { m.shapes_info (sizeof (*this), sizeof (*this)); m.shapes_info (db::mem_used (m_box_tree), db::mem_reqd (m_box_tree)); } private: box_tree_type m_box_tree; box_type m_bbox; bool m_bbox_dirty : 8; bool m_tree_dirty : 8; }; } #endif