mirror of https://github.com/KLayout/klayout.git
Merge branch '25d-with-booleans'
This commit is contained in:
commit
cd07a21ae3
|
|
@ -511,19 +511,52 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell,
|
|||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> >::const_iterator f = var_table.find (i->object ().cell_index ());
|
||||
if (f == var_table.end ()) {
|
||||
|
||||
in_cell.insert (*i);
|
||||
in_cell.insert (*i);
|
||||
|
||||
} else {
|
||||
|
||||
const std::map<db::ICplxTrans, db::cell_index_type> &vt = f->second;
|
||||
|
||||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
bool need_explode = false;
|
||||
bool first = true;
|
||||
db::cell_index_type ci = 0;
|
||||
|
||||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end () && ! need_explode; ++ia) {
|
||||
|
||||
db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia)));
|
||||
std::map<db::ICplxTrans, db::cell_index_type>::const_iterator v = vt.find (rt);
|
||||
tl_assert (v != vt.end ());
|
||||
|
||||
in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ()));
|
||||
if (first) {
|
||||
ci = v->second;
|
||||
first = false;
|
||||
} else {
|
||||
need_explode = (ci != v->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (need_explode) {
|
||||
|
||||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
|
||||
db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia)));
|
||||
std::map<db::ICplxTrans, db::cell_index_type>::const_iterator v = vt.find (rt);
|
||||
tl_assert (v != vt.end ());
|
||||
|
||||
in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ()));
|
||||
|
||||
}
|
||||
|
||||
} else if (ci != i->object ().cell_index ()) {
|
||||
|
||||
db::CellInstArray new_array = *i;
|
||||
new_array.object () = db::CellInst (ci);
|
||||
in_cell.insert (db::CellInstArrayWithProperties (new_array, i->properties_id ()));
|
||||
|
||||
} else {
|
||||
|
||||
in_cell.insert (*i);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1063,11 +1063,6 @@ private:
|
|||
void
|
||||
collect_instance_interactions (const db::CellInstArray *inst1, const db::CellInstArray *inst2)
|
||||
{
|
||||
#if 0
|
||||
printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n",
|
||||
mp_subject_layout->cell_name (inst1->object ().cell_index ()), int (inst1->size ()), (inst1->bbox(db::box_convert<db::CellInst> (*mp_subject_layout)).to_string()).c_str(),
|
||||
mp_intruder_layout->cell_name (inst2->object ().cell_index ()), int (inst2->size ()), (inst2->bbox(db::box_convert<db::CellInst> (*mp_intruder_layout)).to_string()).c_str()); // @@@
|
||||
#endif
|
||||
// TODO: this algorithm is not in particular effective for identical arrays
|
||||
|
||||
const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ());
|
||||
|
|
@ -1076,9 +1071,6 @@ printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n",
|
|||
|
||||
std::unordered_map<db::ICplxTrans, std::list<std::pair<db::cell_index_type, db::ICplxTrans> > > interactions_cache;
|
||||
|
||||
#if 0
|
||||
printf("@@@ -> #%d\n", int(inst1->size()));
|
||||
#endif
|
||||
for (db::CellInstArray::iterator n = inst1->begin (); ! n.at_end (); ++n) {
|
||||
|
||||
db::ICplxTrans tn1 = inst1->complex_trans (*n);
|
||||
|
|
@ -1482,9 +1474,6 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
const typename local_processor_cell_contexts<TS, TI, TR>::context_key_type &intruders,
|
||||
db::Coord dist) const
|
||||
{
|
||||
#if 0 // @@@
|
||||
printf("@@@ --- compute_contexts (%s @ %s)\n", mp_subject_layout->cell_name (subject_cell->cell_index ()), subject_cell_inst.to_string().c_str()); fflush(stdout);
|
||||
#endif
|
||||
CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts)
|
||||
|
||||
if (tl::verbosity () >= m_base_verbosity + 20) {
|
||||
|
|
|
|||
|
|
@ -287,6 +287,32 @@ private:
|
|||
db::Coord m_tolerance;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A fuzzy compare operator for edge pairs
|
||||
* Compares two edge pair objects applying a tolerance between them. The tolerance is the allowed deviation
|
||||
* of points in database units.
|
||||
*/
|
||||
struct EdgePairCompareOpWithTolerance
|
||||
{
|
||||
EdgePairCompareOpWithTolerance (db::Coord tolerance)
|
||||
: m_ec (tolerance)
|
||||
{ }
|
||||
|
||||
bool operator() (const db::EdgePair &a, const db::EdgePair &b) const
|
||||
{
|
||||
if (m_ec (a.first (), b.first ())) {
|
||||
return true;
|
||||
} else if (m_ec (b.first (), a.first ())) {
|
||||
return false;
|
||||
} else {
|
||||
return m_ec (a.second (), b.second ());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EdgeCompareOpWithTolerance m_ec;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A fuzzy compare operator for boxes
|
||||
* Compares two box objects applying a tolerance between them. The tolerance is the allowed deviation
|
||||
|
|
@ -492,6 +518,12 @@ make_edge_compare_func (db::Coord tolerance)
|
|||
return pair_compare_func<db::Edge, db::properties_id_type, EdgeCompareOpWithTolerance, std_compare_func<db::properties_id_type> > (EdgeCompareOpWithTolerance (tolerance), std_compare_func<db::properties_id_type> ());
|
||||
}
|
||||
|
||||
pair_compare_func<db::EdgePair, db::properties_id_type, EdgePairCompareOpWithTolerance, std_compare_func<db::properties_id_type> >
|
||||
make_edge_pair_compare_func (db::Coord tolerance)
|
||||
{
|
||||
return pair_compare_func<db::EdgePair, db::properties_id_type, EdgePairCompareOpWithTolerance, std_compare_func<db::properties_id_type> > (EdgePairCompareOpWithTolerance (tolerance), std_compare_func<db::properties_id_type> ());
|
||||
}
|
||||
|
||||
pair_compare_func<db::Box, db::properties_id_type, BoxCompareOpWithTolerance, std_compare_func<db::properties_id_type> >
|
||||
make_box_compare_func (db::Coord tolerance)
|
||||
{
|
||||
|
|
@ -540,6 +572,21 @@ collect_edges (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
collect_edge_pairs (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair<db::EdgePair, db::properties_id_type> > &shapes, PropertyMapper &pn)
|
||||
{
|
||||
shapes.clear ();
|
||||
|
||||
for (db::ShapeIterator s = c->shapes (layer).begin (db::ShapeIterator::EdgePairs); !s.at_end (); ++s) {
|
||||
db::properties_id_type prop_id = 0;
|
||||
if (! (flags & layout_diff::f_no_properties)) {
|
||||
prop_id = pn (s->prop_id ());
|
||||
}
|
||||
shapes.push_back (std::make_pair (db::EdgePair (), prop_id));
|
||||
s->edge_pair (shapes.back ().first);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
collect_boxes (const db::Layout &, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair<db::Box, db::properties_id_type> > &shapes, PropertyMapper &pn)
|
||||
{
|
||||
|
|
@ -828,6 +875,8 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
std::vector <std::pair <db::Box, db::properties_id_type> > boxes_b;
|
||||
std::vector <std::pair <db::Edge, db::properties_id_type> > edges_a;
|
||||
std::vector <std::pair <db::Edge, db::properties_id_type> > edges_b;
|
||||
std::vector <std::pair <db::EdgePair, db::properties_id_type> > edge_pairs_a;
|
||||
std::vector <std::pair <db::EdgePair, db::properties_id_type> > edge_pairs_b;
|
||||
|
||||
for (unsigned int cci = 0; cci < common_cells.size (); ++cci) {
|
||||
|
||||
|
|
@ -1053,6 +1102,31 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
r.end_edge_differences ();
|
||||
}
|
||||
|
||||
// compare edge pairs
|
||||
|
||||
edge_pairs_a.clear();
|
||||
edge_pairs_b.clear();
|
||||
if (is_valid_a) {
|
||||
collect_edge_pairs (a, cell_a, layer_a, flags, edge_pairs_a, prop_normalize_a);
|
||||
}
|
||||
if (is_valid_b) {
|
||||
collect_edge_pairs (b, cell_b, layer_b, flags, edge_pairs_b, prop_normalize_b);
|
||||
}
|
||||
|
||||
reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0);
|
||||
|
||||
if (!edge_pairs_a.empty () || !edge_pairs_b.empty ()) {
|
||||
differs = true;
|
||||
if (flags & layout_diff::f_silent) {
|
||||
return false;
|
||||
}
|
||||
r.begin_edge_pair_differences ();
|
||||
if (verbose) {
|
||||
r.detailed_diff (n.properties_repository (), edge_pairs_a, edge_pairs_b);
|
||||
}
|
||||
r.end_edge_pair_differences ();
|
||||
}
|
||||
|
||||
r.end_layer ();
|
||||
|
||||
}
|
||||
|
|
@ -1130,6 +1204,9 @@ public:
|
|||
void begin_edge_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b);
|
||||
void end_edge_differences ();
|
||||
void begin_edge_pair_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b);
|
||||
void end_edge_pair_differences ();
|
||||
void begin_text_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &b);
|
||||
void end_text_differences ();
|
||||
|
|
@ -1525,6 +1602,34 @@ PrintingDifferenceReceiver::end_edge_differences ()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
PrintingDifferenceReceiver::begin_edge_pair_differences ()
|
||||
{
|
||||
try {
|
||||
enough (tl::error) << "Edge pairs differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b)
|
||||
{
|
||||
try {
|
||||
enough (tl::info) << "Not in b but in a:";
|
||||
print_diffs (pr, a, b);
|
||||
enough (tl::info) << "Not in a but in b:";
|
||||
print_diffs (pr, b, a);
|
||||
} catch (tl::CancelException &) {
|
||||
// ignore cancel exceptions
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PrintingDifferenceReceiver::end_edge_pair_differences ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PrintingDifferenceReceiver::begin_text_differences ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ public:
|
|||
virtual void begin_edge_differences () { }
|
||||
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::Edge, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::Edge, db::properties_id_type> > & /*b*/) { }
|
||||
virtual void end_edge_differences () { }
|
||||
virtual void begin_edge_pair_differences () { }
|
||||
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > & /*b*/) { }
|
||||
virtual void end_edge_pair_differences () { }
|
||||
virtual void begin_text_differences () { }
|
||||
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::Text, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::Text, db::properties_id_type> > & /*b*/) { }
|
||||
virtual void end_text_differences () { }
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbCellVariants.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlTimer.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -436,9 +437,38 @@ ContextCache::find_layout_context (db::cell_index_type from, db::cell_index_type
|
|||
// ------------------------------------------------------------
|
||||
// Scale and snap a layout
|
||||
|
||||
static void
|
||||
scale_and_snap_cell_instance (db::CellInstArray &ci, const db::ICplxTrans &tr, const db::ICplxTrans &trinv, const db::Vector &delta, db::Coord g, db::Coord m, db::Coord d)
|
||||
{
|
||||
db::Trans ti (ci.front ());
|
||||
|
||||
db::Vector ti_disp = ti.disp ();
|
||||
ti_disp.transform (tr);
|
||||
ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, delta.x (), g, m, d, delta.y ());
|
||||
ti_disp.transform (trinv);
|
||||
|
||||
ci.move (ti_disp - ti.disp ());
|
||||
}
|
||||
|
||||
static db::Edge
|
||||
scaled_and_snapped_edge (const db::Edge &e, db::Coord g, db::Coord m, db::Coord d, db::Coord ox, db::Coord oy)
|
||||
{
|
||||
int64_t dg = int64_t (g) * int64_t (d);
|
||||
|
||||
int64_t x1 = snap_to_grid (int64_t (e.p1 ().x ()) * m + int64_t (ox), dg) / int64_t (d);
|
||||
int64_t y1 = snap_to_grid (int64_t (e.p1 ().y ()) * m + int64_t (oy), dg) / int64_t (d);
|
||||
|
||||
int64_t x2 = snap_to_grid (int64_t (e.p2 ().x ()) * m + int64_t (ox), dg) / int64_t (d);
|
||||
int64_t y2 = snap_to_grid (int64_t (e.p2 ().y ()) * m + int64_t (oy), dg) / int64_t (d);
|
||||
|
||||
return db::Edge (db::Point (x1, y1), db::Point (x2, y2));
|
||||
}
|
||||
|
||||
void
|
||||
scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, tl::to_string (tr ("scale_and_snap")));
|
||||
|
||||
if (g < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value")));
|
||||
}
|
||||
|
|
@ -453,8 +483,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
|
|||
|
||||
db::cell_variants_collector<db::ScaleAndGridReducer> vars (db::ScaleAndGridReducer (g, m, d));
|
||||
|
||||
vars.collect (layout, cell);
|
||||
vars.separate_variants (layout, cell);
|
||||
{
|
||||
tl::SelfTimer timer1 (tl::verbosity () >= 41, tl::to_string (tr ("scale_and_snap: variant formation")));
|
||||
vars.collect (layout, cell);
|
||||
vars.separate_variants (layout, cell);
|
||||
}
|
||||
|
||||
std::set<db::cell_index_type> called_cells;
|
||||
cell.collect_called_cells (called_cells);
|
||||
|
|
@ -463,9 +496,10 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
|
|||
db::LayoutLocker layout_locker (&layout);
|
||||
layout.update ();
|
||||
|
||||
std::vector<db::Point> heap;
|
||||
tl::SelfTimer timer2 (tl::verbosity () >= 41, tl::to_string (tr ("scale_and_snap: snapping and scaling")));
|
||||
|
||||
unsigned int work_layer = layout.insert_layer ();
|
||||
std::vector<db::Point> heap;
|
||||
std::vector<db::Vector> iterated_array_vectors;
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
|
|
@ -486,7 +520,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
|
|||
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
||||
|
||||
db::Shapes &s = c->shapes ((*l).first);
|
||||
db::Shapes &out = c->shapes (work_layer);
|
||||
db::Shapes new_shapes;
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) {
|
||||
|
||||
|
|
@ -495,7 +529,20 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
|
|||
poly.transform (tr);
|
||||
poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap);
|
||||
poly.transform (trinv);
|
||||
out.insert (poly);
|
||||
|
||||
if (si->is_box () && poly.is_box ()) {
|
||||
if (si->has_prop_id ()) {
|
||||
new_shapes.insert (db::BoxWithProperties (poly.box (), si->prop_id ()));
|
||||
} else {
|
||||
new_shapes.insert (poly.box ());
|
||||
}
|
||||
} else {
|
||||
if (si->has_prop_id ()) {
|
||||
new_shapes.insert (db::PolygonWithProperties (poly, si->prop_id ()));
|
||||
} else {
|
||||
new_shapes.insert (poly);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -506,48 +553,94 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
|
|||
text.transform (tr);
|
||||
text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ())));
|
||||
text.transform (trinv);
|
||||
out.insert (text);
|
||||
|
||||
if (si->has_prop_id ()) {
|
||||
new_shapes.insert (db::TextWithProperties (text, si->prop_id ()));
|
||||
} else {
|
||||
new_shapes.insert (text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
s.swap (out);
|
||||
out.clear ();
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
|
||||
|
||||
db::Edge edge;
|
||||
si->edge (edge);
|
||||
edge.transform (tr);
|
||||
edge = scaled_and_snapped_edge (edge, g, m , d, tr_disp.x (), tr_disp.y ());
|
||||
edge.transform (trinv);
|
||||
|
||||
if (si->has_prop_id ()) {
|
||||
new_shapes.insert (db::EdgeWithProperties (edge, si->prop_id ()));
|
||||
} else {
|
||||
new_shapes.insert (edge);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) {
|
||||
|
||||
db::EdgePair edge_pair;
|
||||
si->edge_pair (edge_pair);
|
||||
edge_pair.transform (tr);
|
||||
edge_pair = db::EdgePair (scaled_and_snapped_edge (edge_pair.first (), g, m , d, tr_disp.x (), tr_disp.y ()),
|
||||
scaled_and_snapped_edge (edge_pair.second (), g, m , d, tr_disp.x (), tr_disp.y ()));
|
||||
edge_pair.transform (trinv);
|
||||
|
||||
if (si->has_prop_id ()) {
|
||||
new_shapes.insert (db::EdgePairWithProperties (edge_pair, si->prop_id ()));
|
||||
} else {
|
||||
new_shapes.insert (edge_pair);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
s.swap (new_shapes);
|
||||
|
||||
}
|
||||
|
||||
// Snap instance placements to grid and magnify
|
||||
// NOTE: we can modify the instances because the ScaleAndGridReducer marked every cell with children
|
||||
// as a variant cell (an effect of ScaleAndGridReducer::want_variants(cell) == true where cells have children).
|
||||
// Variant cells are not copied blindly back to the original layout.
|
||||
|
||||
std::list<db::CellInstArray> new_insts;
|
||||
// The variant formation also made sure the iterated and regular arrays are exploded where required.
|
||||
|
||||
for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
const db::CellInstArray &ia = inst->cell_inst ();
|
||||
for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) {
|
||||
|
||||
db::Trans ti (*i);
|
||||
db::Vector ti_disp = ti.disp ();
|
||||
ti_disp.transform (tr);
|
||||
ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
|
||||
ti_disp.transform (trinv);
|
||||
ti.disp (ti_disp);
|
||||
iterated_array_vectors.clear ();
|
||||
db::Vector a, b;
|
||||
unsigned long na, nb;
|
||||
|
||||
if (ia.is_complex ()) {
|
||||
new_insts.push_back (db::CellInstArray (ia.object (), ia.complex_trans (ti)));
|
||||
} else {
|
||||
new_insts.push_back (db::CellInstArray (ia.object (), ti));
|
||||
db::CellInstArray new_array (ia);
|
||||
|
||||
if (ia.is_iterated_array (&iterated_array_vectors)) {
|
||||
|
||||
bool needs_update = false;
|
||||
for (std::vector<db::Vector>::iterator i = iterated_array_vectors.begin (); i != iterated_array_vectors.end (); ++i) {
|
||||
db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
|
||||
if (v != *i) {
|
||||
needs_update = true;
|
||||
*i = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_update) {
|
||||
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ());
|
||||
}
|
||||
|
||||
} else if (ia.is_regular_array (a, b, na, nb)) {
|
||||
|
||||
a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
|
||||
b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
|
||||
|
||||
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d);
|
||||
c->replace (*inst, new_array);
|
||||
|
||||
c->clear_insts ();
|
||||
|
||||
for (std::list<db::CellInstArray>::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) {
|
||||
c->insert (*i);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
|
|||
equal = db::compare_layouts (*subject, layout_au,
|
||||
(n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose)
|
||||
| ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0)
|
||||
| db::layout_diff::f_flatten_array_insts
|
||||
| ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts)
|
||||
/*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/
|
||||
, tolerance, 100 /*max diff lines*/);
|
||||
if (equal && n > 0) {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ enum NormalizationMode
|
|||
WriteOAS = 2, // normalize subject by writing to OASIS and reading back
|
||||
NormFileMask = 7, // bits the extract for file mode
|
||||
NoContext = 8, // write tmp file without context
|
||||
AsPolygons = 16 // paths and boxes are treated as polygons
|
||||
AsPolygons = 16, // paths and boxes are treated as polygons
|
||||
WithArrays = 32 // do not flatten arrays
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include "dbCellMapping.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "dbPropertiesRepository.h"
|
||||
#include "tlString.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
|
|
@ -653,3 +655,127 @@ TEST(18_scale_and_snap)
|
|||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns3.gds");
|
||||
}
|
||||
|
||||
TEST(19_scale_and_snap_basic)
|
||||
{
|
||||
db::Layout l1;
|
||||
db::Layout l2;
|
||||
|
||||
db::PropertiesRepository::properties_set ps1;
|
||||
ps1.insert (std::make_pair (l1.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17)));
|
||||
db::properties_id_type pid1 = l1.properties_repository ().properties_id (ps1);
|
||||
|
||||
db::PropertiesRepository::properties_set ps2;
|
||||
ps2.insert (std::make_pair (l2.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17)));
|
||||
db::properties_id_type pid2 = l2.properties_repository ().properties_id (ps2);
|
||||
|
||||
db::Cell &top1 = l1.cell (l1.add_cell ("TOP"));
|
||||
db::Cell &top2 = l2.cell (l2.add_cell ("TOP"));
|
||||
|
||||
db::Cell &a1 = l1.cell (l1.add_cell ("A"));
|
||||
db::Cell &a2a = l2.cell (l2.add_cell ("A"));
|
||||
|
||||
unsigned int layer1 = l1.insert_layer (db::LayerProperties (1, 0));
|
||||
unsigned int layer2 = l2.insert_layer (db::LayerProperties (1, 0));
|
||||
|
||||
a1.shapes (layer1).insert (db::Box (0, 0, 100, 100));
|
||||
a2a.shapes (layer2).insert (db::Box (0, 0, 100, 100));
|
||||
|
||||
top1.shapes (layer1).insert (db::Box (11, 21, 31, 41));
|
||||
top2.shapes (layer2).insert (db::Box (10, 20, 30, 40));
|
||||
|
||||
top1.shapes (layer1).insert (db::BoxWithProperties (db::Box (11, 21, 31, 41), pid1));
|
||||
top2.shapes (layer2).insert (db::BoxWithProperties (db::Box (10, 20, 30, 40), pid2));
|
||||
|
||||
top1.shapes (layer1).insert (db::Edge (11, 21, 31, 41));
|
||||
top2.shapes (layer2).insert (db::Edge (10, 20, 30, 40));
|
||||
|
||||
top1.shapes (layer1).insert (db::EdgeWithProperties (db::Edge (11, 21, 31, 41), pid1));
|
||||
top2.shapes (layer2).insert (db::EdgeWithProperties (db::Edge (10, 20, 30, 40), pid2));
|
||||
|
||||
top1.shapes (layer1).insert (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141)));
|
||||
top2.shapes (layer2).insert (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140)));
|
||||
|
||||
top1.shapes (layer1).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141)), pid1));
|
||||
top2.shapes (layer2).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140)), pid2));
|
||||
|
||||
top1.shapes (layer1).insert (db::Polygon (db::Box (11, 21, 31, 41)));
|
||||
top2.shapes (layer2).insert (db::Polygon (db::Box (10, 20, 30, 40)));
|
||||
|
||||
top1.shapes (layer1).insert (db::PolygonWithProperties (db::Polygon (db::Box (11, 21, 31, 41)), pid1));
|
||||
top2.shapes (layer2).insert (db::PolygonWithProperties (db::Polygon (db::Box (10, 20, 30, 40)), pid2));
|
||||
|
||||
db::Point pts1[] = {
|
||||
db::Point (1, 101),
|
||||
db::Point (101, 101),
|
||||
db::Point (101, 201)
|
||||
};
|
||||
|
||||
db::Point pts2[] = {
|
||||
db::Point (0, 100),
|
||||
db::Point (100, 100),
|
||||
db::Point (100, 200)
|
||||
};
|
||||
|
||||
top1.shapes (layer1).insert (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20));
|
||||
top2.shapes (layer2).insert (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20));
|
||||
|
||||
top1.shapes (layer1).insert (db::PathWithProperties (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20), pid1));
|
||||
top2.shapes (layer2).insert (db::PathWithProperties (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20), pid2));
|
||||
|
||||
top1.shapes (layer1).insert (db::Text ("t1", db::Trans (db::Vector (11, 21))));
|
||||
top2.shapes (layer2).insert (db::Text ("t1", db::Trans (db::Vector (10, 20))));
|
||||
|
||||
top1.shapes (layer1).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (11, 21))), pid1));
|
||||
top2.shapes (layer2).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (10, 20))), pid2));
|
||||
|
||||
top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21))));
|
||||
top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20))));
|
||||
|
||||
top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21))), pid1));
|
||||
top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20))), pid2));
|
||||
|
||||
top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3));
|
||||
top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3));
|
||||
|
||||
top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid1));
|
||||
top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid2));
|
||||
|
||||
std::vector<db::Vector> ia;
|
||||
ia.push_back (db::Vector (0, 0));
|
||||
ia.push_back (db::Vector (10, 0));
|
||||
ia.push_back (db::Vector (0, 10));
|
||||
|
||||
top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ()));
|
||||
top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ()));
|
||||
|
||||
top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ()), pid1));
|
||||
top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ()), pid2));
|
||||
|
||||
db::scale_and_snap (l1, top1, 10, 1, 1);
|
||||
|
||||
bool equal = db::compare_layouts (l1, l2,
|
||||
db::layout_diff::f_verbose
|
||||
| db::layout_diff::f_boxes_as_polygons
|
||||
| db::layout_diff::f_paths_as_polygons
|
||||
, 0, 100 /*max diff lines*/);
|
||||
EXPECT_EQ (equal, true);
|
||||
}
|
||||
|
||||
TEST(20_scale_and_snap)
|
||||
{
|
||||
db::Layout l1;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/scale_and_snap4.oas";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (l1);
|
||||
}
|
||||
|
||||
db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 10, 95, 100);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns4.oas", db::NormalizationMode (db::WriteOAS + db::WithArrays));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,11 @@ module DRC
|
|||
# Register the new interpreters
|
||||
DRCInterpreter::new(drc_recipe)
|
||||
DRCPlainTextInterpreter::new(drc_recipe)
|
||||
|
||||
# Creates a new macro category
|
||||
if RBA::Application::instance
|
||||
RBA::Application::instance.add_macro_category("drc", "DRC", [ "drc" ])
|
||||
end
|
||||
|
||||
end
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@
|
|||
<widget class="QLabel" name="interpreterLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
|
|
@ -224,25 +223,56 @@
|
|||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Priority</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Prolog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="prolog"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="epilog"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Epilog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="priority">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>for autorun: 0 = first, 1 = second ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="prolog">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="epilog"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ static std::string version (C *)
|
|||
return C::version ();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static void add_macro_category (C *c, const std::string &name, const std::string &description, const std::vector<std::string> &folders)
|
||||
{
|
||||
c->add_macro_category (name, description, folders);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static gsi::Methods application_methods ()
|
||||
{
|
||||
|
|
@ -226,6 +232,12 @@ static gsi::Methods application_methods ()
|
|||
"@brief Returns the architecture string\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
method_ext<C, const std::string &, const std::string &, const std::vector<std::string> &> ("add_macro_category", &add_macro_category<C>, gsi::arg ("name"), gsi::arg ("description"), gsi::arg ("folders"),
|
||||
"@brief Creates a new macro category\n"
|
||||
"Creating a new macro category is only possible during the autorun_early stage. "
|
||||
"The new macro category must correspond to an interpreter registered at the same stage.\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method<C *> ("instance", &C::instance,
|
||||
"@brief Return the singleton instance of the application\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -686,6 +686,22 @@ ApplicationBase::init_app ()
|
|||
|
||||
if (mc) {
|
||||
|
||||
// create the basic macro categories
|
||||
|
||||
if (ruby_interpreter ().available ()) {
|
||||
std::vector<std::string> folders;
|
||||
folders.push_back ("macros");
|
||||
folders.push_back ("ruby");
|
||||
mc->add_macro_category ("macros", "Ruby", folders);
|
||||
}
|
||||
|
||||
if (python_interpreter ().available ()) {
|
||||
std::vector<std::string> folders;
|
||||
folders.push_back ("pymacros");
|
||||
folders.push_back ("python");
|
||||
mc->add_macro_category ("pymacros", "Python", folders);
|
||||
}
|
||||
|
||||
mc->enable_implicit_macros (! m_no_macros);
|
||||
|
||||
// Add the global ruby modules as the first ones.
|
||||
|
|
@ -741,13 +757,29 @@ ApplicationBase::init_app ()
|
|||
}
|
||||
}
|
||||
|
||||
std::set<std::string> already_executed;
|
||||
|
||||
// run all early autorun macros
|
||||
lym::MacroCollection::root ().autorun_early ();
|
||||
lym::MacroCollection::root ().autorun_early (&already_executed);
|
||||
|
||||
// autorun_early may have added macro categories, so we need to call finish() again
|
||||
if (mc) {
|
||||
|
||||
mc->finish ();
|
||||
|
||||
// as this regenerates the macro collection, autorun_early is required again
|
||||
// note: this does no re-execute macros that have been executed already
|
||||
lym::MacroCollection::root ().autorun_early (&already_executed);
|
||||
|
||||
}
|
||||
|
||||
// rescan the folders because early autorun macros might have added
|
||||
// suffixes through the MacroInterpreter interface.
|
||||
lym::MacroCollection::root ().rescan ();
|
||||
|
||||
// and yet another autorun_early pass ..
|
||||
lym::MacroCollection::root ().autorun_early (&already_executed);
|
||||
|
||||
// creates the main window or plugin root as required
|
||||
setup ();
|
||||
|
||||
|
|
@ -785,6 +817,15 @@ ApplicationBase::init_app ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ApplicationBase::add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders)
|
||||
{
|
||||
lay::MacroController *mc = lay::MacroController::instance ();
|
||||
if (mc) {
|
||||
mc->add_macro_category (name, description, folders);
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationBase::~ApplicationBase ()
|
||||
{
|
||||
tl::set_ui_exception_handlers (0, 0, 0);
|
||||
|
|
|
|||
|
|
@ -214,6 +214,13 @@ public:
|
|||
return *mp_python_interpreter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a new macro category
|
||||
*
|
||||
* This method is only effective when called during the autorun_early stage
|
||||
*/
|
||||
void add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders);
|
||||
|
||||
/**
|
||||
* @brief Return true, if undo buffering is enabled
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -49,62 +49,27 @@ MacroController::MacroController ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
static lay::MacroController::MacroCategory ruby_cat ()
|
||||
void
|
||||
MacroController::add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders)
|
||||
{
|
||||
lay::MacroController::MacroCategory cat;
|
||||
cat.name = "macros";
|
||||
cat.description = tl::to_string (QObject::tr ("Ruby"));
|
||||
cat.folders.push_back ("macros");
|
||||
cat.folders.push_back ("ruby");
|
||||
return cat;
|
||||
}
|
||||
|
||||
static lay::MacroController::MacroCategory python_cat ()
|
||||
{
|
||||
lay::MacroController::MacroCategory cat;
|
||||
cat.name = "pymacros";
|
||||
cat.description = tl::to_string (QObject::tr ("Python"));
|
||||
cat.folders.push_back ("pymacros");
|
||||
cat.folders.push_back ("python");
|
||||
return cat;
|
||||
}
|
||||
|
||||
static lay::MacroController::MacroCategory drc_cat ()
|
||||
{
|
||||
lay::MacroController::MacroCategory cat;
|
||||
cat.name = "drc";
|
||||
cat.description = tl::to_string (QObject::tr ("DRC"));
|
||||
cat.folders.push_back ("drc");
|
||||
return cat;
|
||||
}
|
||||
|
||||
static lay::MacroController::MacroCategory lvs_cat ()
|
||||
{
|
||||
lay::MacroController::MacroCategory cat;
|
||||
cat.name = "lvs";
|
||||
cat.description = tl::to_string (QObject::tr ("LVS"));
|
||||
cat.folders.push_back ("lvs");
|
||||
return cat;
|
||||
cat.name = name;
|
||||
cat.description = description;
|
||||
cat.folders = folders;
|
||||
m_macro_categories.push_back (cat);
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::finish ()
|
||||
{
|
||||
lym::MacroCollection::root ().clear ();
|
||||
|
||||
// Scan built-in macros
|
||||
// These macros are always taken, even if there are no macros requested (they are required to
|
||||
// fully form the API).
|
||||
lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-macros", "macros", true);
|
||||
lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-pymacros", "pymacros", true);
|
||||
|
||||
// TODO: consider adding "drc" and "lvs" dynamically and allow more dynamic categories
|
||||
// We can do so if we first load the macros with the initial interpreters, then do autorun (which creates DSL interpreters) and then
|
||||
// register the remaining categories.
|
||||
|
||||
m_macro_categories.push_back (ruby_cat ());
|
||||
m_macro_categories.push_back (python_cat ());
|
||||
m_macro_categories.push_back (drc_cat ());
|
||||
m_macro_categories.push_back (lvs_cat ());
|
||||
|
||||
// scans the macros from techs and packages (this will allow autorun-early on them)
|
||||
// and updates m_external_paths
|
||||
sync_macro_sources ();
|
||||
|
|
|
|||
|
|
@ -147,10 +147,16 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Loads the macros from the predefined paths and establishes the search paths
|
||||
* This method will also establish the macro categories.
|
||||
* This method can be called multiple times.
|
||||
*/
|
||||
void finish ();
|
||||
|
||||
/**
|
||||
* @brief Adds a new macro category
|
||||
* finish() needs to be called after adding a new category.
|
||||
*/
|
||||
void add_macro_category (const std::string &name, const std::string &description, const std::vector<std::string> &folders);
|
||||
|
||||
/**
|
||||
* @brief Adds a temporary macro
|
||||
*
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ MacroPropertiesDialog::update (const lym::Macro *macro)
|
|||
propertiesFrame->setEnabled (! macro->is_readonly ());
|
||||
description->setText (tl::to_qstring (macro->description ()));
|
||||
version->setText (tl::to_qstring (macro->version ()));
|
||||
priority->setText (tl::to_qstring (tl::to_string (macro->priority ())));
|
||||
prolog->setText (tl::to_qstring (macro->prolog ()));
|
||||
epilog->setText (tl::to_qstring (macro->epilog ()));
|
||||
autorun->setChecked (macro->is_autorun ());
|
||||
|
|
@ -98,6 +99,10 @@ MacroPropertiesDialog::commit (lym::Macro *macro)
|
|||
macro->set_show_in_menu (showmenu->isChecked ());
|
||||
macro->set_group_name (tl::to_string (groupName->text ()));
|
||||
macro->set_menu_path (tl::to_string (menuPath->text ()));
|
||||
|
||||
int p = 0;
|
||||
tl::from_string (tl::to_string (priority->text ()), p);
|
||||
macro->set_priority (p);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,6 +159,11 @@ module LVS
|
|||
LVSInterpreter::new(lvs_recipe)
|
||||
LVSPlainTextInterpreter::new(lvs_recipe)
|
||||
|
||||
# Creates a new macro category
|
||||
if RBA::Application::instance
|
||||
RBA::Application::instance.add_macro_category("lvs", "LVS", [ "lvs" ])
|
||||
end
|
||||
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace lym
|
||||
{
|
||||
|
|
@ -53,7 +55,7 @@ namespace lym
|
|||
// ----------------------------------------------------------------------
|
||||
|
||||
Macro::Macro ()
|
||||
: m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_show_in_menu (false), m_is_file (false), mp_parent (0), m_interpreter (None), m_format (Macro::NoFormat)
|
||||
: m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_priority (0), m_show_in_menu (false), m_is_file (false), mp_parent (0), m_interpreter (None), m_format (Macro::NoFormat)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -87,6 +89,7 @@ void Macro::assign (const lym::Macro &other)
|
|||
m_autorun = other.m_autorun;
|
||||
m_autorun_default = other.m_autorun_default;
|
||||
m_autorun_early = other.m_autorun_early;
|
||||
m_priority = other.m_priority;
|
||||
m_show_in_menu = other.m_show_in_menu;
|
||||
m_shortcut = other.m_shortcut;
|
||||
m_format = other.m_format;
|
||||
|
|
@ -111,6 +114,7 @@ bool Macro::operator== (const Macro &other) const
|
|||
m_text == other.m_text &&
|
||||
m_autorun == other.m_autorun &&
|
||||
m_autorun_early == other.m_autorun_early &&
|
||||
m_priority == other.m_priority &&
|
||||
m_show_in_menu == other.m_show_in_menu &&
|
||||
m_shortcut == other.m_shortcut &&
|
||||
m_interpreter == other.m_interpreter &&
|
||||
|
|
@ -182,6 +186,7 @@ static tl::XMLStruct<lym::Macro> xml_struct ("klayout-macro",
|
|||
tl::make_member (&Macro::doc, &Macro::set_doc, "doc") +
|
||||
tl::make_member (&Macro::is_autorun, &Macro::set_autorun, "autorun") +
|
||||
tl::make_member (&Macro::is_autorun_early, &Macro::set_autorun_early, "autorun-early") +
|
||||
tl::make_member (&Macro::priority, &Macro::set_priority, "priority") +
|
||||
tl::make_member (&Macro::shortcut, &Macro::set_shortcut, "shortcut") +
|
||||
tl::make_member (&Macro::show_in_menu, &Macro::set_show_in_menu, "show-in-menu") +
|
||||
tl::make_member (&Macro::group_name, &Macro::set_group_name, "group-name") +
|
||||
|
|
@ -550,19 +555,22 @@ struct PropertyField
|
|||
void (lym::Macro::*string_setter) (const std::string &);
|
||||
bool (lym::Macro::*bool_getter) () const;
|
||||
void (lym::Macro::*bool_setter) (bool);
|
||||
int (lym::Macro::*int_getter) () const;
|
||||
void (lym::Macro::*int_setter) (int);
|
||||
};
|
||||
|
||||
static PropertyField property_fields[] = {
|
||||
{ "description", &lym::Macro::description, &lym::Macro::set_description, 0, 0 },
|
||||
{ "prolog", &lym::Macro::prolog, &lym::Macro::set_prolog, 0, 0 },
|
||||
{ "epilog", &lym::Macro::epilog, &lym::Macro::set_epilog, 0, 0 },
|
||||
{ "version", &lym::Macro::version, &lym::Macro::set_version, 0, 0 },
|
||||
{ "autorun", 0, 0, &lym::Macro::is_autorun, &lym::Macro::set_autorun },
|
||||
{ "autorun-early", 0, 0, &lym::Macro::is_autorun_early, &lym::Macro::set_autorun_early},
|
||||
{ "show-in-menu", 0, 0, &lym::Macro::show_in_menu, &lym::Macro::set_show_in_menu },
|
||||
{ "group-name", &lym::Macro::group_name, &lym::Macro::set_group_name, 0, 0 },
|
||||
{ "menu-path", &lym::Macro::menu_path, &lym::Macro::set_menu_path, 0, 0 },
|
||||
{ "shortcut", &lym::Macro::shortcut, &lym::Macro::set_shortcut, 0, 0 }
|
||||
{ "description", &lym::Macro::description, &lym::Macro::set_description, 0, 0, 0, 0 },
|
||||
{ "prolog", &lym::Macro::prolog, &lym::Macro::set_prolog, 0, 0, 0, 0 },
|
||||
{ "epilog", &lym::Macro::epilog, &lym::Macro::set_epilog, 0, 0, 0, 0 },
|
||||
{ "version", &lym::Macro::version, &lym::Macro::set_version, 0, 0, 0, 0 },
|
||||
{ "autorun", 0, 0, &lym::Macro::is_autorun, &lym::Macro::set_autorun, 0, 0 },
|
||||
{ "autorun-early", 0, 0, &lym::Macro::is_autorun_early, &lym::Macro::set_autorun_early, 0, 0 },
|
||||
{ "show-in-menu", 0, 0, &lym::Macro::show_in_menu, &lym::Macro::set_show_in_menu, 0, 0 },
|
||||
{ "group-name", &lym::Macro::group_name, &lym::Macro::set_group_name, 0, 0, 0, 0 },
|
||||
{ "menu-path", &lym::Macro::menu_path, &lym::Macro::set_menu_path, 0, 0, 0, 0 },
|
||||
{ "shortcut", &lym::Macro::shortcut, &lym::Macro::set_shortcut, 0, 0, 0, 0 },
|
||||
{ "priority", 0, 0, 0, 0, &lym::Macro::priority, &lym::Macro::set_priority }
|
||||
};
|
||||
|
||||
static std::string escape_pta_string (const char *cp)
|
||||
|
|
@ -623,6 +631,11 @@ void Macro::sync_text_with_properties ()
|
|||
if (v) {
|
||||
new_lines.push_back (std::string ("# $") + pf->name);
|
||||
}
|
||||
} else if (pf->int_getter) {
|
||||
int v = (this->*(pf->int_getter)) ();
|
||||
if (v) {
|
||||
new_lines.push_back (std::string ("# $") + pf->name + ": " + tl::to_string (v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -670,6 +683,8 @@ void Macro::sync_properties_with_text ()
|
|||
(this->*(pf->string_setter)) (std::string ());
|
||||
} else if (pf->bool_setter) {
|
||||
(this->*(pf->bool_setter)) (false);
|
||||
} else if (pf->int_setter) {
|
||||
(this->*(pf->int_setter)) (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -694,6 +709,10 @@ void Macro::sync_properties_with_text ()
|
|||
(this->*(pf->string_setter)) (unescape_pta_string (pex.skip ()));
|
||||
} else if (pf->bool_setter) {
|
||||
(this->*(pf->bool_setter)) (true);
|
||||
} else if (pf->int_setter) {
|
||||
int v = 0;
|
||||
tl::from_string (pex.skip (), v);
|
||||
(this->*(pf->int_setter)) (v);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -765,6 +784,15 @@ void Macro::set_autorun (bool f)
|
|||
}
|
||||
}
|
||||
|
||||
void Macro::set_priority (int p)
|
||||
{
|
||||
if (p != m_priority) {
|
||||
m_modified = true;
|
||||
m_priority = p;
|
||||
on_changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void Macro::set_show_in_menu (bool f)
|
||||
{
|
||||
if (f != m_show_in_menu) {
|
||||
|
|
@ -1065,6 +1093,11 @@ MacroCollection::MacroCollection ()
|
|||
}
|
||||
|
||||
MacroCollection::~MacroCollection ()
|
||||
{
|
||||
do_clear ();
|
||||
}
|
||||
|
||||
void MacroCollection::do_clear ()
|
||||
{
|
||||
for (iterator m = begin (); m != end (); ++m) {
|
||||
delete m->second;
|
||||
|
|
@ -1513,6 +1546,13 @@ void MacroCollection::scan (const std::string &path)
|
|||
}
|
||||
}
|
||||
|
||||
void MacroCollection::clear ()
|
||||
{
|
||||
begin_changes ();
|
||||
do_clear ();
|
||||
on_changed ();
|
||||
}
|
||||
|
||||
void MacroCollection::erase (lym::Macro *mp)
|
||||
{
|
||||
for (iterator m = m_macros.begin (); m != m_macros.end (); ++m) {
|
||||
|
|
@ -1861,30 +1901,78 @@ bool MacroCollection::has_autorun_early () const
|
|||
return has_autorun_for (*this, true);
|
||||
}
|
||||
|
||||
static void autorun_for (lym::MacroCollection &collection, bool early)
|
||||
static int collect_priority (lym::MacroCollection &collection, bool early, int from_prio)
|
||||
{
|
||||
int p = -1;
|
||||
|
||||
for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
|
||||
autorun_for (*c->second, early);
|
||||
int pp = collect_priority (*c->second, early, from_prio);
|
||||
if (pp >= from_prio && (p < 0 || pp < p)) {
|
||||
p = pp;
|
||||
}
|
||||
}
|
||||
|
||||
for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
|
||||
if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
|
||||
BEGIN_PROTECTED_SILENT
|
||||
c->second->run ();
|
||||
c->second->install_doc ();
|
||||
END_PROTECTED_SILENT
|
||||
int pp = c->second->priority ();
|
||||
if (pp >= from_prio && (p < 0 || pp < p)) {
|
||||
p = pp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void autorun_for_prio (lym::MacroCollection &collection, bool early, std::set<std::string> *executed_already, int prio)
|
||||
{
|
||||
for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
|
||||
autorun_for_prio (*c->second, early, executed_already, prio);
|
||||
}
|
||||
|
||||
for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
|
||||
|
||||
if (c->second->priority () == prio && c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
|
||||
|
||||
if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) {
|
||||
|
||||
BEGIN_PROTECTED_SILENT
|
||||
c->second->run ();
|
||||
c->second->install_doc ();
|
||||
END_PROTECTED_SILENT
|
||||
|
||||
if (executed_already) {
|
||||
executed_already->insert (c->second->path ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void MacroCollection::autorun ()
|
||||
static void autorun_for (lym::MacroCollection &collection, bool early, std::set<std::string> *executed_already)
|
||||
{
|
||||
autorun_for (*this, false);
|
||||
int prio = 0;
|
||||
while (true) {
|
||||
int p = collect_priority (collection, early, prio);
|
||||
if (p < prio) {
|
||||
break;
|
||||
}
|
||||
autorun_for_prio (collection, early, executed_already, p);
|
||||
prio = p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroCollection::autorun_early ()
|
||||
void MacroCollection::autorun (std::set<std::string> *already_executed)
|
||||
{
|
||||
autorun_for (*this, true);
|
||||
autorun_for (*this, false, already_executed);
|
||||
}
|
||||
|
||||
void MacroCollection::autorun_early (std::set<std::string> *already_executed)
|
||||
{
|
||||
autorun_for (*this, true, already_executed);
|
||||
}
|
||||
|
||||
void MacroCollection::dump (int l)
|
||||
|
|
|
|||
|
|
@ -430,6 +430,20 @@ public:
|
|||
*/
|
||||
void set_autorun_early (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets the priority of the macro in autorun and autorun-early mode
|
||||
* 0 is the first priority, -1 means "never execute".
|
||||
*/
|
||||
int priority () const
|
||||
{
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the priority
|
||||
*/
|
||||
void set_priority (int p);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the macro shall be shown in the menu
|
||||
*/
|
||||
|
|
@ -596,6 +610,7 @@ private:
|
|||
bool m_autorun;
|
||||
bool m_autorun_default;
|
||||
bool m_autorun_early;
|
||||
int m_priority;
|
||||
bool m_show_in_menu;
|
||||
std::string m_group_name;
|
||||
std::string m_menu_path;
|
||||
|
|
@ -845,6 +860,12 @@ public:
|
|||
*/
|
||||
void add_unspecific (lym::Macro *m);
|
||||
|
||||
/**
|
||||
* @brief Empties the collection
|
||||
* Note: only the unspecific on_changed event is generated.
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Erases the given macro from the list
|
||||
*
|
||||
|
|
@ -995,7 +1016,7 @@ public:
|
|||
/**
|
||||
* @brief Runs all macros marked with auto-run
|
||||
*/
|
||||
void autorun ();
|
||||
void autorun (std::set<std::string> *already_executed = 0);
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the collection has an early autorun macro
|
||||
|
|
@ -1005,7 +1026,7 @@ public:
|
|||
/**
|
||||
* @brief Runs all macros marked with early auto-run
|
||||
*/
|
||||
void autorun_early ();
|
||||
void autorun_early (std::set<std::string> *already_executed = 0);
|
||||
|
||||
/**
|
||||
* @brief Redo the scan (will add new files or folders)
|
||||
|
|
@ -1129,6 +1150,8 @@ private:
|
|||
m_readonly = f;
|
||||
}
|
||||
|
||||
void do_clear ();
|
||||
|
||||
// no copying
|
||||
MacroCollection (const MacroCollection &d);
|
||||
MacroCollection &operator= (const MacroCollection &d);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
# $autorun-early
|
||||
# $priority: 1
|
||||
|
||||
require 'pathname'
|
||||
|
||||
module D25
|
||||
|
||||
class D25ZInfo
|
||||
|
||||
attr_accessor :layer, :zstart, :zstop, :display
|
||||
|
||||
def initialize(_layer, _zstart, _zstop, _display)
|
||||
self.layer = _layer
|
||||
self.zstart = _zstart
|
||||
self.zstop = _zstop
|
||||
self.display = _display
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class D25Display
|
||||
|
||||
attr_accessor :fill, :frame, :like
|
||||
|
||||
def initialize
|
||||
self.fill = nil
|
||||
self.frame = nil
|
||||
self.like = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# The D25 engine
|
||||
|
||||
class D25Engine < DRC::DRCEngine
|
||||
|
||||
def initialize
|
||||
|
||||
super
|
||||
|
||||
@current_z = 0.0
|
||||
@zstack = []
|
||||
|
||||
# clip to layout view
|
||||
if RBA::LayoutView::current
|
||||
self.clip(RBA::LayoutView::current.box)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def z(*args)
|
||||
|
||||
self._context("z") do
|
||||
|
||||
layer = nil
|
||||
zstart = nil
|
||||
zstop = nil
|
||||
height = nil
|
||||
|
||||
args.each do |a|
|
||||
|
||||
if a.is_a?(Range)
|
||||
|
||||
zstart = a.min
|
||||
zstop = a.max
|
||||
|
||||
elsif a.is_a?(DRC::DRCLayer)
|
||||
|
||||
if layer
|
||||
raise("Duplicate layer argument")
|
||||
end
|
||||
layer = a
|
||||
|
||||
elsif a.is_a?(1.class) || a.is_a?(1.0.class)
|
||||
|
||||
if height
|
||||
raise("Duplicate height specification")
|
||||
end
|
||||
height = a
|
||||
|
||||
elsif a.is_a?(Hash)
|
||||
|
||||
if a[:height]
|
||||
if height
|
||||
raise("Duplicate height specification")
|
||||
end
|
||||
height = a[:height]
|
||||
end
|
||||
if a[:zstart]
|
||||
if zstart
|
||||
raise("Duplicate zstart specification")
|
||||
end
|
||||
zstart = a[:zstart]
|
||||
end
|
||||
if a[:zstop]
|
||||
if zstop
|
||||
raise("Duplicate zstop specification")
|
||||
end
|
||||
zstop = a[:zstop]
|
||||
end
|
||||
invalid_keys = a.keys.select { |k| ![ :height, :zstart, :zstop ].member?(k) }
|
||||
if invalid_keys.size > 0
|
||||
raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}")
|
||||
end
|
||||
|
||||
else
|
||||
raise("Argument not understood: #{a.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ! zstart
|
||||
zstart = @current_z
|
||||
end
|
||||
if ! zstop && ! height
|
||||
raise("Either height or zstop must be specified")
|
||||
elsif zstop && height
|
||||
raise("Either height or zstop must be specified, not both")
|
||||
end
|
||||
if height
|
||||
zstop = zstart + height
|
||||
end
|
||||
@current_z = zstop
|
||||
|
||||
if ! layer
|
||||
raise("No layer specified")
|
||||
end
|
||||
|
||||
info = D25ZInfo::new(layer.data, zstart, zstop, @display || D25Display::new)
|
||||
@zstack << info
|
||||
|
||||
return info
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def display(*args, &block)
|
||||
|
||||
display = D25Display::new
|
||||
|
||||
args.each do |a|
|
||||
|
||||
if a.is_a?(D25ZInfo)
|
||||
|
||||
@zstack.each do |z|
|
||||
if z == a
|
||||
z.display = display
|
||||
end
|
||||
end
|
||||
|
||||
elsif a.is_a?(Hash)
|
||||
|
||||
hollow_fill = 0xffffffff
|
||||
|
||||
if a[:color]
|
||||
if !a[:color].is_a?(0xffffff.class)
|
||||
raise("'color' must be a color value (an integer)")
|
||||
end
|
||||
display.fill = a[:color]
|
||||
display.frame = a[:color]
|
||||
end
|
||||
if a[:frame]
|
||||
if !a[:frame].is_a?(0xffffff.class)
|
||||
raise("'frame' must be a color value (an integer)")
|
||||
end
|
||||
display.frame = a[:frame]
|
||||
end
|
||||
if a[:fill]
|
||||
if !a[:fill].is_a?(0xffffff.class)
|
||||
raise("'fill' must be a color value (an integer)")
|
||||
end
|
||||
display.fill = a[:fill]
|
||||
end
|
||||
if a[:hollow]
|
||||
if a[:hollow]
|
||||
display.fill = hollow_fill
|
||||
end
|
||||
end
|
||||
|
||||
if a[:like]
|
||||
li = nil
|
||||
if a[:like].is_a?(String)
|
||||
li = RBA::LayerInfo::from_string(a[:like])
|
||||
elsif a[:like].is_a?(RBA::LayerInfo)
|
||||
li = a[:like]
|
||||
else
|
||||
raise("'like' must be a string or LayerInfo object")
|
||||
end
|
||||
display.like = li
|
||||
end
|
||||
|
||||
invalid_keys = a.keys.select { |k| ![ :fill, :frame, :color, :hollow, :like ].member?(k) }
|
||||
if invalid_keys.size > 0
|
||||
raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}")
|
||||
end
|
||||
|
||||
else
|
||||
raise("Argument not understood: #{a.inspect}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def _finish(final = true)
|
||||
|
||||
if final && @zstack.empty?
|
||||
raise("No z calls made in 2.5d script")
|
||||
end
|
||||
|
||||
super(final)
|
||||
|
||||
if final
|
||||
|
||||
view = RBA::LayoutView::current.open_d25_view
|
||||
|
||||
begin
|
||||
|
||||
displays = {}
|
||||
|
||||
@zstack.each do |z|
|
||||
(displays[z.display.object_id] ||= []) << z
|
||||
end
|
||||
|
||||
displays.each do |k,zz|
|
||||
display = zz[0].display
|
||||
view.open_display(display.frame, display.fill, display.like)
|
||||
zz.each do |z|
|
||||
view.entry(z.layer, z.start, z.zstop)
|
||||
end
|
||||
view.close_display
|
||||
end
|
||||
|
||||
view.finish
|
||||
|
||||
rescue => ex
|
||||
view.close
|
||||
raise ex
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
module D25
|
||||
|
||||
# Installs the home menu entries (needs to be done on autorun, not autorun-early)
|
||||
|
||||
if RBA::Application::instance && RBA::Application::instance.main_window
|
||||
|
||||
cat = "d25"
|
||||
name = "2.5d"
|
||||
|
||||
mw = RBA::Application::instance.main_window
|
||||
mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View")
|
||||
|
||||
@new_action = RBA::Action::new
|
||||
@new_action.title = "New #{name} Script"
|
||||
@new_action.on_triggered do
|
||||
mw.show_macro_editor(cat, true)
|
||||
end
|
||||
|
||||
mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", @new_action)
|
||||
|
||||
@edit_action = RBA::Action::new
|
||||
@edit_action.title = "Edit #{name} Script"
|
||||
@edit_action.on_triggered do
|
||||
mw.show_macro_editor(cat, false)
|
||||
end
|
||||
|
||||
mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", @edit_action)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>true</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
module D25
|
||||
|
||||
class D25Executable < RBA::Executable
|
||||
|
||||
def initialize(macro, generator, rdb_index = nil)
|
||||
|
||||
@d25 = D25Engine::new
|
||||
@d25._rdb_index = rdb_index
|
||||
@d25._generator = generator
|
||||
|
||||
@macro = macro
|
||||
|
||||
end
|
||||
|
||||
def execute
|
||||
|
||||
@d25._start("D25: " + @macro.path)
|
||||
|
||||
# Set a debugger scope so that our errors end up with the debugger set to the D25's line
|
||||
RBA::MacroExecutionContext::set_debugger_scope(@macro.path)
|
||||
|
||||
begin
|
||||
|
||||
# No verbosity set in d25 engine - we cannot use the engine's logger
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||
@d25.instance_eval(@macro.text, @macro.path)
|
||||
|
||||
rescue => ex
|
||||
|
||||
@d25.error("In #{@macro.path}: #{ex.to_s}")
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise ex
|
||||
|
||||
end
|
||||
|
||||
nil
|
||||
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
# cleans up and creates layout and report views
|
||||
@d25._finish
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A DSL implementation for a D25 language (XML format)
|
||||
class D25Interpreter < RBA::MacroInterpreter
|
||||
|
||||
# Constructor
|
||||
def initialize(recipe)
|
||||
|
||||
@recipe = recipe
|
||||
|
||||
# Make the DSL use ruby syntax highlighting
|
||||
self.syntax_scheme = "ruby"
|
||||
self.suffix = "lyd25"
|
||||
self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger
|
||||
self.storage_scheme = RBA::MacroInterpreter::MacroFormat
|
||||
self.description = "D25"
|
||||
|
||||
# Registers the new interpreter
|
||||
register("d25-dsl-xml")
|
||||
|
||||
# create a template for the macro editor:
|
||||
create_template(":/d25-templates/d25.lym")
|
||||
|
||||
# if available, create a menu branch
|
||||
if RBA::Application::instance && RBA::Application::instance.main_window
|
||||
mw = RBA::Application::instance.main_window
|
||||
mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Implements the execute method
|
||||
def executable(macro)
|
||||
D25Executable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A DSL implementation for a D25 language (Plain text format)
|
||||
class D25PlainTextInterpreter < RBA::MacroInterpreter
|
||||
|
||||
# Constructor
|
||||
def initialize(recipe)
|
||||
|
||||
@recipe = recipe
|
||||
|
||||
# Make the DSL use ruby syntax highlighting
|
||||
self.syntax_scheme = "ruby"
|
||||
self.suffix = "d25"
|
||||
self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger
|
||||
self.storage_scheme = RBA::MacroInterpreter::PlainTextWithHashAnnotationsFormat
|
||||
self.description = "D25 (Text)"
|
||||
|
||||
# Registers the new interpreter
|
||||
register("d25-dsl")
|
||||
|
||||
end
|
||||
|
||||
# Implements the execute method
|
||||
def executable(macro)
|
||||
D25Executable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A recipe implementation allowing the D25 run to be redone
|
||||
class D25Recipe < RBA::Recipe
|
||||
|
||||
def initialize
|
||||
super("d25", "D25 recipe")
|
||||
end
|
||||
|
||||
def executable(params)
|
||||
|
||||
script = params["script"]
|
||||
if ! script
|
||||
return
|
||||
end
|
||||
|
||||
macro = RBA::Macro::macro_by_path(script)
|
||||
macro || raise("Can't find D25 script #{script} - unable to re-run")
|
||||
|
||||
D25Executable::new(macro, self.generator("script" => script), params["rdb_index"])
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Register the recipe
|
||||
d25_recipe = D25Recipe::new
|
||||
|
||||
# Register the new interpreters
|
||||
D25Interpreter::new(d25_recipe)
|
||||
D25PlainTextInterpreter::new(d25_recipe)
|
||||
|
||||
# Creates a new macro category
|
||||
if RBA::Application::instance
|
||||
RBA::Application::instance.add_macro_category("d25", "2.5d View", [ "d25" ])
|
||||
end
|
||||
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<RCC>
|
||||
<qresource prefix="/built-in-macros">
|
||||
<file alias="_d25_engine.rb">built-in-macros/_d25_engine.rb</file>
|
||||
<file alias="d25_interpreters.lym">built-in-macros/d25_interpreters.lym</file>
|
||||
<file alias="d25_install.lym">built-in-macros/d25_install.lym</file>
|
||||
</qresource>
|
||||
<qresource prefix="/d25-templates">
|
||||
<file alias="d25.lym">templates/d25.lym</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
@ -26,6 +26,9 @@ SOURCES = \
|
|||
FORMS = \
|
||||
D25View.ui \
|
||||
|
||||
RESOURCES = \
|
||||
layD25Resources.qrc \
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 5) {
|
||||
QT += openglwidgets
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>General;;2.5d view generator script (*.lyd25)\nA script generating a 2.5d view</description>
|
||||
<version/>
|
||||
<category>d25</category>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>true</show-in-menu>
|
||||
<group-name>d25_scripts</group-name>
|
||||
<menu-path>tools_menu.d25.end</menu-path>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
# Read about 2.5d generator scripts in the User Manual in "Various Topics/The 2.5d View"
|
||||
|
||||
# The script utilizes the DRC language with these two extensions
|
||||
#
|
||||
# z(layer, options ...):
|
||||
#
|
||||
# This function generates a extruded view from the given layer.
|
||||
# The "options" describe the z extension. Valid forms are:
|
||||
#
|
||||
# z(layer, 0.1 .. 0.2) extrude layer to z = 0.1 to 0.2 um
|
||||
# z(layer, zstart: 0.1, zstop: 0.2) same as above
|
||||
# z(layer, zstart: 0.1, height: 0.1) same as above, but with height instead of zstop
|
||||
# z(layer, height: 200.nm) extrude layer from last z position with a height of 200nm
|
||||
#
|
||||
# If layer is an original layer, the display options (colors, hollow) are taken
|
||||
# from the original layer's display style. Otherwise KLayout decides about the
|
||||
# initial display options. Use "display(...)" to control the display options.
|
||||
#
|
||||
# display(options) { block }
|
||||
# display(z(...), z(...), ..., options):
|
||||
#
|
||||
# Specify the display options to use for the layers generated inside the block
|
||||
# (which must contains at least one "z" call) or the given z calls:
|
||||
#
|
||||
# Options are:
|
||||
#
|
||||
# display(..., color: 0xff0000) use bright red for the material color (RGB)
|
||||
# display(..., frame: 0xff0000) use bright red for the frame color (combine with "color" for the fill)
|
||||
# display(..., hollow: true) use hollow style (only frame is drawn)
|
||||
# display(..., like: "7/0") borrow style from layout view's style for layer "7/0"
|
||||
#
|
||||
|
||||
z(input(1, 0), 0.1 .. 0.2)
|
||||
|
||||
display(like: 7/0) do
|
||||
z(input(7, 0), height: 100.nm)
|
||||
z(input(8, 0), height: 150.nm)
|
||||
end
|
||||
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue