mirror of https://github.com/KLayout/klayout.git
367 lines
8.4 KiB
C
367 lines
8.4 KiB
C
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
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
|
||
|
|
|
||
|
|
|