Автор: Paul.Alkhimov - 2010-03-26T11:01:10.000000Z
;; DATA STRUCTURE:
;; Vertex is just plain _array_ of three doubles: (0 0 0). Here three
;; values stand for X Y and Z respectively. Array of 3D vertexes is
;; just plain array, where 3D vertexes are following one after
;; another: ( x0 y0 z0 x1 y1 z1 x2 y2 z2 ... ). Here x# y# and z# are
;; some values of the first, the second and the third vertexes. #
;; means the index of the 3D vertex. To reference any coordinate use
;; the following form: (ref-of V C) where V is vertex containing three
;; doubles and C is X Y or Z. Also you can use this: (ref-of V C IA I)
;; where V and C are the same to previous example and IA and I mean
;; the following things: IA is array of indexes and I is index in the
;; array IA. So (ref-of COORDS :Z IND i) in C/C++ would mean the
;; following: COORDS[ IND[i] + 2 ]; In fact, last two parameters are
;; representing indirect indexing mechanism. This lets us store the
;; whole geometry in one array. Each part then can be referenced with
;; independent array of indexes. Also, we can reference the same
;; vertex as many times as necessary.
(defmacro ref-of (values coordinate &optional indexes index)
"Please see DATA STRUCTURE for details."
(if indexes
(cond ((eq coordinate :x) `(aref ,values (aref ,indexes ,index)))
((eq coordinate :y) `(aref ,values (+ 1 (aref ,indexes ,index))))
((eq coordinate :z) `(aref ,values (+ 2 (aref ,indexes ,index))))
(T (error "The symbol ~S is not :X, :Y or :Z." coordinate)))
(cond ((eq coordinate :x) `(aref ,values 0))
((eq coordinate :y) `(aref ,values 1))
((eq coordinate :z) `(aref ,values 2))
(T (error "The symbol ~S is not :X, :Y or :Z." coordinate)))))
(defmacro zero-p (v &optional indexes index)
"Checks if the vector is 'almost' zero length."
`(and (< (ref-of ,v :x ,indexes ,index) *min+*)
(< (ref-of ,v :y ,indexes ,index) *min+*)
(< (ref-of ,v :z ,indexes ,index) *min+*)
(> (ref-of ,v :x ,indexes ,index) *min-*)
(> (ref-of ,v :y ,indexes ,index) *min-*)
(> (ref-of ,v :z ,indexes ,index) *min-*)))
(defmacro do-op-on (op name1 coord1 name2 coord2 &optional is1 i1 is2 i2)
"Replaces provided names with two vectors and coordinates. Indexes supplied as well.
Example: (do-op-on * A :x B :y i n) == A[i[n]].x*B.y"
`(,op (ref-of ,name1 ,coord1 ,is1 ,i1) (ref-of ,name2 ,coord2 ,is2 ,i2)))
(defun make-v3 (x y z)
"VECTOR of 3 doubles: X Y Z."
(make-array 3 :element-type 'double-float :initial-contents (list x y z)))
(defun normalize (a &optional indexes i)
"Returns normalized A."
(pragma
(format t "Data=~A ~A ~A" a indexes i)
(if (zero-p a indexes i)
a ;; cannot normalize empty vector
(let* ((mmm (format t "Zero?=~a" (zero-p a indexes i)))
(L (sqrt (+ (do-op-on * a :x a :x indexes i indexes i)
(do-op-on * a :y a :y indexes i indexes i)
(do-op-on * a :z a :z indexes i indexes i))))
(mmm (format t "L=~a" L))
(L (/ 1D0 L))
(mmm (format t "L=~a" L))) ; L=1/length(A)
(make-V3 (* (ref-of a :x indexes i) l)
(* (ref-of a :y indexes i) l)
(* (ref-of a :z indexes i) l))))))
;; Vertex is just plain _array_ of three doubles: (0 0 0). Here three
;; values stand for X Y and Z respectively. Array of 3D vertexes is
;; just plain array, where 3D vertexes are following one after
;; another: ( x0 y0 z0 x1 y1 z1 x2 y2 z2 ... ). Here x# y# and z# are
;; some values of the first, the second and the third vertexes. #
;; means the index of the 3D vertex. To reference any coordinate use
;; the following form: (ref-of V C) where V is vertex containing three
;; doubles and C is X Y or Z. Also you can use this: (ref-of V C IA I)
;; where V and C are the same to previous example and IA and I mean
;; the following things: IA is array of indexes and I is index in the
;; array IA. So (ref-of COORDS :Z IND i) in C/C++ would mean the
;; following: COORDS[ IND[i] + 2 ]; In fact, last two parameters are
;; representing indirect indexing mechanism. This lets us store the
;; whole geometry in one array. Each part then can be referenced with
;; independent array of indexes. Also, we can reference the same
;; vertex as many times as necessary.
(defmacro ref-of (values coordinate &optional indexes index)
"Please see DATA STRUCTURE for details."
(if indexes
(cond ((eq coordinate :x) `(aref ,values (aref ,indexes ,index)))
((eq coordinate :y) `(aref ,values (+ 1 (aref ,indexes ,index))))
((eq coordinate :z) `(aref ,values (+ 2 (aref ,indexes ,index))))
(T (error "The symbol ~S is not :X, :Y or :Z." coordinate)))
(cond ((eq coordinate :x) `(aref ,values 0))
((eq coordinate :y) `(aref ,values 1))
((eq coordinate :z) `(aref ,values 2))
(T (error "The symbol ~S is not :X, :Y or :Z." coordinate)))))
(defmacro zero-p (v &optional indexes index)
"Checks if the vector is 'almost' zero length."
`(and (< (ref-of ,v :x ,indexes ,index) *min+*)
(< (ref-of ,v :y ,indexes ,index) *min+*)
(< (ref-of ,v :z ,indexes ,index) *min+*)
(> (ref-of ,v :x ,indexes ,index) *min-*)
(> (ref-of ,v :y ,indexes ,index) *min-*)
(> (ref-of ,v :z ,indexes ,index) *min-*)))
(defmacro do-op-on (op name1 coord1 name2 coord2 &optional is1 i1 is2 i2)
"Replaces provided names with two vectors and coordinates. Indexes supplied as well.
Example: (do-op-on * A :x B :y i n) == A[i[n]].x*B.y"
`(,op (ref-of ,name1 ,coord1 ,is1 ,i1) (ref-of ,name2 ,coord2 ,is2 ,i2)))
(defun make-v3 (x y z)
"VECTOR of 3 doubles: X Y Z."
(make-array 3 :element-type 'double-float :initial-contents (list x y z)))
(defun normalize (a &optional indexes i)
"Returns normalized A."
(pragma
(format t "Data=~A ~A ~A" a indexes i)
(if (zero-p a indexes i)
a ;; cannot normalize empty vector
(let* ((mmm (format t "Zero?=~a" (zero-p a indexes i)))
(L (sqrt (+ (do-op-on * a :x a :x indexes i indexes i)
(do-op-on * a :y a :y indexes i indexes i)
(do-op-on * a :z a :z indexes i indexes i))))
(mmm (format t "L=~a" L))
(L (/ 1D0 L))
(mmm (format t "L=~a" L))) ; L=1/length(A)
(make-V3 (* (ref-of a :x indexes i) l)
(* (ref-of a :y indexes i) l)
(* (ref-of a :z indexes i) l))))))