G代码圆弧 您所在的位置:网站首页 G代码编程例题 G代码圆弧

G代码圆弧

2024-07-15 06:29| 来源: 网络整理| 查看: 265

圆弧总结 说明

工作中经常画图经常会遇到圆弧,开始的时候我并不是很理解,随着深入发现其实有些坑的,这里总结记录一下,可能并不是最优的解法,但肯定是自己理解后想出来的,如果这些能给你提供一些思路和帮助,那便是极好的。

G-Code的G02/G03 G02 顺时针圆弧/G03 逆时针圆弧

在这里插入图片描述

圆心的计算 I, J, K模式 G02 X20 Y10 I0 J-10 G03 X10.5 I3.0 J4.0

G02/G03指令,是已知起始点S(Xs, Ys),终止点E(Xe, Ye),相对圆心的增量(I, J),顺逆时针状态。通过这些信息我们是可以算出圆心的。

一般来说是(I, J)是圆弧起点相对圆心的增量,即圆心O坐标是(Xs + I, Ys + J)。而我遇到的情况,(I, J)的表示可能有以下几种情况:

相对圆弧起点的增量相对圆弧终点的增量绝对圆弧中心 计算

这个就很简单了,针对(I, J)表示不同时计算方式也不同

相对圆弧起点时,圆心坐标

O x = X s + I ; O y = Y s + J ; O_x = X_s + I;\\ O_y = Y_s + J;\\ Ox​=Xs​+I;Oy​=Ys​+J;

相对圆弧终点时,圆心坐标

O x = X e + I ; O y = Y e + J ; O_x = X_e + I;\\ O_y = Y_e + J;\\ Ox​=Xe​+I;Oy​=Ye​+J;

绝对圆弧中心

O x = I ; O y = J ; O_x = I;\\ O_y = J; Ox​=I;Oy​=J;

R模式 G02 X20 Y10 R10 F300

注意相同的起点、终点、半径和方向,计算出来的圆心可能有两种。其中,

R>0时,圆弧和中心的夹角小于180°,即圆弧段小于或等于半圆;R0时,圆心是黑色圆的,如果R //!< atan2 计算得到的弧度范围是[-PI, PI],可以转换成[0, 2 * PI]来计算 float startAngNew = atan2f(v1.y, v1.x); float startAngNew2 = atan2f(v2.y, v2.x); if (startAngNew sweepNew = abs(2 * PI - abs(sweepNew)); } } return sweepNew; } //!< 已知圆弧,圆心,起点,终点,方向,计算出圆弧夹角(弧度制) void calcArcAngle(Point center, Point s, Point e, bool isClockWise, double& angle) { //!< 起点终点相同的情况,就是个整圆 if (s == e) { angle = PI * 2; } else { Vector v1, v2; v1.x = start.x - center.x; v1.y = start.y - center.y; v2.x = end.x - center.x; v2.y = end.y - center.y; angle = calc2VecAngle(v1, v2, (cw ? 1 : -1)); } } 在圆弧上

上面的方法中,可以已知圆弧圆心,圆弧起点,圆弧终点,方向,是可以计算判断出某个点在不在圆弧上。

//!< 两点的距离 double getLength(const Point& p1, const Point& p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } //!< 计算角度,需要用到atan2f值域[-π, π],这个很重要 //!< 可以转换成[0, 2π]来计算 double getAngle(const Point& p1, const Point& p2) { double ang = atan2f((p2.y - p1.y), (p2.x - p1.x)); // [-π, π] if (ang //!< 如果圆是个整圆,任一角度都在圆弧上 if (start == end) { return true; } //[0, 2π] double startAng = getAngle(center, start); double endAng = getAngle(center, end); double curAng = angle; bool bIsOn = false; //!< 顺时针 if (cw) { //!< 圆弧起始角度 > 终止角度的情况 if (startAng > endAng) { //!< curAng 满足区间 [endAng, startAng] if (curAng >= endAng && curAng //!< 顺时针时 起始角度 < 终止角度则说明圆弧经过了0°, 则此时可以 //!< 在两个区间判断角度, 满足任一区间即可, [endAng, 2π], [0, startAng] if ((curAng >= endAng && curAng = eps && curAng //!< 圆弧起始角度 < 终止角度的情况 if (startAng bIsOn = true; } } //!< 圆弧起始角度 > 终止角度 else { //!< 逆时针时 起始角度 > 终止角度则说明圆弧经过了0°, 则此时可以 //!< 在两个区间判断角度, 满足任一区间即可, [startAng, 2π], [0, endAng] if ((curAng >= startAng && curAng = eps && curAng double radius = getLength(center, start); double len = getLength(center, pt); //!< 半径不匹配肯定是不在圆上的 if (abs(len - radius) > eps) return false; double curAng = getAngle(m_center, pt); return isOn(center, start, end, cw, curAng, eps); } 圆弧外接矩形计算 不带角度

下图中黑色圆弧为实际圆弧,黑色点为圆的四个顶点位置,绿色为需要计算的圆弧外接矩形,这个时候求圆弧外接矩形是分两种情况的:

小于90° 小于90°的圆弧

大于等于90° 大于90°的圆弧

计算 从圆的上下左右四个顶点中,找出在圆弧上的顶点计算出已知点集的外接矩形 #define MAX_NUM 1E20 #define MIN_NUM -1E20 //!< 外接矩形 struct rect { float left; float top; float right; float bottom; }; //!< 计算圆弧的外接矩形 rect calcRectangle(const Point& center, const Point& start, const Point& end, const bool& cw) { rect rc; double radius = getLength(center, start); //!< 如果是个整圆 if (start == end) { rc.left = center.x - radius; rc.right = center.x + radius; rc.top = center.y + radius; rc.bottom = center.y - radius; } else { std::vector vArcVertex; vArcVertex.push_back(start); vArcVertex.push_back(end); //!< 判断圆的四个顶点是不是在圆弧上,在圆弧上的顶点参与计算外接矩形 sPoint ptCirList[] = { center + Point(0, radius), center + Point(radius, 0), center + Point(-radius, 0), center + Point(0, -radius) }; for (int i = 0; i vArcVertex.push_back(ptCirList[i]); } } rc.right = rc.top = MIN_NUM; rc.left = rc.bottom = MAX_NUM; for (auto& pt : vArcVertex) { rc.left = min(rc.left, pt.x); rc.right = max(rc.right, pt.x); rc.top = max(rc.top, pt.y); rc.bottom = min(rc.bottom, pt.y); } } return rc; } 圆弧相对距离的点

在这里插入图片描述

//!< 根据某点旋转 void rotate(Point& src, const Point& center, const float& sweepAng) { float xOrg = src.x, yOrg = src.y; src.x = center.x + (xOrg - center.x) * cos(angle) - (yOrg - center.y) * sin(angle); src.y = center.y + (xOrg - center.x) * sin(angle) + (yOrg - center.y) * cos(angle); } //!< 圆弧上以起点位置,计算相对偏移distance的点 Point getSatrtOffsetOnArc(const Point& center, const Point& start, const Point& end, const bool& cw, const float& distance) { //!< 计算圆弧半径 double radius = getLength(center, start); //!< 圆弧长度对应圆心角 float sweepAng = distance / radius; Point curPoint = start; if (cw) sweepAng = -sweepAng; rotate(curPoint, center, sweepAng); return curPoint; } 圆弧与线段相交

在这里插入图片描述

计算 判断圆心到线段的最短距离是不是小于半径,大于半径的时候肯定是不会与圆弧相交的求出圆弧与直线的交点,最多两个,需要满足既在圆弧上,也在线段上 //!< 判断点p是否在线段(s, e)上 bool isOnLineSeg(const Point& s, const Point& e, const Point& p, const float& eps) { float c = getLength(s, e); float a = getLength(s, p); float b = getLength(e, p); //!< 构成三角形,运用定理两边之和大于第三边,等于第三边则构成线段,点p在线段上 if (abs(a + b - c) float t1 = (-b + sqrt(discriminant)) / (2 * a); float t2 = (-b - sqrt(discriminant)) / (2 * a); Point intersection1 = { x1 + t1 * dx, y1 + t1 * dy }; Point intersection2 = { x1 + t2 * dx, y1 + t2 * dy }; Point intersectionArray[] = {intersection1, intersection2}; int resultSize = 2; //!< 相切的情况, 只有一个解 if (abs(t1 - t2) if (isOn(center, start, end, cw, intersectionArray[i], eps) && isOnLineSeg(s, e, intersectionArray[i], eps)) { vCrossPoint.push(intersection1); } } } return vCrossPoint; } 线段外与圆相切的问题 需要做的效果

在这里插入图片描述

已知 已知线段起点终点鼠标位置需要构建一个相切与该线段的圆,圆弧终点为鼠标当前点,起点为线段端点(就认为是起点吧) 计算 鼠标位置与线段端点连线组成线段AB,提前可知圆上任意两点连线即(AB)的中垂线必过圆心,所以AB的中垂线必过圆心因为原线段需要与所求的圆弧相切,即原线段端点的垂线也必过该圆心以上所得两直线的交点即为圆心 //!< 计算线段的中垂线 void getMidPerpendicularLine(const Point& s1, const Point& e1, Point& s2, Point& e2, const float& eps) { Point midPoint = (s1 + e1) / 2.0f; float len = getLength(s1, e1) / 2.0f; if (abs(s1.x - e1.x) s2.x = midPoint.x; s2.y = midPoint.y + len; e2.x = midPoint.x; e2.y = midPoint.y - len; } else if (abs(s1.y - e1.y) //!< 沿着中点随便旋转90°都可以组成中垂线 s2 = s1; rotate(s2, midPoint, PI / 2); e2 = e1; rotate(e2, midPoint, PI / 2); } } //!< 两直线求交点 bool getLineCross(const Point& p1, const Point& p2, const Point& p3, const Point& p4, sPoint& p, const float& eps) { //!< 构建直线L1 int sign = 1; double a1 = p2.y - p1.y; if (a1 sign = -1; a2 = sign * a2; } double b2 = sign * (p3.x - p4.x); double c2 = sign * (p3.y * p4.x - p3.x * p4.y); //!< 求L1和L2的交点 double d = a1 * b2 - a2 * b1; if (abs(d) center = pArcCenter; arcStart = s; arcEnd = mousePos; } } 实现效果

下面的效果中,我是已知轮廓的方向的,所以做出了镜像的圆弧

在这里插入图片描述

圆弧分割成多线段

一些时候画圆弧+线段连起来的时候,一些API并并不能完美的画出来,起点是对的,终点会有些偏差,可能缩小的时候看不出来差别,放大到了节点处会出现断开的情况。一些做法画圆弧,不用画圆弧的函数来做,把圆弧分成很多个线段,连起来。这样起点和终点可以保证正确。

//!< 圆弧分割成多线段集 void vector toPoints(const Point& center, const Point& start, const Point& end, const bool& cw, const int& ptCnts) { std::vector vPts; // 起点,圆心,终点 float radius = getLength(center, start); float startAngle = getAngle(center, start); float sweepAngle = 0.0f; calcArcAngle(center, start, end, cw, sweepAngle) sPoint ptCur = start; vPts.push_back(ptCur); for (int i = 1; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有