def currentState(self, relativeTo=None): pos = self['start'] dir = self['dir'] if relativeTo is None: return pos, dir else: trans = self.itemTransform(relativeTo)[0] p1 = trans.map(pos) p2 = trans.map(pos + dir) return Point(p1), Point(p2 - p1)
def intersectRay(self, ray): ## return the point of intersection and the angle of incidence #print "intersect ray" h = self.h2 r = self.r p, dir = ray.currentState(relativeTo=self) # position and angle of ray in local coords. #print " ray: ", p, dir p = p - Point(r, 0) ## move position so center of circle is at 0,0 #print " adj: ", p, r if r == 0: #print " flat" if dir[0] == 0: y = 0 else: y = p[1] - p[0] * dir[1]/dir[0] if abs(y) > h: return None, None else: return (Point(0, y), atan2(dir[1], dir[0])) else: #print " curve" ## find intersection of circle and line (quadratic formula) dx = dir[0] dy = dir[1] dr = hypot(dx, dy) # length D = p[0] * (p[1]+dy) - (p[0]+dx) * p[1] idr2 = 1.0 / dr**2 disc = r**2 * dr**2 - D**2 if disc < 0: return None, None disc2 = disc**0.5 if dy < 0: sgn = -1 else: sgn = 1 br = self.path.boundingRect() x1 = (D*dy + sgn*dx*disc2) * idr2 y1 = (-D*dx + abs(dy)*disc2) * idr2 if br.contains(x1+r, y1): pt = Point(x1, y1) else: x2 = (D*dy - sgn*dx*disc2) * idr2 y2 = (-D*dx - abs(dy)*disc2) * idr2 pt = Point(x2, y2) if not br.contains(x2+r, y2): return None, None norm = atan2(pt[1], pt[0]) if r < 0: norm += np.pi dp = p - pt ang = atan2(dp[1], dp[0]) return pt + Point(r, 0), ang-norm
def qgo_draw_markers( markers: list, color: Color, p: QtGui.QPainter, left: float, right: float, right_offset: float, ) -> float: """Paint markers in ``pg.GraphicsItem`` style by first removing the view transform for the painter, drawing the markers in scene coords, then restoring the view coords. """ # paint markers in native coordinate system orig_tr = p.transform() start = orig_tr.map(Point(left, 0)) end = orig_tr.map(Point(right, 0)) up = orig_tr.map(Point(left, 1)) dif = end - start # length = Point(dif).length() angle = np.arctan2(dif.y(), dif.x()) * 180 / np.pi p.resetTransform() p.translate(start) p.rotate(angle) up = up - start det = up.x() * dif.y() - dif.x() * up.y() p.scale(1, 1 if det > 0 else -1) p.setBrush(fn.mkBrush(color)) # p.setBrush(fn.mkBrush(self.currentPen.color())) tr = p.transform() sizes = [] for path, pos, size in markers: p.setTransform(tr) # XXX: we drop the "scale / %" placement # x = length * pos x = right_offset p.translate(x, 0) p.scale(size, size) p.drawPath(path) sizes.append(size) p.setTransform(orig_tr) return max(sizes)
def __new_target(self, center, offset=False): """Get new rectangle centered around center.""" dx, dy = self.__get_size() left_size, up_size = 0.5, 0.5 if offset: # offset target rectangle size, more natural for zooming vr = self.targetRect() left_size = (center.x() - vr.topLeft().x()) / vr.width() up_size = (center.y() - vr.topLeft().y()) / vr.height() tl = center + Point(-dx * left_size, -dy * up_size) br = center + Point(dx * (1 - left_size), dy * (1 - up_size)) return QRectF(tl, br)
def shape(self): if self._shape is None: radius = self.getState()['size'][1] p = QtGui.QPainterPath() p.moveTo(Point(0, -radius)) p.lineTo(Point(0, radius)) p.moveTo(Point(-radius, 0)) p.lineTo(Point(radius, 0)) p = self.mapToDevice(p) stroker = QtGui.QPainterPathStroker() stroker.setWidth(10) outline = stroker.createStroke(p) self._shape = self.mapFromDevice(outline) return self._shape
def test_update_view_range(self): self.graph.reset_graph() self.view_box.recalculate_zoom.reset_mock() self.view_box.match_zoom.reset_mock() self.graph.update_view_range() self.view_box.recalculate_zoom.assert_called_once_with( 0.7 - 0.5, 0.8 - 0.6) self.view_box.match_zoom.assert_called_once_with(Point(0.6, 0.7)) self.view_box.recalculate_zoom.reset_mock() self.view_box.match_zoom.reset_mock() self.graph.update_view_range(match_data=False) self.assertFalse(self.view_box.recalculate_zoom.called) self.view_box.match_zoom.assert_called_once_with(Point(0.15, 0.35))
def paint(self, p, *args): if self.levelMode != 'mono': return pen = self.region.lines[0].pen rgn = self.getLevels() p1 = self.vb.mapFromViewToItem(self, Point(self.vb.viewRect().center().x(), rgn[0])) p2 = self.vb.mapFromViewToItem(self, Point(self.vb.viewRect().center().x(), rgn[1])) gradRect = self.gradient.mapRectToParent(self.gradient.gradRect.rect()) for pen in [fn.mkPen((0, 0, 0, 100), width=3), pen]: p.setPen(pen) p.drawLine(p1 + Point(0, 5), gradRect.bottomLeft()) p.drawLine(p2 - Point(0, 5), gradRect.topLeft()) p.drawLine(gradRect.topLeft(), gradRect.topRight()) p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight())
def getArrayIndexes(self, spacing=1, **kwds): imgPts = self.get_vertex() positions = [] for i in range(len(imgPts) - 1): d = Point(imgPts[i + 1] - imgPts[i]) o = Point(imgPts[i]) vect = Point(d.norm()) Npts = 0 while Npts * spacing < d.length(): positions.append(((o + Npts * spacing * vect).x(), (o + Npts * spacing * vect).y())) Npts += 1 return positions
def step_scale(self, pos, step_mode=False): self.scale = np.linalg.norm(Point(pos) - self.origin) / self.ini_dist if step_mode: incr = 0.1 self.scale = round(self.scale / incr) * incr for item in self.proxy_items: item.setScale(self.scale)
def getArrayRegion(self, arr, img=None): """ Return the result of ROI.getArrayRegion() masked by the arc shape of the ROI. Regions outside the arc are set to 0. """ w = arr.shape[-2] h = arr.shape[-1] centerangle = self.outerhandle.pos().angle(Point(1, 0)) startangle = centerangle - self.thetawidth / 2 # generate an ellipsoidal mask mask = np.fromfunction( lambda y, x: ( self.innerhandle.pos().length() < ( (x - self.pos().y()) ** 2.0 + (y - self.pos().x()) ** 2.0) ** 0.5 ) & (((x - self.pos().y()) ** 2.0 + ( y - self.pos().x()) ** 2.0) ** 0.5 < self.outerhandle.pos().length()) & ((np.degrees(np.arctan2(y - self.pos().x(), x - self.pos().y())) - startangle) % 360 > 0) & ((np.degrees( np.arctan2(y - self.pos().x(), x - self.pos().y())) - startangle) % 360 < self.thetawidth), (w, h), ) return arr * mask
def start_rot(self, pos): self._create_proxy_items() self.origin = self._selection_centroid() for item in self.proxy_items: item.setTransformOriginPoint(self.origin) direction = Point(pos) - self.origin self.ini_angle = math.atan2(direction[1], direction[0])
def getLabelArray(self, arr, img: pg.ImageItem = None): labels = np.zeros(arr.shape[-2:]) centerangle = -self.outerhandle.pos().angle(Point(0, 1)) startangle = centerangle - self.thetawidth / 2 endangle = centerangle + self.thetawidth / 2 radii = np.linspace(self.innerradius, self.outerradius, self.segments_radial + 1, endpoint=True) angles = np.linspace(startangle, endangle, self.segments_angular + 1, endpoint=True) start_radii = radii[:-1] end_radii = radii[1:] start_angles = angles[:-1] end_angles = angles[1:] for i, (start_radius, end_radius) in enumerate(zip(start_radii, end_radii)): for j, (start_angle, end_angle) in enumerate(zip(start_angles, end_angles)): # generate an ellipsoidal mask mask = np.fromfunction( lambda x, y: (start_radius <= ((x - self.pos().y()) ** 2.0 + (y - self.pos().x()) ** 2.0) ** 0.5) & (((x - self.pos().y()) ** 2.0 + (y - self.pos().x()) ** 2.0) ** 0.5 <= end_radius) & ((np.degrees( np.arctan2(y - self.pos().x(), x - self.pos().y())) - start_angle) % 360 >= 0) & ((np.degrees(np.arctan2(y - self.pos().x(), x - self.pos().y())) - start_angle) % 360 <= end_angle - start_angle), arr.shape[-2:], ) labels[mask] = i * self.segments_radial + j + 1 return labels
def setPos(self, pos): if pos != self.pos: self.pos = pos # self.informViewBoundsChanged() # self.sigPlotChanged.emit(self) # self._boundingRect = None GraphicsObject.setPos(self, Point([self.pos, 0]))
def mousePressEvent(self, ev): if self.is_manual_edit or self.is_zoom_edit: self.select_status = True point = self.plotItem.vb.mapSceneToView(ev.pos()) self.x = point.x() self.y = point.y() if self.is_rate_edit: point = self.plotItem.vb.mapSceneToView(ev.pos()) # 添加竖线 base_line = pg.InfiniteLine(angle=90, movable=False, pen=pg.mkPen('g', width=1)) self.addItem(base_line, ignoreBounds=True) base_line.setPos(point.x()) if self.undo_base_point_list is not None: self.base_point_list.append( datetime.datetime.fromtimestamp(point.x())) self.base_point_list.sort() self.undo_base_point_list.append(base_line) else: QtGui.QGraphicsView.mousePressEvent(self, ev) if not self.mouseEnabled: return self.lastMousePos = Point(ev.pos()) self.mousePressPos = ev.pos() self.clickAccepted = ev.isAccepted() if not self.clickAccepted: self.scene().clearSelection() return ## Everything below disabled for now..
def safe_update_scale_box(self, buttonDownPos, currentPos): x, y = currentPos if buttonDownPos[0] == x: x += 1 if buttonDownPos[1] == y: y += 1 self.updateScaleBox(buttonDownPos, Point(x, y))
def _update_view_range(self, min_x, max_x, min_y, max_y, keep_zoom=False): if not keep_zoom: self.view_box.recalculate_zoom(max_x - min_x, max_y - min_y) center = Point(min_x + (max_x - min_x) / 2, min_y + (max_y - min_y) / 2) self.view_box.match_zoom(center)
def paint(self, p, opt, widget): super(SegmentedArcROI, self).paint(p, opt, widget) pen = self.currentPen # pen.setColor(QColor(255, 0, 255)) pen.setStyle(Qt.DashLine) p.setPen(pen) centerangle = self.innerhandle.pos().angle(Point(1, 0)) startangle = centerangle - self.thetawidth / 2 endangle = centerangle + self.thetawidth / 2 segment_angles = np.linspace(startangle, endangle, self.segments_angular, endpoint=False)[1:] segment_radii = np.linspace(self.innerradius, self.outerradius, self.segments_radial, endpoint=False)[1:] r = QCircRectF(radius=0.5) radius = self.innerradius / self.outerradius / 2 r = QCircRectF() r.radius = radius # draw segments for segment_radius in segment_radii: r.radius = segment_radius / self.outerradius / 2 # p.drawRect(r) p.drawArc(r, -startangle * 16, -self.thetawidth * 16) if self.innerradius < self.outerradius: for segment_angle in segment_angles: segment_vector = QPointF(np.cos(np.radians(segment_angle)), np.sin(np.radians(segment_angle))) p.drawLine(segment_vector * self.innerradius / self.outerradius / 2, segment_vector / 2)
def __init__(self, pos=None, size=None, parent=None, **kwargs): assert parent if size == None: size = [0, 0] if pos == None: pos = [0, 0] self._shape = None linepen = pg.mkPen("#FFA500", width=2) self._vline = pg.InfiniteLine((0, 0), angle=90, movable=False, pen=linepen) self._hline = pg.InfiniteLine((0, 0), angle=0, movable=False, pen=linepen) super(BetterCrosshairROI, self).__init__(pos, size, parent=parent, **kwargs) parent.addItem(self) self.sigRegionChanged.connect(self.invalidate) self.addTranslateHandle(Point(0, 0)) self.aspectLocked = True parent.addItem(self._vline) parent.getViewBox().addItem(self._hline)
def mouseDragEvent(self, ev, axis=None): ## if axis is specified, event will only affect that axis. if self.parent is None or (self.parent is not None and not self.parent.in_stroke): ev.accept() ## we accept all buttons pos = ev.pos() lastPos = ev.lastPos() dif = pos - lastPos dif = dif * -1 ## Ignore axes if mouse is disabled mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float) mask = mouseEnabled.copy() if axis is not None: mask[1 - axis] = 0.0 ## Scale or translate based on mouse button if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton): if self.state['mouseMode'] == pg.ViewBox.RectMode: if ev.isFinish( ): ## This is the final move in the drag; change the view scale now #print "finish" self.rbScaleBox.hide() ax = QtCore.QRectF( Point(ev.buttonDownPos(ev.button())), Point(pos)) ax = self.childGroup.mapRectFromParent(ax) self.showAxRect(ax) self.axHistoryPointer += 1 self.axHistory = self.axHistory[:self. axHistoryPointer] + [ ax ] else: ## update shape of scale box self.updateScaleBox(ev.buttonDownPos(), ev.pos()) else: tr = dif * mask tr = self.mapToView(tr) - self.mapToView(Point(0, 0)) x = tr.x() if mask[0] == 1 else None y = tr.y() if mask[1] == 1 else None self._resetTarget() if x is not None or y is not None: self.translateBy(x=x, y=y) self.sigRangeChangedManually.emit( self.state['mouseEnabled'])
def start_scale(self, pos): self._create_proxy_items() self.origin = self._selection_centroid() for item in self.proxy_items: item.setTransformOriginPoint(self.origin) self.ini_dist = np.linalg.norm(Point(pos) - self.origin) if math.isclose(self.ini_dist, 0): self.ini_dist = 1
def setOffset(self, offset): self.offset = offset offset = Point(self.offset) anchorx = 1 if offset[0] <= 0 else 0 anchory = 1 if offset[1] <= 0 else 0 anchor = (anchorx, anchory) self.anchor(itemPos=anchor, parentPos=anchor, offset=offset)
def step_rot(self, pos, step_mode=False): direction = Point(pos) - self.origin self.angle = math.atan2(direction[1], direction[0]) - self.ini_angle if step_mode: incr = math.pi / 12 self.angle = round(self.angle / incr) * incr for item in self.proxy_items: item.setRotation(math.degrees(self.angle))
def wheelEvent(self, ev, axis=None): """Override wheel event so we manually track changes of zoom and update map accordingly.""" delta = 0.5 * np.sign(ev.delta()) self.__zoom_level = self.__clipped_zoom(self.__zoom_level + delta) center = Point(fn.invertQTransform(self.childGroup.transform()).map(ev.pos())) self.match_zoom(center, offset=True) ev.accept()
def mouseClickEvent(self, ev): if ev.button() == Qt.RightButton and \ (self.action == ZOOMING or self.action in [SELECT, SELECT_SQUARE, SELECT_POLYGON]): ev.accept() self.set_mode_panning() elif ev.button() == Qt.RightButton: ev.accept() self.autoRange() add = ev.modifiers( ) & Qt.ControlModifier and self.graph.selection_type == SELECTMANY if self.action != ZOOMING and self.action not in [SELECT, SELECT_SQUARE, SELECT_POLYGON] \ and ev.button() == Qt.LeftButton and self.graph.selection_type: pos = self.childGroup.mapFromParent(ev.pos()) self.graph.select_by_click(pos, add) ev.accept() if self.action == ZOOMING and ev.button() == Qt.LeftButton: if self.zoomstartpoint is None: self.zoomstartpoint = ev.pos() else: self.updateScaleBox(self.zoomstartpoint, ev.pos()) self.rbScaleBox.hide() ax = QRectF(Point(self.zoomstartpoint), Point(ev.pos())) ax = self.childGroup.mapRectFromParent(ax) self.showAxRect(ax) self.axHistoryPointer += 1 self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax] self.set_mode_panning() ev.accept() if self.action in [SELECT, SELECT_SQUARE, SELECT_POLYGON] \ and ev.button() == Qt.LeftButton and self.graph.selection_type: pos = self.childGroup.mapFromParent(ev.pos()) if self.current_selection is None: self.current_selection = [pos] else: startp = self.current_selection[0] if self.action == SELECT: self.graph.select_line(startp, pos, add) self.set_mode_panning() elif self.action == SELECT_SQUARE: self.graph.select_square(startp, pos, add) self.set_mode_panning() elif self.action == SELECT_POLYGON: self.polygon_point_click(pos, add) ev.accept()
def setParentItem(self, parent): ret = GraphicsWidget.setParentItem(self, parent) if self.offset is not None: offset = Point(self.offset) anchorx = 1 if offset[0] <= 0 else 0 anchory = 1 if offset[1] <= 0 else 0 anchor = (anchorx, anchory) self.anchor(itemPos=anchor, parentPos=anchor, offset=offset) parent.items.append(self) return ret
def setParentItem(self, p): print(p) ret = GraphicsObject.setParentItem(self, p) if self.offset is not None: offset = Point(self.offset) anchorx = 1 if offset[0] <= 0 else 0 anchory = 1 if offset[1] <= 0 else 0 anchor = (anchorx, anchory) self.anchor(itemPos=anchor, parentPos=anchor, offset=offset) return ret
def render(self): # Convert data to QImage for display. profile = debug.Profiler() if self.image is None or self.image.size == 0: return if isinstance(self.lut, collections.Callable): lut = self.lut(self.image) else: lut = self.lut if self.autoDownsample: # reduce dimensions of image based on screen resolution o = self.mapToDevice(QtCore.QPointF(0, 0)) x = self.mapToDevice(QtCore.QPointF(1, 0)) y = self.mapToDevice(QtCore.QPointF(0, 1)) w = Point(x - o).length() h = Point(y - o).length() if w == 0 or h == 0: self.qimage = None return xds = max(1, int(1.0 / w)) yds = max(1, int(1.0 / h)) axes = [1, 0] if self.axisOrder == 'row-major' else [0, 1] #TODO adapt downsample #image = fn.downsample(self.image, xds, axis=axes[0]) #image = fn.downsample(image, yds, axis=axes[1]) self._lastDownsample = (xds, yds) else: image = self.image # if the image data is a small int, then we can combine levels + lut # into a single lut for better performance levels = self.levels # Assume images are in column-major order for backward compatibility # (most images are in row-major order) self.triangulation, self.tri_data, rgba_values, alpha = makeAlphaTriangles( image, lut=lut, levels=levels, useRGBA=True) polygons = makePolygons(self.triangulation) self.qimage = dict(polygons=polygons, values=rgba_values, alpha=alpha)
def mouseMoveEvent(self, ev): if self.position_lable: point = self.plotItem.vb.mapSceneToView(ev.pos()) self.updata_position(point.x(), point.y()) if (self.is_manual_edit or self.is_zoom_edit) and self.select_status: point = self.plotItem.vb.mapSceneToView(ev.pos()) # 注意反向的问题 w = point.x() - self.x h = point.y() - self.y if self.region: self.region.setPos([self.x, self.y]) self.region.setSize([w, h]) else: if self.lastMousePos is None: self.lastMousePos = Point(ev.pos()) delta = Point(ev.pos() - QtCore.QPoint(*self.lastMousePos)) self.lastMousePos = Point(ev.pos()) QtGui.QGraphicsView.mouseMoveEvent(self, ev) if not self.mouseEnabled: return self.sigSceneMouseMoved.emit(self.mapToScene(ev.pos())) if self.clickAccepted: ## Ignore event if an item in the scene has already claimed it. return if ev.buttons() == QtCore.Qt.RightButton: delta = Point(np.clip(delta[0], -50, 50), np.clip(-delta[1], -50, 50)) scale = 1.01**delta self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos)) self.sigDeviceRangeChanged.emit(self, self.range) elif ev.buttons() in [QtCore.Qt.MidButton, QtCore.Qt.LeftButton ]: ## Allow panning by left or mid button. px = self.pixelSize() tr = -delta * px self.translate(tr[0], tr[1]) self.sigDeviceRangeChanged.emit(self, self.range)
def propagateRay(self, ray): """Refract, reflect, absorb, and/or scatter ray. This function may create and return new rays""" """ NOTE:: We can probably use this to compute refractions faster: (from GLSL 120 docs) For the incident vector I and surface normal N, and the ratio of indices of refraction eta, return the refraction vector. The result is computed by k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)) if (k < 0.0) return genType(0.0) else return eta * I - (eta * dot(N, I) + sqrt(k)) * N The input parameters for the incident vector I and the surface normal N must already be normalized to get the desired results. eta == ratio of IORs For reflection: For the incident vector I and surface orientation N, returns the reflection direction: I – 2 ∗ dot(N, I) ∗ N N must already be normalized in order to achieve the desired result. """ iors = [self.ior(ray['wl']), 1.0] for i in [0, 1]: surface = self.surfaces[i] ior = iors[i] p1, ai = surface.intersectRay(ray) #print "surface intersection:", p1, ai*180/3.14159 #trans = self.sceneTransform().inverted()[0] * surface.sceneTransform() #p1 = trans.map(p1) if p1 is None: ray.setEnd(None) break p1 = surface.mapToItem(ray, p1) #print "adjusted position:", p1 #ior = self.ior(ray['wl']) rd = ray['dir'] a1 = np.arctan2(rd[1], rd[0]) ar = a1 - ai + np.arcsin((np.sin(ai) * ray['ior'] / ior)) #print [x for x in [a1, ai, (np.sin(ai) * ray['ior'] / ior), ar]] #print ai, np.sin(ai), ray['ior'], ior ray.setEnd(p1) dp = Point(np.cos(ar), np.sin(ar)) #p2 = p1+dp #p1p = self.mapToScene(p1) #p2p = self.mapToScene(p2) #dpp = Point(p2p-p1p) ray = Ray(parent=ray, ior=ior, dir=dp) return [ray]
def mouseClickEvent(self, ev): if ev.button() == Qt.RightButton and \ (self.action == ZOOMING or self.action == SELECT): ev.accept() self.set_mode_panning() elif ev.button() == Qt.RightButton: ev.accept() self.autoRange() add = ev.modifiers() & Qt.ControlModifier and self.graph.selection_type == SELECTMANY if self.action != ZOOMING and self.action != SELECT \ and ev.button() == Qt.LeftButton and self.graph.selection_type \ and self.graph.viewtype == INDIVIDUAL: clicked_curve = self.graph.highlighted if clicked_curve is not None: self.graph.make_selection([self.graph.sampled_indices[clicked_curve]], add) else: self.graph.make_selection(None, add) ev.accept() if self.action == ZOOMING and ev.button() == Qt.LeftButton: if self.zoomstartpoint == None: self.zoomstartpoint = ev.pos() else: self.updateScaleBox(self.zoomstartpoint, ev.pos()) self.rbScaleBox.hide() ax = QRectF(Point(self.zoomstartpoint), Point(ev.pos())) ax = self.childGroup.mapRectFromParent(ax) self.showAxRect(ax) self.axHistoryPointer += 1 self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax] self.set_mode_panning() ev.accept() if self.action == SELECT and ev.button() == Qt.LeftButton and self.graph.selection_type: if self.selection_start is None: self.selection_start = ev.pos() else: startp = self.childGroup.mapFromParent(self.selection_start) endp = self.childGroup.mapFromParent(ev.pos()) intersected = self.intersect_curves((startp.x(), startp.y()), (endp.x(), endp.y())) self.graph.make_selection(intersected if len(intersected) else None, add) self.set_mode_panning() ev.accept()