本帖最后由 llsheng_73 于 2014-6-10 21:42 编辑
对于不闭合的多线段,严格来说它不能确定是哪个方向的,因为它接下来直接封闭之后才能确定它是顺时针方向还是逆时针方向,当然,如果假定把它的首尾点连起来让它封闭,那么就可以和闭合多线段一样确定它的方向了,对于Q3的那种判定方法是有理论依据的
【越飞越高讲堂17】论点、线、面、三角形及多边形
http://bbs.mjtd.com/forum.php?mo ... &fromuid=202795
但我从来没有真正理解到它,所以我是从多线段上找三个点来组成一个三角形(比如起点,中间任意一点,止点,当然得检查它们不共直线,如果共直线了换掉一个点),最后通过计算三角形中心到三角形第一顶点、第二顶点、第三顶点的角度来进行判断的
- (defun PoInPl(pt p / d d0 d1 p1 n);;:点表是否包围指定点
- (setq p1(cons(last pt)pt)n 0 d 1e99)
- (repeat(length pt)(setq d0(car(PTOLINE p(nth n p1)(nth(setq n(1+ n))p1)))d(if(< d0 d)d0 d)))
- (if(equal d 0 1e-8)0
- (progn
- (setq n 0 d1 1e99 pt(OFFSETPT pt 1 0)p1(cons(last pt)pt))
- (repeat(length pt)(setq d0(car(PTOLINE p(nth n p1)(nth(setq n(1+ n))p1)))d1(if(< d0 d1)d0 d1)))
- (if(> d1 d)1 -1))))
- (defun PlDir(p / n m p1 p2 p3 o a a1 a2)
- (setq n(length p)pi2(* pi 2)m 2 p1(nth 0 p)p2(nth 1 p))
- (while(< m n)
- (setq p3(nth m p)
- o(list(/(+(+(car p1)(car p2))(car p3))3)(/(+(+(cadr p1)(cadr p2))(cadr p3))3))
- m(if(<(PoInPl p o)1)n(1+ m))))
- (setq a(angle o p1) a1(-(angle o p2)a)
- a1(if(< a1 0)(+ a1 pi2)a1)
- a2(-(angle o p3)a)
- a2(if(< a2 0)(+ a2 pi2)a2)
- m(if(> a1 a2)t)))
- (defun offsetpt(pt d flag / offsetpt1);|falg 0闭合点表,1不闭合它;d<0向内>0向外(假定它有内外)|;
- (defun offsetpt1(pt d flag / m0 m n pi2 d1 p1 p0 p q0 q2 q22 q1 q pt1 pt2 fx)
- (setq m(length pt)d1(abs d)n flag
- pi15(*(if(> d 0)1 -1) pi 1.5)pt2 pt)
- (while(< n(- m flag))
- (setq p(nth n pt2)
- p0(if(<(1- n)0)(last pt2)(nth(1- n)pt2))
- p1(if(=(1+ n)m)(car pt2)(nth(1+ n)pt2))
- n(1+ n)
- ang1(+(angle p0 p)pi15)
- ang2(+(angle p p1)pi15)
- q(inters (polar p0 ang1 d1)(polar p ang1 d1)(polar p ang2 d1)(polar p1 ang2 d1) nil)
- q(if q q (polar p ang2 d1)))
- (if(=(* flag n)2)(setq pt1(append pt1(list q0))))
- (setq pt1(append pt1(list q)))
- (if(=(* flag n)(- m flag))(setq pt1(append pt1(list q1)))))
- pt1)
- (if(= flag 0)
- (setq d0(apply '+(mapcar'(lambda(x)(distance(nth(1-(vl-position x pt))pt)x))(cdr pt)))
- pt1(offsetpt1 pt(if(> d 0)0.1 -0.1)flag)
- d1(apply '+(mapcar'(lambda(x)(distance(nth(1-(vl-position x pt1))pt1)x))(cdr pt1)))
- pt1(offsetpt1(if((if(> d 0)> <)d1 d0)pt(reverse pt))d flag)
- pt1(if((if(> d 0)> <)d1 d0)pt1(reverse pt1)))
- (offsetpt1 pt d flag)))
- (defun Plinexy(e / p a b n ob q et d d1 en et) ;;多线段节点坐标(滤掉了多余点,未处理假闭合)
- (setq a(entget e)ob(vlax-ename->vla-object e)et(cdr(assoc 0 a))n 0 p nil d nil)
- (cond((="LWPOLYLINE"et)
- (repeat(length a)(setq b (nth n a) n (+ n 1))
- (if (= 10 (car b))(progn
- (setq q(list (cadr b) (caddr b))d1(vlax-curve-getDistAtPoint ob q))
- (if p (if (not(member d1 d)) (setq p (append p (list q))d (append d (list d1))))
- (setq p (list q))))
- )))
- ((="POLYLINE"et)
- (SETQ EN (ENTGET (SETQ E (ENTNEXT E))))
- (WHILE (/= (CDR (ASSOC 0 EN)) "SEQEND")
- (SETQ q (CDR (ASSOC 10 EN))d1(vlax-curve-getDistAtPoint ob q)q(reverse(cdr(reverse q))))
- (if p(if (not(member d1 d)) (setq p (append p (list q))d (append d (list d1))))
- (setq p (list q)))
- (SETQ EN (ENTGET (SETQ E (ENTNEXT E)))))
- (setq p(reverse p))
- ))
- P)
- (defun ptoline(p p1 p2 / l a b c d);;p在线外p1近端点p2远端点
- (setq a(distance p1 p2)
- c(distance p p1)
- b(distance p p2)
- l(/(-(+(* a a)(* c c))(* b b))(* a 2))
- d(polar p1(angle p1 p2)(abs l)))
- (if(< 0 l a)(list(distance p d)p d)
- (if(> b c)(list c p p1)(list b p p2))))
;;(pldir(plinexy(car(entsel))))
顺时针方向返回T否则返回nil
对于有凸度的情况,比如只有两顶点的一段弧,中间点得通过vlax-curve-getPointAtDist去取出,由于我所涉及到的多线段它不允许凸度存在所以没有考虑它
由于不懂高飞鸟的矩阵运算,所以写得特别啰嗦,并且对于取出的三点是否会共直线也没有进行检查处理,下边的内容是发了这个帖子后又去看了高飞鸟的贴子后整理出来的,对于它的精髓仍然无法理解,但经过验证,结果和上边完全由我自己写的一样但明显效率高得多也简洁得多,这就让人不得不感慨数学功底的差别所带来的影响
- (defun MAT:Det2v(p1 p2);;by- highflybir ,这个地方我把参数改过,因为我把那里的所有函数找到后发现原来是四个参数,而用到它的时候只有两个表
- (-(*(car p1)(cadr p2))(*(car p2)(cadr p1))))
- (defun POLY:Area(pts);;by- highflybir
- (*(apply'+(mapcar'MAT:Det2V pts(append(cdr pts)(list(car pts)))))0.5)
- )
- (defun POLY:dir(pts / );;by- highflybir
- (<(POLY:Area pts)0)
- )
上边的全是从高飞鸟的帖子里边整理出来的,只是把最后一个POLY:IsCCW 改为了POLY:dir,个人这样容易记一些,返回结果与原来的相反,也仅仅是因为个人习惯问题
使用这一段的时候一是要记得感谢高飞鸟,另外要注意根据需要把凸度上的点加进去,不然对于由一个弧转成的多线段如果只用顶点是不够的 |