mirror of https://github.com/KLayout/klayout.git
commit
abf2970438
|
|
@ -774,7 +774,6 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
|
|||
|
||||
checkpoint ();
|
||||
|
||||
// in point mode just store that found that has the least "distance"
|
||||
m_founds.push_back (founds_vector_type::value_type ());
|
||||
|
||||
lay::ObjectInstPath &inst_path = m_founds.back ().first;
|
||||
|
|
@ -786,7 +785,8 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
|
|||
inst_path.set_layer (*l);
|
||||
inst_path.set_shape (*shape);
|
||||
|
||||
// in point mode, test the edges and use a "closest" criterion
|
||||
// in box mode, select the edges depending on whether an endpoint is inside the
|
||||
// box or not
|
||||
if (shape->is_polygon ()) {
|
||||
|
||||
for (unsigned int c = 0; c < shape->holes () + 1; ++c) {
|
||||
|
|
@ -897,155 +897,164 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
|
|||
const db::Shapes &shapes = cell.shapes (*l);
|
||||
std::vector <EdgeWithIndex> edge_sel;
|
||||
|
||||
db::ShapeIterator shape = shapes.begin_touching (scan_box, flags (), prop_sel (), inv_prop_sel ());
|
||||
while (! shape.at_end ()) {
|
||||
// two passes - one with points, second with edges
|
||||
|
||||
bool match = false;
|
||||
double d = std::numeric_limits<double>::max ();
|
||||
bool any = false;
|
||||
for (int pass = 0; pass < 2 && ! any; ++pass) {
|
||||
|
||||
edge_sel.clear ();
|
||||
db::ShapeIterator shape = shapes.begin_touching (scan_box, flags (), prop_sel (), inv_prop_sel ());
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
checkpoint ();
|
||||
bool match = false;
|
||||
double d = std::numeric_limits<double>::max ();
|
||||
|
||||
// in point mode, test the edges and use a "closest" criterion
|
||||
if (shape->is_polygon ()) {
|
||||
edge_sel.clear ();
|
||||
|
||||
for (unsigned int c = 0; c < shape->holes () + 1; ++c) {
|
||||
checkpoint ();
|
||||
|
||||
// in point mode, test the edges and use a "closest" criterion
|
||||
if (shape->is_polygon ()) {
|
||||
|
||||
for (unsigned int c = 0; c < shape->holes () + 1; ++c) {
|
||||
|
||||
unsigned int n = 0;
|
||||
db::Shape::polygon_edge_iterator ee;
|
||||
for (db::Shape::polygon_edge_iterator e = shape->begin_edge (c); ! e.at_end (); e = ee, ++n) {
|
||||
|
||||
ee = e;
|
||||
++ee;
|
||||
unsigned int nn = ee.at_end () ? 0 : n + 1;
|
||||
|
||||
unsigned int r = test_edge (t, *e, pass == 0, d, match);
|
||||
if (r) {
|
||||
edge_sel.clear ();
|
||||
if ((r & 1) != 0) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p1 (), (*e).p1 ()), n, n, c));
|
||||
}
|
||||
if ((r & 2) != 0) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p2 (), (*e).p2 ()), nn, nn, c));
|
||||
}
|
||||
if (r == 3) {
|
||||
edge_sel.push_back (EdgeWithIndex (*e, n, nn, c));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (shape->is_path ()) {
|
||||
|
||||
// test the "spine"
|
||||
db::Shape::point_iterator pt = shape->begin_point ();
|
||||
if (pt != shape->end_point ()) {
|
||||
db::Point p (*pt);
|
||||
++pt;
|
||||
unsigned int n = 0;
|
||||
for (; pt != shape->end_point (); ++pt, ++n) {
|
||||
unsigned int r = test_edge (t, db::Edge (p, *pt), pass == 0, d, match);
|
||||
if (r) {
|
||||
edge_sel.clear ();
|
||||
if ((r & 1) != 0) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (p, p), n, n, 0));
|
||||
}
|
||||
if ((r & 2) != 0) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (*pt, *pt), n + 1, n + 1, 0));
|
||||
}
|
||||
if (r == 3) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (p, *pt), n, n + 1, 0));
|
||||
}
|
||||
}
|
||||
p = *pt;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (shape->is_box ()) {
|
||||
|
||||
const db::Box &box = shape->box ();
|
||||
|
||||
// convert to polygon and test those edges
|
||||
db::Polygon poly (box);
|
||||
|
||||
unsigned int n = 0;
|
||||
db::Shape::polygon_edge_iterator ee;
|
||||
for (db::Shape::polygon_edge_iterator e = shape->begin_edge (c); ! e.at_end (); e = ee, ++n) {
|
||||
for (db::Shape::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); e = ee, ++n) {
|
||||
|
||||
ee = e;
|
||||
++ee;
|
||||
unsigned int nn = ee.at_end () ? 0 : n + 1;
|
||||
|
||||
unsigned int r = test_edge (t, *e, d, match);
|
||||
unsigned int r = test_edge (t, *e, pass == 0, d, match);
|
||||
if (r) {
|
||||
edge_sel.clear ();
|
||||
if ((r & 1) == 1) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p1 (), (*e).p1 ()), n, n, c));
|
||||
if ((r & 1) != 0) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p1 (), (*e).p1 ()), n, n, 0));
|
||||
}
|
||||
if ((r & 2) == 2) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p2 (), (*e).p2 ()), nn, nn, c));
|
||||
if ((r & 2) != 0) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p2 (), (*e).p2 ()), nn, nn, 0));
|
||||
}
|
||||
if (r == 3) {
|
||||
edge_sel.push_back (EdgeWithIndex (*e, n, nn, c));
|
||||
edge_sel.push_back (EdgeWithIndex (*e, n, nn, 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else if (shape->is_text ()) {
|
||||
|
||||
} else if (shape->is_path ()) {
|
||||
db::Point tp (shape->text_trans () * db::Point ());
|
||||
|
||||
// test the "spine"
|
||||
db::Shape::point_iterator pt = shape->begin_point ();
|
||||
if (pt != shape->end_point ()) {
|
||||
db::Point p (*pt);
|
||||
++pt;
|
||||
unsigned int n = 0;
|
||||
for (; pt != shape->end_point (); ++pt, ++n) {
|
||||
unsigned int r = test_edge (t, db::Edge (p, *pt), d, match);
|
||||
if (r) {
|
||||
if (text_info ()) {
|
||||
|
||||
db::CplxTrans t_dbu = db::CplxTrans (layout ().dbu ()) * t;
|
||||
db::Text text;
|
||||
shape->text (text);
|
||||
db::Box tb (t_dbu.inverted () * text_info ()->bbox (t_dbu * text, vp));
|
||||
if (tb.contains (hit_box.center ())) {
|
||||
d = tp.distance (hit_box.center ());
|
||||
edge_sel.clear ();
|
||||
if ((r & 1) == 1) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (p, p), n, n, 0));
|
||||
}
|
||||
if ((r & 2) == 2) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (*pt, *pt), n + 1, n + 1, 0));
|
||||
}
|
||||
if (r == 3) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (p, *pt), n, n + 1, 0));
|
||||
}
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
}
|
||||
p = *pt;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (shape->is_box ()) {
|
||||
} else {
|
||||
|
||||
const db::Box &box = shape->box ();
|
||||
|
||||
// convert to polygon and test those edges
|
||||
db::Polygon poly (box);
|
||||
|
||||
unsigned int n = 0;
|
||||
db::Shape::polygon_edge_iterator ee;
|
||||
for (db::Shape::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); e = ee, ++n) {
|
||||
|
||||
ee = e;
|
||||
++ee;
|
||||
unsigned int nn = ee.at_end () ? 0 : n + 1;
|
||||
|
||||
unsigned int r = test_edge (t, *e, d, match);
|
||||
if (r) {
|
||||
edge_sel.clear ();
|
||||
if ((r & 1) == 1) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p1 (), (*e).p1 ()), n, n, 0));
|
||||
}
|
||||
if ((r & 2) == 2) {
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge ((*e).p2 (), (*e).p2 ()), nn, nn, 0));
|
||||
}
|
||||
if (r == 3) {
|
||||
edge_sel.push_back (EdgeWithIndex (*e, n, nn, 0));
|
||||
if (hit_box.contains (tp)) {
|
||||
d = tp.distance (hit_box.center ());
|
||||
edge_sel.clear ();
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (shape->is_text ()) {
|
||||
if (match && closer (d)) {
|
||||
|
||||
db::Point tp (shape->text_trans () * db::Point ());
|
||||
|
||||
if (text_info ()) {
|
||||
|
||||
db::CplxTrans t_dbu = db::CplxTrans (layout ().dbu ()) * t;
|
||||
db::Text text;
|
||||
shape->text (text);
|
||||
db::Box tb (t_dbu.inverted () * text_info ()->bbox (t_dbu * text, vp));
|
||||
if (tb.contains (hit_box.center ())) {
|
||||
d = tp.distance (hit_box.center ());
|
||||
edge_sel.clear ();
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
// in point mode just store that found that has the least "distance"
|
||||
if (m_founds.empty ()) {
|
||||
m_founds.push_back (founds_vector_type::value_type ());
|
||||
}
|
||||
|
||||
} else {
|
||||
lay::ObjectInstPath &inst_path = m_founds.back ().first;
|
||||
|
||||
if (hit_box.contains (tp)) {
|
||||
d = tp.distance (hit_box.center ());
|
||||
edge_sel.clear ();
|
||||
edge_sel.push_back (EdgeWithIndex (db::Edge (tp, tp), 0, 0, 0));
|
||||
match = true;
|
||||
}
|
||||
inst_path.set_cv_index (cv_index ());
|
||||
inst_path.set_topcell (topcell ());
|
||||
inst_path.assign_path (path ().begin (), path ().end ());
|
||||
inst_path.set_layer (*l);
|
||||
inst_path.set_shape (*shape);
|
||||
|
||||
m_founds.back ().second = edge_sel;
|
||||
|
||||
any = true;
|
||||
|
||||
}
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
if (match && closer (d)) {
|
||||
|
||||
// in point mode just store that found that has the least "distance"
|
||||
if (m_founds.empty ()) {
|
||||
m_founds.push_back (founds_vector_type::value_type ());
|
||||
}
|
||||
|
||||
lay::ObjectInstPath &inst_path = m_founds.back ().first;
|
||||
|
||||
inst_path.set_cv_index (cv_index ());
|
||||
inst_path.set_topcell (topcell ());
|
||||
inst_path.assign_path (path ().begin (), path ().end ());
|
||||
inst_path.set_layer (*l);
|
||||
inst_path.set_shape (*shape);
|
||||
|
||||
m_founds.back ().second = edge_sel;
|
||||
|
||||
}
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1153,6 +1162,7 @@ PartialService::timeout ()
|
|||
m_hover = true;
|
||||
|
||||
mp_view->clear_transient_selection ();
|
||||
clear_mouse_cursors ();
|
||||
|
||||
// compute search box
|
||||
double l = catch_distance ();
|
||||
|
|
@ -2413,6 +2423,10 @@ PartialService::enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_obj
|
|||
db::DEdge ee = db::DEdge (db::DPoint (ep2) + ((db::DPoint (ep1) - db::DPoint (ep2)) * 0.25), db::DPoint (ep2));
|
||||
marker->set (ee, db::DCplxTrans (gt), tv);
|
||||
|
||||
if (transient && sel->second.size () == 1) {
|
||||
add_mouse_cursor (ep2, sel->first.cv_index (), gt, tv, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (p1_sel && !p12_sel) {
|
||||
|
|
@ -2423,12 +2437,22 @@ PartialService::enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_obj
|
|||
db::DEdge ee = db::DEdge (db::DPoint (ep1), db::DPoint (ep1) + ((db::DPoint (ep2) - db::DPoint (ep1)) * 0.25));
|
||||
marker->set (ee, db::DCplxTrans (gt), tv);
|
||||
|
||||
}
|
||||
if (transient && sel->second.size () == 1) {
|
||||
add_mouse_cursor (ep1, sel->first.cv_index (), gt, tv, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (p12_sel) {
|
||||
|
||||
lay::Marker *marker = new_marker (nmarker, sel->first.cv_index (), transient);
|
||||
marker->set_vertex_size (0);
|
||||
marker->set (enew, gt, tv);
|
||||
|
||||
if (transient) {
|
||||
add_edge_marker (enew, sel->first.cv_index (), gt, tv, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1480,6 +1480,18 @@ GuiApplication::initialize ()
|
|||
bool
|
||||
GuiApplication::notify (QObject *receiver, QEvent *e)
|
||||
{
|
||||
QWheelEvent *wheel_event = dynamic_cast<QWheelEvent *>(e);
|
||||
if (wheel_event) {
|
||||
// intercept wheel events targeting QComboBox objects to avoid
|
||||
// changing them through wheel actions.
|
||||
for (auto r = receiver; r != 0; r = r->parent ()) {
|
||||
if (dynamic_cast<QComboBox *>(r)) {
|
||||
// stop further processing
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_cast<QPaintEvent *> (e)) {
|
||||
// NOTE: we don't want recursive paint events - the painters are not reentrant.
|
||||
// Hence we disable process_events_impl (specifically for progress reporters).
|
||||
|
|
@ -1543,18 +1555,18 @@ GuiApplication::force_update_app_menu ()
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// By Thomas Lima (March 7, 2018)
|
||||
//
|
||||
// This event interceptor catches MacOS "Open With" event, and KLayout should respond
|
||||
// similarly to the Drop event in MainWindow::dropEvent.
|
||||
//
|
||||
// This particular implementation always creates a new window.
|
||||
//
|
||||
// This was implemented with the inspiration of http://doc.qt.io/qt-5/qfileopenevent.html
|
||||
bool
|
||||
GuiApplication::event (QEvent *event)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
// By Thomas Lima (March 7, 2018)
|
||||
//
|
||||
// This event interceptor catches MacOS "Open With" event, and KLayout should respond
|
||||
// similarly to the Drop event in MainWindow::dropEvent.
|
||||
//
|
||||
// This particular implementation always creates a new window.
|
||||
//
|
||||
// This was implemented with the inspiration of http://doc.qt.io/qt-5/qfileopenevent.html
|
||||
if (event->type() == QEvent::FileOpen) {
|
||||
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
|
||||
if (mp_mw)
|
||||
|
|
@ -1566,10 +1578,10 @@ GuiApplication::event (QEvent *event)
|
|||
mp_mw->add_mru (file, tech);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return QApplication::event(event);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -459,12 +459,9 @@ public:
|
|||
void force_update_app_menu ();
|
||||
|
||||
/**
|
||||
* @brief Handles MacOS file open
|
||||
* This function is used to process the "Open With" event sent by MacOS.
|
||||
* @brief Handles events
|
||||
*/
|
||||
#ifdef __APPLE__
|
||||
bool event (QEvent *event);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void setup ();
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ LogFile::LogFile (size_t max_entries, bool register_global)
|
|||
{
|
||||
connect (&m_timer, SIGNAL (timeout ()), this, SLOT (timeout ()));
|
||||
|
||||
m_last_yield = tl::Clock::current ();
|
||||
|
||||
m_timer.setSingleShot (true);
|
||||
m_timer.setInterval (0);
|
||||
|
||||
|
|
@ -190,6 +192,9 @@ LogFile::timeout ()
|
|||
bool attn = false, last_attn = false;
|
||||
|
||||
m_lock.lock ();
|
||||
|
||||
m_last_yield = tl::Clock::current ();
|
||||
|
||||
if (m_generation_id != m_last_generation_id) {
|
||||
attn = m_has_errors || m_has_warnings;
|
||||
last_attn = m_last_attn;
|
||||
|
|
@ -197,6 +202,7 @@ LogFile::timeout ()
|
|||
m_last_generation_id = m_generation_id;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
m_lock.unlock ();
|
||||
|
||||
if (changed) {
|
||||
|
|
@ -254,7 +260,9 @@ LogFile::yield ()
|
|||
{
|
||||
// will update on next processEvents
|
||||
if (lay::ApplicationBase::instance ()->qapp_gui () && QThread::currentThread () == lay::ApplicationBase::instance ()->qapp_gui ()->thread ()) {
|
||||
m_timer.start ();
|
||||
if ((tl::Clock::current () - m_last_yield).seconds () > 0.2) {
|
||||
m_timer.start ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "ui_LogViewerDialog.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlTimer.h"
|
||||
#include "layCommon.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
|
@ -220,6 +221,7 @@ signals:
|
|||
void attention_changed (bool f);
|
||||
|
||||
private:
|
||||
tl::Clock m_last_yield;
|
||||
QTimer m_timer;
|
||||
mutable QMutex m_lock;
|
||||
LogReceiver m_error_receiver;
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ EditorServiceBase::EditorServiceBase (LayoutViewBase *view)
|
|||
: lay::ViewService (view->canvas ()),
|
||||
lay::Editable (view),
|
||||
lay::Plugin (view),
|
||||
mp_view (view),
|
||||
m_cursor_enabled (true),
|
||||
m_has_tracking_position (false)
|
||||
{
|
||||
|
|
@ -229,12 +230,30 @@ EditorServiceBase::add_mouse_cursor (const db::DPoint &pt, bool emphasize)
|
|||
m_mouse_cursor_markers.push_back (new MouseCursorViewObject (this, ui (), pt, emphasize));
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::add_mouse_cursor (const db::Point &pt, unsigned int cv_index, const db::ICplxTrans >, const std::vector<db::DCplxTrans> &tv, bool emphasize)
|
||||
{
|
||||
double dbu = mp_view->cellview (cv_index)->layout ().dbu ();
|
||||
for (auto t = tv.begin (); t != tv.end (); ++t) {
|
||||
add_mouse_cursor (*t * db::CplxTrans (dbu) * gt * pt, emphasize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::add_edge_marker (const db::DEdge &e, bool emphasize)
|
||||
{
|
||||
m_mouse_cursor_markers.push_back (new EdgeMarkerViewObject (this, ui (), e, emphasize));
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::add_edge_marker (const db::Edge &e, unsigned int cv_index, const db::ICplxTrans >, const std::vector<db::DCplxTrans> &tv, bool emphasize)
|
||||
{
|
||||
double dbu = mp_view->cellview (cv_index)->layout ().dbu ();
|
||||
for (auto t = tv.begin (); t != tv.end (); ++t) {
|
||||
add_edge_marker (*t * db::CplxTrans (dbu) * gt * e, emphasize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::clear_mouse_cursors ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,10 +74,20 @@ public:
|
|||
*/
|
||||
void add_mouse_cursor (const db::DPoint &pt, bool emphasize = false);
|
||||
|
||||
/**
|
||||
* @brief Adds a mouse cursor to the given point in layout space
|
||||
*/
|
||||
void add_mouse_cursor (const db::Point &pt, unsigned int cv_index, const db::ICplxTrans >, const std::vector<db::DCplxTrans> &tv, bool emphasize = false);
|
||||
|
||||
/**
|
||||
* @brief Adds an edge marker for the given edge
|
||||
*/
|
||||
void add_edge_marker (const db::DEdge &e, bool emphasize);
|
||||
void add_edge_marker (const db::DEdge &e, bool emphasize = false);
|
||||
|
||||
/**
|
||||
* @brief Adds an edge marker for the given edge in layout space
|
||||
*/
|
||||
void add_edge_marker (const db::Edge &e, unsigned int cv_index, const db::ICplxTrans >, const std::vector<db::DCplxTrans> &tv, bool emphasize = false);
|
||||
|
||||
/**
|
||||
* @brief Resets the mouse cursor
|
||||
|
|
@ -132,6 +142,7 @@ protected:
|
|||
|
||||
private:
|
||||
// The marker representing the mouse cursor
|
||||
lay::LayoutViewBase *mp_view;
|
||||
std::vector<lay::ViewObject *> m_mouse_cursor_markers;
|
||||
tl::Color m_cursor_color;
|
||||
bool m_cursor_enabled;
|
||||
|
|
|
|||
|
|
@ -123,47 +123,74 @@ Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vect
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Finder::test_edge (const db::ICplxTrans &trans, const db::Edge &edge, double &distance, bool &match)
|
||||
{
|
||||
if (test_edge (trans, edge, true, distance, match) == 0) {
|
||||
test_edge (trans, edge, false, distance, match);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
Finder::test_edge (const db::ICplxTrans &trans, const db::Edge &edg, double &distance, bool &match)
|
||||
Finder::test_edge (const db::ICplxTrans &trans, const db::Edge &edg, bool points, double &distance, bool &match)
|
||||
{
|
||||
db::Point p1 = trans * edg.p1 ();
|
||||
db::Point p2 = trans * edg.p2 ();
|
||||
|
||||
unsigned int ret = 0;
|
||||
|
||||
// we hit the region with the edge end points - take the closest vertex
|
||||
if (m_region.contains (p1) || m_region.contains (p2)) {
|
||||
if (points) {
|
||||
|
||||
double d1 = p1.double_distance (m_region.center ());
|
||||
double d2 = p2.double_distance (m_region.center ());
|
||||
// we hit the region with the edge end points - take the closest vertex
|
||||
if (m_region.contains (p1) || m_region.contains (p2)) {
|
||||
|
||||
double d1 = p1.double_distance (m_region.center ());
|
||||
double d2 = p2.double_distance (m_region.center ());
|
||||
if (d1 < d2) {
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
double d = std::min (d1, d2);
|
||||
// add a penalty of 1 DBU for being on the wrong
|
||||
// side of the edge - this favors the right edge
|
||||
// in case of butting corners
|
||||
if (ret == 1) {
|
||||
if (db::sprod_sign (m_region.center () - p1, p2 - p1) < 0) {
|
||||
d += trans.ctrans (1);
|
||||
}
|
||||
} else {
|
||||
if (db::sprod_sign (m_region.center () - p2, p1 - p2) < 0) {
|
||||
d += trans.ctrans (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (! match || d < distance) {
|
||||
distance = d;
|
||||
}
|
||||
|
||||
match = true;
|
||||
|
||||
double d = std::min (d1, d2);
|
||||
if (! match || d < distance) {
|
||||
distance = d;
|
||||
}
|
||||
|
||||
if (d1 < d2) {
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
match = true;
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
// if the edge cuts through the active region: test the
|
||||
// edge as a whole
|
||||
if (ret == 0) {
|
||||
// if the edge cuts through the active region: test the
|
||||
// edge as a whole
|
||||
db::Edge edg_trans (p1, p2);
|
||||
if (edg_trans.clipped (m_region).first) {
|
||||
|
||||
double d = edg_trans.distance_abs (m_region.center ());
|
||||
if (! match || d < distance) {
|
||||
distance = d;
|
||||
ret = 3;
|
||||
}
|
||||
|
||||
ret = 3;
|
||||
match = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -176,11 +176,18 @@ protected:
|
|||
*
|
||||
* "trans" is the transformation to be applied to the edge before the test.
|
||||
*
|
||||
* If "points" is true, only points are tested, otherwise edges are tested.
|
||||
*
|
||||
* This method returns a mask indicating which point of the edge was matching.
|
||||
* Bit 0 of this mask indicates the first point is matching, bit 1 indicates the
|
||||
* second point is matching.
|
||||
*/
|
||||
unsigned int test_edge (const db::ICplxTrans &trans, const db::Edge &edge, double &distance, bool &match);
|
||||
unsigned int test_edge (const db::ICplxTrans &trans, const db::Edge &edge, bool points, double &distance, bool &match);
|
||||
|
||||
/**
|
||||
* @brief Tests an edge in point mode and edge mode (later)
|
||||
*/
|
||||
void test_edge (const db::ICplxTrans &trans, const db::Edge &edge, double &distance, bool &match);
|
||||
|
||||
private:
|
||||
void do_find (const db::Cell &cell, int level, const db::DCplxTrans &vp, const db::ICplxTrans &t);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "gsiDeclBasic.h"
|
||||
#include "layBrowserDialog.h"
|
||||
#include "layBrowserPanel.h"
|
||||
#include "layFileDialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
|
|
@ -926,11 +927,30 @@ static tl::Variant ask_open_file_name (const std::string &title, const std::stri
|
|||
|
||||
static tl::Variant ask_save_file_name (const std::string &title, const std::string &dir, const std::string &filter)
|
||||
{
|
||||
QString f = QFileDialog::getSaveFileName (QApplication::activeWindow (), tl::to_qstring (title), tl::to_qstring (dir), tl::to_qstring (filter));
|
||||
QString selected_filter;
|
||||
|
||||
QString f = QFileDialog::getSaveFileName (QApplication::activeWindow (), tl::to_qstring (title), tl::to_qstring (dir), tl::to_qstring (filter), &selected_filter);
|
||||
if (f.isEmpty ()) {
|
||||
return tl::Variant ();
|
||||
} else {
|
||||
return tl::Variant (tl::to_string (f));
|
||||
return tl::Variant (lay::FileDialog::add_default_extension (tl::to_string (f), selected_filter));
|
||||
}
|
||||
}
|
||||
|
||||
static tl::Variant ask_save_file_name2 (const std::string &title, const std::string &dir, const std::string &filter)
|
||||
{
|
||||
QString selected_filter;
|
||||
QString qfilter = tl::to_qstring (filter);
|
||||
|
||||
QString f = QFileDialog::getSaveFileName (QApplication::activeWindow (), tl::to_qstring (title), tl::to_qstring (dir), qfilter, &selected_filter);
|
||||
if (f.isEmpty ()) {
|
||||
return tl::Variant ();
|
||||
} else {
|
||||
tl::Variant v;
|
||||
v.set_list ();
|
||||
v.push (lay::FileDialog::add_default_extension (tl::to_string (f), selected_filter));
|
||||
v.push (lay::FileDialog::find_selected_filter (qfilter, selected_filter));
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1012,6 +1032,16 @@ Class<FileDialog> decl_FileDialog ("lay", "FileDialog",
|
|||
"@return The path of the file chosen or \"nil\" if \"Cancel\" was pressed\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23. It is somewhat easier to use than the get_... equivalent.\n"
|
||||
) +
|
||||
gsi::method ("ask_save_file_name_with_filter", &ask_save_file_name2, gsi::arg ("title"), gsi::arg ("dir"), gsi::arg ("filter"),
|
||||
"@brief Select one file for writing\n"
|
||||
"\n"
|
||||
"@param title The title of the dialog\n"
|
||||
"@param dir The directory selected initially\n"
|
||||
"@param filter The filters available, for example \"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)\"\n"
|
||||
"@return \"nil\" if \"Cancel\" was pressed, otherwise a pair: The path of the file chosen and the index selected file type (-1 if no specific type was selected)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.11.\n"
|
||||
),
|
||||
"@brief Various methods to request a file name\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "layFileDialog.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlString.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -60,32 +62,53 @@ FileDialog::~FileDialog ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
// not used if standard dialogs are used (disabled to avoid compiler warning):
|
||||
#if 0
|
||||
static void
|
||||
split_filters (const QString &filters, QStringList &slist)
|
||||
int
|
||||
FileDialog::find_selected_filter (const QString &fs, const QString &selected_filter)
|
||||
{
|
||||
QString s;
|
||||
for (const char *cp = filters.ascii (); *cp; ++cp) {
|
||||
if (cp[0] == ';' && cp[1] == ';') {
|
||||
slist << s;
|
||||
++cp;
|
||||
s = "";
|
||||
} else {
|
||||
s += *cp;
|
||||
QStringList filters = fs.split (tl::to_qstring (";;"));
|
||||
|
||||
for (auto f = filters.begin (); f != filters.end (); ++f) {
|
||||
if (*f == selected_filter) {
|
||||
return int (f - filters.begin ());
|
||||
}
|
||||
}
|
||||
|
||||
if (s != "") {
|
||||
slist << s;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string
|
||||
FileDialog::add_default_extension (const std::string &path, const QString &selected_filter)
|
||||
{
|
||||
if (tl::extension (path).empty ()) {
|
||||
|
||||
std::string sf = tl::to_string (selected_filter);
|
||||
|
||||
auto star = sf.find ("*.");
|
||||
if (star != std::string::npos) {
|
||||
|
||||
tl::Extractor ex (sf.c_str () + star + 2);
|
||||
std::string ext;
|
||||
|
||||
if (ex.try_read_word (ext)) {
|
||||
return path + "." + ext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
int
|
||||
FileDialog::selected_filter () const
|
||||
{
|
||||
return find_selected_filter (m_filters, m_sel_filter);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
FileDialog::get_open (std::string &fp, const std::string &title)
|
||||
{
|
||||
#if 1
|
||||
// Use the standard (system) dialogs:
|
||||
|
||||
QString file_name;
|
||||
|
|
@ -107,54 +130,11 @@ FileDialog::get_open (std::string &fp, const std::string &title)
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
QString file_name;
|
||||
if (! fp.empty ()) {
|
||||
QFileInfo fi (fp.c_str ());
|
||||
m_dir = fi.absoluteDir ();
|
||||
file_name = fi.fileName ();
|
||||
}
|
||||
|
||||
QFileDialog fdia (QApplication::activeWindow ());
|
||||
|
||||
fdia.setDirectory (m_dir);
|
||||
if (m_def_suffix != "") {
|
||||
fdia.setDefaultSuffix (m_def_suffix);
|
||||
}
|
||||
|
||||
QStringList types;
|
||||
split_filters (m_filters, types);
|
||||
fdia.setFilters (types);
|
||||
|
||||
fdia.setReadOnly (true);
|
||||
fdia.setViewMode (QFileDialog::Detail);
|
||||
fdia.setFileMode (QFileDialog::ExistingFile);
|
||||
fdia.setAcceptMode (QFileDialog::AcceptOpen);
|
||||
fdia.setConfirmOverwrite (true);
|
||||
fdia.setCaption (QString (tl::to_string (QObject::tr ("Open ")).c_str ()) + (title.empty () ? m_title : tl::to_qstring (title)));
|
||||
if (! file_name.isEmpty ()) {
|
||||
fdia.selectFile (file_name);
|
||||
}
|
||||
|
||||
QStringList files;
|
||||
if (fdia.exec ()) {
|
||||
files = fdia.selectedFiles();
|
||||
if (files.size () > 0) {
|
||||
fp = tl::to_string (files [0]);
|
||||
QFileInfo fi (files [0]);
|
||||
m_dir = fi.absoluteDir ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
FileDialog::get_open (std::vector<std::string> &fp, const std::string &dir, const std::string &title)
|
||||
{
|
||||
#if 1
|
||||
// Use the standard (system) dialogs:
|
||||
|
||||
if (! dir.empty ()) {
|
||||
|
|
@ -175,68 +155,11 @@ FileDialog::get_open (std::vector<std::string> &fp, const std::string &dir, cons
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (! dir.empty ()) {
|
||||
QDir fi (dir.c_str ());
|
||||
m_dir = fi.absolutePath ();
|
||||
}
|
||||
|
||||
QStringList file_names;
|
||||
for (std::vector<std::string>::const_iterator f = fp.begin (); f != fp.end (); ++f) {
|
||||
QFileInfo fi (f->c_str ());
|
||||
m_dir = fi.absoluteDir ();
|
||||
file_names << QString (f->c_str ());
|
||||
}
|
||||
|
||||
QFileDialog fdia (QApplication::activeWindow ());
|
||||
|
||||
fdia.setDirectory (m_dir);
|
||||
if (m_def_suffix != "") {
|
||||
fdia.setDefaultSuffix (m_def_suffix);
|
||||
}
|
||||
|
||||
QStringList types;
|
||||
split_filters (m_filters, types);
|
||||
fdia.setFilters (types);
|
||||
|
||||
fdia.setReadOnly (true);
|
||||
fdia.setViewMode (QFileDialog::Detail);
|
||||
fdia.setFileMode (QFileDialog::ExistingFiles);
|
||||
fdia.setAcceptMode (QFileDialog::AcceptOpen);
|
||||
fdia.setConfirmOverwrite (true);
|
||||
fdia.setCaption (QString (tl::to_string (QObject::tr ("Open ")).c_str ()) + (title.empty () ? m_title : tl::to_qstring (title)));
|
||||
|
||||
for (QStringList::iterator f = file_names.begin (); f != file_names.end (); ++f) {
|
||||
fdia.selectFile (*f);
|
||||
}
|
||||
|
||||
QStringList files;
|
||||
if (fdia.exec ()) {
|
||||
|
||||
files = fdia.selectedFiles();
|
||||
if (! files.isEmpty ()) {
|
||||
|
||||
fp.clear ();
|
||||
for (QStringList::iterator f = files.begin (); f != files.end (); ++f) {
|
||||
fp.push_back (tl::to_string (*f));
|
||||
QFileInfo fi (*f);
|
||||
m_dir = fi.absoluteDir ();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
FileDialog::get_save (std::string &fp, const std::string &title)
|
||||
{
|
||||
#if 1
|
||||
// Use the standard (system) dialogs:
|
||||
|
||||
QString file_name;
|
||||
|
|
@ -251,55 +174,16 @@ FileDialog::get_save (std::string &fp, const std::string &title)
|
|||
QString f = QFileDialog::getSaveFileName (QApplication::activeWindow (), (title.empty () ? m_title : tl::to_qstring (title)), file_name, m_filters, &m_sel_filter);
|
||||
|
||||
if (! f.isEmpty ()) {
|
||||
fp = tl::to_string (f);
|
||||
|
||||
fp = add_default_extension (tl::to_string (f), m_sel_filter);
|
||||
|
||||
QFileInfo fi (f);
|
||||
m_dir = fi.absoluteDir ();
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
QString file_name;
|
||||
if (! fp.empty ()) {
|
||||
QFileInfo fi (fp.c_str ());
|
||||
m_dir = fi.absoluteDir ();
|
||||
file_name = fi.fileName ();
|
||||
}
|
||||
|
||||
QFileDialog fdia (QApplication::activeWindow ());
|
||||
|
||||
fdia.setDirectory (m_dir);
|
||||
if (m_def_suffix != "") {
|
||||
fdia.setDefaultSuffix (m_def_suffix);
|
||||
}
|
||||
|
||||
QStringList types;
|
||||
split_filters (m_filters, types);
|
||||
fdia.setFilters (types);
|
||||
|
||||
fdia.setReadOnly (false);
|
||||
fdia.setViewMode (QFileDialog::Detail);
|
||||
fdia.setFileMode (QFileDialog::AnyFile);
|
||||
fdia.setAcceptMode (QFileDialog::AcceptSave);
|
||||
fdia.setConfirmOverwrite (true);
|
||||
fdia.setCaption (QString (tl::to_string (QObject::tr ("Save ")).c_str ()) + (title.empty () ? m_title : tl::to_qstring (title)));
|
||||
if (! file_name.isEmpty ()) {
|
||||
fdia.selectFile (file_name);
|
||||
}
|
||||
|
||||
QStringList files;
|
||||
if (fdia.exec ()) {
|
||||
files = fdia.selectedFiles();
|
||||
if (files.size () > 0) {
|
||||
fp = tl::to_string (files [0]);
|
||||
QFileInfo fi (files [0]);
|
||||
m_dir = fi.absoluteDir ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace lay
|
||||
|
|
|
|||
|
|
@ -65,20 +65,27 @@ public:
|
|||
~FileDialog ();
|
||||
|
||||
/**
|
||||
* @brief Get a file name to read
|
||||
* @brief Gets a file name to read
|
||||
*/
|
||||
bool get_open (std::string &file_name, const std::string &title = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Read multiple files names
|
||||
* @brief Reads multiple files names
|
||||
*/
|
||||
bool get_open (std::vector<std::string> &file_names, const std::string &dir = std::string (), const std::string &title = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Get a file name to save
|
||||
* @brief Gets a file name to save
|
||||
*/
|
||||
bool get_save (std::string &file_name, const std::string &title = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Gets the selected filter or -1 if no specific filter was selected
|
||||
*
|
||||
* This value is only set after get_open or get_save returned true
|
||||
*/
|
||||
int selected_filter () const;
|
||||
|
||||
/**
|
||||
* @brief Make the file names use UTF8 encoding
|
||||
*
|
||||
|
|
@ -87,6 +94,16 @@ public:
|
|||
*/
|
||||
static void set_utf8 (bool utf);
|
||||
|
||||
/**
|
||||
* @brief Gets the index of the selected filter from the filter list
|
||||
*/
|
||||
static int find_selected_filter (const QString &filters, const QString &selected_filter);
|
||||
|
||||
/**
|
||||
* @brief Adds the default extension unless there is one already
|
||||
*/
|
||||
static std::string add_default_extension (const std::string &path, const QString &selected_filter);
|
||||
|
||||
private:
|
||||
QDir m_dir;
|
||||
QString m_title;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
virtual std::string format_name () const { return "CIF"; }
|
||||
virtual std::string format_desc () const { return "CIF"; }
|
||||
virtual std::string format_title () const { return "CIF (Caltech interchange format)"; }
|
||||
virtual std::string file_format () const { return "CIF files (*.CIF *.cif *.cif.gz *.CIF.gz)"; }
|
||||
virtual std::string file_format () const { return "CIF files (*.cif *.CIF *.cif.gz *.CIF.gz)"; }
|
||||
|
||||
static tl::Extractor &skip_blanks (tl::Extractor &ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
virtual std::string format_name () const { return "DXF"; }
|
||||
virtual std::string format_desc () const { return "DXF"; }
|
||||
virtual std::string format_title () const { return "DXF (AutoCAD)"; }
|
||||
virtual std::string file_format () const { return "DXF files (*.DXF *.dxf *.dxf.gz *.DXF.gz)"; }
|
||||
virtual std::string file_format () const { return "DXF files (*.dxf *.DXF *.dxf.gz *.DXF.gz)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &s) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -814,15 +814,15 @@ De Boor algorithm for NURBS
|
|||
*/
|
||||
|
||||
static db::DPoint
|
||||
b_spline_point (double x, const std::vector<std::pair<db::DPoint, double> > &control_points, int p, const std::vector<double> &t)
|
||||
b_spline_point (double x, const std::vector<std::pair<db::DPoint, double> > &control_points, int p, const std::vector<double> &t, int &k)
|
||||
{
|
||||
int k = (int) (std::lower_bound (t.begin (), t.end (), x + 1e-6) - t.begin ());
|
||||
if (k <= p) {
|
||||
return control_points.front ().first;
|
||||
} else if (k > (int) control_points.size ()) {
|
||||
return control_points.back ().first;
|
||||
}
|
||||
k = (int) (std::lower_bound (t.begin (), t.end (), x - 1e-6) - t.begin ());
|
||||
--k;
|
||||
if (k < p) {
|
||||
k = p;
|
||||
} else if (k >= (int) control_points.size ()) {
|
||||
k = (int) control_points.size () - 1;
|
||||
}
|
||||
|
||||
std::vector<db::DPoint> d;
|
||||
std::vector<double> dw;
|
||||
|
|
@ -878,14 +878,16 @@ spline_interpolate (std::list<db::DPoint> &curve_points,
|
|||
std::list<db::DPoint>::iterator pe = pm;
|
||||
++pe;
|
||||
|
||||
db::DPoint s1 = b_spline_point (t_start + 0.5 * dt, control_points, degree, knots);
|
||||
db::DPoint s2 = b_spline_point (t_start + 1.5 * dt, control_points, degree, knots);
|
||||
int k1 = 0, k2 = 0;
|
||||
|
||||
db::DPoint s1 = b_spline_point (t_start + 0.5 * dt, control_points, degree, knots, k1);
|
||||
db::DPoint s2 = b_spline_point (t_start + 1.5 * dt, control_points, degree, knots, k2);
|
||||
|
||||
db::DVector p1 (s1, *current_curve_point);
|
||||
db::DVector p2 (*pm, s1);
|
||||
double pl1 = p1.length(), pl2 = p2.length();
|
||||
|
||||
if (curve_points.size () < control_points.size () - degree - 1) {
|
||||
if (k1 != k2) {
|
||||
|
||||
curve_points.insert (pm, s1);
|
||||
spline_interpolate (curve_points, current_curve_point, t_start, dt * 0.5, control_points, degree, knots, sin_da, accu);
|
||||
|
|
@ -958,12 +960,12 @@ DXFReader::spline_interpolation (std::vector<std::pair<db::DPoint, double> > &co
|
|||
double accu = std::max (m_circle_accuracy, m_dbu / m_unit);
|
||||
|
||||
std::list<db::DPoint> new_points;
|
||||
new_points.push_back (control_points.front ().first);
|
||||
|
||||
double dt = 0.5 * (tn - t0);
|
||||
|
||||
for (double t = t0 + dt; t < tn + 1e-6; t += dt) {
|
||||
db::DPoint s = b_spline_point (t, control_points, degree, knots);
|
||||
for (double t = t0; t < tn + 1e-6; t += dt) {
|
||||
int k = 0;
|
||||
db::DPoint s = b_spline_point (t, control_points, degree, knots, k);
|
||||
new_points.push_back (s);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ TEST(15)
|
|||
db::DXFReaderOptions opt;
|
||||
opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20");
|
||||
opt.create_other_layers = true;
|
||||
run_test (_this, "t15.dxf.gz", "t15_au2.gds.gz", opt);
|
||||
run_test (_this, "t15.dxf.gz", "t15_au2_2.gds.gz", opt);
|
||||
}
|
||||
|
||||
TEST(16)
|
||||
|
|
@ -190,7 +190,7 @@ TEST(16)
|
|||
db::DXFReaderOptions opt;
|
||||
opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20");
|
||||
opt.create_other_layers = true;
|
||||
run_test (_this, "t16.dxf.gz", "t16_au2.gds.gz", opt);
|
||||
run_test (_this, "t16.dxf.gz", "t16_au2_2.gds.gz", opt);
|
||||
}
|
||||
|
||||
TEST(17)
|
||||
|
|
@ -198,7 +198,7 @@ TEST(17)
|
|||
db::DXFReaderOptions opt;
|
||||
opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20");
|
||||
opt.create_other_layers = true;
|
||||
run_test (_this, "t17.dxf.gz", "t17_au2.gds.gz", opt);
|
||||
run_test (_this, "t17.dxf.gz", "t17_au2_2.gds.gz", opt);
|
||||
}
|
||||
|
||||
TEST(18)
|
||||
|
|
@ -515,3 +515,24 @@ TEST(34)
|
|||
|
||||
run_test_public (_this, "issue_1173.dxf", "issue_1173_au.gds.gz", opt);
|
||||
}
|
||||
|
||||
// issue #1422
|
||||
TEST(35a)
|
||||
{
|
||||
db::DXFReaderOptions opt;
|
||||
run_test_public (_this, "issue_1422a.dxf", "issue_1422a_au.gds.gz", opt);
|
||||
}
|
||||
|
||||
// issue #1422
|
||||
TEST(35b)
|
||||
{
|
||||
db::DXFReaderOptions opt;
|
||||
run_test_public (_this, "issue_1422b.dxf", "issue_1422b_au.gds.gz", opt);
|
||||
}
|
||||
|
||||
// issue #1422
|
||||
TEST(35c)
|
||||
{
|
||||
db::DXFReaderOptions opt;
|
||||
run_test_public (_this, "issue_1422c.dxf", "issue_1422c_au.gds.gz", opt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class GDS2FormatDeclaration
|
|||
virtual std::string format_name () const { return "GDS2"; }
|
||||
virtual std::string format_desc () const { return "GDS2"; }
|
||||
virtual std::string format_title () const { return "GDS2"; }
|
||||
virtual std::string file_format () const { return "GDS2 files (*.GDS *.gds *.gds.gz *.GDS.gz *.GDS2 *.gds2 *.gds2.gz *.GDS2.gz)"; }
|
||||
virtual std::string file_format () const { return "GDS2 files (*.gds *.GDS *.gds.gz *.GDS.gz *.GDS2 *.gds2 *.gds2.gz *.GDS2.gz)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
virtual std::string format_name () const { return "MAG"; }
|
||||
virtual std::string format_desc () const { return "Magic"; }
|
||||
virtual std::string format_title () const { return "MAG (Magic layout format)"; }
|
||||
virtual std::string file_format () const { return "Magic files (*.MAG *.mag *.mag.gz *.MAG.gz)"; }
|
||||
virtual std::string file_format () const { return "Magic files (*.mag *.MAG *.mag.gz *.MAG.gz)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &s) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ public:
|
|||
virtual std::string format_name () const { return "OASIS"; }
|
||||
virtual std::string format_desc () const { return "OASIS"; }
|
||||
virtual std::string format_title () const { return "OASIS"; }
|
||||
virtual std::string file_format () const { return "OASIS files (*.OAS *.oas *.oas.gz *.OAS.gz)"; }
|
||||
virtual std::string file_format () const { return "OASIS files (*.oas *.OAS *.oas.gz *.OAS.gz)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1168,7 +1168,7 @@ class GerberFormatDeclaration
|
|||
virtual std::string format_name () const { return "GerberPCB"; }
|
||||
virtual std::string format_desc () const { return "Gerber PCB"; }
|
||||
virtual std::string format_title () const { return "Gerber PCB (project files)"; }
|
||||
virtual std::string file_format () const { return "Gerber PCB project files (*.pcb)"; }
|
||||
virtual std::string file_format () const { return "Gerber PCB project files (*.pcb *.PCB)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1034,8 +1034,8 @@ OutputStream::seek (size_t pos)
|
|||
// ---------------------------------------------------------------
|
||||
// OutputFileBase implementation
|
||||
|
||||
OutputFileBase::OutputFileBase (const std::string &path, int keep_backups)
|
||||
: m_keep_backups (keep_backups), m_path (tl::absolute_file_path (path)), m_has_error (false)
|
||||
OutputFileBase::OutputFileBase (const std::string &p, int keep_backups)
|
||||
: m_keep_backups (keep_backups), m_path (tl::absolute_file_path (p)), m_has_error (false)
|
||||
{
|
||||
if (tl::file_exists (m_path)) {
|
||||
m_backup_path = m_path + ".~backup";
|
||||
|
|
@ -1133,20 +1133,19 @@ void OutputFileBase::reject ()
|
|||
// ---------------------------------------------------------------
|
||||
// OutputFile implementation
|
||||
|
||||
OutputFile::OutputFile (const std::string &path, int keep_backups)
|
||||
: OutputFileBase (path, keep_backups), m_fd (-1)
|
||||
OutputFile::OutputFile (const std::string &p, int keep_backups)
|
||||
: OutputFileBase (p, keep_backups), m_fd (-1)
|
||||
{
|
||||
m_source = path;
|
||||
#if defined(_WIN32)
|
||||
int fd = _wopen (tl::to_wstring (path).c_str (), _O_CREAT | _O_TRUNC | _O_BINARY | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE );
|
||||
int fd = _wopen (tl::to_wstring (path ()).c_str (), _O_CREAT | _O_TRUNC | _O_BINARY | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE );
|
||||
if (fd < 0) {
|
||||
throw FileOpenErrorException (m_source, errno);
|
||||
throw FileOpenErrorException (path (), errno);
|
||||
}
|
||||
m_fd = fd;
|
||||
#else
|
||||
int fd = open (path.c_str (), O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
int fd = open (path ().c_str (), O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0) {
|
||||
throw FileOpenErrorException (m_source, errno);
|
||||
throw FileOpenErrorException (path (), errno);
|
||||
}
|
||||
m_fd = fd;
|
||||
#endif
|
||||
|
|
@ -1187,28 +1186,27 @@ OutputFile::write_file (const char *b, size_t n)
|
|||
ptrdiff_t ret = ::write (m_fd, b, (unsigned int) n);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
throw FileWriteErrorException (m_source, errno);
|
||||
throw FileWriteErrorException (path (), errno);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// OutputZLibFile implementation
|
||||
|
||||
OutputZLibFile::OutputZLibFile (const std::string &path, int keep_backups)
|
||||
: OutputFileBase (path, keep_backups), mp_d (new ZLibFilePrivate ())
|
||||
OutputZLibFile::OutputZLibFile (const std::string &p, int keep_backups)
|
||||
: OutputFileBase (p, keep_backups), mp_d (new ZLibFilePrivate ())
|
||||
{
|
||||
m_source = path;
|
||||
#if defined(_WIN32)
|
||||
FILE *file = _wfopen (tl::to_wstring (path).c_str (), L"wb");
|
||||
FILE *file = _wfopen (tl::to_wstring (path ()).c_str (), L"wb");
|
||||
if (file == NULL) {
|
||||
throw FileOpenErrorException (m_source, errno);
|
||||
throw FileOpenErrorException (path (), errno);
|
||||
}
|
||||
mp_d->zs = gzdopen (_fileno (file), "wb");
|
||||
#else
|
||||
mp_d->zs = gzopen (tl::string_to_system (path).c_str (), "wb");
|
||||
mp_d->zs = gzopen (tl::string_to_system (path ()).c_str (), "wb");
|
||||
#endif
|
||||
if (mp_d->zs == NULL) {
|
||||
throw FileOpenErrorException (m_source, errno);
|
||||
throw FileOpenErrorException (path (), errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1231,9 +1229,9 @@ OutputZLibFile::write_file (const char *b, size_t n)
|
|||
int gz_err = 0;
|
||||
const char *em = gzerror (mp_d->zs, &gz_err);
|
||||
if (gz_err == Z_ERRNO) {
|
||||
throw FileWriteErrorException (m_source, errno);
|
||||
throw FileWriteErrorException (path (), errno);
|
||||
} else {
|
||||
throw ZLibWriteErrorException (m_source, em);
|
||||
throw ZLibWriteErrorException (path (), em);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,6 +928,22 @@ public:
|
|||
*/
|
||||
virtual void reject ();
|
||||
|
||||
/**
|
||||
* @brief Gets the actual path
|
||||
*/
|
||||
const std::string &path () const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the path of the backup file
|
||||
*/
|
||||
const std::string &backup_path () const
|
||||
{
|
||||
return m_backup_path;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void seek_file (size_t s) = 0;
|
||||
virtual void write_file (const char *b, size_t n) = 0;
|
||||
|
|
@ -990,7 +1006,6 @@ private:
|
|||
OutputZLibFile (const OutputZLibFile &);
|
||||
OutputZLibFile &operator= (const OutputZLibFile &);
|
||||
|
||||
std::string m_source;
|
||||
ZLibFilePrivate *mp_d;
|
||||
};
|
||||
|
||||
|
|
@ -1051,7 +1066,6 @@ private:
|
|||
OutputFile (const OutputFile &);
|
||||
OutputFile &operator= (const OutputFile &);
|
||||
|
||||
std::string m_source;
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
Reference in New Issue