Files
envi-code/SourceCode/Code2026/tg_shs/shs_siteplan/RoadArith.cpp
T
2026-09-28 15:28:50 +08:00

543 lines
16 KiB
C++

#include "StdAfx.h"
#include <gevec2d.h>
#include "commonRoad.h"
#include "RoadArith.h"
bool CRoadArith::PointInLineDir(const AcGeLineSeg2d &line, bool bDir, const AcGePoint2d &ptInter)
{
AcGeVector2d lineVec = bDir ? line.startPoint() - line.endPoint() : line.endPoint() - line.startPoint();
AcGeVector2d interVec = bDir ? ptInter - line.endPoint() : ptInter - line.startPoint();
if (interVec.dotProduct(lineVec) > 0)
return true;
return false;
}
bool CRoadArith::PointInArcDir(const AcGeCircArc2d &arc, bool bDir, const AcGePoint2d &ptInter)
{
// 延伸长度不超过1/4
double dExend = 0.25;
AcGePoint2d accurateStatPoint = bDir ? arc.endPoint() : arc.startPoint();
AcGePoint2d accurateEndPoint = bDir ? arc.startPoint() : arc.endPoint();
AcGePoint2d ptCenter = arc.center();
double dAccurateStartAngle = AcGeVector2d(accurateStatPoint - ptCenter).angle();
double dAccurateEndAngle = AcGeVector2d(accurateEndPoint - ptCenter).angle();
double dptAngle = AcGeVector2d(ptInter - ptCenter).angle();
bool bClock = (arc.isClockWise() == Adesk::kTrue) ? !bDir : bDir;
// 当前点和accurateStatPoint构成的圆弧角度
double dInterEndAngle = AngleInClock(bClock, dAccurateStartAngle, dAccurateEndAngle);
// 圆弧的角度
double dInterPtAngle = AngleInClock(bClock, dAccurateStartAngle, dptAngle);
// 圆弧延伸不能太长
return (dInterPtAngle < dInterEndAngle * (1.0+dExend));
}
void CRoadArith::NearPtInLine(const AcGeLineSeg2d &line, bool bStart, const AcGePoint2d &pt1, const AcGePoint2d &pt2,
double &dLen1, double &dLen2)
{
AcGePoint2d ptAccurate = bStart ? line.startPoint() : line.endPoint();
dLen1 = pt1.distanceTo(ptAccurate);
dLen2 = pt2.distanceTo(ptAccurate);
}
void CRoadArith::NearPtInArc(const AcGeCircArc2d &arc, bool bStart, const AcGePoint2d &pt1, const AcGePoint2d &pt2,
double &dLen1, double &dLen2)
{
ASSERT(arc.radius() > 1.0);
// 处于节点区间中的那个点
AcGePoint2d ptAccurateEnd = bStart ? arc.startPoint() : arc.endPoint();
AcGePoint2d ptAccurateStart = bStart ? arc.endPoint() : arc.startPoint();
AcGePoint2d ptCenter = arc.center();
double dAccurateEndAngle = AcGeVector2d(ptAccurateEnd - ptCenter).angle();
double dAccurateStartAngle = AcGeVector2d(ptAccurateStart - ptCenter).angle();
double dAngle1 = AcGeVector2d(pt1 - ptCenter).angle();
double dAngle2 = AcGeVector2d(pt2 - ptCenter).angle();
// 角度的计算方向:ptAccurateStart -> ptAccurateEnd;
bool bClock = (arc.isClockWise() == Adesk::kTrue) ? !bStart : bStart;
double dInterAngleAccurateEnd = AngleInClock(bClock, dAccurateStartAngle, dAccurateEndAngle);
double dInterAngle1 = AngleInClock(bClock, dAccurateStartAngle, dAngle1);
double dInterAngle2 = AngleInClock(bClock, dAccurateStartAngle, dAngle2);
dLen1 = fabs(dInterAngle1 - dInterAngleAccurateEnd)*arc.radius()*0.5/PI;
dLen2 = fabs(dInterAngle2 - dInterAngleAccurateEnd)*arc.radius()*0.5/PI;
}
// 直线和圆弧交与两点,找出一个合适的交点
bool CRoadArith::TestProperPoint(const AcGeLineSeg2d &line1, bool bStart1, const AcGeCircArc2d &arc2, bool bStart2,
const AcGePoint2d &pt1, const AcGePoint2d &pt2, AcGePoint2d &ptDest)
{
// 按照圆弧的顺序
double dLen11 = 0.0, dLen12 = 0.0, dLen21 = 0.0, dLen22 = 0.0;
NearPtInLine(line1, bStart1, pt1, pt2, dLen11, dLen12);
NearPtInArc(arc2, bStart2, pt1, pt2, dLen21, dLen22);
if (dLen11 + dLen21 < dLen12 + dLen22)
{
ptDest = pt1;
}
else
{
ptDest = pt2;
}
// 交点在线段的方向上,则正确。
return PointInLineDir(line1, bStart1, ptDest) && PointInArcDir(arc2, bStart2, ptDest);
}
// 两个圆弧有两个交点
bool CRoadArith::TestProperPoint(const AcGeCircArc2d &arc1, bool bStart1, const AcGeCircArc2d &arc2, bool bStart2,
const AcGePoint2d &pt1, const AcGePoint2d &pt2, AcGePoint2d &ptDest)
{
double dLen11 = 0.0, dLen12 = 0.0, dLen21 = 0.0, dLen22 = 0.0;
NearPtInArc(arc1, bStart1, pt1, pt2, dLen11, dLen12);
NearPtInArc(arc2, bStart2, pt1, pt2, dLen21, dLen22);
if (dLen11 + dLen21 < dLen12 + dLen22)
{
ptDest = pt1;
}
else
{
ptDest = pt2;
}
// 交点在线段的方向上,则正确。
return PointInArcDir(arc1, bStart1, ptDest) && PointInArcDir(arc2, bStart2, ptDest);
}
/*
边线倒角算法:
总体描述倒角算法即:先找到倒角的圆心。以该圆心出发向两条边线分别作垂线段,两个交点即为倒角圆弧的两个端点。
查找倒角圆心从数学上描述为:找到一个到两条边线垂直距离皆为倒角半径的一个点,
进一步的描述是:对于每一个边线来看,到其距离为倒角半径的点分别是一个集合,从从这两个集合中找到一个交集,即为倒角圆心
对于线段来讲,这个集合是线段两侧的两个线段,对于圆弧来讲,这个集合是两个圆弧。
因为找圆心的过程既是:找线段与线段,线段与圆弧,或者圆弧与圆弧的交点的过程。
找到圆心之后,下边的操作即简单了。对应的找到垂足即可,而圆心到这两个垂足的距离应该都等于倒角半径。
*/
const double ANGLE_TOL = 0.02;
bool CRoadArith::Off(const AcGeVector2d &vecL1, const AcGeVector2d &vecR1, const AcGeVector2d &vecL2, const AcGeVector2d &vecR2,
const AcGeVector2d &dir1, const AcGeVector2d &dir2, bool &bLeft1, bool &bLeft2)
{
double dDotL1 = vecL1.dotProduct(dir2);
double dDotR1 = vecR1.dotProduct(dir2);
double dDotL2 = vecL2.dotProduct(dir1);
double dDotR2 = vecR2.dotProduct(dir1);
const double ZERO = 0.0;
// 说明两个边线平行了。
if (DoubleEqual(dDotL1, ZERO) || DoubleEqual(dDotL2, ZERO) || DoubleEqual(dDotR1, ZERO) || DoubleEqual(dDotR2, ZERO))
return false;
if (dDotL1 > ZERO)
bLeft1 = true;
else if (dDotR1 > ZERO)
bLeft1 = false;
else
return false;
if (dDotL2 > ZERO)
bLeft2 = true;
else if (dDotR2 > ZERO)
bLeft2 = false;
else
return false;
return true;
}
bool CRoadArith::FindUnitVec(const AcGeLineSeg2d &line1, bool bDir1, const AcGeLineSeg2d &line2, bool bDir2,
bool &bLeft1, bool &bLeft2)
{
AcGeVector2d dir1 = line1.direction();
AcGeVector2d dir2 = line2.direction();
// 线段的四个左右向量
AcGeVector2d vecL1 = dir1.perpVector();
AcGeVector2d vecR1 = -vecL1;
AcGeVector2d vecL2 = dir2.perpVector();
AcGeVector2d vecR2 = -vecL2;
if (!bDir1)
dir1 = -dir1;
if (!bDir2)
dir2 = -dir2;
double dAngle1 = dir1.angle();
double dAngle2 = dir2.angle();
if (DoubleEqual(dAngle1, dAngle2, ANGLE_TOL))
return false;
else if (DoubleEqual(fabs(dAngle1 - dAngle2), PI, ANGLE_TOL))
return false;
return Off(vecL1, vecR1, vecL2, vecR2, dir1, dir2, bLeft1, bLeft2);
}
bool CRoadArith::FindUnitVec(const AcGeLineSeg2d &line1, bool bDir1, const AcGeCircArc2d &arc2, bool bDir2,
bool &bLeft1, bool &bIn2)
{
AcGeVector2d dir1 = line1.direction();
AcGeVector2d dir2 = bDir2 ? TanVecOfArcStartPoint(arc2) : TanVecOfArcEndPoint(arc2);
AcGeVector2d vecL1 = dir1.perpVector();
AcGeVector2d vecR1 = -vecL1;
AcGeVector2d vecIn2 = arc2.center() -(bDir2 ? arc2.startPoint() : arc2.endPoint());
AcGeVector2d vecOut2 = -vecIn2;
if (!bDir1)
dir1 = -dir1;
double dAngle1 = dir1.angle();
double dAngle2 = dir2.angle();
// 180°相切,不倒角
if (DoubleEqual(fabs(dAngle1-dAngle2), PI, ANGLE_TOL))
return false;
else if (DoubleEqual(dAngle1, dAngle2, ANGLE_TOL))
{ // 这个时候,直线向着圆弧圆心的方向偏,圆弧向外偏
bIn2 = false; // 向外偏
AcGeVector2d vecLineToArc = arc2.center() - (bDir1 ? (line1.startPoint()) : (line1.endPoint()));
if (vecL1.dotProduct(vecLineToArc) > 0) bLeft1 = true; // 左边和圆弧同向
else bLeft1 = false;
return true;
}
return Off(vecL1, vecR1, vecIn2, vecOut2, dir1, dir2, bLeft1, bIn2);
}
#define ArcStartInAntiClock(arc, bStart) \
((arc).isClockWise() ? (!bStart) : (bStart))
bool CRoadArith::FindUnitVec(const AcGeCircArc2d &arc1, bool bDir1, const AcGeCircArc2d &arc2, bool bDir2,
bool &bIn1, bool &bIn2)
{
AcGeVector2d dir1 = bDir1 ? TanVecOfArcStartPoint(arc1) : TanVecOfArcEndPoint(arc1);
AcGeVector2d dir2 = bDir2 ? TanVecOfArcStartPoint(arc2) : TanVecOfArcEndPoint(arc2);
// 两个圆弧相切:
// 外切,内切,
// 外切的时候,两个弧都想外偏,
// 内切的时候,大圆弧向里偏,小圆弧向外偏
double dAngle1 = dir1.angle();
double dAngle2 = dir2.angle();
if (DoubleEqual(fabs(dAngle1 - dAngle2), PI, ANGLE_TOL))
return false;
else if (DoubleEqual(dAngle1, dAngle2, ANGLE_TOL))
{
bool bStart1 = ArcStartInAntiClock(arc1, bDir1);
bool bStart2 = ArcStartInAntiClock(arc2, bDir2);
if ((!bStart1 && bStart2) || (bStart1 && !bStart2))
{
bIn1 = false;
bIn2 = false;
}
else
{
if (DoubleEqual(arc1.radius(), arc2.radius()))
return false; // 半径相等;
else if (arc1.radius() > arc2.radius())
{
bIn1 = true;
bIn2 = false;
}
else
{
bIn1 = false;
bIn2 = true;
}
}
return true;
}
AcGeVector2d vecIn1 = arc1.center() -(bDir1 ? arc1.startPoint() : arc1.endPoint());
AcGeVector2d vecOut1 = -vecIn1;
AcGeVector2d vecIn2 = arc2.center() -(bDir2 ? arc2.startPoint() : arc2.endPoint());
AcGeVector2d vecOut2 = -vecIn2;
return Off(vecIn1, vecOut1, vecIn2, vecOut2, dir1, dir2, bIn1, bIn2);
}
AcGeRay2d CRoadArith::LineSegToRay(const AcGeLineSeg2d &line, bool bDir)
{
if (bDir)
return AcGeRay2d(line.endPoint(), line.startPoint());
else
return AcGeRay2d(line.startPoint(), line.endPoint());
}
void CRoadArith::ConInterCircle(const AcGePoint2d &ptCenter, const AcGePoint2d &pt1, const AcGePoint2d &pt2, AcGeCircArc2d &interArc)
{
AcGePoint2d ptMidChord = AcGeLineSeg2d(pt1, pt2).midPoint();
AcGeVector2d vecMid(ptMidChord - ptCenter);
double dRadius = ptCenter.distanceTo(pt1);
AcGePoint2d ptMidArc = vecMid.normalize() * dRadius + ptCenter;
interArc.set(pt1, ptMidArc, pt2);
}
bool CRoadArith::ForCenterLineAndLine(AcGeCurve2d *pEnt1, bool bDir1,
AcGeCurve2d *pEnt2, bool bDir2,
double dRadius, AcGePoint2d &ptCenter)
{
AcGeLineSeg2d &line1 = *((AcGeLineSeg2d*)pEnt1);
AcGeLineSeg2d &line2 = *((AcGeLineSeg2d*)pEnt2);
if (dRadius < 1.0)
return false;
// 平行的不倒角
if (line1.isParallelTo(line2))
return false;
bool bLeft1 = false, bLeft2 = false;
// 偏移的线段
if (!FindUnitVec(line1, bDir1, line2, bDir2, bLeft1, bLeft2))
return false;
AcGeLineSeg2d lineOff1 = bLeft1 ? LeftLine(line1, dRadius) : RightLine(line1, dRadius);
AcGeLineSeg2d lineOff2 = bLeft2 ? LeftLine(line2, dRadius) : RightLine(line2, dRadius);
// 偏移的射线,保证交点的方向正确。
AcGeRay2d rayOff1 = LineSegToRay(lineOff1, bDir1);
AcGeRay2d rayOff2 = LineSegToRay(lineOff2, bDir2);
// 无焦点,说明线段找不到圆心
if (!rayOff1.intersectWith(rayOff2, ptCenter))
return false;
return true;
}
bool CRoadArith::ForCenterLineAndArc(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2, double dRadius, AcGePoint2d &ptCenter)
{
AcGeLineSeg2d &line1 = *((AcGeLineSeg2d*)pEnt1);
AcGeCircArc2d &arc2 = *((AcGeCircArc2d*)pEnt2);
if (dRadius < 1.0)
return false;
// 偏移的线段
bool bLeft1 = false, bIn2 = false;
if (!FindUnitVec(line1, bDir1, arc2, bDir2, bLeft1, bIn2))
return false;
AcGeLineSeg2d lineOff1 = bLeft1 ? LeftLine(line1, dRadius) : RightLine(line1, dRadius);
AcGeCircArc2d arcOff2;
if (bIn2)
{
if(arc2.radius() < dRadius + 1.0)
return false;
arcOff2 = InSideArc(arc2, dRadius);
}
else
arcOff2 = OutSideArc(arc2, dRadius);
// 偏移的射线
AcGeRay2d rayOff1 = LineSegToRay(lineOff1, bDir1);
AcGeCircArc2d circleOff2(arcOff2.center(), arcOff2.radius());
int nNum = 0;// 交点个数
AcGePoint2d interPt1, interPt2;
if (!circleOff2.intersectWith(rayOff1, nNum, interPt1, interPt2))
return false;
if (nNum == 1)
ptCenter = interPt1;
else
{
if (!TestProperPoint(line1, bDir1, arc2, bDir2, interPt1, interPt2, ptCenter))
return false;
}
return true;
}
bool CRoadArith::ForCenterArcAndLine(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2, double dRadius, AcGePoint2d &ptCenter)
{
return ForCenterLineAndArc(pEnt2, bDir2, pEnt1, bDir1, dRadius, ptCenter);
}
bool CRoadArith::ForCenterArcAndArc(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2, double dRadius, AcGePoint2d &ptCenter)
{
AcGeCircArc2d &arc1 = *((AcGeCircArc2d*)pEnt1);
AcGeCircArc2d &arc2 = *((AcGeCircArc2d*)pEnt2);
if (dRadius < 1.0)
return false;
// 偏移的线段
bool bIn1 =false, bIn2 = false;
if (!FindUnitVec(arc1, bDir1, arc2, bDir2, bIn1, bIn2))
return false;
// 向着对方移动,然后根据它们求交点
AcGeCircArc2d arcOff1, arcOff2;
if (bIn1)
{
if (arc1.radius() < dRadius + 1.0)
return false;
arcOff1 = InSideArc(arc1, dRadius);
}
else
arcOff1 = OutSideArc(arc1, dRadius);
if (bIn2)
{
if (arc2.radius() < dRadius + 1.0)
return false;
arcOff2 = InSideArc(arc2, dRadius);
}
else
arcOff2 = OutSideArc(arc2, dRadius);
// 偏移的射线
AcGeCircArc2d circleOff1(arcOff1.center(), arcOff1.radius());
AcGeCircArc2d circleOff2(arcOff2.center(), arcOff2.radius());
// 无焦点,说明线段找不到圆心
int nNum = 0;// 交点个数
AcGePoint2d interPt1, interPt2;
if (!circleOff2.intersectWith(circleOff1, nNum, interPt1, interPt2))
return false;
if (nNum == 1)
ptCenter = interPt1;
else
{
if (!TestProperPoint(arc1, bDir1, arc2, bDir2, interPt1, interPt2, ptCenter))
return false;
}
return true;
}
// 线段跟线段的倒角处理
bool CRoadArith::InterCircleLineAndLine(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2,
double dRadius, AcGeCircArc2d &interCircle)
{
AcGeLineSeg2d &line1 = *((AcGeLineSeg2d*)pEnt1);
AcGeLineSeg2d &line2 = *((AcGeLineSeg2d*)pEnt2);
AcGePoint2d ptCenter;
if (!ForCenterLineAndLine(pEnt1, bDir1, pEnt2, bDir2, dRadius, ptCenter))
return false;
// 找垂足:
AcGeRay2d ray1 = LineSegToRay(line1, bDir1);
AcGeRay2d ray2 = LineSegToRay(line2, bDir2);
AcGePoint2d perpPt1 = ray1.closestPointTo(ptCenter);
AcGePoint2d perpPt2 = ray2.closestPointTo(ptCenter);
// 检测拆分点在直线上是否合适
if (!PointInLineDir(line1, bDir1, perpPt1) || !PointInLineDir(line2, bDir2, perpPt2))
return false;
// 构造圆弧,设置原始线段
ConInterCircle(ptCenter, perpPt1, perpPt2, interCircle);
ResetLine(line1, bDir1, perpPt1);
ResetLine(line2, bDir2, perpPt2);
return true;
}
// 线段跟弧线的倒角,参数同上
bool CRoadArith::InterCircleLineAndArc(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2,
double dRadius, AcGeCircArc2d &interCircle)
{
AcGeLineSeg2d &line1 = *((AcGeLineSeg2d*)pEnt1);
AcGeCircArc2d &arc2 = *((AcGeCircArc2d*)pEnt2);
AcGePoint2d ptCenter;
if (!ForCenterLineAndArc(pEnt1, bDir1, pEnt2, bDir2, dRadius, ptCenter))
return false;
// 找垂足:
AcGeRay2d ray1 = LineSegToRay(line1, bDir1);
AcGeCircArc2d circle2(arc2.center(), arc2.radius());
AcGePoint2d perpPt1 = ray1.closestPointTo(ptCenter);
AcGePoint2d perpPt2 = circle2.closestPointTo(ptCenter);
// 检测拆分点在直线上是否合适
if (!PointInLineDir(line1, bDir1, perpPt1) || !PointInArcDir(arc2, bDir2, perpPt2))
return false;
// 构造圆弧,设置原始线段
ConInterCircle(ptCenter, perpPt1, perpPt2, interCircle);
ResetLine(line1, bDir1, perpPt1);
ResetArc(arc2, bDir2, perpPt2);
return true;
}
bool CRoadArith::InterCircleArcAndLine(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2,
double dRadius, AcGeCircArc2d &interCircle)
{
return InterCircleLineAndArc(pEnt2, bDir2, pEnt1, bDir1, dRadius, interCircle);
}
// 弧线跟弧线的倒角,参数同上
bool CRoadArith::InterCircleArcAndArc(AcGeCurve2d *pEnt1, bool bDir1, AcGeCurve2d *pEnt2, bool bDir2,
double dRadius, AcGeCircArc2d &interCircle)
{
AcGeCircArc2d &arc1 = *((AcGeCircArc2d*)pEnt1);
AcGeCircArc2d &arc2 = *((AcGeCircArc2d*)pEnt2);
AcGePoint2d ptCenter;
if (!ForCenterArcAndArc(pEnt1, bDir1, pEnt2, bDir2, dRadius, ptCenter))
return false;
// 找垂足:
AcGeCircArc2d circle1(arc1.center(), arc1.radius());
AcGeCircArc2d circle2(arc2.center(), arc2.radius());
AcGePoint2d perpPt1 = circle1.closestPointTo(ptCenter);
AcGePoint2d perpPt2 = circle2.closestPointTo(ptCenter);
// 检测拆分点在直线上是否合适
if (!PointInArcDir(arc1, bDir1, perpPt1) || !PointInArcDir(arc2, bDir2, perpPt2))
return false;
// 构造圆弧,设置原始线段
ConInterCircle(ptCenter, perpPt1, perpPt2, interCircle);
ResetArc(arc1, bDir1, perpPt1);
ResetArc(arc2, bDir2, perpPt2);
return true;
}