klayout/src/laybasic/layAnnotationShapes.h

367 lines
8.4 KiB
C
Raw Normal View History

/*
KLayout Layout Viewer
Copyright (C) 2006-2016 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_layAnnotationShapes
#define HDR_layAnnotationShapes
#include "laybasicCommon.h"
#include "dbUserObject.h"
#include "dbObject.h"
#include "dbLayer.h"
#include "dbLayoutStateModel.h"
#include <vector>
namespace lay
{
class AnnotationShapes;
/**
* @brief A undo/redo queue object for the layer
*
* This class is used internally to queue an insert or erase operation
* into the db::Object manager's undo/redo queue.
*/
class LAYBASIC_PUBLIC AnnotationLayerOp
: public db::Op
{
public:
typedef db::DUserObject shape_type;
AnnotationLayerOp (bool insert, const shape_type &sh)
: m_insert (insert)
{
m_shapes.push_back (sh);
}
template <class Iter>
AnnotationLayerOp (bool insert, Iter from, Iter to)
: m_insert (insert)
{
m_shapes.insert (m_shapes.end (), from, to);
}
template <class Iter>
AnnotationLayerOp (bool insert, Iter from, Iter to, bool /*dummy*/)
: m_insert (insert)
{
m_shapes.reserve (std::distance (from, to));
for (Iter i = from; i != to; ++i) {
m_shapes.push_back (**i);
}
}
virtual void undo (AnnotationShapes *shapes)
{
if (m_insert) {
erase (shapes);
} else {
insert (shapes);
}
}
virtual void redo (AnnotationShapes *shapes)
{
if (m_insert) {
insert (shapes);
} else {
erase (shapes);
}
}
private:
bool m_insert;
std::vector<shape_type> m_shapes;
void insert (AnnotationShapes *shapes);
void erase (AnnotationShapes *shapes);
};
/**
* @brief A collection of DUserObject objects that serves as a container for annotation shapes
*/
class LAYBASIC_PUBLIC AnnotationShapes
: public db::LayoutStateModel,
public db::Object
{
public:
typedef db::DCoord coord_type;
typedef db::box<coord_type> box_type;
typedef db::DUserObject shape_type;
typedef db::layer<shape_type, db::stable_layer_tag> layer_type;
typedef layer_type::overlapping_iterator overlapping_iterator;
typedef layer_type::touching_iterator touching_iterator;
typedef layer_type::iterator iterator;
/**
* @brief Standard ctor: create an empty collection referencing a graph
*
* The graph reference is used to invalid the bbox flag of the graph
* whenever something changes on the shapes list.
*/
AnnotationShapes (db::Manager *manager = 0);
/**
* @brief Dtor: clear all ..
*/
~AnnotationShapes ();
/**
* @brief Copy ctor
*/
AnnotationShapes (const AnnotationShapes &d);
/**
* @brief Assignment operator
*/
AnnotationShapes &operator= (const AnnotationShapes &d);
/**
* @brief Insert a shape_type
*/
const shape_type &insert (const shape_type &sh);
/**
* @brief Insert a sequence of DUserObject shapes
*
* Inserts a sequence of shapes [from,to)
*/
template <class Iter>
void insert (Iter from, Iter to)
{
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new AnnotationLayerOp (true /*insert*/, from, to));
}
invalidate_state ();
m_layer.insert (from, to);
}
/**
* @brief Reserve the number of elements for a shape type
*
* @param n The number of elements to reserve
*/
void reserve (size_t n);
/**
* @brief Erase an element
*
* Erases a shape at the given position
*
* @param tag The shape type's tag (i.e. db::Polygon::tag)
* @param pos The position of the shape to erase
*/
void erase (layer_type::iterator pos);
/**
* @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.
*
* @param first The start of the sequence of iterators
* @param last The end of the sequence of iterators
*/
template <class I>
void erase_positions (I first, I last)
{
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new AnnotationLayerOp (false /*not insert*/, first, last, true /*dummy*/));
}
invalidate_state (); // HINT: must come before the change is done!
m_layer.erase_positions (first, last);
}
/**
* @brief Replace an element at the given position with another shape
*
* Replaces the element at the position pos with the
* new element.
*
* @param pos The position at which to replace the shape
* @param sh The shape to replace
*
* @return A reference to the object created
*/
const shape_type &replace (iterator pos, const shape_type &sh);
/**
* @brief updates the bbox
*
* Updating the bbox is required after insert operations
* and is performed only as far as necessary.
*/
void update_bbox ()
{
m_layer.update_bbox ();
}
/**
* @brief check if the bounding box needs update
*
* Returns true if the bounding box of the shapes has changed and
* requires an update.
*/
bool is_bbox_dirty () const
{
return m_layer.is_bbox_dirty ();
}
/**
* @brief Retrieve the bbox
*
* Retrieving the bbox might required an update_bbox
* before the bbox is valid. It will assert if the bbox
* was not valid.
* Doing a update_bbox before does not imply a performance penalty
* since the state is cached.
*/
box_type bbox () const
{
return m_layer.bbox ();
}
/**
* @brief Clears the collection
*/
void clear ();
/**
* @brief Do a region search in "touching" mode
*
* @return The region iterator
*/
layer_type::touching_iterator begin_touching (const box_type &b) const
{
const_cast<layer_type &> (m_layer).sort (); // ensure the box tree is made
return m_layer.begin_touching (b);
}
/**
* @brief The region iterator end token
*/
size_t end_touching () const
{
return 0; // KLUDGE: some shortcut but basically an implementation detail ..
}
/**
* @brief Do a region search in "overlapping" mode
*
* @return The region iterator
*/
layer_type::overlapping_iterator begin_overlapping (const box_type &b) const
{
const_cast<layer_type &> (m_layer).sort (); // ensure the box tree is made
return m_layer.begin_overlapping (b);
}
/**
* @brief The region iterator end token
*/
size_t end_overlapping () const
{
return 0; // KLUDGE: some shortcut but basically an implementation detail ..
}
/**
* @brief begin iterator of all elements
*
* @return The first position of the shapes
*/
layer_type::iterator begin () const
{
return m_layer.begin ();
}
/**
* @brief end iterator of all elements
*
* @return The post-end position of the shapes
*/
layer_type::iterator end () const
{
return m_layer.end ();
}
/**
* @brief find a given shape (exactly)
*
* @param s The shape to find
*
* @return end(Sh::tag) if the shape was not found, the position otherwise
*/
layer_type::iterator find (const shape_type &s) const
{
return m_layer.find (s);
}
/**
* @brief get the iterator from a pointer
*
* @param p The pointer to the element to retrieve
* @return The iterator pointing to that element
*/
layer_type::iterator iterator_from_pointer (const shape_type *p) const
{
return m_layer.iterator_from_pointer (p);
}
/**
* @brief Implementation of the redo method
*/
void redo (db::Op *op);
/**
* @brief Implementation of the undo method
*/
void undo (db::Op *op);
/**
* @brief Collect memory usage
*/
void collect_mem_stat (db::MemStatistics &m) const;
private:
void invalidate_state ()
{
invalidate_bboxes ();
}
virtual void do_update ();
layer_type m_layer;
};
}
#endif