admin 发表于 2024-2-17 23:08:54

将一组对象从正交参考系投影到 倾斜的视角,然后从一个倾斜的视角到另一个倾斜的视角

;;-------------------------=={ 2D Projection }==------------------------;;
;;                                                                      ;;
;;This program provides the user with a means of projecting a         ;;
;;selected set of planar objects from one reference frame to another. ;;
;;                                                                      ;;
;;Upon issuing the command syntax '2dpro' at the AutoCAD            ;;
;;command-line, the user is prompted to select a set of 2D planar   ;;
;;objects to be projected. This selection is restricted to Arcs,      ;;
;;Circles, Elipses, Lines, LWPolylines, 2D (Heavy) Polylines,         ;;
;;2D Splines & Points.                                                ;;
;;                                                                      ;;
;;The user is then prompted to select a source reference frame &      ;;
;;a destination reference frame. For each of these prompts, the       ;;
;;program requires the user to select a closed LWPolyline with four   ;;
;;non-collinear vertices. Following each selection, the program       ;;
;;will ensure the points are counter-clockwise oriented with the      ;;
;;points ordered such that the lower-left vertex appears first.       ;;
;;                                                                      ;;
;;Following valid user responses, the program will then convert the   ;;
;;four 2D points defining each reference frame into homogeneous       ;;
;;coordinates, and will calculate the transformation matrix to map    ;;
;;from the source reference frame (or projective space) to the      ;;
;;destination reference frame.                                        ;;
;;                                                                      ;;
;;The program will then iterate over the set of selected objects      ;;
;;and, for each object, will calculate a 2D point set describing or   ;;
;;(in the case of curved objects) approximating the object.         ;;
;;                                                                      ;;
;;Each point is then converted to homogeneous coordinates and mapped;;
;;to the destination reference frame using the tranformation matrix,;;
;;before being converted back to cartesian coordinates.               ;;
;;                                                                      ;;
;;The program will then generate either a Point, Line or LWPolyline   ;;
;;from the mapped point(s) with properties matching those of the      ;;
;;original object.                                                    ;;
;;----------------------------------------------------------------------;;
;;Author:Lee Mac, Copyright ?2014-www.lee-mac.com            ;;
;;----------------------------------------------------------------------;;
;;Version 1.0    -    2014-10-10                                    ;;
;;                                                                      ;;
;;First release.                                                      ;;
;;----------------------------------------------------------------------;;

(defun c:2dpro ( / *error* des ent enx idx lst mat ocs sel src typ )

    (defun *error* ( msg )
      (LM:endundo (LM:acdoc))
      (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
      )
      (princ)
    )

    (LM:startundo (LM:acdoc))
    (if
      (and
             (setq sel
               (LM:ssget "\nSelect objects to project: "
                  '(   "采用:L"
                         (
                           (-4 . "<OR")
                                 (-4 . "<AND")
                                     (0 . "ARC,CIRCLE,ELLIPSE,LINE,*POLYLINE,POINT")
                                     (-4 . "<NOT")
                                       (-4 . "<AND")
                                             (0 . "POLYLINE") (-4 . "&") (70 . 88)
                                       (-4 . "AND>")
                                     (-4 . "NOT>")
                                 (-4 . "AND>")
                                 (-4 . "<AND")
                                     (0 . "SPLINE") (-4 . "&=") (70 . 8)
                                 (-4 . "AND>")
                           (-4 . "OR>")
                         )
                     )
               )
             )
             (setq src (2dprojection:getreferenceframe "\nSelect source reference frame: "))
             (setq des (2dprojection:getreferenceframe "\nSelect destination reference frame: "))
             (setq mat (2dprojection:getmatrix src des))
             (setq ocs (trans '(0.0 0.0 1.0) 1 0 t))
      )
      (repeat (setq idx (sslength sel))
            (setq ent (ssname sel (setq idx (1- idx)))
                  enx (entget ent)
                  typ (cdr (assoc 0 enx))
            )
            (cond
                (   (= "POINT" typ)
                  (entmake
                        (vl-list*
                           '(0 . "POINT")
                            (cons 10 (trans (2dprojection:mappoint mat (trans (cdr (assoc 10 enx)) 0 ocs)) ocs 0))
                            (LM:defaultprops enx)
                        )
                  )
                )
                (   (= "LINE" typ)
                  (entmake
                        (vl-list*
                           '(0 . "LINE")
                            (cons 10 (trans (2dprojection:mappoint mat (trans (cdr (assoc 10 enx)) 0 ocs)) ocs 0))
                            (cons 11 (trans (2dprojection:mappoint mat (trans (cdr (assoc 11 enx)) 0 ocs)) ocs 0))
                            (LM:defaultprops enx)
                        )
                  )
                )
                (   (setq lst (LM:Entity->PointList ent))
                  (entmake
                        (append
                            (list
                               '(000 . "LWPOLYLINE")
                               '(100 . "AcDbEntity")
                               '(100 . "AcDbPolyline")
                              (cons 90 (length lst))
                              (if (vlax-curve-isclosed ent) '(70 . 1) '(70 . 0))
                            )
                            (LM:defaultprops enx)
                            (mapcar '(lambda ( p ) (cons 10 (2dprojection:mappoint mat (trans p 0 ent)))) lst)
                            (list (assoc 210 enx))
                        )
                  )
                )
            )
      )
    )
    (LM:endundo (LM:acdoc))
    (princ)
)

;; 2D Projection: Get Reference Frame-Lee Mac
;; Prompts the user to select a closed planar polyline with 4 vertices in
;; order to obtain 4 counter-clockwise oriented non-collinear points
;; defining a reference frame for the transformation.

(defun 2dprojection:getreferenceframe ( msg / ent enx lst tmp )
    (while
      (progn (setvar 'errno 0) (setq ent (car (entsel msg)))
            (cond
                (   (= 7 (getvar 'errno))
                  (princ "\nMissed, try again.")
                )
                (   (null ent) nil)
                (   (or (/= "LWPOLYLINE" (cdr (assoc 0 (setq enx (entget ent)))))
                        (zerop (logand 1 (cdr (assoc 70 enx))))
                        (/= 4 (cdr (assoc 90 enx)))
                        (/= 4 (length (setq lst (2dprojection:uniquefuzz (mapcar 'cdr (vl-remove-if-not '(lambda ( x ) (= 10 (car x))) enx)) 1e-8))))
                        (2dprojection:checkcollinearity (cons (last lst) lst))
                  )
                  (setq lst nil)
                  (princ "\nPlease select a closed polyline with 4 non-collinear vertices.")
                )
            )
      )
    )
    (if lst
      (progn
            (if (2dprojection:clockwise-p lst)
                (setq lst (reverse lst))
            )
            (setq tmp (apply 'mapcar (cons 'min lst)))
            (repeat (car (vl-sort-i lst '(lambda ( a b ) (< (distance a tmp) (distance b tmp)))))
                (setq lst (append (cdr lst) (list (car lst))))
            )
            lst
      )
    )
)

;; 2D Projection: Unique with Fuzz-Lee Mac
;; Returns a list with all elements considered duplicate to a given tolerance removed.

(defun 2dprojection:uniquefuzz ( lst fuz )
    (if lst
      (cons (car lst)
            (2dprojection:uniquefuzz
                (vl-remove-if
                  (function (lambda ( x ) (equal x (car lst) fuz)))
                  (cdr lst)
                )
                fuz
            )
      )
    )
)

;; 2D Projection: Check Collinearity-Lee Mac
;; Returns T if any three points in a supplied list are collinear.

(defun 2dprojection:checkcollinearity ( lst )
    (and (caddr lst)
      (or (   (lambda ( a b c )
                  (or (equal (+ a b) c 1e-8)
                        (equal (+ b c) a 1e-8)
                        (equal (+ c a) b 1e-8)
                  )
                )
                (distance (carlst) (cadrlst))
                (distance (cadr lst) (caddr lst))
                (distance (carlst) (caddr lst))
            )
            (2dprojection:checkcollinearity (cdr lst))
      )
    )
)

;; 2D Projection: Clockwise-p-Lee Mac
;; Returns T if the supplied point list is clockwise oriented.

(defun 2dprojection:clockwise-p ( lst )
    (minusp
      (apply '+
            (mapcar
                (function
                  (lambda ( a b )
                        (- (* (car b) (cadr a)) (* (car a) (cadr b)))
                  )
                )
                lst (cons (last lst) lst)
            )
      )
    )
)

;; 2D Projection: Map Point-Lee Mac
;; Converts a supplied 2D point to homogeneous coordinates, applies a
;; matrix transformation & then converts the result back to cartesian coordinates.

(defun 2dprojection:mappoint ( mat pnt )
    (apply (function (lambda ( x y z ) (list (/ x z) (/ y z))))
      (mxv mat (list (car pnt) (cadr pnt) 1.0))
    )
)

;; 2D Projection: Get Matrix-Lee Mac
;; Calculates the transformation matrix for transforming
;; homogeneous 2D points from one reference frame to another.

(defun 2dprojection:getmatrix ( l1 l2 / f )
    (mxm
      (
            (setq f
                (lambda ( l / c m )
                  (setq c
                        (mxv
                            (invm
                              (setq m
                                    (trp
                                        (mapcar
                                          (function
                                                (lambda ( a b )
                                                    (list (car a) (cadr a) b)
                                                )
                                          )
                                          l '(1.0 1.0 1.0)
                                        )
                                    )
                              )
                            )
                            (list (car (last l)) (cadr (last l)) 1.0)
                        )
                  )
                  (mapcar '(lambda ( r ) (mapcar '* r c)) m)
                )
            )
            l2
      )
      (invm (f l1))
    )
)

;; Default Properties-Lee Mac
;; Returns a list of DXF properties for the supplied DXF data,
;; substituting default values for absent DXF groups

(defun LM:defaultprops ( enx )
    (mapcar '(lambda ( x ) (cond ((assoc (car x) enx)) ( x )))
       '(
            (006 . "BYLAYER")
            (008 . "0")
            (039 . 0.0)
            (048 . 1.0)
            (062 . 256)
            (370 . -1)
      )
    )
)

;; Entity to Point List-Lee Mac
;; Returns a list of points describing or approximating the supplied entity,
;; else nil if the entity is not supported.

(defun LM:entity->pointlist ( ent / acc der di1 di2 di3 enx fun inc lst par rad typ )
    (setq enx (entget ent)
          typ (cdr (assoc 0 enx))
          acc 35.0
    )
    (cond
      (   (= "POINT" typ)
            (list (cdr (assoc 10 enx)))
      )
      (   (= "LINE" typ)
            (list (cdr (assoc 10 enx)) (cdr (assoc 11 enx)))
      )
      (   (wcmatch typ "CIRCLE,ARC")
            (setq di1 0.0
                  di2 (vlax-curve-getdistatparam ent (vlax-curve-getendparam ent))
                  inc (/ di2 (1+ (fix (* acc (/ di2 (cdr (assoc 40 enx)) (+ pi pi))))))
                  fun (if (vlax-curve-isclosed ent) < <=)
            )
            (while (fun di1 di2)
                (setq lst (cons (vlax-curve-getpointatdist ent di1) lst)
                      di1 (+ di1 inc)
                )
            )
            lst
      )
      (   (or (= typ "LWPOLYLINE")
                (and (= typ "POLYLINE") (zerop (logand (cdr (assoc 70 enx)) 80)))
            )
            (setq par 0)
            (repeat (fix (1+ (vlax-curve-getendparam ent)))
                (if (setq der (vlax-curve-getsecondderiv ent par))
                  (if (equal der '(0.0 0.0 0.0) 1e-8)
                        (setq lst (cons (vlax-curve-getpointatparam ent par) lst))
                        (if (setq rad (distance '(0.0 0.0) (vlax-curve-getfirstderiv ent par))
                                  di1 (vlax-curve-getdistatparam ent par)
                                  di2 (vlax-curve-getdistatparam ent (1+ par))
                            )
                            (progn
                              (setq inc (/ (- di2 di1) (1+ (fix (* acc (/ (- di2 di1) rad (+ pi pi)))))))
                              (while (< di1 di2)
                                    (setq lst (cons (vlax-curve-getpointatdist ent di1) lst)
                                          di1 (+ di1 inc)
                                    )
                              )
                            )
                        )
                  )
                )
                (setq par (1+ par))
            )
            (if (or (vlax-curve-isclosed ent) (equal '(0.0 0.0 0.0) der 1e-8))
                lst
                (cons (vlax-curve-getendpoint ent) lst)
            )
      )
      (   (= "ELLIPSE" typ)
            (setq di1 (vlax-curve-getdistatparam ent (vlax-curve-getstartparam ent))
                  di2 (vlax-curve-getdistatparam ent (vlax-curve-getendparam   ent))
                  di3 (* di2 (/ (+ pi pi) (abs (- (vlax-curve-getendparam ent) (vlax-curve-getstartparam ent)))))
            )
            (while (< di1 di2)
                (setq lst (cons (vlax-curve-getpointatdist ent di1) lst)
                      der (distance '(0.0 0.0) (vlax-curve-getsecondderiv ent (vlax-curve-getparamatdist ent di1)))
                      di1 (+ di1 (/ di3 (1+ (fix (/ acc (/ di3 der (+ pi pi)))))))
                )
            )
            (if (vlax-curve-isclosed ent)
                lst
                (cons (vlax-curve-getendpoint ent) lst)
            )
      )
      (   (= "SPLINE" typ)
            (setq di1 (vlax-curve-getdistatparam ent (vlax-curve-getstartparam ent))
                  di2 (vlax-curve-getdistatparam ent (vlax-curve-getendparam   ent))
                  inc (/ di2 25.0)
            )
            (while (< di1 di2)
                (setq lst (cons (vlax-curve-getpointatdist ent di1) lst)
                      der (/ (distance '(0.0 0.0) (vlax-curve-getsecondderiv ent (vlax-curve-getparamatdist ent di1))) inc)
                      di1 (+ di1 (if (equal 0.0 der 1e-10) inc (min inc (/ 1.0 der (* 10. inc)))))
                )
            )
            (if (vlax-curve-isclosed ent)
                lst
                (cons (vlax-curve-getendpoint ent) lst)
            )
      )
    )
)

;; Matrix Inverse-gile & Lee Mac
;; Uses Gauss-Jordan Elimination to return the inverse of a non-singular nxn matrix.
;; Args: m - nxn matrix

(defun invm ( m / c f p r )
    (defun f ( p m ) (mapcar '(lambda ( x ) (mapcar '(lambda ( a b ) (- a (* (car x) b))) (cdr x) p)) m))
    (setqm (mapcar 'append m (imat (length m))))
    (while m
      (setq c (mapcar '(lambda ( x ) (abs (car x))) m))
      (repeat (vl-position (apply 'max c) c)
            (setq m (append (cdr m) (list (car m))))
      )
      (if (equal 0.0 (caar m) 1e-14)
            (setq m nil
                  r nil
            )
            (setq p (mapcar '(lambda ( x ) (/ (float x) (caar m))) (cdar m))
                  m (f p (cdr m))
                  r (cons p (f p r))
            )
      )
    )
    (reverse r)
)

;; Identity Matrix-Lee Mac
;; Args: n - matrix dimension

(defun imat ( n / i j l m )
    (repeat (setq i n)
      (repeat (setq j n)
            (setq l (cons (if (= i j) 1.0 0.0) l)
                  j (1- j)
            )
      )
      (setq m (cons l m)
            l nil
            i (1- i)
      )
    )
    m
)

;; Matrix x Matrix-Vladimir Nesterovsky
;; Args: m,n - nxn matrices

(defun mxm ( m n )
    ((lambda ( a ) (mapcar '(lambda ( r ) (mxv a r)) m)) (trp n))
)

;; Matrix x Vector-Vladimir Nesterovsky
;; Args: m - nxn matrix, v - vector in R^n

(defun mxv ( m v )
    (mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m)
)

;; Matrix Transpose-Doug Wilson
;; Args: m - nxn matrix

(defun trp ( m )
    (apply 'mapcar (cons 'list m))
)

;; ssget-Lee Mac
;; A wrapper for the ssget function to permit the use of a custom selection prompt
;; msg - selection prompt
;; arg - list of ssget arguments

(defun LM:ssget ( msg arg / sel )
    (princ msg)
    (setvar 'nomutt 1)
    (setq sel (vl-catch-all-apply 'ssget arg))
    (setvar 'nomutt 0)
    (if (not (vl-catch-all-error-p sel)) sel)
)

;; Start Undo-Lee Mac
;; Opens an Undo Group.

(defun LM:startundo ( doc )
    (LM:endundo doc)
    (vla-startundomark doc)
)

;; End Undo-Lee Mac
;; Closes an Undo Group.

(defun LM:endundo ( doc )
    (while (= 8 (logand 8 (getvar 'undoctl)))
      (vla-endundomark doc)
    )
)

;; Active Document-Lee Mac
;; Returns the VLA Active Document Object

(defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc)
)

;;----------------------------------------------------------------------;;

(vl-load-com)
(princ
    (strcat
      "\n:: 2DProjection.lsp | Version 1.0 | \\U+00A9 Lee Mac "
      (menucmd "m=$(edtime,0,yyyy)")
      " www.lee-mac.com ::"
      "\n:: Type \"2dpro\" to Invoke ::"
    )
)
(princ)

;;----------------------------------------------------------------------;;
;;                           End of File                              ;;
;;----------------------------------------------------------------------;;
页: [1]
查看完整版本: 将一组对象从正交参考系投影到 倾斜的视角,然后从一个倾斜的视角到另一个倾斜的视角