📄 rs_arc.cpp
字号:
/****************************************************************************** $Id: rs_arc.cpp 2399 2005-06-06 18:12:30Z andrew $**** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.**** This file is part of the qcadlib Library project.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** Licensees holding valid qcadlib Professional Edition licenses may use ** this file in accordance with the qcadlib Commercial License** Agreement provided with the Software.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.ribbonsoft.com for further details.**** Contact info@ribbonsoft.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "rs_arc.h"#include "rs_constructionline.h"#include "rs_linetypepattern.h"#include "rs_information.h"#include "rs_math.h"#include "rs_graphicview.h"#include "rs_painter.h"/** * Default constructor. */RS_Arc::RS_Arc(RS_EntityContainer* parent, const RS_ArcData& d) : RS_AtomicEntity(parent), data(d) { calculateEndpoints(); calculateBorders();}/** * Creates this arc from 3 given points which define the arc line. * * @param p1 1st point. * @param p2 2nd point. * @param p3 3rd point. */bool RS_Arc::createFrom3P(const RS_Vector& p1, const RS_Vector& p2, const RS_Vector& p3) { if (p1.distanceTo(p2)>RS_TOLERANCE && p2.distanceTo(p3)>RS_TOLERANCE && p3.distanceTo(p1)>RS_TOLERANCE) { // middle points between 3 points: RS_Vector mp1, mp2; RS_Vector dir1, dir2; double a1, a2; // intersection of two middle lines mp1 = (p1 + p2)/2.0; a1 = p1.angleTo(p2) + M_PI/2.0; dir1.setPolar(100.0, a1); mp2 = (p2 + p3)/2.0; a2 = p2.angleTo(p3) + M_PI/2.0; dir2.setPolar(100.0, a2); RS_ConstructionLineData d1(mp1, mp1 + dir1); RS_ConstructionLineData d2(mp2, mp2 + dir2); RS_ConstructionLine midLine1(NULL, d1); RS_ConstructionLine midLine2(NULL, d2); RS_VectorSolutions sol = RS_Information::getIntersection(&midLine1, &midLine2); data.center = sol.get(0); data.radius = data.center.distanceTo(p3); data.angle1 = data.center.angleTo(p1); data.angle2 = data.center.angleTo(p3); data.reversed = RS_Math::isAngleBetween(data.center.angleTo(p2), data.angle1, data.angle2, true); if (sol.get(0).valid && data.radius<1.0e14 && data.radius>RS_TOLERANCE) { calculateEndpoints(); calculateBorders(); return true; } else { RS_DEBUG->print("RS_Arc::createFrom3P(): " "Cannot create an arc with inf radius."); return false; } } else { RS_DEBUG->print("RS_Arc::createFrom3P(): " "Cannot create an arc with radius 0.0."); return false; }}/** * Creates an arc from its startpoint, endpoint, start direction (angle) * and radius. * * @retval true Successfully created arc * @retval false Cannot creats arc (radius to small or endpoint to far away) */bool RS_Arc::createFrom2PDirectionRadius(const RS_Vector& startPoint, const RS_Vector& endPoint, double direction1, double radius) { RS_Vector ortho; ortho.setPolar(radius, direction1 + M_PI/2.0); RS_Vector center1 = startPoint + ortho; RS_Vector center2 = startPoint - ortho; if (center1.distanceTo(endPoint) < center2.distanceTo(endPoint)) { data.center = center1; } else { data.center = center2; } data.radius = radius; data.angle1 = data.center.angleTo(startPoint); data.angle2 = data.center.angleTo(endPoint); data.reversed = false; double diff = RS_Math::correctAngle(getDirection1()-direction1); if (fabs(diff-M_PI)<1.0e-1) { data.reversed = true; } calculateEndpoints(); calculateBorders(); return true;}/** * Creates an arc from its startpoint, endpoint and bulge. */bool RS_Arc::createFrom2PBulge(const RS_Vector& startPoint, const RS_Vector& endPoint, double bulge) { data.reversed = (bulge<0.0); double alpha = atan(bulge)*4.0; RS_Vector middle = (startPoint+endPoint)/2.0; double dist = startPoint.distanceTo(endPoint)/2.0; // alpha can't be 0.0 at this point data.radius = fabs(dist / sin(alpha/2.0)); double wu = fabs(RS_Math::pow(data.radius, 2.0) - RS_Math::pow(dist, 2.0)); double h = sqrt(wu); double angle = startPoint.angleTo(endPoint); if (bulge>0.0) { angle+=M_PI/2.0; } else { angle-=M_PI/2.0; } if (fabs(alpha)>M_PI) { h*=-1.0; } data.center.setPolar(h, angle); data.center+=middle; data.angle1 = data.center.angleTo(startPoint); data.angle2 = data.center.angleTo(endPoint); calculateEndpoints(); calculateBorders(); return true;}/** * Recalculates the endpoints using the angles and the radius. */void RS_Arc::calculateEndpoints() { startpoint.set(data.center.x + cos(data.angle1) * data.radius, data.center.y + sin(data.angle1) * data.radius); endpoint.set(data.center.x + cos(data.angle2) * data.radius, data.center.y + sin(data.angle2) * data.radius);}void RS_Arc::calculateBorders() { double minX = std::min(startpoint.x, endpoint.x); double minY = std::min(startpoint.y, endpoint.y); double maxX = std::max(startpoint.x, endpoint.x); double maxY = std::max(startpoint.y, endpoint.y); double a1 = !isReversed() ? data.angle1 : data.angle2; double a2 = !isReversed() ? data.angle2 : data.angle1; // check for left limit: if ((a1<M_PI && a2>M_PI) || (a1>a2-1.0e-12 && a2>M_PI) || (a1>a2-1.0e-12 && a1<M_PI) ) { minX = std::min(data.center.x - data.radius, minX); } // check for right limit: if (a1 > a2-1.0e-12) { maxX = std::max(data.center.x + data.radius, maxX); } // check for bottom limit: if ((a1<(M_PI_2*3) && a2>(M_PI_2*3)) || (a1>a2-1.0e-12 && a2>(M_PI_2*3)) || (a1>a2-1.0e-12 && a1<(M_PI_2*3)) ) { minY = std::min(data.center.y - data.radius, minY); } // check for top limit: if ((a1<M_PI_2 && a2>M_PI_2) || (a1>a2-1.0e-12 && a2>M_PI_2) || (a1>a2-1.0e-12 && a1<M_PI_2) ) { maxY = std::max(data.center.y + data.radius, maxY); } minV.set(minX, minY); maxV.set(maxX, maxY);}RS_VectorSolutions RS_Arc::getRefPoints() { RS_VectorSolutions ret(startpoint, endpoint, data.center); return ret;}RS_Vector RS_Arc::getNearestEndpoint(const RS_Vector& coord, double* dist) { double dist1, dist2; RS_Vector* nearerPoint; dist1 = startpoint.distanceTo(coord); dist2 = endpoint.distanceTo(coord); if (dist2<dist1) { if (dist!=NULL) { *dist = dist2; } nearerPoint = &endpoint; } else { if (dist!=NULL) { *dist = dist1; } nearerPoint = &startpoint; } return *nearerPoint;}RS_Vector RS_Arc::getNearestPointOnEntity(const RS_Vector& coord, bool onEntity, double* dist, RS_Entity** entity) { RS_Vector vec(false); if (entity!=NULL) { *entity = this; } double angle = (coord-data.center).angle(); if (onEntity==false || RS_Math::isAngleBetween(angle, data.angle1, data.angle2, isReversed())) { vec.setPolar(data.radius, angle); vec+=data.center; } if (dist!=NULL) { *dist = fabs((vec-data.center).magnitude()-data.radius); } return vec;}RS_Vector RS_Arc::getNearestCenter(const RS_Vector& coord, double* dist) { if (dist!=NULL) { *dist = coord.distanceTo(data.center); } return data.center;}RS_Vector RS_Arc::getNearestMiddle(const RS_Vector& coord, double* dist) { RS_Vector ret = getMiddlepoint(); if (dist!=NULL) { *dist = coord.distanceTo(ret); } return ret;}RS_Vector RS_Arc::getNearestDist(double distance, const RS_Vector& coord, double* dist) { if (data.radius<1.0e-6) { if (dist!=NULL) { *dist = RS_MAXDOUBLE; } return RS_Vector(false); } double a1, a2; RS_Vector p1, p2; double aDist = distance / data.radius; if (isReversed()) { a1 = data.angle1 - aDist; a2 = data.angle2 + aDist; } else { a1 = data.angle1 + aDist; a2 = data.angle2 - aDist; } p1.setPolar(data.radius, a1); p1 += data.center; p2.setPolar(data.radius, a2); p2 += data.center; double dist1, dist2; RS_Vector* nearerPoint; dist1 = p1.distanceTo(coord); dist2 = p2.distanceTo(coord); if (dist2<dist1) { if (dist!=NULL) { *dist = dist2; } nearerPoint = &p2; } else { if (dist!=NULL) { *dist = dist1; } nearerPoint = &p1; } return *nearerPoint;}RS_Vector RS_Arc::getNearestDist(double distance, bool startp) { if (data.radius<1.0e-6) { return RS_Vector(false); } double a; RS_Vector p; double aDist = distance / data.radius; if (isReversed()) { if (startp) { a = data.angle1 - aDist; } else { a = data.angle2 + aDist; } } else { if (startp) { a = data.angle1 + aDist; } else { a = data.angle2 - aDist; } } p.setPolar(data.radius, a); p += data.center; return p;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -