最近很忙,忙的连写日记的功夫都没有了。
有个项目的需求是需要把多个圆环的区域合并。得到包络线和内部空洞的线。
查了查google。类似的实现比较少见。简单的说说我的实现方法。
基本想法就是通过判断一段圆弧和圆环组的关系,来判断这段圆弧是否是属于合并后的包络线的一部分
如图,左边的圆盒右边的圆相交。则这两个圆就被分成了两段。
对外包络线,如上图。将所有圆环的外圆(粗线)相交。把每个圆都切成一段段的圆弧,如左边的黑色圆,则切成了黑色段和黑色+红色的两段。对每一段,我们测试这一段弧是否在其它圆环的大圆内部,如果这段圆弧不在其它的环的大圆内部(不包括内部小圆),则这段圆弧属于外包络线的一部分。否则不是。
内部透空的小圆的合并稍微麻烦一些。因为透空的部分,不光是小圆的弧,还会有大圆弧的参与。
考察小圆的圆弧,同样的,我们将小圆 和其它圆环的求交点,把小圆切成一段段的弧线(注意小圆和其它环求交的时候,就要跟这个环的大小圆都交一遍,而不光是小圆和小圆了)。如果这一段弧线不在这组圆环内(指的是环的内部,而不是大圆的内部),则表示这段弧是属于内包络线的一部分。
考察大圆的弧,大圆产生内包络线的原因主要是大圆会抵消一部分小圆的透空作用。所以同样的我们将大圆 和其它圆环的求交点,把小圆切成一段段的弧线--跟外包络不同,这次求交的时候,该大圆要和其它圆环的大小圆都求交,而不光是大圆对大圆。 对每一段圆弧,如果弧线不在环的内部,而且该段弧应该还需要位于某个环的小圆内部(看图就明白为什么了)。则该大圆弧也是内包络的一部分。
这里求圆弧在环的内部还是在大小圆内,有一个偷懒的方法。因为我们已经保证这段圆弧除了两个端点以外不和其它任何弧相交,所以只要用这段弧的中点来代替弧来作判断就好了。使得复杂性大大降低了。
以上是效果图,三个环合并成一个区域。
以下是主要代码
class CRingGroup
{
public:
bool load(const wchar_t* _ringGroupsFile)
{
xXmlDocument doc;
if(doc.load(_ringGroupsFile) == false )
return false;
xXmlNode::XmlNodes ringNodes;
doc.findAllNode(L"ring" , ringNodes);
if(ringNodes.size() == 0)
return false;
for(size_t i = 0 ; i < ringNodes.size() ; i ++)
{
xXmlNode* pNode = ringNodes[i];
xRing _ring;
_ring.m_InnerR = pNode->float_value(L"r1");
_ring.m_OutR = pNode->float_value(L"r2");
_ring.m_Center = pNode->get_value<float2>(L"center");
m_vRings.push_back(_ring);
}
}
void toSplineDrawer(CSplineDraw& drawer)
{
drawer.m_vArcs.clear();
for(int i = 0 ; i < m_vRings.size() ; i ++)
{
std::vector<float> CutPoints;
xRing& ring = m_vRings[i];
ring.toArcs(CutPoints , true , drawer.m_vArcs);
}
for(int i = 0 ; i < m_vRings.size() ; i ++)
{
std::vector<float> CutPoints;
xRing& ring = m_vRings[i];
ring.toArcs(CutPoints , false , drawer.m_vArcs);
}
}
void toInnerLine(std::vector<xArc>& vOut)
{
for(int i = 0 ; i < m_vRings.size() ; i ++)
{
std::vector<float> vCutPoints;
std::vector<xArc> vArcs;
//先来切内圆
xRing& _ring = m_vRings[i];
for(int j = 0 ; j < m_vRings.size() ; j ++)
{
if(j == i) continue;
xRing& _ring2 = m_vRings[j];
_ring.CutByCircle(_ring2.m_Center , _ring2.m_OutR , vCutPoints , false );
_ring.CutByCircle(_ring2.m_Center , _ring2.m_InnerR , vCutPoints , false);
}
_ring.toArcs(vCutPoints , false , vArcs);
//内圆的弧,必须在所有的外圆的外部。
for(int iArc = 0 ; iArc < vArcs.size() ; iArc ++)
{
xArc& _arc = vArcs[iArc];
bool bInRing = false;
for(int k = 0 ; k < m_vRings.size() ; k ++)
{
if( k == i ) continue;
xRing& _ring2 = m_vRings[k];
if( true == _ring2.IsInRing( _arc ) )
{
bInRing = true;
}
}
//////////////////////////////////////////////////////////////////////////
if(bInRing == false)
{
vOut.push_back(_arc);
}
}
//内圆切完了。来切外圆套在其它内圆中的部分。
vCutPoints.clear();
vArcs.clear();
for(int j = 0 ; j < m_vRings.size() ; j ++)
{
if(j == i) continue;
xRing& _ring2 = m_vRings[j];
_ring.CutByCircle(_ring2.m_Center , _ring2.m_OutR , vCutPoints , true );
_ring.CutByCircle(_ring2.m_Center , _ring2.m_InnerR , vCutPoints , true);
}
_ring.toArcs(vCutPoints , true , vArcs);
//内圆的弧,必须在所有的外圆的外部。
for(int iArc = 0 ; iArc < vArcs.size() ; iArc ++)
{
xArc& _arc = vArcs[iArc];
bool bInRing = false;
bool bInSmallRing = false;
for(int k = 0 ; k < m_vRings.size() ; k ++)
{
if( k == i ) continue;
xRing& _ring2 = m_vRings[k];
if( true == _ring2.IsInRing( _arc ) )
{
bInRing = true;
}
if( true == _ring2.IsInSmallRing( _arc) )
{
bInSmallRing = true;
}
}
//////////////////////////////////////////////////////////////////////////
if(bInRing == false && bInSmallRing == true)
{
vOut.push_back(_arc);
}
}
}
return ;
}
void toOutLine(std::vector<xArc>& vOut)
{
//return ;
for(int i = 0 ; i < m_vRings.size() ; i ++)
{
std::vector<float> vCutPoints;
xRing& _ring = m_vRings[i];
for(int j = 0 ; j < m_vRings.size() ; j ++)
{
if(j == i) continue;
xRing& _ring2 = m_vRings[j];
_ring.CutByCircle(_ring2.m_Center , _ring2.m_OutR , vCutPoints , true);
}
std::vector<xArc> vArcs;
_ring.toArcs(vCutPoints , true , vArcs);
//判断生成的圆弧是不是在内部。
for(int iArc = 0 ; iArc < vArcs.size() ; iArc ++)
{
xArc& _arc = vArcs[iArc];
bool bInRing = false;
for(int k = 0 ; k < m_vRings.size() ; k ++)
{
if( k == i ) continue;
xRing& _ring2 = m_vRings[k];
if( true == _ring2.IsInOutRing(_arc ) )
{
bInRing = true;
}
}
//////////////////////////////////////////////////////////////////////////
if(bInRing == false)
{
vOut.push_back(_arc);
}
}
}
return ;
}
public:
std::vector<xRing> m_vRings;
};
分享到:
相关推荐
2. **Tecplot界面组成**: - **菜单栏**: 提供了软件的主要功能入口,如文件管理(File)、编辑(Edit)、查看(View)等。 - **工具栏**: 包含了常用的操作按钮,如不同类型的图形显示切换、数据处理等。 - **工作区**:...
界面主要分为几个区域,如工具栏、工作区、状态栏等,每个区域都承载着不同的功能与信息显示。 - **草图与尺寸指定**:草图绘制是几何建模的基础,DesignModeler支持精确控制尺寸与约束,确保模型符合设计规范。...
并集将多个面域合并为一个大面域;差集是去除一个面域中另一个面域的部分;交集则是找出两个或多个面域相交的部分。这些运算有助于简化设计并创建复杂的形状。 **从面域中提取数据** 面域对象具备额外的质量特性,...
UNION命令用于将两个或多个三维实体合并成一个单一实体。通过这种方式,可以创建复杂的组合形状。 ##### 减去(SUBTRACT) SUBTRACT命令用于从一个或多个实体中减去另一个实体,以创建具有凹陷部分的三维模型。 ##...
创建面域的方法是使用“面域”(REGION)命令,选定一个或多个封闭图形后,系统会将它们转换为面域。面域不仅包含边的信息,还包括边界内的信息,这使得我们可以对它进行布尔运算并从中提取工程属性,比如面积、质心和...
多段线(PLINE)允许创建由多个线段或圆弧组成的连续线,而多边形(POLYGON)则用于绘制边数相等的正多边形。矩形(REC)命令不仅可生成标准矩形,还能绘制带有圆角或倒角的矩形。此外,射线(RAY)是从一点向无限...
5. **PL**:多段线 - 用于创建由多个线段组成的连续线。 6. **PO**:创建点 - 创建单个或多个点对象。 7. **U回车**:撤销 - 撤销上一步操作,等同于Ctrl+Z。 8. **SKETCH**:徒手画线 - 在没有精确捕捉的情况下自由...
5. MA:特性匹配 - 将一个对象的特性复制到另一个或多个对象上,相当于格式刷功能。 6. ATT:定义属性块 - 创建包含可编辑属性的块,例如在建筑设计中,可以创建一个具有门编号和类型属性的门块。 7. B:创建内部...
具体来说,环形颜色直方图将每个特征点所在的区域划分为多个扇区,并统计每个扇区内各种颜色出现的频率。这种方法能够有效地保留特征点的局部颜色信息以及它们在图像中的相对位置关系。 环形颜色直方图的构造过程...
- **多段线PLINE**:绘制由多个线段组成的连续线。 - **圆CIRCLE**:基于圆心和半径绘制圆形。 - **圆弧ARC**:创建不同形式的圆弧。 - **矩形RECTANGLE**:绘制矩形。 - **多边形POLYGON**:绘制等边多边形。 ...
39. **合并多段线(PE)**:合并多个线段为一个对象。 40. **倒角(CHA)**:为对象添加倒角。 41. **涂层(LA)**:管理对象的图层,包括颜色、线型、线宽等属性。 42. **标注样式(D)**:自定义标注的外观,包括文字、...
4. PL:多段线 - 创建由多个线段组成的线。 5. POL:多边形 - 绘制规则的多边形。 6. REC:矩形 - 绘制矩形。 7. SPL:样条曲线 - 绘制平滑的曲线。 8. EL:椭圆 - 绘制椭圆或圆弧。 9. PO:单点 - 添加单个点标记。...
82. **UNI**: 合并命令,用于合并多个对象为一个对象。 83. **V**: 视图命令,用于控制当前视图的显示方式。 84. **VP**: 视口命令,用于创建、调整视口大小或位置。 85. **W**: 保存命令,用于保存当前的图纸...
57. INTERFERE / INF(创建三维复合实体):检测并合并两个或多个三维实体的公共部分。 58. INTERSECT / IN(交集创建复合实体):找到两个或多个实体或面域的交集,形成新的实体或面域。 59. INSERTOBJ / IO...
- **定义**: 一个图表可以包含多个数据系列,每个系列可能包含多个数据点。 - **作用**: 组织和展示不同类型的数据集合。 #### 二、Echarts图表类型详解 **1. Line(折线图)** - **定义**: 包括折线图、堆积折线...