沿边排列建筑
要求
首先明确输入和输出。
我们有图一所示的边缘线,以及图二所示的四个矩形.数据都已经在图中给出.我们要将图二的矩形在图一的边缘线上排列。
最终输入如图三所示,注意二点:
1. a处属于阳角,所以可以延伸出去。
2. b处最后一个矩形之所以这么排列,是因为前面的矩形导致的,也就是按照顺序排列。
解决方法
对于上面的问题,我采用域线的方法去解决。
我认为自己的方法只是解决这个问题的方法之一,肯定有更高效,更便捷的方法等待发现,希望我的方法能给大家一点灵感。
在我们已经排完a,b段后,我们现在需要排c段,那么在c段的上空可以看到,存在两条红色的域线,以及一条蓝色的中空区域(代表可以排任意高度)。得到这些域线后,就可以遍历每个域线,根据每条域线的性质来安放矩形
这就是我的大致思路。
构造
对于上述的方法需要构造几个类,分别是矩形(Rectangle),道路(Path_list),单条道路(Path),域线(Segment),域点(Areapoint).矩形与域点又继承了(Polyline),(Point2D)类.
伪代码
介绍一下具体实现的流程
可以思考一下一些具体的方法应该放在哪个类里面实现
获得域线
我们回到c段,当我们想获得c段的域线,首先得用c段之外的所有节点对c段做投影。
可以看到,一共9个点投影到了c段所在的直线上。
接下来对点进行一个筛选,选择5,6,7,8这几个在c段范围内的点。
然后反向将这些点与除了c段外的所有线段求垂点,并且选出最低的垂点。
我们选出了a,b,c,d点连线。再加上c段的起始点和末尾点。在这里大家和之前主动画出来的域线比较一下会发现,b,c点间缺少一条垂直线作为过渡。
也就是说,b点其实是一个特殊的点,如何判断出b点这些特殊的点我试了一些方法,但是都没有成功…(我认为是能成功判断的,希望大家能找到方法TAT)。于是我采取了一个折中的方法,我会在每个点之间再插入若干个点,比如6,7之间再插入10个点,那么就可以得到近似于之前的域线了。由于这种方法可以用点的数量控制精度,到最后可以完美模拟,所以我认为可以采取这个方法。
还有几个应该注意的点
1/图中案例c段末尾是阴角,所以最后添加c段末端点并且把范围外的点都排除了。如果c段末尾是阳角(意味着矩形可以超出边界),超出c段末尾的点也要被加入计算中。
2/图中c-d的域线其实是空域,所以需要一开始知道空域的范围,在算出所有域线后减去在空域中的域线
3/关于计算上的边界条件,比如遇到平行,以及除法后精确的问题
求域线的流程基本如下1
2
3
4
5
6
7
8
9
10
11
12
13
14#求域线的伪代码
if 阴角:
得到除了当前段外其他所有的点
根据角的性质排除掉不符合的点
求空域的区间
得到点在当前段上的投影点
在投影点间插入精度点(按数量还是距离都随意)
精度点反向投影到其他线段上,得到域点
连接域点得到域线
根据空域的区间减去空域范围的域线
返回域线
else:
...
排列矩形
得到域线后就该放入矩形了,可以想象一下,我们现在要往c段放入矩形了,而c段的上方是一条条我们已经算出来的域线。而域线的种类无非三种,上升/下降/无。这里和c段平行的域线可以被看做是上升或下降的特殊情况一起讨论。下面是排列矩形的伪代码。
注意域线不存在的情况
1 |
|
代码实现
下面我用代码实现一下,因为细节太多(包括空域其实还有种类,如何处理误差,>=之间的判断都是要反复琢磨的),所以前面主要讲的还是逻辑,具体实现就直接上代码了。
1 | #因为域点和矩形分别继承了Point2D和Polyline,所以我先描述这两类 |
好吧好吧,实在是有点长。很多精力都花费在了边界条件上,比如一个大于等于0会造成什么后果,如何处理这种问题还得多总结。