def __init__(self, Nr=0, caller=None): self.Typ = 'Ellipse' self.Nr = Nr # Initialisieren der Werte # Initialise the values self.Layer_Nr = 0 self.center = Point(0, 0) # Centre of the geometry self.vector = Point(1, 0) # Vector A = semi-major axis. # a = rotation of the ellipse # http://de.wikipedia.org/wiki/Gro%C3%9Fe_Halbachse self.ratio = 1 # Verh�ltnis der kleinen zur gro�en Halbachse (b/a) # Ratio of the minor to major axis (b/a) # self.AngS = 0 # Startwinkel beim zeichnen eines Ellipsensegments # Starting angle when drawing an ellipse segment # self.AngE = radians(360) # Endwinkel (Winkel im DXF als Radians!) # End angle (angle in radians as DXF!) # Die folgenden Grundwerte werden sp�ter ein mal berechnet # The following limits are calculated later self.length = 0 self.Points = [] self.Points.append(self.center) # Lesen der Geometrie / Read the geometry self.Read(caller) # Zuweisen der Toleranz f�rs Fitting / Assign the tolerance for fitting tol = g.config.fitting_tolerance # Errechnen der Ellipse / Calculate the ellipse self.Ellipse_Grundwerte() self.Ellipse_2_Arcs(tol)
def arc_arc_intersection(arc1, arc2, refpoint): # based on # http://stackoverflow.com/questions/3349125/circle-circle-intersection-points d = arc1.O.distance(arc2.O) if d > (arc1.r + arc2.r): # there are no solutions, the circles are separate return None elif d + 1e-5 < abs(arc1.r - arc2.r): # there are no solutions because one circle is contained within the other return None elif d == 0: # then the circles are coincident and there are an infinite number of solutions return None else: a = (arc1.r**2 - arc2.r**2 + d**2) / (2 * d) if arc1.r**2 - a**2 < 0: return None h = sqrt(arc1.r**2 - a**2) P2 = arc1.O + a * (arc2.O - arc1.O) / d p1 = Point(P2.x + h * (arc2.O.y - arc1.O.y) / d, P2.y - h * (arc2.O.x - arc1.O.x) / d) p2 = Point(P2.x - h * (arc2.O.y - arc1.O.y) / d, P2.y + h * (arc2.O.x - arc1.O.x) / d) intersections = [] if Intersect.point_belongs_to_arc(p1, arc1) and Intersect.point_belongs_to_arc(p1, arc2): intersections.append(p1) if Intersect.point_belongs_to_arc(p2, arc1) and Intersect.point_belongs_to_arc(p2, arc2): intersections.append(p2) intersections.sort(key=lambda x: (refpoint - x).length_squared()) if len(intersections) > 0: return intersections[0] return None
def get_start_end_points(self, start_point, angles=None): if angles is None: return self elif angles: return self, 0 else: return self, Point(0, -1) if start_point else Point(0, -1)
def __init__(self, Ps=Point(0, 0), Pe=Point(0, 0), hdl=[]): """ Standard method to initialize the class """ self.Ps = Ps self.Pe = Pe
def drawOrientationArrows(self): rCone = 0.01 rCylinder = 0.004 zTop = 0.05 zMiddle = 0.02 zBottom = -0.03 segments = 20 arrow = GL.glGenLists(1) GL.glNewList(arrow, GL.GL_COMPILE) self.drawCone(Point(), rCone, zTop, zMiddle, segments) self.drawSolidCircle(Point(), rCone, zMiddle, segments) self.drawCylinder(Point(), rCylinder, zMiddle, zBottom, segments) self.drawSolidCircle(Point(), rCylinder, zBottom, segments) GL.glEndList() self.orientation = GL.glGenLists(1) GL.glNewList(self.orientation, GL.GL_COMPILE) self.setColorRGBA(0.0, 0.0, 1.0, 0.5) GL.glCallList(arrow) GL.glRotatef(90, 0, 1, 0) self.setColorRGBA(1.0, 0.0, 0.0, 0.5) GL.glCallList(arrow) GL.glRotatef(90, 1, 0, 0) self.setColorRGBA(0.0, 1.0, 0.0, 0.5) GL.glCallList(arrow) GL.glEndList()
def drawWpZero(self): r = 0.02 segments = 20 # must be a multiple of 4 self.wpZero = GL.glGenLists(1) GL.glNewList(self.wpZero, GL.GL_COMPILE) self.setColorRGBA(0.2, 0.2, 0.2, 0.7) self.drawSphere(r, segments, segments // 4, segments, segments // 4) GL.glBegin(GL.GL_TRIANGLE_FAN) GL.glVertex3f(0, 0, 0) for i in range(segments // 4 + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r) # GL.glNormal3f(0, -1, 0) GL.glVertex3f(xy2.x, 0, xy2.y) for i in range(segments // 4 + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r) # GL.glNormal3f(-1, 0, 0) GL.glVertex3f(0, -xy2.y, -xy2.x) for i in range(segments // 4 + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r) # GL.glNormal3f(0, 0, 1) GL.glVertex3f(-xy2.y, xy2.x, 0) GL.glEnd() self.setColorRGBA(0.6, 0.6, 0.6, 0.5) self.drawSphere(r * 1.25, segments, segments, segments, segments) GL.glEndList()
def bulge2arc(self, Ps, Pe, bulge): """ bulge2arc() """ c = (1 / bulge - bulge) / 2 # Berechnung des Mittelpunkts (Formel von Mickes!) # Calculation of the center (Micke's formula) O = Point((Ps.x + Pe.x - (Pe.y - Ps.y) * c) / 2, (Ps.y + Pe.y + (Pe.x - Ps.x) * c) / 2) # Radius = Distance between the centre and Ps r = O.distance(Ps) # Kontrolle ob beide gleich sind (passt ...) # Check if they are equal (fits ...) # r=O.distance(Pe) # Unterscheidung f�r den �ffnungswinkel. # Distinction for the opening angle. ??? if bulge > 0: return ArcGeo(Ps=Ps, Pe=Pe, O=O, r=r) else: arc = ArcGeo(Ps=Pe, Pe=Ps, O=O, r=r) arc.reverse() return arc
def drawArrowHead(self, origin, rx, ry, rz, offset): r = 0.01 segments = 10 zTop = 0 + offset zBottom = -0.02 + offset GL.glBegin(GL.GL_TRIANGLE_FAN) zeroTop = Point3D(0, 0, zTop) GL.glVertex3f(zeroTop * rx + origin.x, -zeroTop * ry - origin.y, zeroTop * rz + origin.z) for i in range(segments + 1): ang = i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r).to3D(zBottom) GL.glVertex3f(xy2 * rx + origin.x, -xy2 * ry - origin.y, xy2 * rz + origin.z) GL.glEnd() GL.glBegin(GL.GL_TRIANGLE_FAN) zeroBottom = Point3D(0, 0, zBottom) GL.glVertex3f(zeroBottom * rx + origin.x, -zeroBottom * ry - origin.y, zeroBottom * rz + origin.z) for i in range(segments + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r).to3D(zBottom) GL.glVertex3f(xy2 * rx + origin.x, -xy2 * ry - origin.y, xy2 * rz + origin.z) GL.glEnd()
def calc_bounding_box(self): """ Calculated the BoundingBox of the geometry and saves it into self.BB """ Ps = Point(x=min(self.Ps.x, self.Pe.x), y=min(self.Ps.y, self.Pe.y)) Pe = Point(x=max(self.Ps.x, self.Pe.x), y=max(self.Ps.y, self.Pe.y)) self.BB = BoundingBox(Ps=Ps, Pe=Pe)
def calc_bounding_box(self, radius=1): """ Calculated the BoundingBox of the geometry and saves it into self.BB @param radius: The Radius of the HoleGeo to be used for BoundingBox """ Ps = Point(x=self.Ps.x - radius, y=self.Ps.y - radius) Pe = Point(x=self.Ps.x + radius, y=self.Ps.y + radius) self.BB = BoundingBox(Ps=Ps, Pe=Pe)
def Read(self, caller): """ Read() """ # Assign short name lp = caller.line_pairs e = lp.index_code(0, caller.start + 1) # Assign layer s = lp.index_code(8, caller.start + 1) self.Layer_Nr = caller.Get_Layer_Nr(lp.line_pair[s].value) # X Value s = lp.index_code(10, s + 1) x0 = float(lp.line_pair[s].value) # Y Value s = lp.index_code(20, s + 1) y0 = float(lp.line_pair[s].value) # Radius s = lp.index_code(40, s + 1) r = float(lp.line_pair[s].value) # Searching for an extrusion direction s_nxt_xt = lp.index_code(230, s + 1, e) # If there is a extrusion direction given flip around x-Axis if s_nxt_xt is not None: extrusion_dir = float(lp.line_pair[s_nxt_xt].value) logger.debug(self.tr('Found extrusion direction: %s') % extrusion_dir) if extrusion_dir == -1: x0 = -x0 O = Point(x0, y0) # Calculate the start and end values of the circle without clipping s_ang = -3 * pi / 4 m_ang = s_ang - pi e_ang = -3 * pi / 4 # Calculate the start and end values of the arcs Ps = Point(cos(s_ang) * r, sin(s_ang) * r) + O Pm = Point(cos(m_ang) * r, sin(m_ang) * r) + O Pe = Point(cos(e_ang) * r, sin(e_ang) * r) + O # Annexes to ArcGeo class for geometry self.geo.append(ArcGeo(Ps=Ps, Pe=Pm, O=O, r=r, s_ang=s_ang, e_ang=m_ang, direction=-1)) self.geo.append(ArcGeo(Ps=Pm, Pe=Pe, O=O, r=r, s_ang=m_ang, e_ang=e_ang, direction=-1)) # Length corresponds to the length (circumference?) of the circle self.length = self.geo[-1].length+self.geo[-2].length # New starting value for the next geometry caller.start = s
def Read(self, caller): """ This function does read the geometry. @param caller: The instance which is calling the function """ # Assign short name lp = caller.line_pairs e = lp.index_code(0, caller.start + 1) # Assign layer s = lp.index_code(8, caller.start + 1) self.Layer_Nr = caller.Get_Layer_Nr(lp.line_pair[s].value) # X Value sl = lp.index_code(10, s + 1) x0 = float(lp.line_pair[sl].value) # Y Value s = lp.index_code(20, sl + 1) y0 = float(lp.line_pair[s].value) # X Value 2 s = lp.index_code(11, sl + 1) x1 = float(lp.line_pair[s].value) # Y Value 2 s = lp.index_code(21, s + 1) y1 = float(lp.line_pair[s].value) # Searching for an extrusion direction s_nxt_xt = lp.index_code(230, s + 1, e) # If there is a extrusion direction given flip around x-Axis if s_nxt_xt is not None: extrusion_dir = float(lp.line_pair[s_nxt_xt].value) logger.debug( self.tr('Found extrusion direction: %s') % extrusion_dir) if extrusion_dir == -1: x0 = -x0 x1 = -x1 Ps = Point(x0, y0) Pe = Point(x1, y1) # Anhängen der LineGeo Klasse für die Geometrie # Annexes to LineGeo class for geometry ??? self.geo.append(LineGeo(Ps=Ps, Pe=Pe)) # Länge entspricht der Länge des Kreises # Length corresponding to the length (circumference?) of the circle self.length = self.geo[-1].length # Neuen Startwert für die nächste Geometrie zurückgeben # New starting value for the next geometry caller.start = s
def calc_O1_O2_k(self, r1, r2, tan_a, theta): """ calc_O1_O2_k() """ # print("r1: %0.3f, r2: %0.3f, tan_a: %0.3f, theta: %0.3f" %(r1,r2,tan_a,theta)) # print("N1: x: %0.3f, y: %0.3f" %(-sin(tan_a), cos(tan_a))) # print("V: x: %0.3f, y: %0.3f" %(-sin(theta+tan_a),cos(theta+tan_a))) O1 = Point(self.Ps.x - r1 * sin(tan_a), self.Ps.y + r1 * cos(tan_a)) k = Point(self.Ps.x + r1 * (-sin(tan_a) + sin(theta + tan_a)), self.Ps.y + r1 * (cos(tan_a) - cos(tan_a + theta))) O2 = Point(k.x + r2 * (-sin(theta + tan_a)), k.y + r2 * (cos(theta + tan_a))) return O1, O2, k
def calc_bounding_box(self): """ Calculated the BoundingBox of the geometry and saves it into self.BB """ Ps = Point(x=self.O.x - self.r, y=self.O.y - self.r) Pe = Point(x=self.O.x + self.r, y=self.O.y + self.r) # Do the calculation only for arcs have positiv extend => switch angles if self.ext >= 0: s_ang = self.s_ang e_ang = self.e_ang elif self.ext < 0: s_ang = self.e_ang e_ang = self.s_ang # If the positive X Axis is crossed if not (self.wrap(s_ang, 0) >= self.wrap(e_ang, 1)): Pe.x = max(self.Ps.x, self.Pe.x) # If the positive Y Axis is crossed if not (self.wrap(s_ang - pi / 2, 0) >= self.wrap(e_ang - pi / 2, 1)): Pe.y = max(self.Ps.y, self.Pe.y) # If the negative X Axis is crossed if not (self.wrap(s_ang - pi, 0) >= self.wrap(e_ang - pi, 1)): Ps.x = min(self.Ps.x, self.Pe.x) # If the negative Y is crossed if not (self.wrap(s_ang - 1.5 * pi, 0) >= self.wrap( e_ang - 1.5 * pi, 1)): Ps.y = min(self.Ps.y, self.Pe.y) self.BB = BoundingBox(Ps=Ps, Pe=Pe)
def Read(self, caller): """ Read() """ # Assign short name lp = caller.line_pairs e = lp.index_code(0, caller.start + 1) # Assign layer s = lp.index_code(8, caller.start + 1) self.Layer_Nr = caller.Get_Layer_Nr(lp.line_pair[s].value) # X Value s = lp.index_code(10, s + 1) x0 = float(lp.line_pair[s].value) # Y Value s = lp.index_code(20, s + 1) y0 = float(lp.line_pair[s].value) Ps = Point(x0, y0) self.geo.append(HoleGeo(Ps)) # self.geo.append(LineGeo(Ps=Point(0,0), Pe=P)) # Neuen Startwert für die nächste Geometrie zurückgeben # New starting value for the next geometry caller.start = s
def mouseMoveEvent(self, event): """ MouseMoveEvent of the Graphiscview. May also be used for the Statusbar. @purpose: Get the MouseMoveEvent and use it for the Rubberband Selection @param event: Event Parameters passed to function """ if self.mppos is not None: Point = event.pos() - self.mppos if Point.manhattanLength() > 3: # print 'the mouse has moved more than 3 pixels since the oldPosition' # print "Mouse Pointer is currently hovering at: ", event.pos() rect = QtCore.QRect(self.mppos, event.pos()) ''' The following is needed because of PyQt5 doesn't like to switch from sign it will keep displaying last rectangle, i.e. you can end up will multiple rectangles ''' if self.prvRectRubberBand.width() > 0 and not rect.width() > 0 or rect.width() == 0 or\ self.prvRectRubberBand.height() > 0 and not rect.height() > 0 or rect.height() == 0: self.rubberBand.hide() self.rubberBand.setGeometry(rect.normalized()) self.rubberBand.show() self.prvRectRubberBand = rect scpoint = self.mapToScene(event.pos()) # self.setStatusTip('X: %3.1f; Y: %3.1f' % (scpoint.x(), -scpoint.y())) # works not as supposed to self.setToolTip('X: %3.1f; Y: %3.1f' % (scpoint.x(), -scpoint.y())) super(MyGraphicsView, self).mouseMoveEvent(event)
def calc_curve(self, n=0, cpts_nr=20): """ Berechnen von eine Anzahl gleichm�ssig verteilter Punkte bis zur n-ten Ableitung """ # Anfangswerte f�r Step und u u = 0 step = float(self.Knots[-1]) / (cpts_nr - 1) Points = [] # Wenn die erste Ableitung oder h�her errechnet wird die ersten # Ableitung in dem tan als Winkel in rad gespeichert tang = [] while u <= self.Knots[-1]: CK = self.bspline_ders_evaluate(n=n, u=u) # Den Punkt in einem Punkt List abspeichern Points.append(Point(x=CK[0][0], y=CK[0][1])) # F�r die erste Ableitung wird den Winkel der tangente errechnet if n >= 1: tang.append(atan2(CK[1][1], CK[1][0])) u += step return Points, tang
def __init__(self, startp=Point(), endp=None, length=60.0, angle=50.0, color=QtCore.Qt.red, pencolor=QtCore.Qt.green, startarrow=True): """ Initialisation of the class. """ self.sc = None super(Arrow, self).__init__() self.startp = QtCore.QPointF(startp.x, -startp.y) self.endp = endp self.length = length self.angle = angle self.startarrow = startarrow self.allwaysshow = False self.arrowHead = QPolygonF() self.setFlag(QGraphicsItem.ItemIsSelectable, False) self.myColor = color self.pen = QPen(pencolor, 1, QtCore.Qt.SolidLine) self.pen.setCosmetic(True) self.arrowSize = 8.0
def analyse_and_opt(self): """ analyse_and_opt() """ summe = 0 # Richtung in welcher der Anfang liegen soll (unten links) # Direction of the top (lower left) ??? Popt = Point(-1e3, -1e6) # Calculation of the alignment after Gaussian-Elling # Positive value means CW, negative value indicates CCW # closed polygon for Line in self.geo: summe += Line.Ps.x * Line.Pe.y - Line.Pe.x * Line.Ps.y if summe > 0.0: self.reverse() # Suchen des kleinsten Startpunkts von unten Links X zuerst (Muss neue Schleife sein!) # Find the smallest starting point from bottom left X (Must be new loop!) min_distance = self.geo[0].Ps.distance(Popt) min_geo_nr = 0 for geo_nr in range(1, len(self.geo)): if self.geo[geo_nr].Ps.distance(Popt) < min_distance: min_distance = self.geo[geo_nr].Ps.distance(Popt) min_geo_nr = geo_nr # Kontur so anordnen das neuer Startpunkt am Anfang liegt # Order Contour so the new starting point is at the beginning self.geo = self.geo[min_geo_nr:len(self.geo)] + self.geo[0:min_geo_nr]
def __init__( self, text='S', startp=Point(x=0.0, y=0.0), ): """ Initialisation of the class. """ QGraphicsItem.__init__(self) self.setFlag(QGraphicsItem.ItemIsSelectable, False) self.text = text self.sc = 1.0 self.startp = QtCore.QPointF(startp.x, -startp.y) pencolor = QColor(0, 200, 255) self.brush = QColor(0, 100, 255) self.pen = QPen(pencolor, 1, QtCore.Qt.SolidLine) self.pen.setCosmetic(True) self.path = QPainterPath() self.path.addText(QtCore.QPointF(0, 0), QFont("Arial", 10 / self.sc), self.text)
def joinBB(self, other): """ Joins two Bounding Box Classes and returns the new one @param other: The 2nd Bounding Box @return: Returns the joined Bounding Box Class """ if type(self.Ps) == type(None) or type(self.Pe) == type(None): return BoundingBox(deepcopy(other.Ps), deepcopy(other.Pe)) xmin = min(self.Ps.x, other.Ps.x) xmax = max(self.Pe.x, other.Pe.x) ymin = min(self.Ps.y, other.Ps.y) ymax = max(self.Pe.y, other.Pe.y) return BoundingBox(Ps=Point(xmin, ymin), Pe=Point(xmax, ymax))
def contains_point(self, point): """ Method to determine the minimal distance from the point to the shape @param point: a QPointF @return: minimal distance """ min_distance = float(0x7fffffff) ref_point = Point(point.x(), point.y()) t = 0.0 while t < 1.0: per_point = self.path.pointAtPercent(t) spline_point = Point(per_point.x(), per_point.y()) distance = ref_point.distance(spline_point) if distance < min_distance: min_distance = distance t += 0.01 return min_distance
def AnalyseAndOptimize(self): self.setNearestStPoint(Point()) logger.debug( self.tr("Analysing the shape for CW direction Nr: %s" % self.nr)) if self.isDirectionOfGeosCCW(self.geos): self.reverse() logger.debug(self.tr("Had to reverse the shape to be CW")) self.cw = True
def determineSelectedPosition(self, clicked, forZ, offset): angleX = -radians(self.rotX) angleY = -radians(self.rotY) zv = forZ - offset.z clickedZ = ((zv + clicked.x * sin(angleY)) / cos(angleY) - clicked.y * sin(angleX)) / cos(angleX) sx, sy, sz = self.deRotate(clicked.x, clicked.y, clickedZ) return Point(sx + offset.x, -sy - offset.y) #, sz + offset.z
def getClickedDetails(self, event): min_side = min(self.frameSize().width(), self.frameSize().height()) clicked = Point( (event.pos().x() - self.frameSize().width() / 2), (event.pos().y() - self.frameSize().height() / 2)) / min_side / self.scale offset = Point3D(-self.posX, -self.posY, -self.posZ) / self.scale tol = 4 * self.scaleCorr / min_side / self.scale return clicked, offset, tol
def contextMenuEvent(self, event): """ Create the contextmenu. @purpose: Links the new Class of ContextMenu to Graphicsview. """ position = self.mapToGlobal(event.pos()) GVPos = self.mapToScene(event.pos()) real_pos = Point(GVPos.x(), -GVPos.y()) menu = MyDropDownMenu(self.scene(), position, real_pos)
def addexprouteen(self): st = self.expprv en = Point(g.config.vars.Plane_Coordinates['axis1_start_end'], g.config.vars.Plane_Coordinates['axis2_start_end']) self.expcol = QtCore.Qt.darkRed self.routearrows.append( Arrow(startp=en, endp=st, color=self.expcol, pencolor=self.expcol)) self.addItem(self.routearrows[-1])
def get_start_end_points(self, start_point, angles=None): if start_point: if angles is None: return self.Ps elif angles: return self.Ps, self.s_ang + pi / 2 * self.ext / abs(self.ext) else: direction = (self.O - self.Ps).unit_vector() direction = -direction if self.ext >= 0 else direction return self.Ps, Point(-direction.y, direction.x) else: if angles is None: return self.Pe elif angles: return self.Pe, self.e_ang - pi / 2 * self.ext / abs(self.ext) else: direction = (self.O - self.Pe).unit_vector() direction = -direction if self.ext >= 0 else direction return self.Pe, Point(-direction.y, direction.x)
def Ellipse_Point(self, alpha=0): # Point(0,0) """ Ellipse_Point() """ # gro�e Halbachse, kleine Halbachse, rotation der Ellipse (rad), Winkel des Punkts in der Ellipse (rad) # Semi-major axis, minor axis, rotation of the ellipse (rad), the point in the ellipse angle (rad) ??? Ex = self.a * cos(alpha) * cos( self.rotation) - self.b * sin(alpha) * sin(self.rotation) Ey = self.a * cos(alpha) * sin( self.rotation) + self.b * sin(alpha) * cos(self.rotation) return Point(self.center.x + Ex, self.center.y + Ey)
def pointisinBB(self, Point=Point(), tol=eps): """ Checks if the Point is within the bounding box @param Point: The Point which shall be ckecke @return: Returns true or false """ x_inter_pos = (self.Pe.x + tol > Point.x) and \ (self.Ps.x - tol < Point.x) y_inter_pos = (self.Pe.y + tol > Point.y) and \ (self.Ps.y - tol < Point.y) return x_inter_pos and y_inter_pos