llsheng_73 发表于 2013-12-9 03:36:24

关于多个点是否共直线

本帖最后由 llsheng_73 于 2014-11-8 04:20 编辑

关于三个点是否共直线有很多种算法,我能想到的有以下几种
1。角度比较:由于三个点p1,p2,p3不一定按顺序,所以可以比较p1p2,p1p3计算出的角度是否相等或者相差180度
2。夹角比较:以中间一点为起点求出夹角看它是否等于180度或者不找中间一点直接计算出两个角度来计算夹角不管它是0还是180都共线,不过比较第一个方法来,总之这个减法计算是多余的,还得对负数进行处理或者判断里边再加上-180度
3。长度比较:计算出三个边长排好序,是否两边和等于第三边
4。计算1个点到另两个点的垂距,看它是否等于0
5。计算它们的面积是否等于0
6。把这三个点交给CAD让它绘圆,如果绘制不出来就共直线(这个办法是临时想到的)

由三个点是否共线想到多于3个点怎么判断它们是否共线?
对于这个我想到的办法就少了
1。角度比较好象也比较直观
2。夹角比较
3.长度比较,要防止所用来计算距离的点跨越点
4.计算面积,虽然点太多了这个计算量会很大,但可以交给CAD,把这些点绘制成一根最短的不闭合多线段,如果面积为0就共线
5.还是把问题交给CAD,用POINT绘制出所有的点,找出距离最大的两个点(或者直接计算两个足够远点更快些也可能,点比较多的话)用它们进行ssget"F"看能否选中所有点
6.用最大距离的两个点绘制一条线段(其实要不要绘制出来都不影响),计算其余点到这条线的距离
以上是我能想到的办法,至于哪个最快最有效还不得而知,个人觉得第5个办法最简单也最奇特,但是如果点太多可能就不太合适了,最后一个办法可能更有用,第3、4两个办法都需要对点先进行排序(比如按到长度最大的两个点的其中之一距离进行排序),总之比较麻烦

不知道各位高手的更好的招数舍不舍得分享出来,就算不想分享你的高招也请选出你认为最可行或者最有效的方法并说明你的理由先谢谢各位了哈

(defun CK:ColineP(ptlst / a);;ptlst坐标点表(第二维以后被忽略,可以所有点坐标相同也可以前几个点相同
(if(and(=(type ptlst)'list)
         (=(type(car ptlst))'list)
         (apply'and(apply'append(mapcar'(lambda(x)(cons(>(length x)1)(mapcar'(lambda(x)(member(type x)'(real int)))x)))ptlst))))
    ;;;最后一项检查的后边很大程度上不是必须的,因为坐标点通常直接根据图元提取或者屏幕点击,这里只是顺便写出来
    ;;;前两项检查是必须的,不然(CK:ColineP nil)也会返回真,一个点说它共线勉强可以说得过去,但空表共线这说不通,所以加上这两项检查
    (setq a(car ptlst)
    ptlst(vl-remove a ptlst)
    a(mapcar'- a(car ptlst))
    a(apply'and(mapcar'(lambda(x)(equal(cadr(trans x 0 a))0 1e-8))ptlst)))
    )
)

此问题讨论了近一年,得到众多坛友的关注,Gu_xl版主 、vormittag 、edata 、xyp1964 院长、wowan1314 、自贡黄明儒 等众多高手提供思路和算法,最终采用了vormittag 构建直线坐标系的方法,加入数据检查后完成该函数,在此贴出对众多坛友的关注表示感谢
当然,此算法由于取前两个不同的点构建直线坐标系,有可能因为这两个点距离过小产生计算误差,导致同样的坐标点因为点的顺序而产生二义性,因此最终版本应该取最远的两个点来构建直线坐标系,这个等有了时间再加上



llsheng_73 发表于 2013-12-9 05:00:10

本帖最后由 llsheng_73 于 2013-12-9 05:01 编辑

泡杯茶坐点支烟在沙发上等你的见解哟

自贡黄明儒 发表于 2013-12-9 08:15:02

解决问题是关键,三点没有交点,不就在一条直线上了?这个有讨论的必要吗?

vormittag 发表于 2013-12-9 09:19:53

任选两点计算向量,把所有点坐标trans 到以该向量为法向量的对象坐标系,如果trans后的所有点 x y 坐标在允许的误差之内均一致,n点共线,否则不共线。

vormittag 发表于 2013-12-9 09:24:09

代码如下:(defun CK:ColineP (ptlst / linenormal templst firstpt)
        (setq linenormal (mapcar '- (car ptlst) (cadr ptlst))
                templst (mapcar '(lambda(x) (mapcar '+ '(0.0 0.0) (trans x 0 linenormal))) ptlst)
                firstpt (car templst)
                templst (apply 'append (mapcar '(lambda(x) (mapcar '- x firstpt)) templst)))
        (apply 'and (mapcar '(lambda(x) (equal 0.0 x 1e-8)) templst)))

c961806787 发表于 2013-12-9 09:30:58

vormittag 发表于 2013-12-9 09:24 static/image/common/back.gif
代码如下:

代码太长、太复杂

edata 发表于 2013-12-9 21:41:08

,三角形法则应该适用。另外有这个
计算几何算法概览
http://bbs.mjtd.com/forum.php?mod=viewthread&tid=48974&fromuid=338795

 

fszs 发表于 2013-12-9 23:01:38

直接转换坐标,用前2个点定义x轴,查看第点的y坐标,r如果是0就表示共线
(command "ucs" pt1 (trans pt2 0 1) "@0,1")
(if (= (nth 1 (trans pt3 0 1)) 0)

xyp1964 发表于 2013-12-10 00:36:47

(defun aaa (ptn / s1 mode i pt)
(entmake (list '(0 . "line")(cons 10 (car ptn))(cons 11 (cadr ptn))))
(setq s1   (entlast)
      mode t
      i    0
)
(while (and mode (setq pt (nth i ptn)))
    (if (> (distance (vlax-curve-getclosestpointto s1 pt t) pt) 0)
      (setq mode nil)
      (setq i (1+ i))
    )
)
(entdel s1)
mode
)

Gu_xl 发表于 2013-12-10 10:42:52

(defun ListColinear-p(lst / ColinearP)
(defun ColinearP(p1 p2 p3)
    (
   (lambda (a b c)
       (or
       (equal (+ a b) c 1e-8)
       (equal (+ b c) a 1e-8)
       (equal (+ c a) b 1e-8)
       )
       )
      (distance p1 p2)
      (distance p2 p3)
      (distance p1 p3)
      )
    )
(or (null (cddr lst))
      (not
        (vl-some
          '(lambda (a) (not (ColinearP (car lst) (cadr lst) a)))
          (cddr lst)
          )
        )
      )
)
页: [1] 2
查看完整版本: 关于多个点是否共直线