#+TITLE: Mesh.org
#+AUTHOR: screwtape
* gmsh sphere geometry utility
#+BEGIN_EXAMPLE
 I just got into 3D printing. I'm not  this doesn't  produce;   your slicer
 interested   in downloading  others'  probably can add that automatically.
 stuff   in general,  I want to  make  The  program   is basically  a  poor
 stuff. Rather than thinking  through  man's   macro  system  inside   CLOS
 extrusions, I had the idea to simply  methods   so as to use class   scope
 csg-sum   unit spheres  at different  allocated    indices  to  create   a
 scales  and  positions  (using  gmsh  combined  geometry  file output.  It
 which uses oce). The lowest surfaces  adds spheres don't worry about it.
 of a sphere generally need  supports

#+END_EXAMPLE

** Geometry of two overlapping spheres
#+name: twospheres
#+begin_src lisp :noweb yes :results output
 <<mesh>>

 (defvar *aball* (make-instance 'sphere :x 0 :y 0 :z 0 :r 10 :lc 5))
 (defvar *bball* (make-instance 'sphere :x 10 :y 0 :z 0 :r 10 :lc 5))


 (geo-beginning *aball*)
 (fill-forms *aball*)
 (fill-forms *bball*)

 (mapc 'eval (forms *aball*))
 (mapc 'eval (forms *bball*))
#+end_src

#+RESULTS: twospheres
#+begin_example
 Mesh.Algorithm = 6;

 lc = 5;
 Point(1) = {0,0,0,lc};
 Point(2) = {10,0,0,lc};
 Point(3) = {0,10,0,lc};
 Circle(1) = {2,1,3};
 Point(4) = {-10,0,0,lc};
 Point(5) = {0,-10,0,lc};
 Circle(2) = {3,1,4};
 Circle(3) = {4,1,5};
 Circle(4) = {5,1,2};
 Point(6) = {0,0,-10,lc};
 Point(7) = {0,0,10,lc};
 Circle(5) = {3,1,6};
 Circle(6) = {6,1,5};
 Circle(7) = {5,1,7};
 Circle(8) = {7,1,3};
 Circle(9) = {2,1,7};
 Circle(10) = {7,1,4};
 Circle(11) = {4,1,6};
 Circle(12) = {6,1,2};
 Curve Loop(13) = {2,8,-10};
 Surface(14) = {13};
 Curve Loop(15) = {10,3,7};
 Surface(16) = {15};
 Curve Loop(17) = {-8,-9,1};
 Surface(18) = {17};
 Curve Loop(19) = {-11,-2,5};
 Surface(20) = {19};
 Curve Loop(21) = {-5,-12,-1};
 Surface(22) = {21};
 Curve Loop(23) = {-3,11,6};
 Surface(24) = {23};
 Curve Loop(25) = {-7,4,9};
 Surface(26) = {25};
 Curve Loop(27) = {-4,12,-6};
 Surface(28) = {27};
 Surface Loop(29) = {28,26,16,14,20,24,22,18};
 Volume(30) = {29};

 Physical Surface(1) = {28,26,16,14,20,24,22,18};
 Physical Volume(2) = {30};

 Point(8) = {10,0,0,lc};
 Point(9) = {20,0,0,lc};
 Point(10) = {10,10,0,lc};
 Circle(31) = {9,8,10};
 Point(11) = {0,0,0,lc};
 Point(12) = {10,-10,0,lc};
 Circle(32) = {10,8,11};
 Circle(33) = {11,8,12};
 Circle(34) = {12,8,9};
 Point(13) = {10,0,-10,lc};
 Point(14) = {10,0,10,lc};
 Circle(35) = {10,8,13};
 Circle(36) = {13,8,12};
 Circle(37) = {12,8,14};
 Circle(38) = {14,8,10};
 Circle(39) = {9,8,14};
 Circle(40) = {14,8,11};
 Circle(41) = {11,8,13};
 Circle(42) = {13,8,9};
 Curve Loop(43) = {32,38,-40};
 Surface(44) = {43};
 Curve Loop(45) = {40,33,37};
 Surface(46) = {45};
 Curve Loop(47) = {-38,-39,31};
 Surface(48) = {47};
 Curve Loop(49) = {-41,-32,35};
 Surface(50) = {49};
 Curve Loop(51) = {-35,-42,-31};
 Surface(52) = {51};
 Curve Loop(53) = {-33,41,36};
 Surface(54) = {53};
 Curve Loop(55) = {-37,34,39};
 Surface(56) = {55};
 Curve Loop(57) = {-34,42,-36};
 Surface(58) = {57};
 Surface Loop(59) = {58,56,46,44,50,54,52,48};
 Volume(60) = {59};

 Physical Surface(3) = {58,56,46,44,50,54,52,48};
 Physical Volume(4) = {60};

#+end_example

#+BEGIN_EXAMPLE
 Output to a geo file can be opened in gmsh, and then mesh>3D'd.   Everything
 could be better!

#+END_EXAMPLE

** Source
#+name: mesh
#+begin_src lisp
 (defpackage mesh (:use cl) (:export sphere geo-beginning fill-forms))
 (in-package mesh)

 (defclass 3d ()
   ((points :initform nil :accessor points)
    (lc :initarg :lc :reader lc)
    (complexes :initform nil :accessor complexes)
    (phys :initform nil :accessor phys)
    (surface :accessor surface)
    (volume :accessor volume)
    (next-point :allocation :class)
    (next-phy :allocation :class)
    (next-complex :allocation :class))
   (:default-initargs :lc 5))

 (defmethod new-pnt ((obj 3d)) "
 (new-pnt 3D)
 Adds a class-scope new point.
 "
   (let ((idx (incf (slot-value obj 'next-point))))
     (if (null (points obj))
         (setf (points obj) (list idx))
       (nconc (points obj) (list idx)))
     (values idx)))

 (defmethod pof ((obj 3d) n) "
 (pof 3d x)
 Gets the locally scoped (1- x) indexed point
 "
   (nth (1- n) (points obj)))


 (defmethod cof ((obj 3d) n) "
 (cof 3d x)
 Gets the locally scoped (1- x) indexed complex
 "
   (nth (1- n) (complexes obj)))

 (defmethod new-phy ((obj 3d)) "
 (new-phy 3d)
 Adds a class-scope physical object
 "
   (let ((idx (incf (slot-value obj 'next-phy))))
     (if (null (phys obj))
         (setf (phys obj) (list idx))
       (nconc (phys obj) (list idx)))
     (values idx)))

 (defmethod new-cpx ((obj 3d)) "
 (new-cpx 3d)
 Adds a class-scope complex object
 "
   (let ((idx (incf (slot-value obj 'next-complex))))
     (if (null (complexes obj))
         (setf (complexes obj) (list idx))
       (nconc (complexes obj) (list idx)))
     (values idx)))

 (defmethod shared-initialize :after ((obj 3d) names &rest args)
   (declare (ignore names args))
   (unless (slot-boundp obj 'next-point)
    (setf (slot-value obj 'next-point) 0
          (slot-value obj 'next-complex) 0
          (slot-value obj 'next-phy) 0)))

 (defclass sphere (3d)
   ((x :initarg :x :accessor x)
    (y :initarg :y :accessor y)
    (z :initarg :z :accessor z)
    (r :initarg :r :accessor r)
    (sphere-forms :type list :initform (list) :accessor forms))
   (:documentation "
 (make-instance mesh:sphere :x 3 :y 4 :z 5 :r 10 :lc 3)
 Instantiates an object for the printing of a gmsh geometry of
 said sphere equivalent to gmsh's unit sphere
 (but with class scope indices)
 "))

 (defun blank () '(format t "~%"))

 (defmethod add-point ((obj 3d) x y z)
  (let ((p (new-pnt obj)))
  `(format t "Point(~d) = {~d,~d,~d,lc};~%" ,p ,x ,y ,z)))

 (defmethod add-circle ((obj 3d) a b c &aux (p (pof obj a)) (q (pof obj b)) (r (pof obj c)))
  (let ((s (new-cpx obj)))
   `(format t "Circle(~d) = {~d,~d,~d};~%" ,s ,p ,q ,r)))

 (defun sgn (n) (if (plusp n) 1 -1))

 (defmethod add-curvel ((obj 3d) a b c &aux
                         (p (* (sgn a) (cof obj (abs a))))
                         (q (* (sgn b) (cof obj (abs b))))
                         (r (* (sgn c) (cof obj (abs c)))))
  (let ((s (new-cpx obj)))
   `(format t "Curve Loop(~d) = {~d,~d,~d};~%" ,s ,p ,q ,r)))

 (defmethod add-surface ((obj 3d) x)
  (let ((s (new-cpx obj)))
   `(format t "Surface(~d) = {~d};~%" ,s ,(cof obj x))))

 (defmethod add-volume ((obj 3d) x)
  (let ((s (new-cpx obj)))
   `(format t "Volume(~d) = {~d};~%" ,s ,(cof obj x))))

 (defmethod add-surfl ((obj 3d) &rest args)
  (let ((s (new-cpx obj)) (new-args (mapcar (lambda (x) (cof obj x)) args)))
   `(format t "Surface Loop(~d) = {~@{~d~^,~}};~%" ,s ,@new-args)))

 (defmethod phy-surf ((obj 3d) &rest args)
  (let ((s (new-phy obj)) (new-args (mapcar (lambda (x) (cof obj x)) args)))
   `(format t "Physical Surface(~d) = {~@{~d~^,~}};~%" ,s ,@new-args)))

 (defmethod phy-vol ((obj 3d) vol)
  (let ((s (new-phy obj)))
   `(format t "Physical Volume(~d) = {~d};~%" ,s ,(cof obj vol))))

 (defmethod geo-beginning ((obj sphere) &aux (mesh-algo 6) (lc (lc obj)))
   (setf (forms obj)
         (list `(format t "~a = ~d;~%" "Mesh.Algorithm" ,mesh-algo)
               (blank)
               `(format t "lc = ~d;~%" ,lc))))

 (defmethod fill-forms ((obj sphere)
                        &aux (x (x obj)) (y (y obj)) (z (z obj))
                        (r (r obj)) (lc (lc obj))) "
 (fill-forms sphere)
 Prints the Gmsh geometry of a unit sphere at (x sphere) ..
 of radius/lc (r sphere) (lc sphere)
 Exactly equivalent to the the unit sphere from gmsh.
 The point / extrusion / physical counters are class scope
 so subsequent mesh::3d instances can be printed in the same
 geometry. 'complexes' is an erroneous name.
 "
  (setf (forms obj)
   (nconc (forms obj)
    (list (add-point obj x y z)
     (add-point obj (+ x r) y z)
     (add-point obj x (+ y r) z)
     (add-circle obj 2 1 3)
     (add-point obj (- x r) y z)
     (add-point obj x (- y r) z)
     (add-circle obj 3 1 4) ; 10
     (add-circle obj 4 1 5)
     (add-circle obj 5 1 2)
     (add-point obj x y (- z r))
     (add-point obj x y (+ z r)) ; 14
     (add-circle obj 3 1 6)
     (add-circle obj 6 1 5)
     (add-circle obj 5 1 7)
     (add-circle obj 7 1 3)
     (add-circle obj 2 1 7)
     (add-circle obj 7 1 4)
     (add-circle obj 4 1 6)
     (add-circle obj 6 1 2) ; 22
     (add-curvel obj 2 8 -10)
     (add-surface obj 13)
     (add-curvel obj 10 3 7)
     (add-surface obj 15)
     (add-curvel obj -8 -9 1)
     (add-surface obj 17) ; 28
     (add-curvel obj -11 -2 5)
     (add-surface obj 19)
     (add-curvel obj -5 -12 -1)
     (add-surface obj 21)
     (add-curvel obj -3 11 6)
     (add-surface obj 23)
     (add-curvel obj -7 4 9)
     (add-surface obj 25)
     (add-curvel obj -4 12 -6)
     (add-surface obj 27) ; 38
     (add-surfl obj 28 26 16 14 20 24 22 18)
     (add-volume obj 29)
     (blank)
     (phy-surf obj 28 26 16 14 20 24 22 18)
     (phy-vol obj 30)
     (blank)))))

#+end_src