mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into wip2
This commit is contained in:
commit
476c7156ab
|
|
@ -128,6 +128,19 @@ size_t hash_value (const db::LayerProperties *l)
|
|||
return std::hfunc (*l);
|
||||
}
|
||||
|
||||
static bool log_equal_ext (const db::LayerProperties *lp1, const db::LayerProperties &lp2)
|
||||
{
|
||||
if (lp1->log_equal (lp2)) {
|
||||
return true;
|
||||
}
|
||||
// compare by name as fallback if one argument is named and the other is not
|
||||
// (this gives a way to look up
|
||||
if ((lp1->is_named () || lp2.is_named()) && ! lp1->name.empty () && ! lp2.name.empty ()) {
|
||||
return lp1->name == lp2.name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// since there already exists a "LayerProperties" object, we call this one "LayerInfo"
|
||||
Class<db::LayerProperties> decl_LayerInfo ("db", "LayerInfo",
|
||||
gsi::constructor ("new", &ctor_layer_info_default,
|
||||
|
|
@ -194,14 +207,31 @@ Class<db::LayerProperties> decl_LayerInfo ("db", "LayerInfo",
|
|||
"\n"
|
||||
"This method was added in version 0.18.\n"
|
||||
) +
|
||||
gsi::method ("is_equivalent?", &db::LayerProperties::log_equal, gsi::arg ("b"),
|
||||
gsi::method_ext ("is_equivalent?", &log_equal_ext, gsi::arg ("b"),
|
||||
"@brief Equivalence of two layer info objects\n"
|
||||
"@return True, if both are equivalent\n"
|
||||
"\n"
|
||||
"First, layer and datatype are compared. The name is of second order and used only if no layer or datatype is given.\n"
|
||||
"This is basically a weak comparison that reflects the search preferences.\n"
|
||||
"First, layer and datatype are compared. The name is of second order and used only if no layer or datatype is given "
|
||||
"for one of the operands.\n"
|
||||
"This is basically a weak comparison that reflects the search preferences. It is the basis for \\Layout#find_layer.\n"
|
||||
"Here are some examples:\n"
|
||||
"\n"
|
||||
"This method was added in version 0.18.\n"
|
||||
"@code\n"
|
||||
"# no match as layer/datatypes or names differ:\n"
|
||||
"RBA::LayerInfo::new(1, 17).is_equivalent?(RBA::LayerInfo::new(1, 18)) -> false\n"
|
||||
"RBA::LayerInfo::new('metal1').is_equivalent?(RBA::LayerInfo::new('m1')) -> false\n"
|
||||
"# exact match for numbered or named layers:\n"
|
||||
"RBA::LayerInfo::new(1, 17).is_equivalent?(RBA::LayerInfo::new(1, 17)) -> true\n"
|
||||
"RBA::LayerInfo::new('metal1').is_equivalent?(RBA::LayerInfo::new('metal1')) -> true\n"
|
||||
"# match as names are second priority over layer/datatypes:\n"
|
||||
"RBA::LayerInfo::new(1, 17, 'metal1').is_equivalent?(RBA::LayerInfo::new(1, 17, 'm1')) -> true\n"
|
||||
"# match as name matching is fallback:\n"
|
||||
"RBA::LayerInfo::new(1, 17, 'metal1').is_equivalent?(RBA::LayerInfo::new('metal1')) -> true\n"
|
||||
"# no match as neither names or layer/datatypes match:\n"
|
||||
"RBA::LayerInfo::new(1, 17, 'metal1').is_equivalent?(RBA::LayerInfo::new('m1')) -> false\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method was added in version 0.18 and modified to compare non-named vs. named layers in version 0.28.11.\n"
|
||||
) +
|
||||
gsi::method_ext ("hash", &hash_value,
|
||||
"@brief Computes a hash value\n"
|
||||
|
|
@ -504,9 +534,15 @@ static tl::Variant find_layer (db::Layout *l, const db::LayerProperties &lp)
|
|||
// for a null layer info always return nil
|
||||
return tl::Variant ();
|
||||
} else {
|
||||
// if we have a layer with the requested properties already, return this.
|
||||
// if we have a layer with the requested properties already, return this one.
|
||||
// first pass: exact match
|
||||
int index = l->get_layer_maybe (lp);
|
||||
if (index >= 0) {
|
||||
return tl::Variant ((unsigned int) index);
|
||||
}
|
||||
// second pass: relaxed match
|
||||
for (db::Layout::layer_iterator li = l->begin_layers (); li != l->end_layers (); ++li) {
|
||||
if ((*li).second->log_equal (lp)) {
|
||||
if (log_equal_ext ((*li).second, lp)) {
|
||||
return tl::Variant ((*li).first);
|
||||
}
|
||||
}
|
||||
|
|
@ -530,7 +566,7 @@ static tl::Variant find_layer3 (db::Layout *l, int ln, int dn, const std::string
|
|||
return find_layer (l, db::LayerProperties (ln, dn, name));
|
||||
}
|
||||
|
||||
static std::vector<unsigned int> layer_indices (const db::Layout *l)
|
||||
static std::vector<unsigned int> layer_indexes (const db::Layout *l)
|
||||
{
|
||||
std::vector<unsigned int> layers;
|
||||
for (unsigned int i = 0; i < l->layers (); ++i) {
|
||||
|
|
@ -1555,7 +1591,19 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"If a layer with the given properties already exists, this method will return the index of that layer."
|
||||
"If no such layer exists, it will return nil.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
"In contrast to \\layer, this method will also find layers matching by name only. "
|
||||
"For example:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# finds layer '17/0' and 'name (17/0)':\n"
|
||||
"index = layout.find_layer(RBA::LayerInfo::new(17, 0))\n"
|
||||
"# finds layer 'name' (first priority), but also 'name (17/0)' (second priority):\n"
|
||||
"index = layout.find_layer(RBA::LayerInfo::new('name'))\n"
|
||||
"# note that this will not match layer 'name (17/0)' and create a new name-only layer:\n"
|
||||
"index = layout.layer(RBA::LayerInfo::new('name'))\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23 and has been extended to name queries in version 0.28.11.\n"
|
||||
) +
|
||||
gsi::method_ext ("find_layer", &find_layer1, gsi::arg ("name"),
|
||||
"@brief Finds a layer with the given name\n"
|
||||
|
|
@ -1563,7 +1611,17 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"If a layer with the given name already exists, this method will return the index of that layer."
|
||||
"If no such layer exists, it will return nil.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
"In contrast to \\layer, this method will also find numbered layers if the name matches. "
|
||||
"For example:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# finds layer 'name' (first priority), but also 'name (17/0)' (second priority):\n"
|
||||
"index = layout.find_layer('name')\n"
|
||||
"# note that this will not match layer 'name (17/0)' and create a new name-only layer:\n"
|
||||
"index = layout.layer('name')\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23 and has been extended to name queries in version 0.28.11.\n"
|
||||
) +
|
||||
gsi::method_ext ("find_layer", &find_layer2, gsi::arg ("layer"), gsi::arg ("datatype"),
|
||||
"@brief Finds a layer with the given layer and datatype number\n"
|
||||
|
|
@ -1755,7 +1813,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"@param layer_index The index of the layer to delete.\n"
|
||||
) +
|
||||
gsi::method_ext ("layer_indexes|#layer_indices", &layer_indices,
|
||||
gsi::method_ext ("layer_indexes|#layer_indices", &layer_indexes,
|
||||
"@brief Gets a list of valid layer's indices\n"
|
||||
"This method returns an array with layer indices representing valid layers.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@
|
|||
#include "dbTilingProcessor.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QImage>
|
||||
#endif
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
|
|
@ -437,27 +441,22 @@ static ImageRef *new_image ()
|
|||
return new ImageRef ();
|
||||
}
|
||||
|
||||
static ImageRef *new_image_f (const std::string &filename)
|
||||
{
|
||||
return new ImageRef (img::Object (filename, db::DCplxTrans ()));
|
||||
}
|
||||
|
||||
static ImageRef *new_image_ft (const std::string &filename, const db::DCplxTrans &trans)
|
||||
{
|
||||
return new ImageRef (img::Object (filename, trans));
|
||||
}
|
||||
|
||||
/*
|
||||
static ImageRef *new_image_whc (size_t w, size_t h, bool color)
|
||||
static ImageRef *new_image_pbt (const tl::PixelBuffer &pixel_buffer, const db::DCplxTrans &trans)
|
||||
{
|
||||
return new ImageRef (img::Object (w, h, db::DCplxTrans (), color));
|
||||
return new ImageRef (img::Object (pixel_buffer, trans));
|
||||
}
|
||||
|
||||
static ImageRef *new_image_whtc (size_t w, size_t h, const db::DCplxTrans &trans, bool color)
|
||||
#if HAVE_QT
|
||||
static ImageRef *new_image_qit (const QImage &image, const db::DCplxTrans &trans)
|
||||
{
|
||||
return new ImageRef (img::Object (w, h, trans, color));
|
||||
return new ImageRef (img::Object (image, trans));
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
static ImageRef *new_image_whd (size_t w, size_t h, const std::vector<double> &data)
|
||||
{
|
||||
|
|
@ -576,17 +575,8 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
|
|||
"This will create an empty image without data and no particular pixel width or related.\n"
|
||||
"Use the \\read_file or \\set_data methods to set image properties and pixel values.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &gsi::new_image_f, gsi::arg ("filename"),
|
||||
"@brief Constructor from a image file \n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a file (which can have any format supported by Qt) and \n"
|
||||
"a unit transformation. The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
"will have a size of 1 (micron). \n"
|
||||
"\n"
|
||||
"@param filename The path to the image file to load.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &gsi::new_image_ft, gsi::arg ("filename"), gsi::arg ("trans"),
|
||||
"@brief Constructor from a image file \n"
|
||||
gsi::constructor ("new", &gsi::new_image_ft, gsi::arg ("filename"), gsi::arg ("trans", db::DCplxTrans (), "unity"),
|
||||
"@brief Constructor from a image file\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a file (which can have any format supported by Qt) and \n"
|
||||
"a transformation. The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
|
|
@ -595,6 +585,31 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
|
|||
"@param filename The path to the image file to load.\n"
|
||||
"@param trans The transformation to apply to the image when displaying it.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &gsi::new_image_pbt, gsi::arg ("pixels"), gsi::arg ("trans", db::DCplxTrans (), "unity"),
|
||||
"@brief Constructor from a image pixel buffer\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a pixel buffer object. This object holds RGB or mono image data similar to "
|
||||
"QImage, except it is available also when Qt is not available (e.g. inside the Python module).\n"
|
||||
"\n"
|
||||
"The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
"will have a size of 1. The transformation describes how to transform this image into micron space.\n"
|
||||
"\n"
|
||||
"@param filename The path to the image file to load.\n"
|
||||
"@param trans The transformation to apply to the image when displaying it.\n"
|
||||
) +
|
||||
#if defined(HAVE_QT)
|
||||
gsi::constructor ("new", &gsi::new_image_qit, gsi::arg ("image"), gsi::arg ("trans", db::DCplxTrans (), "unity"),
|
||||
"@brief Constructor from a image pixel buffer\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a pixel QImage object and uses RGB or mono image data to generate the image.\n"
|
||||
"\n"
|
||||
"The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
"will have a size of 1. The transformation describes how to transform this image into micron space.\n"
|
||||
"\n"
|
||||
"@param filename The path to the image file to load.\n"
|
||||
"@param trans The transformation to apply to the image when displaying it.\n"
|
||||
) +
|
||||
#endif
|
||||
gsi::constructor ("new", &gsi::new_image_whd, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("data"),
|
||||
"@brief Constructor for a monochrome image with the given pixel values\n"
|
||||
"\n"
|
||||
|
|
@ -624,39 +639,6 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
|
|||
"@param trans The transformation from pixel space to micron space\n"
|
||||
"@param d The data (see method description)\n"
|
||||
) +
|
||||
/* HINT: these declarations cannot be used currently since any array is case to the boolean color parameter
|
||||
gsi::constructor ("new", &img::new_image_whc, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("color"),
|
||||
"@brief Constructor for monochrome or color images with zero pixel values\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a data set describing one monochrome channel\n"
|
||||
"or three color channels.\n"
|
||||
"Each channel consists of an array of x*y values where the first \"x\" values describe the first (lowest!) row\n"
|
||||
"and so on. Note, that the rows are oriented in the mathematical sense (first one is the lowest) contrary to \n"
|
||||
"the common convention for image data.\n"
|
||||
"The data fields can be accessed with the \"data\", \"set_data\", \"pixel\" or \"set_pixel\" methods.\n"
|
||||
"Initially the pixel width and height will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
||||
"\n"
|
||||
"@param w The width of the image\n"
|
||||
"@param h The height of the image\n"
|
||||
"@param color True to create a color image.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &img::new_image_whtc, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("trans"), gsi::arg ("color"),
|
||||
"@brief Constructor for monochrome or color images with zero pixel values\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a data set describing one monochrome channel\n"
|
||||
"or three color channels.\n"
|
||||
"Each channel consists of an array of x*y values where the first \"x\" values describe the first (lowest!) row\n"
|
||||
"and so on. Note, that the rows are oriented in the mathematical sense (first one is the lowest) contrary to \n"
|
||||
"the common convention for image data.\n"
|
||||
"The data fields can be accessed with the \"data\", \"set_data\", \"pixel\" or \"set_pixel\" methods.\n"
|
||||
"Initially the pixel width and height will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
||||
"\n"
|
||||
"@param w The width of the image\n"
|
||||
"@param h The height of the image\n"
|
||||
"@param trans The transformation to apply to the image when displaying it\n"
|
||||
"@param color True to create a color image.\n"
|
||||
) +
|
||||
*/
|
||||
gsi::constructor ("new", &gsi::new_image_whrgb, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("red"), gsi::arg ("green"), gsi::arg ("blue"),
|
||||
"@brief Constructor for a color image with the given pixel values\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -851,6 +851,30 @@ Object::Object (const std::string &filename, const db::DCplxTrans &trans)
|
|||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
Object::Object (const tl::PixelBuffer &pixel_buffer, const db::DCplxTrans &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_pixel_buffer (pixel_buffer);
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
Object::Object (const QImage &qimage, const db::DCplxTrans &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_qimage (qimage);
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Object::Object (size_t w, size_t h, const db::Matrix3d &trans, bool color, bool byte_data)
|
||||
: m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
|
|
@ -934,6 +958,31 @@ Object::Object (const std::string &filename, const db::Matrix3d &trans)
|
|||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
Object::Object (const tl::PixelBuffer &pixel_buffer, const db::Matrix3d &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_pixel_buffer (pixel_buffer);
|
||||
read_file ();
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
Object::Object (const QImage &qimage, const db::Matrix3d &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_qimage (qimage);
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Object::Object (const img::Object &d)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
|
|
@ -1566,65 +1615,7 @@ Object::read_file ()
|
|||
#if defined(HAVE_QT)
|
||||
|
||||
QImage qimage (tl::to_qstring (m_filename));
|
||||
|
||||
if (! qimage.isNull ()) {
|
||||
|
||||
if (! m_min_value_set) {
|
||||
m_min_value = 0.0;
|
||||
}
|
||||
|
||||
if (! m_max_value_set) {
|
||||
m_max_value = 255.0;
|
||||
}
|
||||
|
||||
m_min_value_set = true;
|
||||
m_max_value_set = true;
|
||||
|
||||
size_t w = qimage.width (), h = qimage.height ();
|
||||
|
||||
mp_data = new DataHeader (w, h, ! qimage.isGrayscale (), true);
|
||||
mp_data->add_ref ();
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
if (is_color ()) {
|
||||
|
||||
unsigned char *red = mp_data->byte_data (0);
|
||||
unsigned char *green = mp_data->byte_data (1);
|
||||
unsigned char *blue = mp_data->byte_data (2);
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
red[i] = qRed (rgb);
|
||||
green[i] = qGreen (rgb);
|
||||
blue[i] = qBlue (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
unsigned char *d = mp_data->byte_data ();
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
*d++ = qGreen (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
create_from_qimage (qimage);
|
||||
|
||||
#elif defined(HAVE_PNG)
|
||||
|
||||
|
|
@ -1635,6 +1626,82 @@ Object::read_file ()
|
|||
img = tl::PixelBuffer::read_png (stream);
|
||||
}
|
||||
|
||||
create_from_pixel_buffer (img);
|
||||
|
||||
#else
|
||||
throw tl::Exception ("No PNG support compiled in - cannot load PNG files");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Object::create_from_qimage (const QImage &qimage)
|
||||
{
|
||||
if (qimage.isNull ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! m_min_value_set) {
|
||||
m_min_value = 0.0;
|
||||
}
|
||||
|
||||
if (! m_max_value_set) {
|
||||
m_max_value = 255.0;
|
||||
}
|
||||
|
||||
m_min_value_set = true;
|
||||
m_max_value_set = true;
|
||||
|
||||
size_t w = qimage.width (), h = qimage.height ();
|
||||
|
||||
mp_data = new DataHeader (w, h, ! qimage.isGrayscale (), true);
|
||||
mp_data->add_ref ();
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
if (is_color ()) {
|
||||
|
||||
unsigned char *red = mp_data->byte_data (0);
|
||||
unsigned char *green = mp_data->byte_data (1);
|
||||
unsigned char *blue = mp_data->byte_data (2);
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
red[i] = qRed (rgb);
|
||||
green[i] = qGreen (rgb);
|
||||
blue[i] = qBlue (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
unsigned char *d = mp_data->byte_data ();
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
*d++ = qGreen (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Object::create_from_pixel_buffer (const tl::PixelBuffer &img)
|
||||
{
|
||||
bool is_color = false;
|
||||
for (unsigned int i = 0; i < img.height () && ! is_color; ++i) {
|
||||
const tl::color_t *d = img.scan_line (i);
|
||||
|
|
@ -1700,10 +1767,6 @@ Object::read_file ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
throw tl::Exception ("No PNG support compiled in - cannot load PNG files");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef HDR_imgObject
|
||||
#define HDR_imgObject
|
||||
|
||||
|
|
@ -34,10 +33,15 @@
|
|||
#include "dbPolygon.h"
|
||||
#include "tlDataMapping.h"
|
||||
#include "tlColor.h"
|
||||
#include "tlPixelBuffer.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
class QImage;
|
||||
#endif
|
||||
|
||||
namespace img {
|
||||
|
||||
class DataHeader;
|
||||
|
|
@ -293,6 +297,26 @@ public:
|
|||
*/
|
||||
Object (const std::string &filename, const db::DCplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a PixelBuffer object
|
||||
*
|
||||
* This constructor creates an image object from a PixelBuffer object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const tl::PixelBuffer &pixel_buffer, const db::DCplxTrans &trans);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Constructor from a QImage object
|
||||
*
|
||||
* This constructor creates an image object from a QImage object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const QImage &image, const db::DCplxTrans &trans);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Constructor for monochrome or color images with zero pixel values
|
||||
*
|
||||
|
|
@ -418,6 +442,26 @@ public:
|
|||
*/
|
||||
Object (const std::string &filename, const db::Matrix3d &trans);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a PixelBuffer object
|
||||
*
|
||||
* This constructor creates an image object from a PixelBuffer object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const tl::PixelBuffer &pixel_buffer, const db::Matrix3d &trans);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Constructor from a QImage object
|
||||
*
|
||||
* This constructor creates an image object from a QImage object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const QImage &image, const db::Matrix3d &trans);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
|
|
@ -984,6 +1028,10 @@ private:
|
|||
void validate_pixel_data () const;
|
||||
void allocate (bool color);
|
||||
void read_file ();
|
||||
#if defined(HAVE_QT)
|
||||
void create_from_qimage (const QImage &qimage);
|
||||
#endif
|
||||
void create_from_pixel_buffer (const tl::PixelBuffer &img);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/run_16px.png</normaloff>:/run_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
|
|
@ -480,27 +480,6 @@
|
|||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="5">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6">
|
||||
<widget class="QToolButton" name="photo_pb">
|
||||
<property name="toolTip">
|
||||
<string>Add snapshot</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Photo</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/photo_16px.png</normaloff>:/photo_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="waive_pb">
|
||||
<property name="toolTip">
|
||||
|
|
@ -515,40 +494,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="flags_pb">
|
||||
<property name="toolTip">
|
||||
<string>Set or reset flag</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Flag</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::MenuButtonPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QToolButton" name="important_pb">
|
||||
<property name="toolTip">
|
||||
<string>Important</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Imp</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/important_16px.png</normaloff>:/important_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<widget class="QToolButton" name="nophoto_pb">
|
||||
<property name="toolTip">
|
||||
|
|
@ -566,6 +511,54 @@ p, li { white-space: pre-wrap; }
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="flags_pb">
|
||||
<property name="toolTip">
|
||||
<string>Set or reset flag</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Flag</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::MenuButtonPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6">
|
||||
<widget class="QToolButton" name="photo_pb">
|
||||
<property name="toolTip">
|
||||
<string>Add snapshot</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Photo</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/photo_16px.png</normaloff>:/photo_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QToolButton" name="important_pb">
|
||||
<property name="toolTip">
|
||||
<string>Important</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Imp</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/important_16px.png</normaloff>:/important_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="7">
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -612,6 +605,63 @@ p, li { white-space: pre-wrap; }
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="7">
|
||||
<widget class="QFrame" name="frame_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="list_shapes_cb">
|
||||
<property name="text">
|
||||
<string>list shapes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace rdb
|
|||
|
||||
std::string cfg_rdb_context_mode ("rdb-context-mode");
|
||||
std::string cfg_rdb_show_all ("rdb-show-all");
|
||||
std::string cfg_rdb_list_shapes ("rdb-list-shapes");
|
||||
std::string cfg_rdb_window_state ("rdb-window-state-v2"); // v2: 0.24++
|
||||
std::string cfg_rdb_window_mode ("rdb-window-mode");
|
||||
std::string cfg_rdb_window_dim ("rdb-window-dim");
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ namespace rdb
|
|||
|
||||
extern std::string cfg_rdb_context_mode;
|
||||
extern std::string cfg_rdb_show_all;
|
||||
extern std::string cfg_rdb_list_shapes;
|
||||
extern std::string cfg_rdb_window_state;
|
||||
extern std::string cfg_rdb_window_mode;
|
||||
extern std::string cfg_rdb_window_dim;
|
||||
|
|
@ -445,6 +446,7 @@ MarkerBrowserDialog::configure (const std::string &name, const std::string &valu
|
|||
bool need_update = false;
|
||||
bool taken = true;
|
||||
bool show_all = mp_ui->browser_frame->show_all ();
|
||||
bool list_shapes = mp_ui->browser_frame->list_shapes ();
|
||||
|
||||
if (name == cfg_rdb_context_mode) {
|
||||
|
||||
|
|
@ -452,6 +454,10 @@ MarkerBrowserDialog::configure (const std::string &name, const std::string &valu
|
|||
MarkerBrowserContextModeConverter ().from_string (value, context);
|
||||
need_update = lay::test_and_set (m_context, context);
|
||||
|
||||
} else if (name == cfg_rdb_list_shapes) {
|
||||
|
||||
tl::from_string (value, list_shapes);
|
||||
|
||||
} else if (name == cfg_rdb_show_all) {
|
||||
|
||||
tl::from_string (value, show_all);
|
||||
|
|
@ -540,6 +546,7 @@ MarkerBrowserDialog::configure (const std::string &name, const std::string &valu
|
|||
}
|
||||
|
||||
mp_ui->browser_frame->show_all (show_all);
|
||||
mp_ui->browser_frame->list_shapes (list_shapes);
|
||||
|
||||
return taken;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ namespace rdb
|
|||
{
|
||||
|
||||
extern std::string cfg_rdb_show_all;
|
||||
extern std::string cfg_rdb_list_shapes;
|
||||
|
||||
struct FlagDescriptor
|
||||
{
|
||||
|
|
@ -1447,6 +1448,7 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/)
|
|||
m_update_needed (false),
|
||||
mp_database (0),
|
||||
m_show_all (true),
|
||||
m_list_shapes (true),
|
||||
mp_view (0),
|
||||
m_cv_index (0),
|
||||
m_num_items (0),
|
||||
|
|
@ -1504,6 +1506,8 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/)
|
|||
markers_list->header ()->setSortIndicatorShown (true);
|
||||
markers_list->header ()->setMinimumSectionSize (24);
|
||||
|
||||
list_shapes_cb->setChecked (m_list_shapes);
|
||||
|
||||
connect (markers_list, SIGNAL (doubleClicked (const QModelIndex &)), this, SLOT (marker_double_clicked (const QModelIndex &)));
|
||||
|
||||
connect (dir_up_pb, SIGNAL (clicked ()), this, SLOT (dir_up_clicked ()));
|
||||
|
|
@ -1519,6 +1523,7 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/)
|
|||
connect (cat_filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ()));
|
||||
connect (cell_filter, SIGNAL (textEdited (const QString &)), this, SLOT (filter_changed ()));
|
||||
connect (rerun_button, SIGNAL (pressed ()), this, SLOT (rerun_button_pressed ()));
|
||||
connect (list_shapes_cb, SIGNAL (clicked ()), this, SLOT (list_shapes_clicked ()));
|
||||
|
||||
m_show_all_action = new QAction (QObject::tr ("Show All"), this);
|
||||
m_show_all_action->setCheckable (true);
|
||||
|
|
@ -1674,7 +1679,20 @@ MarkerBrowserPage::show_all (bool f)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MarkerBrowserPage::list_shapes (bool f)
|
||||
{
|
||||
if (f != m_list_shapes) {
|
||||
|
||||
m_list_shapes = f;
|
||||
list_shapes_cb->setChecked (f);
|
||||
|
||||
update_info_text ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserPage::set_rdb (rdb::Database *database)
|
||||
{
|
||||
if (database != mp_database) {
|
||||
|
|
@ -1975,7 +1993,7 @@ MarkerBrowserPage::update_info_text ()
|
|||
|
||||
for (rdb::Values::const_iterator v = item->values ().begin (); v != item->values ().end (); ++v) {
|
||||
|
||||
if (v->get () != 0) {
|
||||
if (v->get () != 0 && (m_list_shapes || ! v->get ()->is_shape ())) {
|
||||
|
||||
if (v->tag_id () != 0) {
|
||||
const rdb::Tag &tag = mp_database->tags ().tag (v->tag_id ());
|
||||
|
|
@ -2851,7 +2869,15 @@ MarkerBrowserPage::show_all_clicked ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MarkerBrowserPage::list_shapes_clicked ()
|
||||
{
|
||||
if (mp_plugin_root) {
|
||||
mp_plugin_root->config_set (cfg_rdb_list_shapes, tl::to_string (list_shapes_cb->isChecked ()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserPage::unwaive_all ()
|
||||
{
|
||||
if (! mp_database) {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,21 @@ public:
|
|||
*/
|
||||
void show_all (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether to list the shapes in the info panel
|
||||
*/
|
||||
bool list_shapes () const
|
||||
{
|
||||
return m_list_shapes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether to list the shapes in the info panel
|
||||
*
|
||||
* If this property is set to false, shapes will not be listed in the info panel.
|
||||
*/
|
||||
void list_shapes (bool f);
|
||||
|
||||
/**
|
||||
* @brief Update the contents
|
||||
*
|
||||
|
|
@ -176,6 +191,7 @@ public slots:
|
|||
void waive ();
|
||||
void unwaive ();
|
||||
void show_all_clicked ();
|
||||
void list_shapes_clicked ();
|
||||
void info_anchor_clicked (const QUrl &link);
|
||||
void filter_changed ();
|
||||
|
||||
|
|
@ -184,6 +200,7 @@ private:
|
|||
bool m_update_needed;
|
||||
rdb::Database *mp_database;
|
||||
bool m_show_all;
|
||||
bool m_list_shapes;
|
||||
QAction *m_show_all_action;
|
||||
lay::LayoutViewBase *mp_view;
|
||||
unsigned int m_cv_index;
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ void Macro::save_to (const std::string &path)
|
|||
void Macro::load_from (const std::string &fn)
|
||||
{
|
||||
m_format = NoFormat;
|
||||
m_interpreter = None;
|
||||
|
||||
std::pair<bool, std::string> f = format_from_filename (fn, m_interpreter, m_dsl_interpreter, m_autorun_default, m_format);
|
||||
if (f.first) {
|
||||
|
|
@ -252,12 +253,23 @@ void Macro::load_from (const std::string &fn)
|
|||
tl::InputStream stream (path);
|
||||
tl::TextInputStream text_stream (stream);
|
||||
m_text = text_stream.read_all ();
|
||||
sync_properties_with_text ();
|
||||
|
||||
if (m_format == PlainTextWithHashAnnotationsFormat) {
|
||||
sync_properties_with_text ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Unable to determine format for file from suffix or format spec ")) + fn);
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Loading macro from " << fn;
|
||||
}
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
tl::TextInputStream text_stream (stream);
|
||||
m_text = text_stream.read_all ();
|
||||
|
||||
}
|
||||
|
||||
m_modified = true;
|
||||
|
|
@ -268,6 +280,7 @@ void Macro::load_from (const std::string &fn)
|
|||
void Macro::load_from_string (const std::string &text, const std::string &url)
|
||||
{
|
||||
m_format = NoFormat;
|
||||
m_interpreter = None;
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Loading macro from " << url;
|
||||
|
|
@ -294,7 +307,7 @@ void Macro::load_from_string (const std::string &text, const std::string &url)
|
|||
}
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Unable to determine format for file from suffix ")) + url);
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
m_modified = true;
|
||||
|
|
|
|||
|
|
@ -51,11 +51,35 @@ MacroInterpreter::can_run (const lym::Macro *macro)
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class MacroIncludeFileResolver
|
||||
: public tl::IncludeFileResolver
|
||||
{
|
||||
public:
|
||||
MacroIncludeFileResolver () { }
|
||||
|
||||
std::string get_text (const std::string &path) const
|
||||
{
|
||||
// Use lym::Macro to resolve texts - this strips the XML envelope.
|
||||
// Intentionally not compatibility check is made to allow using any
|
||||
// type of input and specifically any extension.
|
||||
lym::Macro macro;
|
||||
macro.load_from (path);
|
||||
return macro.text ();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
MacroInterpreter::include_expansion (const lym::Macro *macro)
|
||||
{
|
||||
MacroIncludeFileResolver include_file_resolver;
|
||||
|
||||
std::pair<std::string, std::string> res;
|
||||
res.first = tl::IncludeExpander::expand (macro->path (), macro->text (), res.second).to_string ();
|
||||
res.first = tl::IncludeExpander::expand (macro->path (), macro->text (), res.second, &include_file_resolver).to_string ();
|
||||
|
||||
if (res.first != macro->path ()) {
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,29 @@ TEST(3_RubyInclude)
|
|||
EXPECT_EQ (np (console.text ()), np ("An error in " + tl::testsrc () + "/testdata/lym/b_inc.rb:3\n"));
|
||||
}
|
||||
|
||||
TEST(4_RubyIncludeFromXML)
|
||||
{
|
||||
tl_assert (rba::RubyInterpreter::instance () != 0);
|
||||
|
||||
lym::Macro macro;
|
||||
|
||||
macro.set_file_path (tl::testsrc () + "/testdata/lym/m4.rb");
|
||||
macro.set_interpreter (lym::Macro::Ruby);
|
||||
macro.load ();
|
||||
|
||||
TestCollectorConsole console;
|
||||
rba::RubyInterpreter::instance ()->push_console (&console);
|
||||
try {
|
||||
EXPECT_EQ (macro.run (), 0);
|
||||
rba::RubyInterpreter::instance ()->remove_console (&console);
|
||||
} catch (...) {
|
||||
rba::RubyInterpreter::instance ()->remove_console (&console);
|
||||
throw;
|
||||
}
|
||||
|
||||
EXPECT_EQ (np (console.text ()), np ("An error in " + tl::testsrc () + "/testdata/lym/b_inc.lym:3\n"));
|
||||
}
|
||||
|
||||
TEST(11_DRCBasic)
|
||||
{
|
||||
tl_assert (rba::RubyInterpreter::instance () != 0);
|
||||
|
|
|
|||
|
|
@ -588,9 +588,6 @@ DEFImporter::read_single_net (std::string &nondefaultrule, Layout &layout, db::C
|
|||
error (tl::to_string (tr ("RECT routing specification not followed by coordinate list")));
|
||||
}
|
||||
|
||||
// breaks wiring
|
||||
pts.clear ();
|
||||
|
||||
// rect spec
|
||||
|
||||
double x1 = get_double ();
|
||||
|
|
|
|||
|
|
@ -986,3 +986,9 @@ TEST(207_joined_paths)
|
|||
run_test (_this, "issue-1345", "lef:in.lef+def:in.def", "au-nojoin.oas.gz", default_options (), false);
|
||||
}
|
||||
|
||||
// issue-1432
|
||||
TEST(208_nets_and_rects)
|
||||
{
|
||||
run_test (_this, "issue-1432", "map:test.map+lef:test.lef+def:test.def", "au.oas", default_options (), false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,49 @@ template <> RDB_PUBLIC std::string Value<db::DText>::to_display_string () const
|
|||
return to_string ();
|
||||
}
|
||||
|
||||
// is_shape implementations
|
||||
|
||||
template <> RDB_PUBLIC bool Value<double>::is_shape () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<std::string>::is_shape () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DPolygon>::is_shape () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DEdge>::is_shape () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DEdgePair>::is_shape () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DBox>::is_shape () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DPath>::is_shape () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DText>::is_shape () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ValueBase::compare (const ValueBase *a, const ValueBase *b)
|
||||
{
|
||||
// compare is the intrinsic compare of equal type and type index for different types.
|
||||
|
|
|
|||
|
|
@ -438,6 +438,8 @@ public:
|
|||
|
||||
virtual std::string to_display_string () const = 0;
|
||||
|
||||
virtual bool is_shape () const = 0;
|
||||
|
||||
virtual ValueBase *clone () const = 0;
|
||||
|
||||
virtual int type_index () const = 0;
|
||||
|
|
@ -508,6 +510,8 @@ public:
|
|||
return m_value < static_cast<const Value<C> *> (other)->m_value;
|
||||
}
|
||||
|
||||
bool is_shape () const;
|
||||
|
||||
std::string to_string () const;
|
||||
|
||||
std::string to_display_string () const;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
namespace tl
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// IncludeExpander implementation
|
||||
|
||||
static const char *valid_fn_chars = "@_:,.\\/-+";
|
||||
|
||||
IncludeExpander::IncludeExpander ()
|
||||
|
|
@ -40,30 +43,30 @@ IncludeExpander::IncludeExpander ()
|
|||
}
|
||||
|
||||
IncludeExpander
|
||||
IncludeExpander::expand (const std::string &path, std::string &expanded_text)
|
||||
IncludeExpander::expand (const std::string &path, std::string &expanded_text, const IncludeFileResolver *resolver)
|
||||
{
|
||||
IncludeExpander ie;
|
||||
int lc = 1;
|
||||
tl::InputStream is (path);
|
||||
ie.read (path, is, expanded_text, ie, lc);
|
||||
ie.read (path, is, expanded_text, lc, resolver);
|
||||
return ie;
|
||||
}
|
||||
|
||||
IncludeExpander
|
||||
IncludeExpander::expand (const std::string &path, const std::string &original_text, std::string &expanded_text)
|
||||
IncludeExpander::expand (const std::string &path, const std::string &original_text, std::string &expanded_text, const IncludeFileResolver *resolver)
|
||||
{
|
||||
IncludeExpander ie;
|
||||
int lc = 1;
|
||||
tl::InputMemoryStream ms (original_text.c_str (), original_text.size ());
|
||||
tl::InputStream is (ms);
|
||||
ie.read (path, is, expanded_text, ie, lc);
|
||||
ie.read (path, is, expanded_text, lc, resolver);
|
||||
return ie;
|
||||
}
|
||||
|
||||
void
|
||||
IncludeExpander::read (const std::string &path, tl::InputStream &is, std::string &expanded_text, IncludeExpander &ie, int &line_counter)
|
||||
IncludeExpander::read (const std::string &path, tl::InputStream &is, std::string &expanded_text, int &line_counter, const IncludeFileResolver *resolver)
|
||||
{
|
||||
ie.m_sections [line_counter] = std::make_pair (path, 1 - line_counter);
|
||||
m_sections [line_counter] = std::make_pair (path, 1 - line_counter);
|
||||
|
||||
tl::TextInputStream text (is);
|
||||
|
||||
|
|
@ -100,8 +103,17 @@ IncludeExpander::read (const std::string &path, tl::InputStream &is, std::string
|
|||
include_path = current_uri.resolved (new_uri).to_abstract_path ();
|
||||
}
|
||||
|
||||
tl::InputStream is (include_path);
|
||||
read (include_path, is, expanded_text, ie, line_counter);
|
||||
std::string include_text;
|
||||
if (resolver) {
|
||||
include_text = resolver->get_text (include_path);
|
||||
} else {
|
||||
tl::InputStream iis (include_path);
|
||||
include_text = iis.read_all ();
|
||||
}
|
||||
|
||||
tl::InputMemoryStream ms (include_text.c_str (), include_text.size ());
|
||||
tl::InputStream is (ms);
|
||||
read (include_path, is, expanded_text, line_counter, resolver);
|
||||
|
||||
emit_section = true;
|
||||
|
||||
|
|
@ -109,7 +121,7 @@ IncludeExpander::read (const std::string &path, tl::InputStream &is, std::string
|
|||
|
||||
if (emit_section) {
|
||||
emit_section = false;
|
||||
ie.m_sections [line_counter] = std::make_pair (path, lnum - line_counter);
|
||||
m_sections [line_counter] = std::make_pair (path, lnum - line_counter);
|
||||
}
|
||||
|
||||
expanded_text += l;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,21 @@ namespace tl
|
|||
|
||||
class InputStream;
|
||||
|
||||
/**
|
||||
* @brief An interface providing the include file resolver
|
||||
*
|
||||
* The task of this object is to obtain the text for an include file path.
|
||||
* The path already underwent variable interpolation and relative path resolution.
|
||||
*/
|
||||
class TL_PUBLIC IncludeFileResolver
|
||||
{
|
||||
public:
|
||||
IncludeFileResolver () { }
|
||||
virtual ~IncludeFileResolver () { }
|
||||
|
||||
virtual std::string get_text (const std::string &path) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provide the basic include expansion and file/line mapping mechanism
|
||||
*
|
||||
|
|
@ -59,7 +74,7 @@ public:
|
|||
*
|
||||
* This method will deliver the expanded text and the include expander object.
|
||||
*/
|
||||
static IncludeExpander expand (const std::string &path, std::string &expanded_text);
|
||||
static IncludeExpander expand (const std::string &path, std::string &expanded_text, const IncludeFileResolver *resolver = 0);
|
||||
|
||||
/**
|
||||
* @brief Provides include expansion
|
||||
|
|
@ -67,7 +82,7 @@ public:
|
|||
* This method will deliver the expanded text and the include expander object.
|
||||
* This version also takes the actual text of the original file.
|
||||
*/
|
||||
static IncludeExpander expand (const std::string &path, const std::string &original_text, std::string &expanded_text);
|
||||
static IncludeExpander expand (const std::string &path, const std::string &original_text, std::string &expanded_text, const IncludeFileResolver *resolver = 0);
|
||||
|
||||
/**
|
||||
* @brief Serializes the include expander information into a string
|
||||
|
|
@ -98,7 +113,7 @@ public:
|
|||
private:
|
||||
std::map<int, std::pair<std::string, int> > m_sections;
|
||||
|
||||
void read (const std::string &path, tl::InputStream &is, std::string &expanded_text, IncludeExpander &ie, int &line_counter);
|
||||
void read (const std::string &path, tl::InputStream &is, std::string &expanded_text, int &line_counter, const IncludeFileResolver *mp_resolver);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,8 @@
|
|||
VERSION 5.8 ;
|
||||
DESIGN test ;
|
||||
UNITS DISTANCE MICRONS 1000 ;
|
||||
DIEAREA ( -1 -1 ) ( 8 8 ) ;
|
||||
NETS 1 ;
|
||||
- dummy + ROUTED M1 ( 0 0 ) ( 5 0 ) VIRTUAL ( 7 1 ) RECT ( -3 0 -1 2 ) ( 7 7 ) ;
|
||||
END NETS
|
||||
END DESIGN
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
UNITS
|
||||
DATABASE MICRONS 1000 ;
|
||||
END UNITS
|
||||
|
||||
MANUFACTURINGGRID 0.001 ;
|
||||
|
||||
LAYER M1
|
||||
TYPE ROUTING ;
|
||||
WIDTH 0.002 ;
|
||||
END M1
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
DIEAREA ALL 108 0
|
||||
M1 NET 31 0
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<priority>0</priority>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
def f
|
||||
raise("An error")
|
||||
end
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
# %include b_inc.lym
|
||||
|
||||
begin
|
||||
puts f
|
||||
rescue => ex
|
||||
ln = ex.backtrace[0].split(":")
|
||||
# NOTE: as the backtrace is a native Ruby feature, include file translation
|
||||
# does not happen. We need to do this explicitly here:
|
||||
puts ex.to_s + " in " + RBA::Macro::real_path(ln[0], ln[1].to_i) + ":" + RBA::Macro::real_line(ln[0], ln[1].to_i).to_s
|
||||
end
|
||||
|
||||
|
|
@ -64,16 +64,38 @@ class DBLayoutTests1_TestClass < TestBase
|
|||
assert_equal(l3.anonymous?, false)
|
||||
assert_equal(l3.is_named?, true)
|
||||
assert_equal(l3.is_equivalent?(l2), false)
|
||||
l3.layer = 1
|
||||
l3.datatype = 100
|
||||
assert_equal(l3.is_named?, false)
|
||||
assert_equal(l3.is_equivalent?(l2), true)
|
||||
assert_equal(l2.is_equivalent?(l3), false)
|
||||
l4 = RBA::LayerInfo::new(1, 100, "aber")
|
||||
assert_equal(l4.to_s, "aber (1/100)")
|
||||
assert_equal(l4.anonymous?, false)
|
||||
assert_equal(l4.is_named?, false)
|
||||
assert_equal(l4.is_equivalent?(l2), true)
|
||||
assert_equal(l2.is_equivalent?(l4), true)
|
||||
assert_equal(l4.is_equivalent?(l3), true)
|
||||
assert_equal(l3.is_equivalent?(l4), true)
|
||||
assert_equal(l4.is_equivalent?(RBA::LayerInfo::new(1, 100, "xyz")), true)
|
||||
assert_equal(l4.is_equivalent?(RBA::LayerInfo::new(1, 101, "aber")), false)
|
||||
|
||||
l1.assign(l4)
|
||||
|
||||
l1.assign(l3)
|
||||
assert_equal(l1.to_s, "aber (1/100)")
|
||||
assert_equal(l1.is_named?, false)
|
||||
assert_equal(l1.is_equivalent?(l3), true)
|
||||
assert_equal(l1 == l3, true)
|
||||
assert_equal(l1.is_equivalent?(l4), true)
|
||||
assert_equal(l1 == l4, true)
|
||||
|
||||
l1.layer = -1
|
||||
l1.datatype = -1
|
||||
assert_equal(l1.is_named?, true)
|
||||
assert_equal(l1.to_s, "aber")
|
||||
|
||||
l1.name = "xyz"
|
||||
assert_equal(l1.is_named?, true)
|
||||
assert_equal(l1.to_s, "xyz")
|
||||
|
||||
l1.layer = 100
|
||||
l1.datatype = 0
|
||||
assert_equal(l1.is_named?, false)
|
||||
assert_equal(l1.to_s, "xyz (100/0)")
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -164,16 +186,50 @@ class DBLayoutTests1_TestClass < TestBase
|
|||
assert_equal(a, nil)
|
||||
a = ly.find_layer(RBA::LayerInfo.new(2, 0))
|
||||
assert_equal(a, li)
|
||||
a = ly.find_layer(3, 0, "hallo")
|
||||
assert_equal(a, nil)
|
||||
li2 = ly.layer("hallo")
|
||||
a = ly.find_layer("hillo")
|
||||
assert_equal(a, nil)
|
||||
a = ly.find_layer("hallo")
|
||||
assert_equal(a, li2)
|
||||
a = ly.find_layer(3, 0, "hallo")
|
||||
assert_equal(a, nil)
|
||||
assert_equal(a, li2)
|
||||
a = ly.find_layer(2, 0, "hallo")
|
||||
assert_equal(a, li)
|
||||
|
||||
ly = RBA::Layout.new
|
||||
li = ly.layer(2, 0, "hallo")
|
||||
a = ly.find_layer(3, 0)
|
||||
assert_equal(a, nil)
|
||||
a = ly.find_layer(2, 0)
|
||||
assert_equal(a, li)
|
||||
a = ly.find_layer("hallo")
|
||||
assert_equal(a, li)
|
||||
a = ly.find_layer(2, 0, "hillo")
|
||||
assert_equal(a, li)
|
||||
a = ly.find_layer(1, 0, "hallo")
|
||||
assert_equal(a, nil)
|
||||
|
||||
ly = RBA::Layout.new
|
||||
li0 = ly.layer("hello")
|
||||
li = ly.layer("hallo")
|
||||
a = ly.find_layer(3, 0)
|
||||
assert_equal(a, nil)
|
||||
a = ly.find_layer(2, 0)
|
||||
assert_equal(a, nil)
|
||||
a = ly.find_layer("hallo")
|
||||
assert_equal(a, li)
|
||||
a = ly.find_layer(2, 0, "hillo")
|
||||
assert_equal(a, nil)
|
||||
a = ly.find_layer(1, 0, "hallo")
|
||||
assert_equal(a, li)
|
||||
li2 = ly.layer(1, 0, "hello")
|
||||
a = ly.find_layer(1, 0, "hello")
|
||||
assert_equal(a, li2)
|
||||
a = ly.find_layer("hello")
|
||||
assert_equal(a, li0)
|
||||
|
||||
end
|
||||
|
||||
def collect(s, l)
|
||||
|
|
|
|||
|
|
@ -415,6 +415,38 @@ class IMG_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# Construction from PixelBuffer
|
||||
def test_6
|
||||
|
||||
fn = ENV["TESTSRC"] + "/testdata/img/gs.png"
|
||||
pb = RBA::PixelBuffer::read_png(fn)
|
||||
|
||||
image = RBA::Image.new(pb)
|
||||
assert_equal(image.trans.to_s, "r0 *1 -513.5,-349")
|
||||
|
||||
assert_equal(image.width, 1027)
|
||||
assert_equal(image.height, 698)
|
||||
|
||||
end
|
||||
|
||||
# Construction from QImage
|
||||
def test_7
|
||||
|
||||
if RBA.constants.find { |x| x == :QImage }
|
||||
|
||||
fn = ENV["TESTSRC"] + "/testdata/img/gs.png"
|
||||
qimage = RBA::QImage::new(fn)
|
||||
|
||||
image = RBA::Image.new(qimage)
|
||||
assert_equal(image.trans.to_s, "r0 *1 -513.5,-349")
|
||||
|
||||
assert_equal(image.width, 1027)
|
||||
assert_equal(image.height, 698)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue