def convertRToCenter(cls, start: QVector3D, end: QVector3D, radius: float, absoluteIJK: bool, clockwise: bool) -> QVector3D: R = radius center = QVector3D() x = end.x() - start.x() y = end.y() - start.y() h_x2_div_d = 4 * R * R - x * x - y * y if h_x2_div_d < 0: print("Error computing arc radius.") h_x2_div_d = (-math.sqrt(h_x2_div_d)) / math.hypot(x, y) if not clockwise: h_x2_div_d = -h_x2_div_d # Special message from gcoder to software for which radius # should be used. if R < 0: h_x2_div_d = -h_x2_div_d # TODO: Places that use this need to run ABS on radius. radius = -radius offsetX = 0.5 * (x - (y * h_x2_div_d)) offsetY = 0.5 * (y + (x * h_x2_div_d)) if not absoluteIJK: center.setX(start.x() + offsetX) center.setY(start.y() + offsetY) else: center.setX(offsetX) center.setY(offsetY) return center
def getAngle(cls, start: QVector3D, end: QVector3D) -> float: ''' Return the angle in radians when going from start to end. ''' deltaX = end.x() - start.x() deltaY = end.y() - start.y() angle = 0.0 if deltaX != 0: # prevent div by 0 # it helps to know what quadrant you are in if deltaX > 0 and deltaY >= 0: # 0 - 90 angle = math.atan(deltaY / deltaX) elif deltaX < 0 and deltaY >= 0: # 90 to 180 angle = cls.M_PI - math.fabs(math.atan(deltaY / deltaX)) elif deltaX < 0 and deltaY < 0: # 180 - 270 angle = cls.M_PI + math.fabs(math.atan(deltaY / deltaX)) elif deltaX > 0 and deltaY < 0: # 270 - 360 angle = cls.M_PI * 2 - math.fabs(math.atan(deltaY / deltaX)) else: # 90 deg if deltaY > 0: angle = cls.M_PI / 2.0 #270 deg else: angle = cls.M_PI * 3.0 / 2.0 return angle
def generatePointsAlongArcBDring_Arc( cls, plane: PointSegment.Plane, start: QVector3D, end: QVector3D, center: QVector3D, clockwise: bool, R: float, minArcLength: float, arcPrecision: float, arcDegreeMode: bool) -> List[QVector3D]: ''' Generates the points along an arc including the start and end points. ''' radius = R # Rotate vectors according to plane m = QMatrix4x4() m.setToIdentity() if plane == PointSegment.Plane.XY: pass elif plane == PointSegment.Plane.ZX: m.rotate(90, 1.0, 0.0, 0.0) elif plane == PointSegment.Plane.YZ: m.rotate(-90, 0.0, 1.0, 0.0) start = m * start end = m * end center = m * center # Check center if qIsNaN(center.length()): return [] # Calculate radius if necessary. if radius == 0: radius = math.sqrt( math.pow((start.x() - center.x(), 2.0) + math.pow(end.y() - center.y(), 2.0))) startAngle = cls.getAngle(center, start) endAngle = cls.getAngle(center, end) sweep = cls.calculateSweep(startAngle, endAngle, clockwise) # Convert units. arcLength = sweep * radius numPoints = 0 if arcDegreeMode and arcPrecision > 0: numPoints = max(1.0, sweep / (cls.M_PI * arcPrecision / 180)) else: if arcPrecision <= 0 and minArcLength > 0: arcPrecision = minArcLength numPoints = math.ceil(arcLength / arcPrecision) return cls.generatePointsAlongArcBDring_Num(plane, start, end, center, clockwise, radius, startAngle, sweep, numPoints)
def generatePointsAlongArcBDring_Num(cls, plane: PointSegment.Plane, p1: QVector3D, p2: QVector3D, center: QVector3D, isCw: bool, radius: float, startAngle: float, sweep: float, numPoints: int) -> List[QVector3D]: ''' Generates the points along an arc including the start and end points. ''' # Prepare rotation matrix to restore plane m = QMatrix4x4() m.setToIdentity() if plane == PointSegment.plane.XY: pass elif plane == PointSegment.plane.ZX: m.rotate(-90, 1.0, 0.0, 0.0) elif plane == PointSegment.plane.YZ: m.rotate(90, 0.0, 1.0, 0.0) lineEnd = QVector3D(p2.x(), p2.y(), p1.z()) segments = [] angle = 0.0 # Calculate radius if necessary. if radius == 0: radius = math.sqrt( math.pow((p1.x() - center.x()), 2.0) + math.pow((p1.y() - center.y()), 2.0)) zIncrement = (p2.z() - p1.z()) / numPoints for i in range(numPoints): if isCw: angle = (startAngle - i * sweep / numPoints) else: angle = (startAngle + i * sweep / numPoints) if angle >= cls.M_PI * 2: angle = angle - cls.M_PI * 2 lineEnd.setX(math.cos(angle) * radius + center.x()) lineEnd.setY(math.sin(angle) * radius + center.y()) lineEnd.setZ(lineEnd.z() + zIncrement) segments.append(m * lineEnd) segments.append(m * p2) return segments
def addLinearPointSegment(self, nextPoint: QVector3D, fastTraverse: bool) -> PointSegment: ps = PointSegment.PointSegment_FromQVector3D(nextPoint, self.m_commandNumber) self.m_commandNumber += 1 zOnly = False # Check for z-only if (self.m_currentPoint.x() == nextPoint.x()) and \ (self.m_currentPoint.y() == nextPoint.y()) and \ (self.m_currentPoint.z() != nextPoint.z()) : \ zOnly = True ps.setIsMetric(self.m_isMetric) ps.setIsZMovement(zOnly) ps.setIsFastTraverse(fastTraverse) ps.setIsAbsolute(self.m_inAbsoluteMode) ps.setSpeed(self.m_traverseSpeed if fastTraverse else self.m_lastSpeed) ps.setSpindleSpeed(self.m_lastSpindleSpeed) self.m_points.append(ps) # Save off the endpoint. self.m_currentPoint = nextPoint return ps
def createCircle(self, center: QVector3D, radius: float, arcs: int, color: QVector3D) -> List[VertexData]: # Vertices circle: List[VertexData] = [] # Prepare vertex vertex = VertexData() vertex.color = color vertex.start = QVector3D(sNaN, sNaN, sNaN) # Create line loop for i in range(self.arcs + 1): angle = 2 * M_PI * i / self.arcs x = center.x() + radius * math.cos(angle) y = center.y() + radius * math.sin(angle) if i > 1: circle.append(VertexData.clone(circle[-1])) elif i == self.arcs: circle.append(VertexData.clone(circle[0])) vertex.position = QVector3D(x, y, center.z()) circle.append(VertexData.clone(vertex)) return circle
def generateG1FromPoints(cls, start: QVector3D, end: QVector3D, absoluteMode: bool, precision: int) -> str: sb = "G1" if absoluteMode: if not qIsNaN(end.x()): sb.append("X" + "%.*f" % (precision, end.x())) if not qIsNaN(end.y()): sb.append("Y" + "%.*f" % (precision, end.y())) if not qIsNaN(end.z()): sb.append("Z" + "%.*f" % (precision, end.z())) else: if not qIsNaN(end.x()): sb.append("X" + "%.*f" % (precision, end.x() - start.x())) if not qIsNaN(end.y()): sb.append("Y" + "%.*f" % (precision, end.y() - start.y())) if not qIsNaN(end.z()): sb.append("Z" + "%.*f" % (precision, end.z() - start.z())) return sb
def PointSegment_FromVectorQVector3DQVector3D(cls, point: QVector3D, num: int, center: QVector3D, radius: float, clockwise: bool): this = PointSegment(point, num) this.m_isArc = True this.m_arcProperties = ArcProperties() this.m_arcProperties.center = QVector3D(center.x(), center.y(), center.z()) this.m_arcProperties.radius = radius this.m_arcProperties.isClockwise = clockwise
def updatePointWithCommand_FromVector3D(cls, initial: QVector3D, x: float, y: float, z: float, absoluteMode: bool) -> QVector3D: ''' Update a point given the new coordinates. ''' newPoint = QVector3D(initial.x(), initial.y(), initial.z()) if absoluteMode: if not qIsNaN(x): newPoint.setX(x) if not qIsNaN(y): newPoint.setY(y) if not qIsNaN(z): newPoint.setZ(z) else: if not qIsNaN(x): newPoint.setX(newPoint.x() + x) if not qIsNaN(y): newPoint.setY(newPoint.y() + y) if not qIsNaN(z): newPoint.setZ(newPoint.z() + z) return newPoint
def calculateVolume(self, size: QtGui.QVector3D) -> float: return size.x() * size.y() * size.z()
def PointSegment_FromQVector3D(cls, b: QVector3D, num: int): this = PointSegment() this.m_point = QVector3D(b.x(), b.y(), b.z()) this.m_lineNumber = num return this
def _(self, p3d: QVector3D): self.testExtremes(p3d.x(), p3d.y(), p3d.z())
def cloneQVector3D(cls, v: QVector3D) -> QVector3D: ''' faster as deepcopy ''' return QVector3D(v.x(), v.y(), v.z())