def gen_dim(self, idx: int, always_above: bool = True) -> 'npt.NDArray[numpy.float64]': """ Generate rendering data for the dimension-lines :param idx: :return: """ a = self.im2V(self.model.dim_handles[0 + idx]) b = self.im2V(self.model.dim_handles[1 + idx]) d = b - a delta = (b - a).norm() normal = Vec2.from_mat(rotate(math.pi / 2)[:2, :2].dot(delta)) if always_above: if numpy.cross(Vec2(1, 0), normal) > 0: normal = -normal res = numpy.array([ a + normal * 8, a + normal * 20, a + normal * 15, b + normal * 15, b + normal * 8, b + normal * 20, ], dtype=numpy.float64) return res
def keyPressEvent(self, evt): keycode = evt.key() jog_keys = { QtCore.Qt.Key_Left: Vec2(-1, 0), QtCore.Qt.Key_Right: Vec2(1, 0), QtCore.Qt.Key_Up: Vec2(0, 1), QtCore.Qt.Key_Down: Vec2(0, -1) } if keycode == QtCore.Qt.Key_Escape: self.abort_entry() elif keycode in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): if self.__point_active: self.commit_entry(evt.modifiers() & QtCore.Qt.ShiftModifier) else: self.__done = DONE_REASON.ACCEPT elif keycode in jog_keys: self.do_jog(jog_keys[keycode]) elif keycode == QtCore.Qt.Key_Q: self.prev_point() elif keycode == QtCore.Qt.Key_W: self.next_point() elif keycode == QtCore.Qt.Key_E: self.make_active() elif keycode == QtCore.Qt.Key_R: self.next_option() else: return False return True
def updated(self, ep): if self.p1_point.is_set: if self.p_bottom_corner.is_set: v = (self.p_bottom_corner.get() - self.p1_point.get()) mag = v.mag() v = v.norm() self._cmodel.theta = v.angle() self._model.pin_spacing = mag / (self._model.side1_pins - 1) self.v_base = Vec2.from_polar(self._cmodel.theta, 1) self.v_vert = Vec2(-self.v_base.y, self.v_base.x).norm() p_edge_center = self.v_base * self._model.pin_spacing * ( self._model.side1_pins - 1) / 2 if self.p_side_3_1.is_set: dv = self.p_side_3_1.get() - self.p1_point.get() v, _ = project_point_line(dv, Point2(0, 0), self.v_vert, False) self._model.dim_2_pincenter = v.mag() self._cmodel.center = self.v_vert * self._model.dim_2_pincenter / 2 + p_edge_center + self.p1_point.get( ) if self.p_side_2_1.is_set: v, _ = project_point_line( self.p_side_2_1.get() - self._cmodel.center, Point2(0, 0), self.v_base, False) self._model.dim_1_pincenter = v.mag() * 2
def __init__(self, view, project, text_renderer): self.__text = text_renderer self.__project = project self.__view = view self.__top_side_labels = TextBatch(text_renderer) self.__top_side_pads = TextBatch(text_renderer) self.__bottom_side_labels = TextBatch(text_renderer) self.__bottom_side_pads = TextBatch(text_renderer) self.__last_generation = None self.__up_vector = Vec2(0, 1) self.__ltor_vector = Vec2(1, 0)
def keyPressEvent(self, evt: QtGui.QKeyEvent) -> None: if evt.key() == QtCore.Qt.Key_Escape: self.model.kp.selected_idx = None elif self.model.kp.selected_idx is not None: if evt.key() in (QtCore.Qt.Key_Delete, QtCore.Qt.Key_Backspace): cmd = cmd_del_keypoint(self.model.kp, self.model.kp.selected_idx) self._parent.undoStack.push(cmd) self.model.kp.selected_idx = None # Basic 1-px nudging elif evt.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): kp_lut: Dict[int, Tuple[int, int]] = { QtCore.Qt.Key_Left: (-1, 0), QtCore.Qt.Key_Right: (1, 0), QtCore.Qt.Key_Up: (0, -1), QtCore.Qt.Key_Down: (0, 1), } nudge = Vec2.from_mat(kp_lut[evt.key()]) current = self.get_keypoint_viewport_center( self.model.kp.keypoints[self.model.kp.selected_idx]) self.do_set_cmd(current + nudge, True)
def __init__(self, view, model): self._model = model self.p1_point = EditablePoint(Point2(0, 0)) self.__theta = 0 self.__corner = Point2(0, 0) rmat = rotate(self.theta) dy = -(model.pin_count / 2 - 1) * model.pin_space v_aligned = Vec2(0, dy) v_delta = projectPoint(rmat, v_aligned) # the pin on the end of the same row as P1 self.p_bottom_corner = OffsetDefaultPoint(self.p1_point, v_delta) # Opposite corner point self.p_opposite = WidthProjectedPoint(self) points = [self.p1_point, self.p_bottom_corner, self.p_opposite] super(DIPEditFlow, self).__init__(view, points, True) if self.view.viewState.current_layer is None: self.side = SIDE.Top else: self.side = self.view.viewState.current_layer.side self.update_matrix()
def keyPressEvent(self, evt): disabled = not self.active or self.model_overall.view_mode if disabled: return False if evt.key() == QtCore.Qt.Key_Escape: self.idx_handle_sel = None elif self.idx_handle_sel is not None: if evt.key() in (QtCore.Qt.Key_Delete, QtCore.Qt.Key_Backspace) and IDX_IS_ANCHOR(self.idx_handle_sel): cmd = cmd_set_handle_position(self.model, self.idx_handle_sel, None) self._parent.undoStack.push(cmd) #self.model.set_handle(self.idx_handle_sel, None) self.idx_handle_sel = None # Basic 1-px nudging elif evt.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): nudge = { QtCore.Qt.Key_Left: (-1, 0), QtCore.Qt.Key_Right: ( 1, 0), QtCore.Qt.Key_Up: ( 0, -1), QtCore.Qt.Key_Down: ( 0, 1), }[evt.key()] current = Vec2(self.im2V(self.model.align_handles[self.idx_handle_sel])) viewspace = self.V2im(current + nudge) cmd = cmd_set_handle_position(self.model, self.idx_handle_sel, viewspace) self._parent.undoStack.push(cmd) #self.model.set_handle(self.idx_handle_sel, viewspace) self.ghost_handle = None
def mouseMoveEvent(self, event): disabled = not self.active or self.model_overall.view_mode if disabled: return False needs_update = False idx = self.get_handle_for_mouse(event.pos()) if self.ghost_handle is not None: self.ghost_handle = None if self.behave_mode == MODE_NONE: if idx is not None: self.idx_handle_hover = idx else: self.idx_handle_hover = None if event.modifiers() & ADD_MODIFIER: line_idx, pos = self.get_line_query_for_mouse(event.pos()) if line_idx is not None: self.ghost_handle = pos elif self.behave_mode == MODE_DRAGGING: w_pos = self.V2im(Vec2(event.pos())) cmd = cmd_set_handle_position(self.model, self.idx_handle_sel, w_pos, merge=True) self._parent.undoStack.push(cmd) #self.model.set_handle(self.idx_handle_sel, w_pos) return False
def gen_dim(self, idx, always_above = True): """ Generate rendering data for the dimension-lines :param idx: :return: """ a = self.im2V(self.model.dim_handles[0 + idx]) b = self.im2V(self.model.dim_handles[1 + idx]) d = b-a delta = (b-a).norm() normal = Point2(rotate(math.pi / 2)[:2,:2].dot(delta)) if always_above: if numpy.cross(Vec2(1,0), normal) > 0: normal = -normal res = numpy.array([ a + normal * 8, a + normal * 20, a + normal * 15, b + normal * 15, b + normal * 8, b + normal * 20, ]) return res
def move(self, cur: Point2) -> None: lx, ly = project_point(self.vs.revMatrix, self.last) nx, ny = project_point(self.vs.revMatrix, cur) self.vs.translate(Vec2(nx - lx, ny - ly)) self.last = cur
def keyPressEvent(self, evt: QtGui.QKeyEvent) -> bool: if self.disabled: return False if evt.key() == QtCore.Qt.Key_Escape: self.__idx_handle_sel = None elif self.__idx_handle_sel is not None: if evt.key() in (QtCore.Qt.Key_Delete, QtCore.Qt.Key_Backspace) and IDX_IS_LINE(self.__idx_handle_sel): cmd = cmd_set_handle_position(self.model, self.__idx_handle_sel, None) self._parent.undoStack.push(cmd) # self.model.set_handle(self.__idx_handle_sel, None) self.__idx_handle_sel = None # Basic 1-px nudging elif evt.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): _nudgetab: Dict[int,Tuple[int, int]] = { QtCore.Qt.Key_Left: (-1, 0), QtCore.Qt.Key_Right: (1, 0), QtCore.Qt.Key_Up: (0, -1), QtCore.Qt.Key_Down: (0, 1), } nudge = _nudgetab[evt.key()] current = self.im2V(self.model.align_handles[self.__idx_handle_sel]) viewspace = self.V2im(current + Vec2.from_mat(nudge)) cmd = cmd_set_handle_position(self.model, self.__idx_handle_sel, viewspace) self._parent.undoStack.push(cmd) # self.model.set_handle(self.__idx_handle_sel, viewspace) self.__ghost_handle = None
def updated(self, ep): if self.p1_point.is_set: if self.p_bottom_corner.is_set: v = (self.p_bottom_corner.get() - self.p1_point.get()) mag = v.mag() v = v.norm() self.__theta = v.angle() self._model.pin_spacing = mag / (self._model.side1_pins - 1) self.v_base = Vec2.fromPolar(self.__theta, 1) self.v_vert = Vec2(-self.v_base.y, self.v_base.x).norm() p_edge_center = self.v_base * self._model.pin_spacing * (self._model.side1_pins - 1) / 2 if self.p_side_3_1.is_set: dv = self.p_side_3_1.get() - self.p1_point.get() v, _ = project_point_line(dv, Point2(0,0), self.v_vert, False) self._model.dim_2_pincenter = v.mag() self.center = self.v_vert * self._model.dim_2_pincenter / 2 + p_edge_center + self.p1_point.get() if self.p_side_2_1.is_set: v, _ = project_point_line(self.p_side_2_1.get() - self.center, Point2(0,0), self.v_base, False) self._model.dim_1_pincenter = v.mag() * 2
def passive_border_va(va: 'VA_xy', cmp: 'Passive2Component') -> None: """ :type cmp: pcbre.model.passivecomponent.Passive2Component :type va: pcbre.accel.vert_array.VA_xy :param cmp: :return: """ if cmp.body_type == Passive2BodyType.CHIP: bx = cmp.body_corner_vec.x by = cmp.body_corner_vec.y va.add_box(cmp.center.x, cmp.center.y, bx * 2, by * 2, cmp.theta) elif cmp.body_type == Passive2BodyType.TH_AXIAL: bx = cmp.body_corner_vec.x by = cmp.body_corner_vec.y va.add_box(cmp.center.x, cmp.center.y, bx * 2, by * 2, cmp.theta) vec = Vec2(math.cos(cmp.theta), math.sin(cmp.theta)) # Add legs pa = cmp.pin_d * vec pb = cmp.body_corner_vec.x * vec va.add_line(pa.x + cmp.center.x, pa.y + cmp.center.y, pb.x + cmp.center.x, pb.y + cmp.center.y) va.add_line(-pa.x + cmp.center.x, -pa.y + cmp.center.y, -pb.x + cmp.center.x, -pb.y + cmp.center.y) elif cmp.body_type == Passive2BodyType.TH_RADIAL: raise NotImplementedError() else: raise NotImplementedError()
def __init__(self, view, model, cmodel): self._model = model self._cmodel = cmodel self.p1_point = EditablePoint(Point2(0, 0)) rmat = rotate(self._cmodel.theta) dy = -(model.pin_count / 2 - 1) * model.pin_space v_aligned = Vec2(0, dy) v_delta = project_point(rmat, v_aligned) # the pin on the end of the same row as P1 self.p_bottom_corner = OffsetDefaultPoint(self.p1_point, v_delta) # Opposite corner point self.p_opposite = WidthProjectedPoint(self) points = [self.p1_point, self.p_bottom_corner, self.p_opposite] super(DIPEditFlow, self).__init__(view, points, True) self.update_matrix()
def __init__(self, is_new: bool = True) -> None: # World-space coordinates of the keypoint self.world = Vec2(0, 0) # Current align-layer-space coordinates of the keypoint (in pixels, not in normalized image coords) self.layer = Vec2(0, 0) # Keypoint created for this layer or existing? # if existing, keypoint should not be moved in worldspace or deleted # since the alignment solution for other layers may rely on it # AlignKeypoint.is_new may also be true if it existed before, but no other layer # ever used it for alignment (since then it may be safely moved or deleted) self.is_new = is_new # Use this keypoint for the alignment solution self.use = False self._orig_kp: Optional[KeyPoint] = None
def __init__(self, view: "BoardViewWidget", project: "Project", text_renderer: "TextRender") -> None: self.__text = text_renderer self.__project = project self.__view = view self.__top_side_labels = TextBatch(text_renderer) self.__top_side_pads = TextBatch(text_renderer) self.__bottom_side_labels = TextBatch(text_renderer) self.__bottom_side_pads = TextBatch(text_renderer) self.__last_generation : Optional[int] = None self.__up_vector = Vec2(0, 1) self.__ltor_vector = Vec2(1, 0)
def __update(self): if self.__pins_cache: return w = self.dim_1_body h = self.dim_2_body pads = [] d_2_pc = self.dim_2_pincenter / 2 d_1_pc = self.dim_1_pincenter / 2 overall_pin_no = 0 for i, side_pin_count in enumerate(self.side_pins): offset = (side_pin_count - 1) / 2 * self.pin_spacing pad_theta = math.pi / 2 * i if i == 0: start = Point2(-d_2_pc, offset) step = Vec2(0, -self.pin_spacing) elif i == 1: start = Point2(-offset, -d_1_pc) step = Vec2(self.pin_spacing, 0) elif i == 2: start = Point2(d_2_pc, -offset) step = Vec2(0, self.pin_spacing) elif i == 3: start = Point2(offset, d_1_pc) step = Vec2(-self.pin_spacing, 0) for pin_no in range(side_pin_count): pin_center = start + step * pin_no pads.append( Pad(self, "%s" % (overall_pin_no + 1), pin_center, pad_theta, self.pin_spacing / 2, self.pin_contact_length, side=self.side)) overall_pin_no += 1 self.__pins_cache = pads
def __init__(self, image): GenModel.__init__(self) self.__image = image # 4 corner handles, 2 (potential) anchor handles per line ini_shape = image.decoded_image.shape max_dim = float(max(ini_shape)) x = ini_shape[1] / max_dim y = ini_shape[0] / max_dim self.__align_handles = [Vec2(-x, -y), Vec2(x, -y), Vec2(x, y), Vec2(-x, y)] + [None] * 8 self.__dim_handles = [self.__align_handles[0], self.__align_handles[1], self.align_handles[1], self.align_handles[2]] self.__placeholder_dim_values = [100, 100] self.__dim_values = [None, None] self.update_matricies()
def update_layer(self) -> None: idx = self.kpts_sel.currentIndex() vx = self.px.getValue() vy = self.py.getValue() if vx is None or vy is None: # TODO - flash bad box? return p = Vec2(vx, vy) cmd = cmd_set_keypoint_px(self.model, idx, p) self._parent.undoStack.push(cmd)
def __init__(self, view, points, can_shortcut=False): self.view = view self.__points = points self.__current_point_index = 0 self.__point_active = False self.is_initial_active = True self.simple_entry = True self.can_shortcut = can_shortcut self.__done = DONE_REASON.NOT_DONE self.__grab_delta = Vec2(0, 0)
def deserialize(project: 'Project', msg: ser.Component.Reader) -> Component: t = msg.smd4 cmp = SMD4Component( project, Vec2(0,0), 0, SIDE.Top, # Placeholder values project, t.side1Pins, t.side2Pins, t.side3Pins, t.side4Pins, t.dim1Body, t.dim1PinEdge, t.dim2Body, t.dim2PinEdge, t.pinContactLength, t.pinContactWidth, t.pinSpacing) Component.deserializeTo(project, msg.common, cmp) return cmp
def pt_inside_pad(pad, pt): """ :param pt: :return: """ point_padspace = pad.world_to_pad(pt) delta = Vec2(point_padspace) if pad.w == pad.l: return delta.mag() < pad.l / 2 else: return pt_inside_trace(pad.trace_repr, pt)
def V2im(self, pt): """ Translate viewport coordinates to image coordinates :param pt: :return: """ world = self.viewState.tfV2W(pt) if self.model_overall.view_mode: inv = numpy.linalg.inv(self.model.image_matrix) return projectPoint(inv, world) else: return Vec2(world)
def __update_pads(self): if self.__pads: return v = Vec2.fromPolar(0, self.pin_d) td = 1 if self.body_type in (PassiveBodyType.TH_AXIAL, PassiveBodyType.TH_RADIAL) else 0 if td: y = x = self.pin_corner_vec.x * 2 else: y = self.pin_corner_vec.y * 2 x = self.pin_corner_vec.x * 2 self.__pads = [Pad(self, 1, v, 0, y, x, td, self.side), Pad(self, 2, -v, 0, y, x, td, self.side)]
def __init__(self, image: 'ImageLayer'): self.__image = image # 4 corner handles, 2 (potential) anchor handles per line ini_shape = image.decoded_image.shape max_dim = float(max(ini_shape)) x = ini_shape[1] / max_dim y = ini_shape[0] / max_dim # print("Initial shape:", x, y) # Expressed in a way that mypy static type checking likes self.__corner_handles: CornerHandleType = ( Vec2(-x, -y), Vec2(x, -y), Vec2(x, y), Vec2(-x, y), ) self.__line_handles: LineHandleType = (None, None, None, None, None, None, None, None) self.__dim_handles = (self.__corner_handles[0], self.__corner_handles[1], self.__corner_handles[1], self.__corner_handles[2]) self.__dims_locked = True self.__placeholder_dim_values: List[float] = [100, 100] self.__dim_values: List[Optional[float]] = [None, None] self.update_matricies() self.translate_x : float = 0 self.translate_y : float = 0 self.origin_idx : int = 0 self.persp_matrix = numpy.identity(3) self.scale_matrix = numpy.identity(3) self.rotate_theta = 0.0 self.flip_x = False self.flip_y = False
def update_matrix(self): rot = rotate(self._cmodel.theta) center_to_corner = Vec2( 0, self._model.pin_space * (self._model.pin_count - 1) / 2) center_to_corner_w = project_point(rot, center_to_corner) self._cmodel.center = self.p1_point.get() - center_to_corner_w self.matrix = translate(self._cmodel.center.x, self._cmodel.center.y).dot( rotate(self._cmodel.theta))
def commit_entry(self, shift_pressed): if self.simple_entry and not shift_pressed: self.__done = DONE_REASON.ACCEPT self.__point_active = False else: self.simple_entry = False if self.__point_active: self.__point_active = False self.next_point() if not self.current_point.is_set: if self.is_initial_active: self.__grab_delta = Vec2(0, 0) self.make_active() else: self.is_initial_active = False
def update_matrix(self): rot = rotate(self._cmodel.theta) sign = self.get_cur_sign() center_to_corner = Vec2( sign * self._model.pin_width / 2, self._model.pin_space * (self._model.pin_count / 2 - 1) / 2) center_to_corner_w = project_point(rot, center_to_corner) self._cmodel.center = self.p1_point.get() - center_to_corner_w self.matrix = translate(self._cmodel.center.x, self._cmodel.center.y).dot( rotate(self._cmodel.theta))
def __update_pads(self) -> None: if self.__pads: return v = Vec2.from_polar(0, self.pin_d) td = 1 if self.body_type in (Passive2BodyType.TH_AXIAL, Passive2BodyType.TH_RADIAL) else 0 if td: y = x = self.pin_corner_vec.x * 2 else: y = self.pin_corner_vec.y * 2 x = self.pin_corner_vec.x * 2 self.__pads = [ Pad(self, "1", v, 0, y, x, td, self.side), Pad(self, "2", -v, 0, y, x, td, self.side), ]
def update_matrix(self): rot = rotate(self.theta) if self.side == SIDE.Top: sign = -1 else: sign = 1 center_to_corner = Vec2( sign * self._model.pin_width / 2, self._model.pin_space * (self._model.pin_count / 2 - 1) / 2) center_to_corner_w = projectPoint(rot, center_to_corner) self.center = self.p1_point.get() - center_to_corner_w self.matrix = translate(self.center.x, self.center.y).dot(rotate(self.theta))
def __build_trace(self) -> None: # Update trace VBO self.working_array["vertex"][0] = (0, 0) self.working_array["ptid"][0] = 0 self.working_array["vertex"][1] = (0, 0) self.working_array["ptid"][1] = 1 end = Vec2(1, 0) for i in range(0, NUM_ENDCAP_SEGMENTS): theta = math.pi * i / (NUM_ENDCAP_SEGMENTS - 1) + math.pi / 2 m = rotate(theta).dot(end.homol()) self.working_array["vertex"][2 + i] = m[:2] self.working_array["ptid"][2 + i] = 0 self.working_array["vertex"][2 + i + NUM_ENDCAP_SEGMENTS] = -m[:2] self.working_array["ptid"][2 + i + NUM_ENDCAP_SEGMENTS] = 1 # Force data copy self.trace_vbo.bind() self.trace_vbo.set_array(self.working_array)
def get_corner_points(self) -> List[Vec2]: # Normalized_dims max_dim = float(max(self.__cached_decode.shape)) x = self.__cached_decode.shape[1]/max_dim y = self.__cached_decode.shape[0]/max_dim corners = ( (-1, -1), (-1, 1), (1, 1), (1, -1)) # Rectangle in pixel space corners_pixspace = [ Vec2(mx * x, my * y) for mx, my in corners ] # Possibly non-rectangular corner points corners_norm = [ project_point(self.transform_matrix, p) for p in corners_pixspace ] return corners_norm
def other_point(): return Vec2.fromPolar(self.theta, self.model.pin_d)
def corner_offset(): mag = self._model.pin_spacing * (self._model.side1_pins - 1) return Vec2.fromPolar(self.__theta, mag)