Merge branch 'master' into issue-1249

This commit is contained in:
Matthias Koefferlein 2023-02-18 09:44:48 +01:00
commit 4e3c106b27
3 changed files with 81 additions and 20 deletions

View File

@ -1552,15 +1552,19 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
m_alt_ac = ac_from_buttons (buttons);
// drag the vertex or edge/segment
if (m_selection.size () == 1 && ! m_selection.begin ()->first.is_cell_inst () && (m_selection.begin ()->second.size () == 1 /*p*/ || m_selection.begin ()->second.size () == 3 /*p1,p2,edge*/)) {
if (is_single_point_selection () || is_single_edge_selection ()) {
lay::PointSnapToObjectResult snap_details;
// for a single selected point or edge, m_start is the original position and we snap the target -
// thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p);
m_current = snap_details.snapped_point;
mouse_cursor_from_snap_details (snap_details);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
m_current = m_start + snap (p - m_start);
} else {
m_current = snap_details.snapped_point;
mouse_cursor_from_snap_details (snap_details);
}
} else {
@ -1601,6 +1605,17 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
return false;
}
static db::DPoint
projected_to_edge (const db::DEdge &edge, const db::DPoint &p)
{
if (edge.is_degenerate ()) {
return edge.p1 ();
} else {
db::DVector v = edge.d () * (1.0 / edge.length ());
return edge.p1 () + v * db::sprod (p - edge.p1 (), v);
}
}
bool
PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio)
{
@ -1674,8 +1689,12 @@ PartialService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bo
if (is_single_point_selection ()) {
// for a single selected point we use the original point as the start location which
// allows bringing a to grid
// allows bringing it to grid
m_current = m_start = single_selected_point ();
} else if (is_single_edge_selection ()) {
// for an edge selection use the point projected to edge as the start location which
// allows bringing it to grid
m_current = m_start = projected_to_edge (single_selected_edge (), p);
} else {
m_current = m_start = p;
}
@ -1863,8 +1882,12 @@ PartialService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bo
if (is_single_point_selection ()) {
// for a single selected point we use the original point as the start location which
// allows bringing a to grid
// allows bringing it to grid
m_current = m_start = single_selected_point ();
} else if (is_single_edge_selection ()) {
// for an edge selection use the point projected to edge as the start location which
// allows bringing it to grid
m_current = m_start = projected_to_edge (single_selected_edge (), p);
} else {
m_current = m_start = p;
}
@ -2390,6 +2413,28 @@ PartialService::is_single_point_selection () const
return (m_selection.size () == 1 && ! m_selection.begin ()->first.is_cell_inst () && m_selection.begin ()->second.size () == 1 /*p*/);
}
db::DEdge
PartialService::single_selected_edge () const
{
// build the transformation variants cache and
// use only the first one of the explicit transformations
// TODO: clarify how this can be implemented in a more generic form or leave it thus.
TransformationVariants tv (view ());
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (m_selection.begin ()->first.cv_index (), m_selection.begin ()->first.layer ());
const lay::CellView &cv = view ()->cellview (m_selection.begin ()->first.cv_index ());
db::ICplxTrans gt (cv.context_trans () * m_selection.begin ()->first.trans ());
db::CplxTrans tt = (*tv_list)[0] * db::CplxTrans (cv->layout ().dbu ()) * gt;
return tt * *m_selection.begin ()->second.begin ();
}
bool
PartialService::is_single_edge_selection () const
{
return (m_selection.size () == 1 && ! m_selection.begin ()->first.is_cell_inst () && m_selection.begin ()->second.size () == 3 /*p1,p2,edge*/);
}
bool
PartialService::select (const db::DBox &box, SelectionMode mode)
{

View File

@ -363,7 +363,9 @@ private:
void resize_markers (size_t n, bool transient);
void resize_inst_markers (size_t n, bool transient);
bool is_single_point_selection () const;
bool is_single_edge_selection () const;
db::DPoint single_selected_point () const;
db::DEdge single_selected_edge () const;
bool handle_guiding_shape_changes ();
void transform_selection (const db::DTrans &move_trans);
};

View File

@ -21,27 +21,41 @@ import unittest
import os
import sys
def compare(pb1, pb2):
if pb1.width() != pb2.width() or pb1.height() != pb2.height():
return False
for x in range(0, pb1.width()):
for y in range(0, pb1.height()):
if pb1.pixel(x, y) != pb2.pixel(x, y):
return False
return True
class LAYPixelBufferTests(unittest.TestCase):
def test_4(self):
pb = pya.PixelBuffer(10, 20)
pb.transparent = True
pb.fill(0xf0010203)
def test_1(self):
png = pb.to_png_data()
pb = pya.PixelBuffer(10, 20)
pb.transparent = True
pb.fill(0xf0010203)
# some range because implementations may differ
self.assertGreater(len(png), 20)
self.assertLess(len(png), 200)
pb_copy = pya.PixelBuffer.from_png_data(png)
self.assertEqual(pb, pb_copy)
png = pb.to_png_data()
ut_testtmp = os.getenv("TESTTMP", ".")
tmp = os.path.join(ut_testtmp, "tmp.png")
# some range because implementations may differ
self.assertGreater(len(png), 20)
self.assertLess(len(png), 200)
pb_copy = pya.PixelBuffer.from_png_data(png)
self.assertEqual(pb, pb_copy)
pb.write_png(tmp)
pb_copy = pya.PixelBuffer.read_png(tmp)
self.assertEqual(pb, pb_copy)
ut_testtmp = os.getenv("TESTTMP", ".")
tmp = os.path.join(ut_testtmp, "tmp.png")
pb.write_png(tmp)
pb_copy = pya.PixelBuffer.read_png(tmp)
self.assertEqual(compare(pb, pb_copy), True)
# run unit tests