ashleytgg 发表于 2018-3-14 16:33:07

用齐次坐标绘制正12面体

本帖最后由 ashleytgg 于 2018-3-14 16:33 编辑

参照《计算机图形学原理教程》编著 ——李建平 , 电子科技大学出版社, 中其次坐标的图形变换原理,写了几个lisp 函数。
    绘制了正12面体, 觉得非常有趣,在此和大家飞享下。 其中也也引用了 high_fly_bird 的一个小函数矢量叉积。



;; 定义一个三维镜像的函数
;; group 为一个四维点集合 , point_A point_Bpoint_C   为镜像平面的三个点
(defun mirror_3d (group      point_A   point_Bpoint_C    /
      Cen      Axis      x_Ceny_Cen    z_Cen
      x_Axis    y_Axis    z_AxisP_1    P_2
      cos_a      sin_a   cos_bsin_b    P1->P2
      Cen->Axis T_ry      T_rxT_XY_mirror
      T_ry-1    T_rx-1    T_m-1T_综合    Vector_0
      Vector_1
   )

;; 求平面 ABC 的 法向量
(setqVector_0 (mapcar '- point_B point_A)
Vector_1 (mapcar '- point_C point_A)
)
;; 求向量Vector_0 Vector_1 的叉积,为平面法向量normal_vector
(setqnormal_vector
   (G:CrossProductor Vector_0 Vector_1)
)
;; 定义新的原点, 和新的 Z轴
(setqCenpoint_A
Axis (mapcar '+ Cen normal_vector)
)
;; 把原点移动到Cen ,Z轴向量转变为 Cen->Axis
(setqT_m (list
      (list 1 0 0 (* (car Cen) -1))
      (list 0 1 0 (* (cadr Cen) -1))
      (list 0 0 1 (* (caddr Cen) -1))
      (list 0 0 0 1)
      )
)

;; 设置point_A point_B 的坐标 x_A y_A z_A ,x_B y_B z_B
(mapcar 'set
    '(x_Cen y_Cen z_Cen x_Axis y_Axis z_Axis)
    (append Cen Axis)
)
(setqP_1    (list y_Cen Z_Cen)
P_2    (list y_Axis Z_Axis)
P1->P2 (distance p_1 P_2)
)
(if (> P1->P2 1e-8)
    (setq
      cos_a (/ (- z_Axis z_Cen) P1->P2)
      sin_a (/ (- y_Axis y_Cen) P1->P2)
    )
    (setq cos_a1
    sin_a0
    )
)
(setqT_rx (list
         (list 1 0 0 0)
         (list 0 cos_a (* -1 sin_a) 0)
         (list 0 sin_a cos_a 0)
         (list 0 0 0 1)
       )
)
(setq
    Cen->Axis (distance Cen Axis)
    cos_b   (/ P1->P2 Cen->Axis)
    sin_b   (/ (- x_Axis x_Cen) Cen->Axis)
)
(setqT_ry (list
         (list cos_b 0 (* -1 sin_b) 0)
         (list 0 1 0 0)
         (list sin_b 0 cos_b 0)
         (list 0 0 0 1)
       )
)
;; 对XY平面 进行镜像
(setqT_XY_mirror
   (list
   (list 1 0 0 0)
   (list 0 1 0 0)
   (list 0 0 -1 0)
   (list 0 0 0 1)
   )
)
(setqT_ry-1 (list
   (list cos_b 0 sin_b 0)
   (list 0 1 0 0)
   (list (* -1 sin_b) 0 cos_b 0)
   (list 0 0 0 1)
         )
)
(setqT_rx-1 (list
   (list 1 0 0 0)
   (list 0 cos_a sin_a 0)
   (list 0 (* -1 sin_a) cos_a 0)
   (list 0 0 0 1)
         )
)
(setqT_m-1 (list
    (list 1 0 0 (car Cen))
    (list 0 1 0 (cadr Cen))
    (list 0 0 1 (caddr Cen))
    (list 0 0 0 1)
      )
)
(setqT_综合
         (mapcar '(lambda(lst)
      (setqlst (mxv T_m lst)
      lst (mxv T_rx lst)
      lst (mxv T_ry lst)
      lst (mxv T_XY_mirror lst)
      lst (mxv T_ry-1 lst)
      lst (mxv T_rx-1 lst)
      lst (mxv T_m-1 lst)
      )
      )
         (list
       '(1 0 0 0)
       '(0 1 0 0)
       '(0 0 1 0)
       '(0 0 0 1)
         )
         )
;; 对T_综合 进行装置
T_综合 (list (mapcar 'car T_综合)
         (mapcar 'cadr T_综合)
         (mapcar 'caddr T_综合)
         (mapcar 'cadddr T_综合)
         )
)
(mapcar '(lambda (u)
       (mxv T_综合 U)
   )
    group
)
)
;;(mirror_3d   group    point_A point_B point_C)
;;定义一个坐标系重置函数,把一个已知坐标系,原点重置为point_A ,Z轴设置方向point_A->point_B
(defun reset_coordinate_system (grouppoint_Apoint_B/x_A
      y_Az_Ax_By_Bz_B
      P_1P_2cos_asin_acos_b
      sin_bP1->P2A->BT_ryT_rx
      T_综合
             )
(setqT_m (list
      (list 1 0 0 (* (car point_A) -1))
      (list 0 1 0 (* (cadr point_A) -1))
      (list 0 0 1 (* (caddr point_A) -1))
      (list 0 0 0 1)
      )
)
(mapcar 'set
    '(x_A y_A z_A x_B y_B z_B)
    (append point_A point_B)
)
(setqP_1    (list y_A Z_A)
P_2    (list y_B Z_B)
P1->P2 (distance p_1 P_2)
)
(if (> P1->P2 1e-8)
    (setq
      cos_a (/ (- z_B z_A) P1->P2)
      sin_a (/ (- y_B y_A) P1->P2)
    )
    (setq cos_a1
    sin_a0
    )
)
(setqT_rx (list
         (list 1 0 0 0)
         (list 0 cos_a (* -1 sin_a) 0)
         (list 0 sin_a cos_a 0)
         (list 0 0 0 1)
       )
)
(setq
    A->B(distance point_A point_B)
    cos_b (/ P1->P2 A->B)
    sin_b (/ (- x_B x_A) A->B)
)
(setqT_ry (list
         (list cos_b 0 (* -1 sin_b) 0)
         (list 0 1 0 0)
         (list sin_b 0 cos_b 0)
         (list 0 0 0 1)
       )
)
(setqT_综合
         (mapcar '(lambda(lst)
      (setqlst (mxv T_m lst)
      lst (mxv T_rx lst)
      lst (mxv T_ry lst)
      )
      )
         (list
       '(1 0 0 0)
       '(0 1 0 0)
       '(0 0 1 0)
       '(0 0 0 1)
         )
         )
;; 对T_综合 进行装置
T_综合 (list (mapcar 'car T_综合)
         (mapcar 'cadr T_综合)
         (mapcar 'caddr T_综合)
         (mapcar 'cadddr T_综合)
         )
)
(mapcar '(lambda (u)
       (mxv T_综合 U)
   )
    group
)
)
;;(reset_coordinate_systemgrouppoint_Apoint_B );;定义一个三维对齐函数,既把一个三维向量P_A->P_B P_A->P_C , 经过一系列平移、旋转操作,和另外一个
;;已经知道的向量target_A->target_B target_A->target_C , 重合
(defun align_3d(group   point_A   point_B
   point_C   target_A   target_B
   target_C   /   normal_vector
   normal_vector_target   axis_rotation_0
   axis_rotation_1 T_m   U_offset
   Vector_0   Vector_1
    )

;; 求平面 ABC 的 平面法向量 normal_vector
(setqVector_0 (mapcar '- point_B point_A)
Vector_1 (mapcar '- point_C point_A)
)
(setqnormal_vector
   (G:CrossProductor Vector_0 Vector_1)
)
;; 求平面target_A target_B target_C 的 平面法向量 normal_vector_target
(setqVector_0 (mapcar '- target_B target_A)
Vector_1 (mapcar '- target_C target_A)
)
(setqnormal_vector_target
   (G:CrossProductor Vector_0 Vector_1)
)
;; 求向量 normal_vector normal_vector_target 组成平面的法向量
(setqAxis_vector
   (G:CrossProductor normal_vector normal_vector_target)
)

(if (= (apply '+ Axis_vector) 0)
    ;; 当Axis_vector 为0 时,表示normal_vector 和normal_vector_target 共线 ,则
    ;; 平面target_A target_B target_C和 平面 ABC 共面
    (setq ang 0)
    ;; 建立以 '(0 0 0)normal_vector normal_vector_target 位XY平面,'(0 0 0)->Axis_vector Z轴的坐标系
    (setq lst      (reset_coordinate_system
          (list normal_vector normal_vector_target)
          '(0 0 0)
          Axis_vector
      )
    ang_0      (angle '(0 0)
         (mapcar '+ '(0 0) (car lst))
      )
    ang_1      (angle '(0 0)
         (mapcar '+ '(0 0) (cadr lst))
      )
    ;; ang为 由平面 ABC 旋转到平面target_A target_B target_C 的旋转角度,
    ;;也是向量O->normal_vector 和O->normal_vector_target 之间的夹角
    ang      (- ang_1 ang_0)
    ;; 求 由平面 ABC 旋转到平面target_A target_B target_C 的旋转轴
    axis_rotation_0 point_A
    axis_rotation_1 (mapcar '+ point_A Axis_vector)
    )
)
(if (/= ang 0)
    ;; 图像group 绕着旋转轴axis_rotation_0 axis_rotation_1 旋转ang度
    (setq group(rotate_3d (append (list (append point_A (list 1))
         (append point_B (list 1))
         )
         group
         )
         axis_rotation_0
         axis_rotation_1
         ang
    )
    )
)
(setqU_offset (mapcar '- target_A point_A)
T_m   (list
       (list 1 0 0 (car U_offset))
       (list 0 1 0 (cadr U_offset))
       (list 0 0 1 (caddr U_offset))
       (list 0 0 0 1)
   )
)
(setqgroup (mapcar '(lambda (u)
       (mxv T_m U)
         )
          group
      )
)
;; 把point_A->point_B target_A->target_B 变成四维点
(setq
    lst_四维 (mapcar
         '(lambda(x)
      (append x (list 1))
    )
         (list (car group) (cadr group) target_A target_B)
       )
)
(setq
    lst    (reset_coordinate_system
      lst_四维
      target_A
      (mapcar '+ target_A normal_vector_target)
    )
    ;; 计算向量 point_A->point_B的象限角
    ang_0 (angle (mapcar '+ '(0 0) (car lst))
   (mapcar '+ '(0 0) (cadr lst))
    )
    ;;计算向量target_A->target_B 的象限角
    ang_1 (angle (mapcar '+ '(0 0) (caddr lst))
   (mapcar '+ '(0 0) (cadddr lst))
    )
    ;; 向量 point_A->point_Btarget_A->target_B 在同一个平面内时的旋转角度 Δ
    Δ    (- ang_1 ang_0)
)
;; 让图像group 绕着 point_A->normal_vector   旋转Δ ,再绕着绕着旋转轴axis_rotation_0 axis_rotation_1 旋转ang度
;; 最后 坐标原点 移动到target_A
(rotate_3d (cddr group)
       target_A
       (mapcar '+ target_A normal_vector_target)
       Δ
)
)


;; group 为一个四维点集合 , point_A point_B 为旋转轴的两个点,φ 为旋转角度,单位弧度
;; 旋转轴point_A point_B 的距离必须大于0 ,本程序不考虑 point_A point_B 重合的情形
(defun rotate_3d (group    point_A point_B φ    /    x_A
      y_A    z_A    x_B    y_B    z_B    P_1
      P_2    cos_a    sin_a    cos_b    sin_b    P1->P2
      A->B    T_ry    T_rx    T_rZ    T_ry-1T_rx-1
      T_m-1    T_综合
   )
(setqT_m (list
      (list 1 0 0 (* (car point_A) -1))
      (list 0 1 0 (* (cadr point_A) -1))
      (list 0 0 1 (* (caddr point_A) -1))
      (list 0 0 0 1)
      )
)

;; 设置point_A point_B 的坐标 x_A y_A z_A ,x_B y_B z_B
(mapcar 'set
    '(x_A y_A z_A x_B y_B z_B)
    (append point_A point_B)
)
(setqP_1    (list y_A Z_A)
P_2    (list y_B Z_B)
P1->P2 (distance p_1 P_2)
)
(if (> P1->P2 1e-8)
    ;; 当向量A->B 不平行于X 轴时
    (setq
      cos_a (/ (- z_B z_A) P1->P2)
      sin_a (/ (- y_B y_A) P1->P2)
    )
    ;; 当向量A->B 平行于X 轴时 ,既垂直于 YZ平面,此时A->B与X轴的夹角为0度
    (setq cos_a1
    sin_a0
    )
)
(setqT_rx (list
         (list 1 0 0 0)
         (list 0 cos_a (* -1 sin_a) 0)
         (list 0 sin_a cos_a 0)
         (list 0 0 0 1)
       )
)
(setq
    A->B(distance point_A point_B)
    cos_b (/ P1->P2 A->B)
    sin_b (/ (- x_B x_A) A->B)
)
(setqT_ry (list
         (list cos_b 0 (* -1 sin_b) 0)
         (list 0 1 0 0)
         (list sin_b 0 cos_b 0)
         (list 0 0 0 1)
       )
)
;; 绕AB顺时针旋转 φ 角度,就变成绕新的Z 轴逆时针旋转φ 角度
(setqT_rZ (list
         (list (cos φ) (* -1 (sin φ)) 0 0)
         (list (sin φ) (cos φ) 0 0)
         (list 0 0 1 0)
         (list 0 0 0 1)
       )
)
(setqT_ry-1 (list
   (list cos_b 0 sin_b 0)
   (list 0 1 0 0)
   (list (* -1 sin_b) 0 cos_b 0)
   (list 0 0 0 1)
         )
)
(setqT_rx-1 (list
   (list 1 0 0 0)
   (list 0 cos_a sin_a 0)
   (list 0 (* -1 sin_a) cos_a 0)
   (list 0 0 0 1)
         )
)
(setqT_m-1 (list
    (list 1 0 0 (car point_A))
    (list 0 1 0 (cadr point_A))
    (list 0 0 1 (caddr point_A))
    (list 0 0 0 1)
      )
)
(setqT_综合
         (mapcar '(lambda(lst)
      (setqlst (mxv T_m lst)
      lst (mxv T_rx lst)
      lst (mxv T_ry lst)
      lst (mxv T_rz lst)
      lst (mxv T_ry-1 lst)
      lst (mxv T_rx-1 lst)
      lst (mxv T_m-1 lst)
      )
      )
         (list
       '(1 0 0 0)
       '(0 1 0 0)
       '(0 0 1 0)
       '(0 0 0 1)
         )
         )
;; 对T_综合 进行装置
T_综合 (list (mapcar 'car T_综合)
         (mapcar 'cadr T_综合)
         (mapcar 'caddr T_综合)
         (mapcar 'cadddr T_综合)
         )
)
(mapcar '(lambda (u)
       (mxv T_综合 U)
   )
    group
)
)
;;( rotate_3dgroup    point_A point_B φ)

renhaitao_nice 发表于 2018-3-14 18:42:18

高手太多,我等惭愧跪拜

ashleytgg 发表于 2018-3-15 12:01:21

都是书本上抄来的,我只是翻译下而已。

434939575 发表于 2018-3-15 16:54:12

确实好用。学习了。
页: [1]
查看完整版本: 用齐次坐标绘制正12面体