mirror of https://github.com/KLayout/klayout.git
More details control over verbosity of region ops
Plus: the region op control attributes (threads, min_coherence etc.) got lost when replacing the delegate of a region. Now they are maintained in most cases.
This commit is contained in:
parent
99f111fe01
commit
1ea687d7b7
|
|
@ -458,6 +458,9 @@ RegionDelegate *
|
|||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const
|
||||
{
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// shortcut
|
||||
if (empty ()) {
|
||||
|
|
@ -1055,6 +1058,9 @@ AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const
|
|||
} else {
|
||||
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -1132,6 +1138,9 @@ AsIfFlatRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
|||
|
||||
// Generic case - the size operation will merge first
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -1213,6 +1222,9 @@ AsIfFlatRegion::and_with (const Region &other) const
|
|||
|
||||
// Generic case
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -1267,6 +1279,9 @@ AsIfFlatRegion::not_with (const Region &other) const
|
|||
|
||||
// Generic case
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -1319,6 +1334,9 @@ AsIfFlatRegion::xor_with (const Region &other) const
|
|||
|
||||
// Generic case
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -1372,6 +1390,9 @@ AsIfFlatRegion::or_with (const Region &other) const
|
|||
|
||||
// Generic case
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
|
|||
|
|
@ -261,6 +261,9 @@ DeepRegion::ensure_merged_polygons_valid () const
|
|||
m_merged_polygons.clear ();
|
||||
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -347,6 +350,9 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
|
|||
db::BoolAndOrNotLocalOperation op (and_op);
|
||||
|
||||
db::LocalProcessor proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
if (base_verbosity ()) {
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ Edges::~Edges ()
|
|||
Edges &Edges::operator= (const Edges &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
set_delegate (other.mp_delegate->clone ());
|
||||
set_delegate (other.mp_delegate->clone (), false);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -100,9 +100,13 @@ Edges::iter () const
|
|||
}
|
||||
|
||||
void
|
||||
Edges::set_delegate (EdgesDelegate *delegate)
|
||||
Edges::set_delegate (EdgesDelegate *delegate, bool keep_attributes)
|
||||
{
|
||||
if (delegate != mp_delegate) {
|
||||
if (keep_attributes && mp_delegate && delegate) {
|
||||
// copy attributes (threads, min_coherence etc.) from old to new
|
||||
*delegate = *mp_delegate;
|
||||
}
|
||||
delete mp_delegate;
|
||||
mp_delegate = delegate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1268,7 +1268,7 @@ private:
|
|||
|
||||
EdgesDelegate *mp_delegate;
|
||||
|
||||
void set_delegate (EdgesDelegate *delegate);
|
||||
void set_delegate (EdgesDelegate *delegate, bool keep_attributes = true);
|
||||
FlatEdges *flat_edges ();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,9 @@ FlatRegion::ensure_merged_polygons_valid () const
|
|||
m_merged_polygons.clear ();
|
||||
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
@ -243,6 +246,9 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi
|
|||
invalidate_cache ();
|
||||
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
|
|||
|
|
@ -255,14 +255,17 @@ LocalProcessorCellContexts::create (const context_key_type &intruders)
|
|||
}
|
||||
|
||||
static void
|
||||
subtract (std::unordered_set<db::PolygonRef> &res, const std::unordered_set<db::PolygonRef> &other, db::Layout *layout, size_t max_vertex_count, double area_ratio)
|
||||
subtract (std::unordered_set<db::PolygonRef> &res, const std::unordered_set<db::PolygonRef> &other, db::Layout *layout, const db::LocalProcessor *proc)
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t max_vertex_count = proc->max_vertex_count ();
|
||||
double area_ratio = proc->area_ratio ();
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.set_base_verbosity (60);
|
||||
ep.set_base_verbosity (proc->base_verbosity () + 30);
|
||||
|
||||
size_t p1 = 0, p2 = 1;
|
||||
|
||||
|
|
@ -328,7 +331,7 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte
|
|||
|
||||
++index;
|
||||
|
||||
if (tl::verbosity () >= 50) {
|
||||
if (tl::verbosity () >= proc->base_verbosity () + 20) {
|
||||
tl::log << tr ("Computing local results for ") << cell->layout ()->cell_name (cell->cell_index ()) << " (context " << index << "/" << total << ")";
|
||||
}
|
||||
|
||||
|
|
@ -374,10 +377,10 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte
|
|||
|
||||
if (! lost.empty ()) {
|
||||
|
||||
subtract (lost, res, cell->layout (), proc->max_vertex_count (), proc->area_ratio ());
|
||||
subtract (lost, res, cell->layout (), proc);
|
||||
|
||||
if (! lost.empty ()) {
|
||||
subtract (common, lost, cell->layout (), proc->max_vertex_count (), proc->area_ratio ());
|
||||
subtract (common, lost, cell->layout (), proc);
|
||||
for (std::vector<std::pair<const context_key_type *, db::LocalProcessorCellContext *> >::const_iterator cc = sorted_contexts.begin (); cc != c; ++cc) {
|
||||
cc->second->propagate (lost);
|
||||
}
|
||||
|
|
@ -394,7 +397,7 @@ LocalProcessorCellContexts::compute_results (const LocalProcessorContexts &conte
|
|||
|
||||
if (! gained.empty ()) {
|
||||
|
||||
subtract (gained, common, cell->layout (), proc->max_vertex_count (), proc->area_ratio ());
|
||||
subtract (gained, common, cell->layout (), proc);
|
||||
|
||||
if (! gained.empty ()) {
|
||||
c->second->propagate (gained);
|
||||
|
|
@ -822,13 +825,13 @@ LocalProcessorResultComputationTask::perform ()
|
|||
// LocalProcessor implementation
|
||||
|
||||
LocalProcessor::LocalProcessor (db::Layout *layout, db::Cell *top)
|
||||
: mp_subject_layout (layout), mp_intruder_layout (layout), mp_subject_top (top), mp_intruder_top (top), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0)
|
||||
: mp_subject_layout (layout), mp_intruder_layout (layout), mp_subject_top (top), mp_intruder_top (top), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_base_verbosity (30)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
LocalProcessor::LocalProcessor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_top)
|
||||
: mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), mp_subject_top (subject_top), mp_intruder_top (intruder_top), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0)
|
||||
: mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), mp_subject_top (subject_top), mp_intruder_top (intruder_top), m_nthreads (0), m_max_vertex_count (0), m_area_ratio (0.0), m_base_verbosity (30)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -844,6 +847,8 @@ std::string LocalProcessor::description (const LocalOperation *op) const
|
|||
|
||||
void LocalProcessor::run (LocalOperation *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layer)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity, tl::to_string (tr ("Executing ")) + description (op));
|
||||
|
||||
LocalProcessorContexts contexts;
|
||||
compute_contexts (contexts, op, subject_layer, intruder_layer);
|
||||
compute_results (contexts, op, output_layer);
|
||||
|
|
@ -861,7 +866,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, const L
|
|||
{
|
||||
try {
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Computing contexts for ")) + description (op));
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 10, tl::to_string (tr ("Computing contexts for ")) + description (op));
|
||||
|
||||
if (m_nthreads > 0) {
|
||||
mp_cc_job.reset (new tl::Job<LocalProcessorContextComputationWorker> (m_nthreads));
|
||||
|
|
@ -916,7 +921,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts,
|
|||
{
|
||||
CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts)
|
||||
|
||||
if (tl::verbosity () >= 50) {
|
||||
if (tl::verbosity () >= m_base_verbosity + 20) {
|
||||
if (! subject_parent) {
|
||||
tl::log << tr ("Computing context for top cell ") << mp_subject_layout->cell_name (subject_cell->cell_index ());
|
||||
} else {
|
||||
|
|
@ -1114,7 +1119,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts,
|
|||
void
|
||||
LocalProcessor::compute_results (LocalProcessorContexts &contexts, const LocalOperation *op, unsigned int output_layer) const
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Computing results for ")) + description (op));
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 10, tl::to_string (tr ("Computing results for ")) + description (op));
|
||||
|
||||
// avoids updates while we work on the layout
|
||||
mp_subject_layout->update ();
|
||||
|
|
@ -1138,7 +1143,7 @@ LocalProcessor::compute_results (LocalProcessorContexts &contexts, const LocalOp
|
|||
while (true) {
|
||||
|
||||
++iter;
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::sprintf (tl::to_string (tr ("Computing results iteration #%d")), iter));
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 10, tl::sprintf (tl::to_string (tr ("Computing results iteration #%d")), iter));
|
||||
|
||||
bool any = false;
|
||||
std::unordered_set<db::cell_index_type> later;
|
||||
|
|
|
|||
|
|
@ -337,6 +337,16 @@ public:
|
|||
m_description = d;
|
||||
}
|
||||
|
||||
void set_base_verbosity (int vb)
|
||||
{
|
||||
m_base_verbosity = vb;
|
||||
}
|
||||
|
||||
int base_verbosity () const
|
||||
{
|
||||
return m_base_verbosity;
|
||||
}
|
||||
|
||||
void set_threads (unsigned int nthreads)
|
||||
{
|
||||
m_nthreads = nthreads;
|
||||
|
|
@ -379,6 +389,7 @@ private:
|
|||
unsigned int m_nthreads;
|
||||
size_t m_max_vertex_count;
|
||||
double m_area_ratio;
|
||||
int m_base_verbosity;
|
||||
mutable std::auto_ptr<tl::Job<LocalProcessorContextComputationWorker> > mp_cc_job;
|
||||
|
||||
std::string description (const LocalOperation *op) const;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
static const int layout_base_verbosity = 30;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// The undo/redo operations
|
||||
|
||||
|
|
@ -1278,7 +1280,7 @@ Layout::update () const
|
|||
void
|
||||
Layout::do_update ()
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Sorting")));
|
||||
tl::SelfTimer timer (tl::verbosity () > layout_base_verbosity, tl::to_string (tr ("Sorting")));
|
||||
|
||||
// establish a progress report since this operation can take some time.
|
||||
// HINT: because of some gcc bug, automatic destruction of the tl::Progress
|
||||
|
|
@ -1293,12 +1295,12 @@ Layout::do_update ()
|
|||
// the hierarchy management informations
|
||||
if (hier_dirty ()) {
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Updating relations");
|
||||
tl::SelfTimer timer (tl::verbosity () > layout_base_verbosity + 10, "Updating relations");
|
||||
pr->set_desc (tl::to_string (tr ("Updating relations")));
|
||||
update_relations ();
|
||||
}
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Topological sort");
|
||||
tl::SelfTimer timer (tl::verbosity () > layout_base_verbosity + 10, "Topological sort");
|
||||
pr->set_desc (tl::to_string (tr ("Topological sorting")));
|
||||
tl_assert (topological_sort ());
|
||||
}
|
||||
|
|
@ -1316,7 +1318,7 @@ Layout::do_update ()
|
|||
if (bboxes_dirty ()) {
|
||||
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Updating bounding boxes");
|
||||
tl::SelfTimer timer (tl::verbosity () > layout_base_verbosity + 10, "Updating bounding boxes");
|
||||
unsigned int layers = 0;
|
||||
pr->set (0);
|
||||
pr->set_desc (tl::to_string (tr ("Updating bounding boxes")));
|
||||
|
|
@ -1338,7 +1340,7 @@ Layout::do_update ()
|
|||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Sorting shapes");
|
||||
tl::SelfTimer timer (tl::verbosity () > layout_base_verbosity + 10, "Sorting shapes");
|
||||
pr->set (0);
|
||||
pr->set_desc (tl::to_string (tr ("Sorting shapes")));
|
||||
for (bottom_up_iterator c = begin_bottom_up (); c != end_bottom_up (); ++c) {
|
||||
|
|
@ -1351,7 +1353,7 @@ Layout::do_update ()
|
|||
|
||||
// sort the instance trees now, since we have computed the bboxes
|
||||
if (hier_dirty () || ! dirty_parents.empty ()) {
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Sorting instances");
|
||||
tl::SelfTimer timer (tl::verbosity () > layout_base_verbosity + 10, "Sorting instances");
|
||||
size_t layers = 0;
|
||||
pr->set (0);
|
||||
pr->set_desc (tl::to_string (tr ("Sorting instances")));
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
for (db::recursive_cluster_shape_iterator<shape_type> si (device_clusters, *l, *ci, *c); ! si.at_end(); ++si) {
|
||||
insert_into_region (*si, si.trans (), r);
|
||||
}
|
||||
r.set_base_verbosity (50);
|
||||
}
|
||||
|
||||
db::Box box;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ void NetlistDeviceExtractorMOS3Transistor::extract_devices (const std::vector<db
|
|||
continue;
|
||||
}
|
||||
|
||||
rgate.set_base_verbosity (50);
|
||||
db::Edges edges (rgate.edges () & rdiff2gate.edges ());
|
||||
if (edges.size () != 2) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Expected two edges interacting gate/diff (found %d) - width and length may be incorrect")), int (edges.size ())), *p);
|
||||
|
|
|
|||
|
|
@ -253,6 +253,9 @@ OriginalLayerRegion::ensure_merged_polygons_valid () const
|
|||
m_merged_polygons.clear ();
|
||||
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
if (base_verbosity ()) {
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
}
|
||||
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
|
|
|
|||
|
|
@ -595,6 +595,26 @@ public:
|
|||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the base verbosity
|
||||
*
|
||||
* Setting this value will make timing measurements appear at least at
|
||||
* the given verbosity level and more detailed timing at the given level
|
||||
* plus 10. The default level is 30.
|
||||
*/
|
||||
void set_base_verbosity (int vb)
|
||||
{
|
||||
mp_delegate->set_base_verbosity (vb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the base verbosity
|
||||
*/
|
||||
unsigned int base_verbosity () const
|
||||
{
|
||||
return mp_delegate->base_verbosity ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable progress reporting
|
||||
*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace db
|
|||
|
||||
RegionDelegate::RegionDelegate ()
|
||||
{
|
||||
m_base_verbosity = 0;
|
||||
m_report_progress = false;
|
||||
m_merged_semantics = true;
|
||||
m_strict_handling = false;
|
||||
|
|
@ -45,6 +46,7 @@ RegionDelegate &
|
|||
RegionDelegate::operator= (const RegionDelegate &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_base_verbosity = other.m_base_verbosity;
|
||||
m_report_progress = other.m_report_progress;
|
||||
m_merged_semantics = other.m_merged_semantics;
|
||||
m_strict_handling = other.m_strict_handling;
|
||||
|
|
@ -69,6 +71,11 @@ void RegionDelegate::disable_progress ()
|
|||
m_report_progress = false;
|
||||
}
|
||||
|
||||
void RegionDelegate::set_base_verbosity (int vb)
|
||||
{
|
||||
m_base_verbosity = vb;
|
||||
}
|
||||
|
||||
void RegionDelegate::set_min_coherence (bool f)
|
||||
{
|
||||
m_merge_min_coherence = f;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,12 @@ public:
|
|||
|
||||
virtual RegionDelegate *clone () const = 0;
|
||||
|
||||
void set_base_verbosity (int vb);
|
||||
int base_verbosity () const
|
||||
{
|
||||
return m_base_verbosity;
|
||||
}
|
||||
|
||||
void enable_progress (const std::string &progress_desc);
|
||||
void disable_progress ();
|
||||
|
||||
|
|
@ -200,6 +206,7 @@ private:
|
|||
bool m_merge_min_coherence;
|
||||
bool m_report_progress;
|
||||
std::string m_progress_desc;
|
||||
int m_base_verbosity;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2384,6 +2384,20 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"@brief Disable progress reporting\n"
|
||||
"Calling this method will disable progress reporting. See \\enable_progress.\n"
|
||||
) +
|
||||
method ("base_verbosity=", &db::Region::set_base_verbosity, gsi::arg ("verbosity"),
|
||||
"@brief Sets the minimum verbosity for timing reports\n"
|
||||
"Timing reports will be given only if the verbosity is larger than this value. "
|
||||
"Detailed reports will be given when the verbosity is more than this value plus 10.\n"
|
||||
"In binary operations, the base verbosity of the first argument is considered.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
) +
|
||||
method ("base_verbosity", &db::Region::base_verbosity,
|
||||
"@brief Gets the minimum verbosity for timing reports\n"
|
||||
"See \\base_verbosity= for details.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
) +
|
||||
method ("Euclidian", &euclidian_metrics,
|
||||
"@brief Specifies Euclidian metrics for the check functions\n"
|
||||
"This value can be used for the metrics parameter in the check functions, i.e. \\width_check. "
|
||||
|
|
|
|||
Loading…
Reference in New Issue