有了上一篇博文打下的基础,读者应该对分析查看几何图形有了初步了解,本着实用的原则,这篇文章,主要介绍Geometry的常用计算。它提供了点线面相交,相离的判断,以及多边形的布尔运算,在几何分析中非常有用,如果读者对深入学习Geometry感兴趣,需要深入学习泛型编程,作者在学习过程中也是感到深深的吃力,特别是缓冲区的代码,SDK提供的算法有时计算不出结果,详情查看注释,代码如下:
//ANormGeoLib.h--计算文件
#pragma once
#include <boost/geometry.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/assign.hpp>
#include <vector>
namespace bg = boost::geometry;
typedef bg::model::d2::point_xy<double, boost::geometry::cs::cartesian> DPoint; //双精度的点
typedef bg::model::segment<DPoint> DSegment; //线段
typedef bg::model::linestring<DPoint> DLineString; //多段线
typedef bg::model::box<DPoint> DBox; //矩形
typedef bg::model::ring<DPoint, false, true> DRing; //环
typedef bg::model::polygon<DPoint, false> DPolygon; //多边形
typedef bg::model::multi_polygon<DPolygon> DMultiPolygon;//多个多边形
typedef bg::model::multi_point<DPoint> DMultiPoint;//多点
#define A_PI 3.141592653589793238462643383279502884197
namespace ANormGeoLib
{
// 二维空间点到直线的垂足
struct _Point
{
double x, y;
_Point(double x, double y) :x(x), y(y)
{
}
_Point() :x(0), y(0)
{
}
};
//获取垂足
inline _Point GetFootOfPerpendicular(
const _Point &pt, // 直线外一点
const _Point &begin, // 直线开始点
const _Point &end) // 直线结束点
{
_Point retVal;
double dx = begin.x - end.x;
double dy = begin.y - end.y;
if (abs(dx) < 0.00000001 && abs(dy) < 0.00000001)
{
retVal = begin;
return retVal;
}
double u = (pt.x - begin.x)*(begin.x - end.x) +
(pt.y - begin.y)*(begin.y - end.y);
u = u / ((dx*dx) + (dy*dy));
retVal.x = begin.x + u*dx;
retVal.y = begin.y + u*dy;
return retVal;
}
//角度转弧度
inline double Degree2Radius(double d)
{
double rlt = d*A_PI / 180;
return rlt;
}
//弧度转角度
inline double Radius2Degree(double r)
{
double rlt = r * 180 / A_PI;
return rlt;
}
//1.两点之间的距离
template<typename T1,typename T2,typename T3,typename T4,typename T5>
inline T1 Distance(T2 x1, T3 y1, T4 x2, T5 y2)
{
double dx1 = x1, dx2 = x2, dy1 = y1, dy2 = y2;
double dr = ::sqrt((dx1 - dx2)*(dx1 - dx2) + (dy1 - dy2)*(dy1 - dy2));
T1 d = static_cast<T1>(dr);
return d;
}
//2.点到线段的垂足并返回到垂足的距离
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
inline T1 Point2Segment(T2 px1, T3 py1, T4 lx1, T5 ly1, T6 lx2, T7 ly2, T8& poutx, T9& pouty)
{
_Point pt = { (double)px1, (double)py1 };
_Point begin = { (double)lx1, (double)ly1 };
_Point end = { (double)lx2, (double)ly2 };
_Point rlt = GetFootOfPerpendicular(pt, begin, end);
poutx = static_cast<T8>(rlt.x);
pouty = static_cast<T9>(rlt.y);
return Distance<T1>(px1, py1, poutx, pouty);
}
//3.点在正常笛卡尔坐标系空间中的逆时针方向角
template<typename T1, typename T2, typename T3>
inline T1 DirectAngleByPoint(T2 x, T3 y)
{
double angle=0;
_Point pt = { (double)x, (double)y };
if (pt.x==0)
{
if (pt.y>0)
{
angle = 90;
}
else if(pt.y<0)
{
angle = 270;
}
else
{
angle = 0;
}
}
else
{
angle = std::atan2(pt.y, pt.x);
angle = Radius2Degree(angle);
if (angle < 0)
{
angle = angle + 360;
}
}
T1 rlt = static_cast<T1>(angle);
return rlt;
}
//4.计算三角形的面积
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
inline T1 AreaBy3Points(T2 px1, T3 py1, T4 px2, T5 py2, T6 px3, T7 py3)
{
_Point pt = { (double)px1, (double)py1 };
_Point begin = { (double)px2, (double)py2 };
_Point end = { (double)px3, (double)py3 };
_Point foot = GetFootOfPerpendicular(pt, begin, end);
double h = Distance<double>(px1, py1, foot.x, foot.y);
double l = Distance<double>(px2, py2, px3, py3);
double a = h*l / 2;
T1 ar = static_cast<T1>(a);
return ar;
}
//5.多边形的缓冲区buffer,缓冲区的计算不是都能成功
template<typename T1>
inline bool PolygonBufferRegion(const std::vector<T1>& pointListSrc, std::vector<T1>& pointListDst, double dis, int ppc)
{
//申明策略
const double buffer_distance = dis;
const int points_per_circle = ppc;
boost::geometry::strategy::buffer::distance_symmetric<double> distance_strategy(buffer_distance);
boost::geometry::strategy::buffer::join_round join_strategy(points_per_circle);
boost::geometry::strategy::buffer::end_round end_strategy(points_per_circle);
boost::geometry::strategy::buffer::point_circle circle_strategy(points_per_circle);
boost::geometry::strategy::buffer::side_straight side_strategy;
//转为多边形
std::vector<DPoint> ptList;
int pointListSrcSize = pointListSrc.size();
for (int i = 0; i < pointListSrcSize;i++)
{
DPoint pt(pointListSrc[i].x, pointListSrc[i].y);
ptList.push_back(pt);
}
DPolygon polySrc;
bg::assign_points(polySrc, ptList);
bg::correct(polySrc);
//计算缓存区
DMultiPolygon result;
if (boost::geometry::is_valid(polySrc))
{
//创建缓存
DMultiPolygon result2;
boost::geometry::buffer(polySrc, result,
distance_strategy, side_strategy,
join_strategy, end_strategy, circle_strategy);
}
//转换结果
if (result.empty())
{
return false;
}
else
{
pointListDst.clear();
BOOST_AUTO(poly, result[0].outer());
int ptSize = poly.size();
for (int i = 0; i < ptSize;i++)
{
T1 pt;
pt.x = poly[i].x();
pt.y = poly[i].y();
pointListDst.push_back(pt);
}
return true;
}
}
};
调用范例代码如下所示:
#include "ANormGeoLib.h"
int main()
{
//两点间距离
double d1 = ANormGeoLib::Distance<double>(0, 0, 10, 10);
//点到线段的垂足和距离
double xout, yout;
double d2 = ANormGeoLib::Point2Segment<double>(10, 10, 20, 20, 20, 0, xout, yout);
//点的角度
double d3 = ANormGeoLib::DirectAngleByPoint<double>(0, -90);
//三角形面积
double d4 = ANormGeoLib::AreaBy3Points<double>(0, 10, -5, 0, 5, 0);
//缓冲区
std::vector<ANormGeoLib::_Point> srcPts, dstPts;
srcPts.push_back(ANormGeoLib::_Point(0.0, 0));
srcPts.push_back(ANormGeoLib::_Point(15.0, 0));
srcPts.push_back(ANormGeoLib::_Point(16, 18));
srcPts.push_back(ANormGeoLib::_Point(0, 19));
srcPts.push_back(ANormGeoLib::_Point(0.0, 0));
ANormGeoLib::PolygonBufferRegion<ANormGeoLib::_Point>(srcPts, dstPts, 5, 36);
return 0;
}
这是作者在研究几何计算项目时经常需要解决的问题,供读者分享。
Geometry官方网址:https://www.boost.org/doc/libs/1_73_0/libs/geometry/doc/html/geometry/reference.html