mirror of https://github.com/KLayout/klayout.git
commit
d5a67080c0
|
|
@ -2198,15 +2198,29 @@ Service::paste ()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<const db::DUserObject *> new_objects;
|
||||
|
||||
for (db::Clipboard::iterator c = db::Clipboard::instance ().begin (); c != db::Clipboard::instance ().end (); ++c) {
|
||||
const db::ClipboardValue<ant::Object> *value = dynamic_cast<const db::ClipboardValue<ant::Object> *> (*c);
|
||||
if (value) {
|
||||
ant::Object *ruler = new ant::Object (value->get ());
|
||||
ruler->id (++idmax);
|
||||
mp_view->annotation_shapes ().insert (db::DUserObject (ruler));
|
||||
new_objects.push_back (&mp_view->annotation_shapes ().insert (db::DUserObject (ruler)));
|
||||
}
|
||||
}
|
||||
|
||||
// make new objects selected
|
||||
|
||||
if (! new_objects.empty ()) {
|
||||
|
||||
for (auto r = new_objects.begin (); r != new_objects.end (); ++r) {
|
||||
m_selected.insert (std::make_pair (mp_view->annotation_shapes ().iterator_from_pointer (*r), 0));
|
||||
}
|
||||
|
||||
selection_to_view ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -644,6 +644,11 @@ void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter)
|
|||
m_pin_refs [pin_id] = iter;
|
||||
}
|
||||
|
||||
bool Circuit::is_empty () const
|
||||
{
|
||||
return m_nets.empty () && m_pins.empty () && m_devices.empty () && m_subcircuits.empty ();
|
||||
}
|
||||
|
||||
void Circuit::blank ()
|
||||
{
|
||||
tl_assert (netlist () != 0);
|
||||
|
|
|
|||
|
|
@ -759,6 +759,11 @@ public:
|
|||
*/
|
||||
void blank ();
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the circuit is empty
|
||||
*/
|
||||
bool is_empty () const;
|
||||
|
||||
/**
|
||||
* @brief Generate memory statistics
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -98,13 +98,13 @@ bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair) const
|
|||
// EdgePairFilterByArea implementation
|
||||
|
||||
InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double a, bool inverted)
|
||||
: m_inverted (inverted), m_checker (a, true, a, true)
|
||||
: m_checker (a, true, a, true, inverted, false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted)
|
||||
: m_inverted (inverted), m_checker (amin, include_amin, amax, include_amax)
|
||||
: m_checker (amin, include_amin, amax, include_amax, inverted, false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -122,7 +122,7 @@ InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair) const
|
|||
std::swap (d1, d2);
|
||||
}
|
||||
|
||||
return m_checker (d1, d2) != m_inverted;
|
||||
return m_checker (d1, d2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,8 +215,13 @@ EdgeSegmentSelector::process (const db::Edge &edge, std::vector<db::Edge> &res)
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeAngleChecker implementation
|
||||
|
||||
EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
if (absolute && angle_start < -db::epsilon) {
|
||||
angle_start = 0.0;
|
||||
include_angle_start = true;
|
||||
}
|
||||
|
||||
m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ());
|
||||
m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ());
|
||||
|
||||
|
|
@ -225,6 +230,9 @@ EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start
|
|||
|
||||
m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0;
|
||||
m_all = (angle_end - angle_start - db::epsilon) > 360.0;
|
||||
|
||||
m_absolute = absolute;
|
||||
m_inverse = inverse;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -255,14 +263,14 @@ EdgeAngleChecker::check (const db::Vector &a, const db::Vector &b) const
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeOrientationFilter implementation
|
||||
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse)
|
||||
: m_inverse (inverse), m_checker (amin, include_amin, amax, include_amax)
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse, bool absolute)
|
||||
: m_checker (amin, include_amin, amax, include_amax, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse)
|
||||
: m_inverse (inverse), m_checker (a, true, a, true)
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse, bool absolute)
|
||||
: m_checker (a, true, a, true, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -273,9 +281,9 @@ EdgeOrientationFilter::selected (const db::Edge &edge) const
|
|||
// NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded).
|
||||
// A horizontal edge has 0 degree, a vertical one has 90 degree.
|
||||
if (edge.dx () < 0 || (edge.dx () == 0 && edge.dy () < 0)) {
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), -edge.d ()) != m_inverse;
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), -edge.d ());
|
||||
} else {
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), edge.d ()) != m_inverse;
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), edge.d ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,20 +297,20 @@ SpecialEdgeOrientationFilter::SpecialEdgeOrientationFilter (FilterType type, boo
|
|||
}
|
||||
|
||||
static EdgeAngleChecker s_ortho_checkers [] = {
|
||||
EdgeAngleChecker (0.0, true, 0.0, true),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true)
|
||||
EdgeAngleChecker (0.0, true, 0.0, true, false, false),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true, false, false)
|
||||
};
|
||||
|
||||
static EdgeAngleChecker s_diagonal_checkers [] = {
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true)
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true, false, false),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true, false, false)
|
||||
};
|
||||
|
||||
static EdgeAngleChecker s_orthodiagonal_checkers [] = {
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true),
|
||||
EdgeAngleChecker (0.0, true, 0.0, true),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true)
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true, false, false),
|
||||
EdgeAngleChecker (0.0, true, 0.0, true, false, false),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true, false, false),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true, false, false)
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -142,22 +142,23 @@ private:
|
|||
class DB_PUBLIC EdgeAngleChecker
|
||||
{
|
||||
public:
|
||||
EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end);
|
||||
EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute);
|
||||
|
||||
bool operator() (const db::Edge &a, const db::Edge &b) const
|
||||
{
|
||||
return m_all || check (a.d (), b.d ());
|
||||
return (m_all || check (a.d (), b.d ()) || (m_absolute && check (b.d (), a.d ()))) != m_inverse;
|
||||
}
|
||||
|
||||
bool operator() (const db::Vector &a, const db::Vector &b) const
|
||||
{
|
||||
return m_all || check (a, b);
|
||||
return (m_all || check (a, b) || (m_absolute && check (b, a))) != m_inverse;
|
||||
}
|
||||
|
||||
private:
|
||||
db::CplxTrans m_t_start, m_t_end;
|
||||
bool m_include_start, m_include_end;
|
||||
bool m_big_angle, m_all;
|
||||
bool m_inverse, m_absolute;
|
||||
|
||||
bool check (const db::Vector &a, const db::Vector &b) const;
|
||||
};
|
||||
|
|
@ -181,22 +182,24 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
* @param amin The minimum angle (measured against the x axis)
|
||||
* @param amax The maximum angle (measured against the x axis)
|
||||
* @param inverse If set to true, only edges not matching this criterion will be filtered
|
||||
* @param absolute Angles are always positive
|
||||
*
|
||||
* This filter will filter out all edges whose angle against x axis
|
||||
* is larger or equal to amin and less than amax.
|
||||
*/
|
||||
EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse);
|
||||
EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse, bool absolute);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param a The angle (measured against the x axis)
|
||||
* @param inverse If set to true, only edges not matching this criterion will be filtered
|
||||
* @param absolute Angles are always positive
|
||||
*
|
||||
* This filter will filter out all edges whose angle against x axis
|
||||
* is equal to a.
|
||||
*/
|
||||
EdgeOrientationFilter (double a, bool inverse);
|
||||
EdgeOrientationFilter (double a, bool inverse, bool absolute);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the edge orientation matches the criterion
|
||||
|
|
|
|||
|
|
@ -943,6 +943,12 @@ SpiceNetlistBuilder::circuit_for (const SpiceCachedCircuit *cc, const parameters
|
|||
if (cp == c->second.end ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a null pointer indicates that we are currently defining this circuit
|
||||
if (cp->second == 0) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Subcircuit '%s' called recursively")), cc->name ()));
|
||||
}
|
||||
|
||||
return cp->second;
|
||||
}
|
||||
|
||||
|
|
@ -1055,7 +1061,8 @@ SpiceNetlistBuilder::build_circuit (const SpiceCachedCircuit *cc, const paramete
|
|||
c->set_name (make_circuit_name (cc->name (), pv));
|
||||
}
|
||||
|
||||
register_circuit_for (cc, pv, c, anonymous_top_level);
|
||||
// pre-register the circuit - allows detecting recursive calls
|
||||
register_circuit_for (cc, pv, 0, false);
|
||||
|
||||
std::unique_ptr<std::map<std::string, db::Net *> > n2n (mp_nets_by_name.release ());
|
||||
mp_nets_by_name.reset (0);
|
||||
|
|
@ -1095,6 +1102,14 @@ SpiceNetlistBuilder::build_circuit (const SpiceCachedCircuit *cc, const paramete
|
|||
std::swap (c, mp_netlist_circuit);
|
||||
std::swap (vars, m_variables);
|
||||
|
||||
// final registration if required
|
||||
if (! anonymous_top_level || ! c->is_empty ()) {
|
||||
register_circuit_for (cc, pv, c, anonymous_top_level);
|
||||
} else {
|
||||
mp_netlist->remove_circuit (c);
|
||||
c = 0;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ namespace db
|
|||
// -----------------------------------------------------------------------------------
|
||||
// CornerDetectorCore implementation
|
||||
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: m_checker (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
: m_checker (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ private:
|
|||
class DB_PUBLIC CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end);
|
||||
CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute);
|
||||
virtual ~CornerDetectorCore () { }
|
||||
|
||||
void detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const;
|
||||
|
|
@ -130,8 +130,8 @@ class DB_PUBLIC CornersAsRectangles
|
|||
: public db::PolygonProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsRectangles (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end), m_dim (dim)
|
||||
CornersAsRectangles (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute, db::Coord dim = 1)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute), m_dim (dim)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -159,8 +159,8 @@ class DB_PUBLIC CornersAsDots
|
|||
: public db::PolygonToEdgeProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsDots (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
CornersAsDots (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -184,8 +184,8 @@ class DB_PUBLIC CornersAsEdgePairs
|
|||
: public db::PolygonToEdgePairProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsEdgePairs (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
CornersAsEdgePairs (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,22 +214,22 @@ static db::CompoundRegionOperationNode *new_count_filter (db::CompoundRegionOper
|
|||
return new db::CompoundRegionCountFilterNode (input, invert, min_count, max_count);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim, bool inverse, bool absolute)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/);
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute, dim), input, true /*processor is owned*/, dim /*dist adder*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_edge_pairs (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_edge_pairs (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperationNode *input, db::Coord e)
|
||||
|
|
@ -341,10 +341,10 @@ static db::CompoundRegionOperationNode *new_edge_length_sum_filter (db::Compound
|
|||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/, true /*sum*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, bool include_amin, double amax, bool include_amax)
|
||||
static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, bool include_amin, double amax, bool include_amax, bool absolute_angle)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, include_amin, amax, include_amax, inverse), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, include_amin, amax, include_amax, inverse, absolute_angle), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_polygons (db::CompoundRegionOperationNode *input, db::Coord e)
|
||||
|
|
@ -617,17 +617,21 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_count_filter", &new_count_filter, gsi::arg ("inputs"), gsi::arg ("invert", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max ()),
|
||||
"@brief Creates a node selecting results but their shape count.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("dim"),
|
||||
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("dim"), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief Creates a node turning corners into rectangles.\n"
|
||||
"\n"
|
||||
"'absolute' and 'inverse' arguments have been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"),
|
||||
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief Creates a node turning corners into dots (single-point edges).\n"
|
||||
"\n"
|
||||
"'absolute' and 'inverse' arguments have been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_edge_pairs", &new_corners_as_edge_pairs, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"),
|
||||
gsi::constructor ("new_corners_as_edge_pairs", &new_corners_as_edge_pairs, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief Creates a node turning corners into edge pairs containing the two edges adjacent to the corner.\n"
|
||||
"The first edge will be the incoming edge and the second one the outgoing edge.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.27.1.\n"
|
||||
"This feature has been introduced in version 0.27.1. 'absolute' and 'inverse' arguments have been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::constructor ("new_extents", &new_extents, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
"@brief Creates a node returning the extents of the objects.\n"
|
||||
|
|
@ -759,8 +763,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_edge_length_sum_filter", &new_edge_length_sum_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"),
|
||||
"@brief Creates a node filtering edges by their length sum (over the local set).\n"
|
||||
) +
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse"), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"),
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse"), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"), gsi::arg ("absolute_angle", false),
|
||||
"@brief Creates a node filtering edges by their orientation.\n"
|
||||
"\n"
|
||||
"'absolute_angle' has been introduced in version 0.29.1."
|
||||
) +
|
||||
gsi::constructor ("new_polygons", &new_polygons, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
"@brief Creates a node converting the input to polygons.\n"
|
||||
|
|
|
|||
|
|
@ -432,14 +432,28 @@ static db::EdgePairs with_length_both2 (const db::EdgePairs *r, const tl::Varian
|
|||
|
||||
static db::EdgePairs with_angle1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse);
|
||||
db::EdgeOrientationFilter f (a, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_angle2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
|
@ -453,14 +467,28 @@ static db::EdgePairs with_angle3 (const db::EdgePairs *r, db::SpecialEdgeOrienta
|
|||
|
||||
static db::EdgePairs with_angle_both1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse);
|
||||
db::EdgeOrientationFilter f (a, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_angle_both2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle_both1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle_both2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
|
@ -967,6 +995,22 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This method has been added in version 0.27.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
|
||||
|
|
@ -1027,6 +1071,21 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This method has been added in version 0.27.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle_both", with_abs_angle_both1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of both of their edges\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle_both, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle_both", with_abs_angle_both2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"\n"
|
||||
"This method behaves like \\with_angle_both, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_angle_both", with_angle_both3, gsi::arg ("type"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
|
||||
|
|
|
|||
|
|
@ -440,13 +440,25 @@ static db::Edges with_length2 (const db::Edges *r, const tl::Variant &min, const
|
|||
|
||||
static db::Edges with_angle1 (const db::Edges *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse);
|
||||
db::EdgeOrientationFilter f (a, inverse, false);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_angle2 (const db::Edges *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, false);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_abs_angle1 (const db::Edges *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse, true);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_abs_angle2 (const db::Edges *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, true);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
|
|
@ -923,7 +935,23 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
|
||||
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
|
||||
"\n"
|
||||
"The two \"include..\" arguments have been added in version 0.27."
|
||||
"The two \"include..\" arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edges by orientation\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"@brief Filter the edges by orientation\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
|
||||
"@brief Filters the edges by orientation type\n"
|
||||
|
|
|
|||
|
|
@ -300,19 +300,19 @@ static db::Region *texts_as_boxes2 (const db::Region *r, db::DeepShapeStore &dss
|
|||
return new db::Region (r->texts_as_boxes (pat, pattern, enl, dss));
|
||||
}
|
||||
|
||||
static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end)
|
||||
static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
return r->processed (db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end));
|
||||
return r->processed (db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute));
|
||||
}
|
||||
|
||||
static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim, bool include_angle_start, bool include_angle_end)
|
||||
static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim, bool include_angle_start, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
return r->processed (db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim));
|
||||
return r->processed (db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute, dim));
|
||||
}
|
||||
|
||||
static db::EdgePairs corners_to_edge_pairs (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end)
|
||||
static db::EdgePairs corners_to_edge_pairs (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
return r->processed (db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end));
|
||||
return r->processed (db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute));
|
||||
}
|
||||
|
||||
static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
||||
|
|
@ -1697,7 +1697,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"@hide\n"
|
||||
"This method is provided for DRC implementation.\n"
|
||||
) +
|
||||
method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_min", -180.0), gsi::arg ("angle_max", 180.0), gsi::arg ("dim", 1), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_min", -180.0), gsi::arg ("angle_max", 180.0), gsi::arg ("dim", 1), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||
"\n"
|
||||
"The angle values specify a range of angles: all corners whose attached edges form an angle "
|
||||
|
|
@ -1706,29 +1706,35 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"If 'include_angle_min' is true, the angle condition is >= min. angle, otherwise it is > min. angle. "
|
||||
"Same for 'include_angle_,ax' and the max. angle.\n"
|
||||
"\n"
|
||||
"The angle is measured "
|
||||
"With 'absolute' set to false (the default), the angle is measured "
|
||||
"between the incoming and the outcoming edge in mathematical sense: a positive value is a turn left "
|
||||
"while a negative value is a turn right. Since polygon contours are oriented clockwise, positive "
|
||||
"angles will report concave corners while negative ones report convex ones.\n"
|
||||
"With the 'absolute' option set to true, there is no such distinction and angle values are always positive.\n"
|
||||
"\n"
|
||||
"With 'inverse' set to true, the method will select corners not meeting the angle criterion.\n"
|
||||
"\n"
|
||||
"A similar function that reports corners as point-like edges is \\corners_dots.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27. "
|
||||
"'inverse' and 'absolute' have been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||
"\n"
|
||||
"This method is similar to \\corners, but delivers an \\Edges collection with dot-like edges for each corner.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27. "
|
||||
"'inverse' and 'absolute' have been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("corners_edge_pairs", &corners_to_edge_pairs, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
method_ext ("corners_edge_pairs", &corners_to_edge_pairs, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||
"\n"
|
||||
"This method is similar to \\corners, but delivers an \\EdgePairs collection with an edge pairs for each corner.\n"
|
||||
"The first edge is the incoming edge of the corner, the second one the outgoing edge.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.1.\n"
|
||||
"This method has been introduced in version 0.27.1. "
|
||||
"'inverse' and 'absolute' have been added in version 0.29.1.\n"
|
||||
) +
|
||||
method ("merge", (db::Region &(db::Region::*) ()) &db::Region::merge,
|
||||
"@brief Merge the region\n"
|
||||
|
|
|
|||
|
|
@ -1043,13 +1043,13 @@ TEST(21_Processors)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true, false, false)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)));
|
||||
db::Region ext;
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), ext);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, false, false, 2000)));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor<db::Polygon> (0, 0)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor<db::Polygon> (1000, 2000)));
|
||||
|
|
|
|||
|
|
@ -836,10 +836,10 @@ void run_test15 (tl::TestBase *_this, bool deep)
|
|||
|
||||
db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode ();
|
||||
|
||||
db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, true, 180.0, true, 1), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 1), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionCountFilterNode count1 (corners1, false, 5, 10000);
|
||||
|
||||
db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, true, 180.0, true), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, true, 180.0, true, false, false), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionCountFilterNode count2 (corners2, true, 5, 10000);
|
||||
|
||||
EXPECT_EQ (count1.result_type () == db::CompoundRegionJoinOperationNode::Region, true);
|
||||
|
|
|
|||
|
|
@ -327,8 +327,8 @@ TEST(5_Filters)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
|
||||
|
||||
db::EdgeOrientationFilter eof1 (0, true, 1, true, false);
|
||||
db::EdgeOrientationFilter eof2 (0, true, 1, true, true);
|
||||
db::EdgeOrientationFilter eof1 (0, true, 1, true, false, false);
|
||||
db::EdgeOrientationFilter eof2 (0, true, 1, true, true, false);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.filtered (eof1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.filtered (eof2));
|
||||
|
|
|
|||
|
|
@ -1264,13 +1264,13 @@ TEST(21_Processors)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true, false, false)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)));
|
||||
db::Region ext;
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), ext);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, false, false, 2000)));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor<db::Polygon> (0, 0)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor<db::Polygon> (1000, 2000)));
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ TEST(5_InternalAngleFilter)
|
|||
{
|
||||
db::EdgePair ep0 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (0, 0)));
|
||||
db::EdgePair ep45 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, 100)));
|
||||
db::EdgePair ep45inv (db::Edge (db::Point (0, 0), db::Point (100, 100)), db::Edge (db::Point (0, 0), db::Point (100, 0)));
|
||||
db::EdgePair ep180 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, 0)));
|
||||
db::EdgePair ep90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (0, 100)));
|
||||
db::EdgePair epm90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 100), db::Point (0, 0)));
|
||||
|
|
@ -187,6 +188,7 @@ TEST(5_InternalAngleFilter)
|
|||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45inv), true);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep180), false);
|
||||
|
|
@ -199,4 +201,12 @@ TEST(5_InternalAngleFilter)
|
|||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45inv), true);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep180), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (epm90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45inv), false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,55 +202,63 @@ TEST(4)
|
|||
EXPECT_EQ (db::compare (rr, "(0,0;0,200);(0,200;100,200);(100,200;100,0);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(200,0;250,200);(250,-200;300,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, true);
|
||||
db::EdgeOrientationFilter f1 (-80.0, true, -50.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(250,200;300,0);(200,0;250,-200)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, false, true);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(200,0;250,200);(250,200;300,0);(200,0;250,-200);(250,-200;300,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, true, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(0,200;100,200);(100,200;100,0);(100,0;0,0);(250,200;300,0);(300,0;200,0);(200,0;250,-200)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 1.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 1.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, false, false, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, true, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, true, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, true, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, true, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, false, 1.0, true, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, false, 1.0, true, false, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (90.0, false);
|
||||
db::EdgeOrientationFilter f1 (90.0, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(100,200;100,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (90.0, true, 91.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (90.0, true, 91.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(100,200;100,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 91.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 91.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(100,200;100,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 90.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 90.0, false, false, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -880,6 +880,40 @@ TEST(23_endl)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(24_recursive_calls)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader24.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
|
||||
try {
|
||||
reader.read (is, nl);
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (tl::Exception &ex) {
|
||||
EXPECT_EQ (ex.msg ().find ("Subcircuit 'C1' called recursively in"), size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(25_dismiss_top_level)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader25.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit TOP (A=A,B=B);\n"
|
||||
" device NMOS '1' (S=A,G=B,D=A,B=B) (L=100,W=100,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(100_ExpressionParser)
|
||||
{
|
||||
std::map<std::string, tl::Variant> vars;
|
||||
|
|
|
|||
|
|
@ -2574,17 +2574,17 @@ TEST(100_Processors)
|
|||
r.insert (db::Box (db::Point (0, 300), db::Point (200, 400)));
|
||||
r.insert (db::Box (db::Point (100, 300), db::Point (200, 500)));
|
||||
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-180.0, true, 180.0, true)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (0.0, true, 180.0, true)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, true)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, true)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, false)).to_string (), "");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-180.0, true, 180.0, true, false, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, true, false, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, true, false, false)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, false, false, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, false, false, false)).to_string (), "");
|
||||
db::Region ext;
|
||||
r.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 10, 10, 20, 20);
|
||||
r.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).extended (ext, 10, 10, 20, 20);
|
||||
EXPECT_EQ (ext.to_string (), "(90,380;90,420;110,420;110,380)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2)), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2)).to_string (), "(98,398;98,402;102,402;102,398)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 2)), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, true, 180.0, true, false, false, 2)).to_string (), "(98,398;98,402;102,402;102,398)");
|
||||
|
||||
EXPECT_EQ (db::compare (r.processed (db::extents_processor<db::Polygon> (0, 0)), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)"), true);
|
||||
EXPECT_EQ (db::compare (r.processed (db::extents_processor<db::Polygon> (10, 20)), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)"), true);
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ out = in.drc((width < 0.3).edges - secondary(waive))
|
|||
This operation selects edges by their angle, measured against the horizontal
|
||||
axis in the mathematical sense.
|
||||
</p><p>
|
||||
For this measurement edges are considered without their direction and straight lines.
|
||||
For this measurement edges are considered without their direction.
|
||||
A horizontal edge has an angle of zero degree. A vertical one has
|
||||
an angle of 90 degrees. The angle range is from -90 (exclusive) to 90 degree (inclusive).
|
||||
</p><p>
|
||||
|
|
@ -172,20 +172,28 @@ If the input shapes are not polygons or edge pairs, they are converted to edges
|
|||
before the angle test is made.
|
||||
</p><p>
|
||||
For example, the following code selects all edges from the primary shape which are 45 degree
|
||||
(up) or 135 degree (down). The "+" will join the results:
|
||||
(up) or -45 degree (down). The "+" operator will join the results:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc((angle == 45) + (angle == 135))
|
||||
out = in.drc((primary.angle == 45) + (primary.angle == 135)) # equivalent
|
||||
out = in.drc((angle == 45) + (angle == -45))
|
||||
out = in.drc((primary.angle == 45) + (primary.angle == -45)) # equivalent
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that angle checks usually imply the need to rotation variant formation as cells which
|
||||
You can avoid using both 45 and -45 degree checks with the 'absolute' option.
|
||||
With this option, angles are not signed and the value is the absolute angle
|
||||
the edge encloses with the x axis:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(angle(absolute) == 45)
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that angle checks usually imply the need for rotation variant formation as cells which
|
||||
are placed non-rotated and rotated by 90 degree cannot be considered identical. This imposes
|
||||
a performance penalty in hierarchical mode. If possible, consider using <a href="/about/drc_ref_drc.xml#rectilinear">DRC#rectilinear</a> for
|
||||
example to detect shapes with non-manhattan geometry instead of using angle checks.
|
||||
</p><p>
|
||||
The "angle" method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
|
||||
The plain function is equivalent to "primary.angle".
|
||||
The plain function is equivalent to the method call "primary.angle".
|
||||
</p>
|
||||
<a name="area"/><h2>"area" - Selects the primary shape if the area is meeting the condition</h2>
|
||||
<keyword name="area"/>
|
||||
|
|
@ -363,8 +371,7 @@ See <a href="/about/drc_ref_layer.xml#centers">layer#centers</a> for details abo
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>expression.corners</tt></li>
|
||||
<li><tt>expression.corners(as_dots)</tt></li>
|
||||
<li><tt>expression.corners(as_boxes)</tt></li>
|
||||
<li><tt>expression.corners([ options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation acts on polygons and selects the corners of the polygons.
|
||||
|
|
@ -374,10 +381,20 @@ and negative for the turn to the right. Hence positive angles indicate concave
|
|||
(inner) corners, negative ones indicate convex (outer) corners.
|
||||
Angles take values between -180 and 180 degree.
|
||||
</p><p>
|
||||
When using "as_dots" for the argument, the operation will return single-point edges at
|
||||
When using "as_dots" for an option, the operation will return single-point edges at
|
||||
the selected corners. With "as_boxes" (the default), small (2x2 DBU) rectangles will be
|
||||
produced at each selected corner.
|
||||
</p><p>
|
||||
Another option is "absolute" which selects the corners by absolute angle - i.e left
|
||||
and right turns will both be considered positive angles.
|
||||
</p><p>
|
||||
Examples for use of the options are:
|
||||
</p><p>
|
||||
<pre>
|
||||
corners(as_dots)
|
||||
corners(as_boxes, absolute)
|
||||
</pre>
|
||||
</p><p>
|
||||
The following example selects all corners:
|
||||
</p><p>
|
||||
<pre>
|
||||
|
|
|
|||
|
|
@ -264,8 +264,11 @@ deliver objects that can be converted into polygons. Such objects are of class <
|
|||
<p>
|
||||
This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||
while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
|
||||
while negative angles indicate a right turn.
|
||||
Since polygons are oriented clockwise, positive angles
|
||||
indicate concave (inner) corners while negative ones indicate convex (outer) corners
|
||||
The 'absolute' option allows turning this off and considering both left and right turns
|
||||
positive angles.
|
||||
</p><p>
|
||||
The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||
</p><p>
|
||||
|
|
@ -276,6 +279,8 @@ The options available are:
|
|||
<li><b>as_dots </b>: with this option, point-like edges will be produced instead of small boxes </li>
|
||||
<li><b>as_edge_pairs </b>: with this option, an edge pair is produced for each corner selected. The first edge
|
||||
is the incoming edge to the corner, the second edge the outgoing edge. </li>
|
||||
<li><b>absolute </b>: with this option, left and right turns will both be considered positive angles </li>
|
||||
<li><b>negative </b>: with this option, all corners <b>not </b>matching the angle criterion are selected </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
The following images show the effect of this method:
|
||||
|
|
@ -3615,13 +3620,13 @@ The following images illustrate the effect of the "without_touching_corners" opt
|
|||
<keyword name="with_angle"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.with_angle(min .. max)</tt></li>
|
||||
<li><tt>layer.with_angle(value)</tt></li>
|
||||
<li><tt>layer.with_angle(min, max)</tt></li>
|
||||
<li><tt>layer.with_angle(min .. max [, absolute])</tt></li>
|
||||
<li><tt>layer.with_angle(value [, absolute])</tt></li>
|
||||
<li><tt>layer.with_angle(min, max [, absolute])</tt></li>
|
||||
<li><tt>layer.with_angle(ortho)</tt></li>
|
||||
<li><tt>layer.with_angle(diagonal)</tt></li>
|
||||
<li><tt>layer.with_angle(diagonal_only)</tt></li>
|
||||
<li><tt>edge_pair_layer.with_angle(... [, both])</tt></li>
|
||||
<li><tt>edge_pair_layer.with_angle(... [, both] [, absolute])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
When called on an edge layer, the method selects edges by their angle,
|
||||
|
|
@ -3641,6 +3646,11 @@ meeting the angle criterion. In this case an additional argument is accepted whi
|
|||
either "both" (plain word) to indicate that both edges have to be within the given interval.
|
||||
Without this argument, it is sufficient for one edge to meet the criterion.
|
||||
</p><p>
|
||||
The "absolute" option is available for edge or edge pair layers.
|
||||
Without the "absolute" option, edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
</p><p>
|
||||
Here are examples for "with_angle" on edge pair layers:
|
||||
</p><p>
|
||||
<pre>
|
||||
|
|
@ -4006,21 +4016,25 @@ This method is available for polygon layers only.
|
|||
<keyword name="without_angle"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.without_angle(min .. max)</tt></li>
|
||||
<li><tt>layer.without_angle(value)</tt></li>
|
||||
<li><tt>layer.without_angle(min, max)</tt></li>
|
||||
<li><tt>layer.without_angle(min .. max [, absolute])</tt></li>
|
||||
<li><tt>layer.without_angle(value [, absolute])</tt></li>
|
||||
<li><tt>layer.without_angle(min, max [, absolute])</tt></li>
|
||||
<li><tt>layer.without_angle(ortho)</tt></li>
|
||||
<li><tt>layer.without_angle(diagonal)</tt></li>
|
||||
<li><tt>layer.without_angle(diagonal_only)</tt></li>
|
||||
<li><tt>edge_pair_layer.without_angle(... [, both])</tt></li>
|
||||
<li><tt>edge_pair_layer.without_angle(... [, both] [, absolute])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method basically is the inverse of <a href="#with_angle">with_angle</a>. It selects all edges
|
||||
of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
|
||||
is not inside the given interval (first and third form) or of the given type (other forms).
|
||||
</p><p>
|
||||
When called on edge pairs, it selects
|
||||
edge pairs by the angles of their edges.
|
||||
When called on edge pairs, it selects edge pairs by the angles of their edges.
|
||||
</p><p>
|
||||
The "absolute" option is available for edge or edge pair layers. Without the "absolute" option,
|
||||
edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
</p><p>
|
||||
A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||
both edges need to be "without_angle". For example
|
||||
|
|
|
|||
|
|
@ -282,6 +282,7 @@ var x = 3; x = x + 1; x
|
|||
<tr><td><tt>combine(</tt>x<tt>,</tt>y<tt>)</tt></td><td>String</td><td>String</td><td>Combines the path components x and y using the system specific separator</td></tr>
|
||||
<tr><td><tt>cosh(</tt>x<tt>)</tt></td><td>Numeric</td><td>Numeric</td><td>Hyperbolic cosine function</td></tr>
|
||||
<tr><td><tt>cos(</tt>x<tt>)</tt></td><td>Numeric</td><td>Numeric</td><td>Cosine function</td></tr>
|
||||
<tr><td><tt>downcase(</tt>x<tt>)</tt></td><td>String</td><td>String</td><td>Converts the given string to lower case</td></tr>
|
||||
<tr><td><tt>env(</tt>x<tt>)</tt></td><td>String</td><td>String</td><td>Access an environment variable</td></tr>
|
||||
<tr><td><tt>error(</tt>x<tt>)</tt></td><td>String</td><td></td><td>Raise an error</td></tr>
|
||||
<tr><td><tt>exp(</tt>x<tt>)</tt></td><td>Numeric</td><td>Numeric</td><td>Exponential function</td></tr>
|
||||
|
|
@ -318,6 +319,7 @@ var x = 3; x = x + 1; x
|
|||
<tr><td><tt>to_f(</tt>x<tt>)</tt></td><td>Any</td><td>Numeric</td><td>Convert argument to numeric if possible</td></tr>
|
||||
<tr><td><tt>to_i(</tt>x<tt>)</tt></td><td>Any</td><td>Numeric (integer)</td><td>Convert argument to numeric (32 bit integer)</td></tr>
|
||||
<tr><td><tt>to_s(</tt>x<tt>)</tt></td><td>Any</td><td>String</td><td>Convert argument to string</td></tr>
|
||||
<tr><td><tt>upcase(</tt>x<tt>)</tt></td><td>String</td><td>String</td><td>Converts the given string to upper case</td></tr>
|
||||
</table>
|
||||
|
||||
</doc>
|
||||
|
|
|
|||
|
|
@ -691,7 +691,7 @@ CODE
|
|||
# This operation selects edges by their angle, measured against the horizontal
|
||||
# axis in the mathematical sense.
|
||||
#
|
||||
# For this measurement edges are considered without their direction and straight lines.
|
||||
# For this measurement edges are considered without their direction.
|
||||
# A horizontal edge has an angle of zero degree. A vertical one has
|
||||
# an angle of 90 degrees. The angle range is from -90 (exclusive) to 90 degree (inclusive).
|
||||
#
|
||||
|
|
@ -699,23 +699,43 @@ CODE
|
|||
# before the angle test is made.
|
||||
#
|
||||
# For example, the following code selects all edges from the primary shape which are 45 degree
|
||||
# (up) or 135 degree (down). The "+" will join the results:
|
||||
# (up) or -45 degree (down). The "+" operator will join the results:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc((angle == 45) + (angle == 135))
|
||||
# out = in.drc((primary.angle == 45) + (primary.angle == 135)) # equivalent
|
||||
# out = in.drc((angle == 45) + (angle == -45))
|
||||
# out = in.drc((primary.angle == 45) + (primary.angle == -45)) # equivalent
|
||||
# @/code
|
||||
#
|
||||
# Note that angle checks usually imply the need to rotation variant formation as cells which
|
||||
# You can avoid using both 45 and -45 degree checks with the 'absolute' option.
|
||||
# With this option, angles are not signed and the value is the absolute angle
|
||||
# the edge encloses with the x axis:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(angle(absolute) == 45)
|
||||
# @/code
|
||||
#
|
||||
# Note that angle checks usually imply the need for rotation variant formation as cells which
|
||||
# are placed non-rotated and rotated by 90 degree cannot be considered identical. This imposes
|
||||
# a performance penalty in hierarchical mode. If possible, consider using \DRC#rectilinear for
|
||||
# example to detect shapes with non-manhattan geometry instead of using angle checks.
|
||||
#
|
||||
# The "angle" method is available as a plain function or as a method on \DRC# expressions.
|
||||
# The plain function is equivalent to "primary.angle".
|
||||
# The plain function is equivalent to the method call "primary.angle".
|
||||
|
||||
def angle
|
||||
DRCOpNodeEdgeOrientationFilter::new(@engine, self)
|
||||
def angle(*args)
|
||||
|
||||
filter = DRCOpNodeEdgeOrientationFilter::new(@engine, self)
|
||||
|
||||
args.each do |a|
|
||||
if a.is_a?(DRCAbsoluteMode)
|
||||
filter.absolute = a.value
|
||||
else
|
||||
raise("Invalid argument (#{a.inspect}) for 'angle' method")
|
||||
end
|
||||
end
|
||||
|
||||
filter
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -758,8 +778,7 @@ CODE
|
|||
# @name corners
|
||||
# @brief Selects corners of polygons
|
||||
# @synopsis expression.corners
|
||||
# @synopsis expression.corners(as_dots)
|
||||
# @synopsis expression.corners(as_boxes)
|
||||
# @synopsis expression.corners([ options ])
|
||||
#
|
||||
# This operation acts on polygons and selects the corners of the polygons.
|
||||
# It can be put into a condition to select corners by their angles. The angle of
|
||||
|
|
@ -768,9 +787,19 @@ CODE
|
|||
# (inner) corners, negative ones indicate convex (outer) corners.
|
||||
# Angles take values between -180 and 180 degree.
|
||||
#
|
||||
# When using "as_dots" for the argument, the operation will return single-point edges at
|
||||
# When using "as_dots" for an option, the operation will return single-point edges at
|
||||
# the selected corners. With "as_boxes" (the default), small (2x2 DBU) rectangles will be
|
||||
# produced at each selected corner.
|
||||
#
|
||||
# Another option is "absolute" which selects the corners by absolute angle - i.e left
|
||||
# and right turns will both be considered positive angles.
|
||||
#
|
||||
# Examples for use of the options are:
|
||||
#
|
||||
# @code
|
||||
# corners(as_dots)
|
||||
# corners(as_boxes, absolute)
|
||||
# @/code
|
||||
#
|
||||
# The following example selects all corners:
|
||||
#
|
||||
|
|
@ -789,14 +818,20 @@ CODE
|
|||
# The "corners" method is available as a plain function or as a method on \DRC# expressions.
|
||||
# The plain function is equivalent to "primary.corners".
|
||||
|
||||
def corners(output_mode = DRCOutputMode::new(:dots))
|
||||
def corners(*args)
|
||||
@engine._context("corners") do
|
||||
if output_mode.is_a?(DRCOutputMode)
|
||||
output_mode = output_mode.value
|
||||
else
|
||||
raise("Invalid argument (#{as_dots.inspect}) for 'corners' method")
|
||||
output_mode = :as_boxes
|
||||
absolute = false
|
||||
args.each do |a|
|
||||
if a.is_a?(DRCOutputMode)
|
||||
output_mode = a.value
|
||||
elsif a.is_a?(DRCAbsoluteMode)
|
||||
absolute = a.value
|
||||
else
|
||||
raise("Invalid argument (#{a.inspect}) for 'corners' method")
|
||||
end
|
||||
end
|
||||
DRCOpNodeCornersFilter::new(@engine, output_mode, self)
|
||||
DRCOpNodeCornersFilter::new(@engine, output_mode, absolute, self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1721,6 +1756,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :inverse
|
||||
attr_accessor :absolute
|
||||
|
||||
def initialize(engine, input)
|
||||
super(engine)
|
||||
|
|
@ -1748,6 +1784,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
|||
args << (self.gt ? false : true)
|
||||
args << (self.lt ? self.lt : (self.le ? self.le + angle_delta : 180.0))
|
||||
args << (self.lt ? false : true)
|
||||
args << self.absolute
|
||||
|
||||
RBA::CompoundRegionOperationNode::new_edge_orientation_filter(*args)
|
||||
|
||||
|
|
@ -2037,12 +2074,16 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :output_mode
|
||||
attr_accessor :inverse
|
||||
attr_accessor :absolute
|
||||
|
||||
def initialize(engine, output_mode, input)
|
||||
def initialize(engine, output_mode, absolute, input)
|
||||
super(engine)
|
||||
self.output_mode = output_mode
|
||||
self.input = input
|
||||
self.description = "corners"
|
||||
self.inverse = false
|
||||
self.absolute = absolute
|
||||
end
|
||||
|
||||
def do_create_node(cache)
|
||||
|
|
@ -2052,14 +2093,26 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
|||
args << (self.lt ? self.lt : (self.le ? self.le : 180.0))
|
||||
args << (self.lt ? false : true)
|
||||
if self.output_mode == :dots || self.output_mode == :edges
|
||||
args << self.inverse
|
||||
args << self.absolute
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_dots(*args)
|
||||
elsif self.output_mode == :edge_pairs
|
||||
args << self.inverse
|
||||
args << self.absolute
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_edge_pairs(*args)
|
||||
else
|
||||
args << 2 # dimension is 2x2 DBU
|
||||
args << self.inverse
|
||||
args << self.absolute
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_rectangles(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def inverted
|
||||
res = self.dup
|
||||
res.inverse = !res.inverse
|
||||
return res
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -770,17 +770,7 @@ CODE
|
|||
# \DRC# expressions (see \Layer#drc and \DRC#length for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_length.
|
||||
|
||||
# %DRC%
|
||||
# @name angle
|
||||
# @brief In universal DRC context: selects edges based on their orientation
|
||||
# @synopsis angle (in condition)
|
||||
#
|
||||
# "angle" represents the edge orientation filter on the primary shape edges in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#angle for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_angle.
|
||||
|
||||
%w(
|
||||
angle
|
||||
area
|
||||
holes
|
||||
hulls
|
||||
|
|
@ -798,6 +788,15 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name angle
|
||||
# @brief In universal DRC context: selects edges based on their orientation
|
||||
# @synopsis angle (in condition)
|
||||
#
|
||||
# "angle" represents the edge orientation filter on the primary shape edges in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#angle for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_angle.
|
||||
|
||||
# %DRC%
|
||||
# @name corners
|
||||
# @brief Selects corners of polygons
|
||||
|
|
@ -817,11 +816,6 @@ CODE
|
|||
# The "corners" operator can be put into a condition which means it's
|
||||
# applied to corners meeting a particular angle constraint.
|
||||
|
||||
def _cop_corners(output_mode = DRCOutputMode::new(:boxes))
|
||||
# NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here.
|
||||
return primary.corners(output_mode)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name extent_refs
|
||||
# @brief Returns partial references to the boundings boxes of the polygons
|
||||
|
|
@ -897,6 +891,8 @@ CODE
|
|||
rounded_corners
|
||||
sized
|
||||
smoothed
|
||||
corners
|
||||
angle
|
||||
).each do |f|
|
||||
# NOTE: these methods are fallback for the respective global ones which route to DRCLayer or here.
|
||||
eval <<"CODE"
|
||||
|
|
|
|||
|
|
@ -551,6 +551,10 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
def absolute
|
||||
DRCAbsoluteMode::new(true)
|
||||
end
|
||||
|
||||
def as_dots
|
||||
DRCOutputMode::new(:dots)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -861,13 +861,13 @@ CODE
|
|||
# %DRC%
|
||||
# @name with_angle
|
||||
# @brief Selects edges by their angle
|
||||
# @synopsis layer.with_angle(min .. max)
|
||||
# @synopsis layer.with_angle(value)
|
||||
# @synopsis layer.with_angle(min, max)
|
||||
# @synopsis layer.with_angle(min .. max [, absolute])
|
||||
# @synopsis layer.with_angle(value [, absolute])
|
||||
# @synopsis layer.with_angle(min, max [, absolute])
|
||||
# @synopsis layer.with_angle(ortho)
|
||||
# @synopsis layer.with_angle(diagonal)
|
||||
# @synopsis layer.with_angle(diagonal_only)
|
||||
# @synopsis edge_pair_layer.with_angle(... [, both])
|
||||
# @synopsis edge_pair_layer.with_angle(... [, both] [, absolute])
|
||||
#
|
||||
# When called on an edge layer, the method selects edges by their angle,
|
||||
# measured against the horizontal axis in the mathematical sense.
|
||||
|
|
@ -886,6 +886,11 @@ CODE
|
|||
# either "both" (plain word) to indicate that both edges have to be within the given interval.
|
||||
# Without this argument, it is sufficient for one edge to meet the criterion.
|
||||
#
|
||||
# The "absolute" option is available for edge or edge pair layers.
|
||||
# Without the "absolute" option, edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
# a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
# edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
#
|
||||
# Here are examples for "with_angle" on edge pair layers:
|
||||
#
|
||||
# @code
|
||||
|
|
@ -931,21 +936,25 @@ CODE
|
|||
# %DRC%
|
||||
# @name without_angle
|
||||
# @brief Selects edges by the their angle
|
||||
# @synopsis layer.without_angle(min .. max)
|
||||
# @synopsis layer.without_angle(value)
|
||||
# @synopsis layer.without_angle(min, max)
|
||||
# @synopsis layer.without_angle(min .. max [, absolute])
|
||||
# @synopsis layer.without_angle(value [, absolute])
|
||||
# @synopsis layer.without_angle(min, max [, absolute])
|
||||
# @synopsis layer.without_angle(ortho)
|
||||
# @synopsis layer.without_angle(diagonal)
|
||||
# @synopsis layer.without_angle(diagonal_only)
|
||||
# @synopsis edge_pair_layer.without_angle(... [, both])
|
||||
# @synopsis edge_pair_layer.without_angle(... [, both] [, absolute])
|
||||
#
|
||||
# The method basically is the inverse of \with_angle. It selects all edges
|
||||
# of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
|
||||
# is not inside the given interval (first and third form) or of the given type (other forms).
|
||||
#
|
||||
# When called on edge pairs, it selects
|
||||
# edge pairs by the angles of their edges.
|
||||
# When called on edge pairs, it selects edge pairs by the angles of their edges.
|
||||
#
|
||||
# The "absolute" option is available for edge or edge pair layers. Without the "absolute" option,
|
||||
# edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
# a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
# edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
#
|
||||
# A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||
# both edges need to be "without_angle". For example
|
||||
#
|
||||
|
|
@ -989,57 +998,101 @@ CODE
|
|||
# The method basically is the inverse of \with_internal_angle. It selects all
|
||||
# edge pairs by the angle enclosed by their edges, applying the opposite criterion than \with_internal_angle.
|
||||
|
||||
%w(angle internal_angle).each do |f|
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_" + f
|
||||
eval <<"CODE"
|
||||
def #{mn}(*args)
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_angle"
|
||||
eval <<"CODE"
|
||||
def #{mn}(*args)
|
||||
|
||||
@engine._context("#{mn}") do
|
||||
@engine._context("#{mn}") do
|
||||
|
||||
f = :with_#{f}
|
||||
self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::EdgePairs) || raise("Requires an edge, edge pair or polygon layer")
|
||||
|
||||
if "#{f}" == "angle"
|
||||
self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::EdgePairs) || raise("Requires an edge, edge pair or polygon layer")
|
||||
args = args.select do |a|
|
||||
if a.is_a?(DRCBothEdges)
|
||||
if !self.data.is_a?(RBA::EdgePairs)
|
||||
raise("'both' keyword is only available for edge pair layers")
|
||||
end
|
||||
f = :with_#{f}_both
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
absolute = false
|
||||
both = false
|
||||
|
||||
args = args.select do |a|
|
||||
if a.is_a?(DRCBothEdges)
|
||||
if !self.data.is_a?(RBA::EdgePairs)
|
||||
raise("'both' keyword is only available for edge pair layers")
|
||||
end
|
||||
else
|
||||
requires_edge_pairs
|
||||
end
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
||||
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a, #{inv.inspect}))
|
||||
both = true
|
||||
false
|
||||
elsif a.is_a?(DRCAbsoluteMode)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'absolute' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
elsif args.size == 2
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, args[0], args[1], #{inv.inspect}))
|
||||
absolute = a.value
|
||||
false
|
||||
else
|
||||
raise("Invalid number of range arguments (1 or 2 expected)")
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
if both
|
||||
f = absolute ? :with_abs_angle_both : :with_angle_both
|
||||
else
|
||||
f = absolute ? :with_abs_angle : :with_angle
|
||||
end
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
||||
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(a), #{inv.inspect}))
|
||||
end
|
||||
elsif args.size == 2
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(args[0]), @engine._make_numeric_value(args[1]), #{inv.inspect}))
|
||||
else
|
||||
raise("Invalid number of range arguments (1 or 2 expected)")
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_internal_angle"
|
||||
eval <<"CODE"
|
||||
def #{mn}(*args)
|
||||
|
||||
@engine._context("#{mn}") do
|
||||
|
||||
f = :with_internal_angle
|
||||
|
||||
requires_edge_pairs
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
||||
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(a), #{inv.inspect}))
|
||||
end
|
||||
elsif args.size == 2
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(args[0]), @engine._make_numeric_value(args[1]), #{inv.inspect}))
|
||||
else
|
||||
raise("Invalid number of range arguments (1 or 2 expected)")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -1231,8 +1284,11 @@ CODE
|
|||
#
|
||||
# This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||
# while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
|
||||
# while negative angles indicate a right turn.
|
||||
# Since polygons are oriented clockwise, positive angles
|
||||
# indicate concave (inner) corners while negative ones indicate convex (outer) corners
|
||||
# The 'absolute' option allows turning this off and considering both left and right turns
|
||||
# positive angles.
|
||||
#
|
||||
# The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||
#
|
||||
|
|
@ -1243,6 +1299,8 @@ CODE
|
|||
# @li @b as_dots @/b: with this option, point-like edges will be produced instead of small boxes @/li
|
||||
# @li @b as_edge_pairs @/b: with this option, an edge pair is produced for each corner selected. The first edge
|
||||
# is the incoming edge to the corner, the second edge the outgoing edge. @/li
|
||||
# @li @b absolute @/b: with this option, left and right turns will both be considered positive angles @/li
|
||||
# @li @b negative @/b: with this option, all corners @b not @/b matching the angle criterion are selected @/li
|
||||
# @/ul
|
||||
#
|
||||
# The following images show the effect of this method:
|
||||
|
|
@ -1264,6 +1322,8 @@ CODE
|
|||
output_mode = :boxes
|
||||
amin = -180.0
|
||||
amax = 180.0
|
||||
absolute = false
|
||||
inverse = false
|
||||
|
||||
args.each do |a|
|
||||
if a.is_a?(Range)
|
||||
|
|
@ -1277,21 +1337,35 @@ CODE
|
|||
amax = a.to_f
|
||||
elsif a.is_a?(DRCOutputMode)
|
||||
output_mode = a.value
|
||||
elsif a.is_a?(DRCAbsoluteMode)
|
||||
absolute = a.value
|
||||
elsif a.is_a?(DRCNegative)
|
||||
inverse = true
|
||||
else
|
||||
raise("Invalid argument #{a.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
f = :corners
|
||||
cls = RBA::Region
|
||||
args = [ amin, amax ]
|
||||
|
||||
if output_mode == :edges || output_mode == :dots
|
||||
f = :corners_dots
|
||||
cls = RBA::Edges
|
||||
elsif output_mode == :edge_pairs
|
||||
f = :corners_edge_pairs
|
||||
cls = RBA::EdgePairs
|
||||
else
|
||||
f = :corners
|
||||
cls = RBA::Region
|
||||
args << 1 # 2x2 DBU boxes
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, cls, f, amin, amax))
|
||||
|
||||
args << true # include amin
|
||||
args << true # include amax
|
||||
args << inverse
|
||||
args << absolute
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, cls, f, *args))
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,16 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
# A wrapper for the "absolute" flag for
|
||||
# some DRC functions. The purpose of this class
|
||||
# is to identify the value by the class.
|
||||
class DRCAbsoluteMode
|
||||
attr_accessor :value
|
||||
def initialize(v)
|
||||
self.value = v
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for a rectangle error filter mode
|
||||
# The purpose of this wrapper is to identify the error filter mode
|
||||
class DRCRectangleErrorFilter
|
||||
|
|
|
|||
|
|
@ -1673,6 +1673,16 @@ TEST(92_issue1594_dual_top)
|
|||
compare_netlists (_this, output, au);
|
||||
}
|
||||
|
||||
TEST(93_withAngle)
|
||||
{
|
||||
run_test (_this, "93", false);
|
||||
}
|
||||
|
||||
TEST(93d_withAngle)
|
||||
{
|
||||
run_test (_this, "93", true);
|
||||
}
|
||||
|
||||
TEST(100_edge_interaction_with_count)
|
||||
{
|
||||
run_test (_this, "100", false);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <QDialog>
|
||||
#include <QApplication>
|
||||
#include <QCloseEvent>
|
||||
|
||||
#include "layBrowser.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
|
@ -81,7 +82,7 @@ Browser::closeEvent (QCloseEvent *event)
|
|||
if (active ()) {
|
||||
m_active = false;
|
||||
deactivated ();
|
||||
QDialog::closeEvent (event);
|
||||
event->accept ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,14 +145,14 @@ ExpressionParserContext::where () const
|
|||
// ----------------------------------------------------------------------------
|
||||
// Utilities for evaluation
|
||||
|
||||
static double to_double (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static double to_double (const ExpressionParserContext &context, const tl::Variant &v, unsigned int narg)
|
||||
{
|
||||
if (v.can_convert_to_double ()) {
|
||||
return v.to_double ();
|
||||
} else if (v.is_list ()) {
|
||||
return v.get_list ().size ();
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Double precision floating point value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Double precision floating point value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,50 +162,50 @@ static double to_double (const ExpressionParserContext &context, const std::vect
|
|||
throw EvalError (tl::to_string (tr ("Function expects a single numeric argument")), context);
|
||||
}
|
||||
|
||||
return to_double (context, v [0]);
|
||||
return to_double (context, v [0], 0);
|
||||
}
|
||||
|
||||
static long to_long (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static long to_long (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_long ()) {
|
||||
return v.to_long ();
|
||||
} else if (v.is_list ()) {
|
||||
return long (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long to_ulong (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static unsigned long to_ulong (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_ulong ()) {
|
||||
return v.to_ulong ();
|
||||
} else if (v.is_list ()) {
|
||||
return (unsigned long) (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
static long long to_longlong (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static long long to_longlong (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_longlong ()) {
|
||||
return v.to_longlong ();
|
||||
} else if (v.is_list ()) {
|
||||
return long (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long long to_ulonglong (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static unsigned long long to_ulonglong (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_ulonglong ()) {
|
||||
return v.to_ulong ();
|
||||
} else if (v.is_list ()) {
|
||||
return (unsigned long long) (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1089,13 +1089,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_longlong ()) {
|
||||
v.set (tl::Variant (v->to_longlong () << to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_longlong () << to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong ()) {
|
||||
v.set (tl::Variant (v->to_ulonglong () << to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulonglong () << to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong ()) {
|
||||
v.set (tl::Variant (v->to_ulong () << to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulong () << to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) << to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) << to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1145,13 +1145,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_longlong ()) {
|
||||
v.set (tl::Variant (v->to_longlong () >> to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_longlong () >> to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong ()) {
|
||||
v.set (tl::Variant (v->to_ulonglong () >> to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulonglong () >> to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong ()) {
|
||||
v.set (tl::Variant (v->to_ulong () >> to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulong () >> to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) >> to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) >> to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1203,17 +1203,17 @@ public:
|
|||
} else if (v->is_a_string () || b->is_a_string ()) {
|
||||
v.set (tl::Variant (std::string (v->to_string ()) + b->to_string ()));
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
v.set (tl::Variant (to_double (m_context, *v) + to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) + to_double (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) + to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) + to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) + to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) + to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) + to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) + to_ulong (m_context, *b, 1)));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
v.set (tl::Variant (to_long (m_context, *v) + to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) + to_long (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_double (m_context, *v) + to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) + to_double (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1263,17 +1263,17 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
v.set (tl::Variant (to_double (m_context, *v) - to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) - to_double (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) - to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) - to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) - to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) - to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) - to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) - to_ulong (m_context, *b, 1)));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
v.set (tl::Variant (to_long (m_context, *v) - to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) - to_long (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_double (m_context, *v) - to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) - to_double (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1324,7 +1324,7 @@ public:
|
|||
|
||||
} else if (v->is_a_string ()) {
|
||||
|
||||
long x = to_long (m_context, *b);
|
||||
long x = to_long (m_context, *b, 1);
|
||||
if (x < 0) {
|
||||
throw EvalError (tl::to_string (tr ("Numeric argument of '*' operator with string must be positive")), m_context);
|
||||
}
|
||||
|
|
@ -1339,7 +1339,7 @@ public:
|
|||
|
||||
} else if (b->is_a_string ()) {
|
||||
|
||||
long x = to_long (m_context, *v);
|
||||
long x = to_long (m_context, *v, 0);
|
||||
if (x < 0) {
|
||||
throw EvalError (tl::to_string (tr ("Numeric argument of '*' operator with string must be positive")), m_context);
|
||||
}
|
||||
|
|
@ -1353,17 +1353,17 @@ public:
|
|||
v.set (tl::Variant (s));
|
||||
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
v.set (tl::Variant (to_double (m_context, *v) * to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) * to_double (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) * to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) * to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) * to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) * to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) * to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) * to_ulong (m_context, *b, 1)));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
v.set (tl::Variant (to_long (m_context, *v) * to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) * to_long (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_double (m_context, *v) * to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) * to_double (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1413,41 +1413,41 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
double d = to_double (m_context, *b);
|
||||
double d = to_double (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_double (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) / d));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
unsigned long long d = to_ulonglong (m_context, *b);
|
||||
unsigned long long d = to_ulonglong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) / d));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
long long d = to_longlong (m_context, *b);
|
||||
long long d = to_longlong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) / d));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
unsigned long d = to_ulong (m_context, *b);
|
||||
unsigned long d = to_ulong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) / d));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
long d = to_long (m_context, *b);
|
||||
long d = to_long (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_long (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) / d));
|
||||
} else {
|
||||
double d = to_double (m_context, *b);
|
||||
double d = to_double (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_double (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) / d));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1497,29 +1497,29 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
unsigned long long d = to_ulonglong (m_context, *b);
|
||||
unsigned long long d = to_ulonglong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) % d));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
long long d = to_longlong (m_context, *b);
|
||||
long long d = to_longlong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) % d));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
unsigned long d = to_ulong (m_context, *b);
|
||||
unsigned long d = to_ulong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) % d));
|
||||
} else {
|
||||
long d = to_long (m_context, *b);
|
||||
long d = to_long (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_long (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) % d));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1569,13 +1569,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) & to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) & to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) & to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) & to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) & to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) & to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) & to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) & to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1625,13 +1625,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) | to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) | to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) | to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) | to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) | to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) | to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) | to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) | to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1681,13 +1681,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) ^ to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) ^ to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) ^ to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) ^ to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) ^ to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) ^ to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) ^ to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) ^ to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1826,7 +1826,7 @@ public:
|
|||
} else if (v->is_ulonglong ()) {
|
||||
v.set (-(long long)(v->to_ulonglong ()));
|
||||
} else {
|
||||
v.set (-to_double (m_context, *v));
|
||||
v.set (-to_double (m_context, *v, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1881,7 +1881,7 @@ public:
|
|||
} else if (v->is_ulonglong ()) {
|
||||
v.set (~v->to_ulonglong ());
|
||||
} else {
|
||||
v.set (~to_long (m_context, *v));
|
||||
v.set (~to_long (m_context, *v, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -2388,7 +2388,7 @@ abs_f (const ExpressionParserContext &context, tl::Variant &out, const std::vect
|
|||
} else if (v[0].is_double ()) {
|
||||
out = fabs (v[0].to_double ());
|
||||
} else {
|
||||
out = labs (to_long (context, v[0]));
|
||||
out = labs (to_long (context, v[0], 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2463,7 +2463,7 @@ pow_f (const ExpressionParserContext &context, tl::Variant &out, const std::vect
|
|||
throw EvalError (tl::to_string (tr ("'pow' function expects exactly two arguments")), context);
|
||||
}
|
||||
|
||||
out = pow (to_double (context, vv [0]), to_double (context, vv [1]));
|
||||
out = pow (to_double (context, vv [0], 0), to_double (context, vv [1], 1));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2473,7 +2473,7 @@ atan2_f (const ExpressionParserContext &context, tl::Variant &out, const std::ve
|
|||
throw EvalError (tl::to_string (tr ("'atan2' function expects exactly two arguments")), context);
|
||||
}
|
||||
|
||||
out = atan2 (to_double (context, vv [0]), to_double (context, vv [1]));
|
||||
out = atan2 (to_double (context, vv [0], 0), to_double (context, vv [1], 1));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2690,10 +2690,10 @@ substr_f (const ExpressionParserContext &context, tl::Variant &out, const std::v
|
|||
|
||||
long len = -1;
|
||||
if (vv.size () > 2) {
|
||||
len = std::max (long (0), to_long (context, vv [2]));
|
||||
len = std::max (long (0), to_long (context, vv [2], 2));
|
||||
}
|
||||
|
||||
long l = to_long (context, vv [1]);
|
||||
long l = to_long (context, vv [1], 1);
|
||||
if (l < 0) {
|
||||
l = long (s.size ()) + l;
|
||||
if (l < 0) {
|
||||
|
|
@ -2713,6 +2713,26 @@ substr_f (const ExpressionParserContext &context, tl::Variant &out, const std::v
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
upcase_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
||||
{
|
||||
if (vv.size () != 1) {
|
||||
throw EvalError (tl::to_string (tr ("'upcase' function expects one argument")), context);
|
||||
}
|
||||
|
||||
out = tl::to_upper_case (vv [0].to_string ());
|
||||
}
|
||||
|
||||
static void
|
||||
downcase_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
||||
{
|
||||
if (vv.size () != 1) {
|
||||
throw EvalError (tl::to_string (tr ("'upcase' function expects one argument")), context);
|
||||
}
|
||||
|
||||
out = tl::to_lower_case (vv [0].to_string ());
|
||||
}
|
||||
|
||||
static void
|
||||
join_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
||||
{
|
||||
|
|
@ -2752,7 +2772,7 @@ item_f (const ExpressionParserContext &context, tl::Variant &out, const std::vec
|
|||
throw EvalError (tl::to_string (tr ("First argument of 'item' function must be a list")), context);
|
||||
}
|
||||
|
||||
long index = to_long (context, vv [1]);
|
||||
long index = to_long (context, vv [1], 1);
|
||||
if (index < 0 || index >= long (vv [0].end () - vv [0].begin ())) {
|
||||
out = tl::Variant ();
|
||||
} else {
|
||||
|
|
@ -3042,6 +3062,8 @@ static EvalStaticFunction f55 ("file_exists", &file_exists_f);
|
|||
static EvalStaticFunction f56 ("is_dir", &is_dir_f);
|
||||
static EvalStaticFunction f57 ("combine", &combine_f);
|
||||
static EvalStaticFunction f58 ("abs", &abs_f);
|
||||
static EvalStaticFunction f59 ("upcase", &upcase_f);
|
||||
static EvalStaticFunction f60 ("downcase", &downcase_f);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Implementation of a constant wrapper
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "tlDeferredExecution.h"
|
||||
#include "tlObject.h"
|
||||
#include "tlTimer.h"
|
||||
#include "tlSleep.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
|
@ -447,9 +448,18 @@ InputHttpStreamPrivateData::read (char *b, size_t n)
|
|||
issue_request (QUrl (tl::to_qstring (m_url)));
|
||||
}
|
||||
|
||||
tl::Clock start_time = tl::Clock::current ();
|
||||
while (mp_reply == 0 && (m_timeout <= 0.0 || (tl::Clock::current() - start_time).seconds () < m_timeout)) {
|
||||
const unsigned long tick_ms = 10;
|
||||
double time_waited = 0.0;
|
||||
|
||||
while (mp_reply == 0 && (m_timeout <= 0.0 || time_waited < m_timeout)) {
|
||||
|
||||
mp_stream->tick ();
|
||||
|
||||
// NOTE: as tick() includes waiting for the password dialog, we must not include
|
||||
// the time spent there.
|
||||
tl::msleep (tick_ms);
|
||||
time_waited += tick_ms * 1e-3;
|
||||
|
||||
}
|
||||
|
||||
if (! mp_reply) {
|
||||
|
|
|
|||
|
|
@ -784,6 +784,10 @@ TEST(6)
|
|||
EXPECT_EQ (v.to_string (), std::string ("0"));
|
||||
v = e.parse ("rfind('abcabc','x')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("nil"));
|
||||
v = e.parse ("upcase('abcABC')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("ABCABC"));
|
||||
v = e.parse ("downcase('abcABC')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("abcabc"));
|
||||
v = e.parse ("len('abcabc')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("6"));
|
||||
v = e.parse ("len([])").execute ();
|
||||
|
|
@ -859,6 +863,14 @@ TEST(6)
|
|||
msg = ex.msg();
|
||||
}
|
||||
EXPECT_EQ (msg, std::string ("My error"));
|
||||
// argument index in error messages
|
||||
msg.clear ();
|
||||
try {
|
||||
v = e.parse ("substr('abcabc',2,'xyz')").execute ();
|
||||
} catch (tl::Exception &ex) {
|
||||
msg = ex.msg();
|
||||
}
|
||||
EXPECT_EQ (msg, std::string ("Integer value expected for argument #3 at position 0 (substr('abcabc',2,'x..)"));
|
||||
}
|
||||
|
||||
// compare ops
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
* Testing recursive call detection
|
||||
|
||||
.subckt c1 a b
|
||||
x1 a b c2
|
||||
.end
|
||||
|
||||
.subckt c2 a b
|
||||
x1 a b c1
|
||||
.ends
|
||||
|
||||
xtop vdd vss c2
|
||||
|
||||
.end
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
* Test: dismiss empty top level circuit
|
||||
|
||||
.subckt top a b
|
||||
m1 a b a b nmos
|
||||
.ends
|
||||
|
||||
* this triggered generation of a top level circuit
|
||||
.param p1 17
|
||||
|
||||
.end
|
||||
|
||||
|
|
@ -27,4 +27,6 @@ l1.drc(angle < 0.0).output(111, 0)
|
|||
l1.drc(primary.angle > 0.0).output(112, 0)
|
||||
l1.drc(primary.edges.angle == 90).output(113, 0)
|
||||
l1.drc((angle == 0.0) + (angle == 90)).output(114, 0)
|
||||
l1.drc(angle == 45).output(115, 0)
|
||||
l1.drc(angle(absolute) == 45).output(116, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ l1.drc(corners(as_boxes) == -90).output(102, 0) # outer corners
|
|||
l1.drc(corners(as_boxes) == 90).output(103, 0) # inner corners
|
||||
l1.drc(corners(as_boxes) <= -90).output(104, 0)
|
||||
l1.drc(corners(as_edge_pairs) == 90).output(105, 0)
|
||||
l1.drc(corners(as_boxes, absolute) == 90).output(106, 0) # inner and outer corners
|
||||
l1.drc(corners(as_boxes) != 90).output(107, 0) # not inner corners
|
||||
|
||||
l1.drc(middle).output(110, 0)
|
||||
l1.drc(middle(as_dots)).output(111, 0)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -14,10 +14,12 @@ end
|
|||
a1 = input(1)
|
||||
b1 = input(2)
|
||||
c1 = input(3)
|
||||
e1 = input(5)
|
||||
|
||||
a1.output(1, 0)
|
||||
b1.output(2, 0)
|
||||
c1.output(3, 0)
|
||||
e1.output(5, 0)
|
||||
|
||||
c1.rounded_corners(0.5, 0.5, 16).output(1010, 0)
|
||||
c1.smoothed(1.5).output(1011, 0)
|
||||
|
|
@ -70,6 +72,11 @@ a1.corners(-90.0, as_edge_pairs).polygons(0).output(1063, 0)
|
|||
a1.corners(-90.0, as_edge_pairs).first_edges.start_segments(0.1).extended(0.05, 0.05, 0.05, 0.05).output(1064, 0)
|
||||
a1.corners(-90.0, as_edge_pairs).second_edges.start_segments(0.1).extended(0.05, 0.05, 0.05, 0.05).output(1065, 0)
|
||||
|
||||
e1.corners(90.0, as_boxes).sized(0.05).output(1066, 0)
|
||||
e1.corners(90.0, absolute, as_boxes).sized(0.05).output(1067, 0)
|
||||
e1.corners(90.0, negative, as_boxes).sized(0.05).output(1068, 0)
|
||||
e1.corners(44.0 .. 46.0, absolute, as_boxes).sized(0.05).output(1069, 0)
|
||||
|
||||
a1.select { |p| p.bbox.width < 0.8 }.output(1100, 0)
|
||||
a1.collect { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1101, 0)
|
||||
a1.collect_to_region { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1102, 0)
|
||||
|
|
|
|||
|
|
@ -18,9 +18,13 @@ ep.without_distance(0.25, nil).polygons(0).output(121, 0)
|
|||
ep.with_angle(45.0).polygons(0).output(200, 0)
|
||||
ep.with_angle(0.0).polygons(0).output(201, 0)
|
||||
ep.with_angle(45.0..91.0).polygons(0).output(202, 0)
|
||||
ep.with_angle(45.0, absolute).polygons(0).output(203, 0)
|
||||
ep.with_angle(45.0..91.0, absolute).polygons(0).output(204, 0)
|
||||
ep.with_angle(45.0, 91.0, absolute).polygons(0).output(205, 0)
|
||||
ep.with_angle(45.0, both).polygons(0).output(210, 0)
|
||||
ep.with_angle(0.0, both).polygons(0).output(211, 0)
|
||||
ep.with_angle(45.0..91.0, both).polygons(0).output(212, 0)
|
||||
ep.with_angle(45.0..91.0, absolute, both).polygons(0).output(213, 0)
|
||||
|
||||
ep.without_angle(45.0).polygons(0).output(220, 0)
|
||||
ep.without_angle(0.0).polygons(0).output(221, 0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
r = input(1, 0)
|
||||
e = r.edges
|
||||
|
||||
r.output(1, 0)
|
||||
|
||||
r.with_angle(45.0).polygons(0).output(100, 0)
|
||||
r.with_angle(90.0).polygons(0).output(101, 0)
|
||||
r.with_angle(91.0..100.0).polygons(0).output(102, 0)
|
||||
|
||||
r.without_angle(45.0).polygons(0).output(120, 0)
|
||||
r.without_angle(90.0).polygons(0).output(121, 0)
|
||||
r.without_angle(45.0..100.0).polygons(0).output(122, 0)
|
||||
|
||||
e.with_angle(45.0).output(200, 0)
|
||||
e.with_angle(0.0).output(201, 0)
|
||||
e.with_angle(45.0..91.0).output(202, 0)
|
||||
e.with_angle(45.0, absolute).output(203, 0)
|
||||
e.with_angle(45.0..91.0, absolute).output(204, 0)
|
||||
e.with_angle(45.0, 91.0, absolute).output(205, 0)
|
||||
|
||||
e.without_angle(45.0).output(220, 0)
|
||||
e.without_angle(0.0).output(221, 0)
|
||||
e.without_angle(45.0..91.0).output(222, 0)
|
||||
e.without_angle(45.0, absolute).output(223, 0)
|
||||
e.without_angle(45.0..91.0, absolute).output(224, 0)
|
||||
e.without_angle(45.0, 91.0, absolute).output(225, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -294,6 +294,7 @@ class DBEdgePairs_TestClass < TestBase
|
|||
ep4 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 10, 10))
|
||||
|
||||
r1 = RBA::EdgePairs::new([ ep1, ep2, ep3, ep4 ])
|
||||
assert_equal(r1.with_angle(0, 90, false).to_s, "") # @@@
|
||||
|
||||
assert_equal(r1.with_distance(10, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_distance(5, 20, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
|
@ -310,15 +311,25 @@ class DBEdgePairs_TestClass < TestBase
|
|||
assert_equal(r1.with_length_both(10, true).to_s, "(0,0;0,20)/(10,20;10,0)")
|
||||
|
||||
assert_equal(r1.with_angle(0, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle(0, false).to_s, "")
|
||||
assert_equal(r1.with_angle(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(0, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle_both(0, false).to_s, "")
|
||||
assert_equal(r1.with_angle_both(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle_both(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle_both(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_angle_both(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle_both(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
||||
assert_equal(r1.with_area(0, false).to_s, "(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_area(150, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
|
|
|
|||
|
|
@ -585,12 +585,19 @@ class DBEdges_TestClass < TestBase
|
|||
r.insert(RBA::Edge::new(0, 0, 100, 0))
|
||||
r.insert(RBA::Edge::new(100, 0, 100, 50))
|
||||
assert_equal(r.with_angle(0, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_abs_angle(0, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_angle(0, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(0, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_angle(90, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(90, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_angle(90, true).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_abs_angle(90, true).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_angle(-10, 10, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_abs_angle(-10, 10, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_angle(-10, 10, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(-10, 10, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_angle(80, 100, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(80, 100, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_length(100, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_length(100, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_length(50, false).to_s, "(100,0;100,50)")
|
||||
|
|
|
|||
Loading…
Reference in New Issue