Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 175 lines (128 sloc) 5.877 kb
15e88c2 @colah Added a file on how to contribute to ImplicitCAD.
authored
1
2 ImplicitCAD Hacking How To
3 ==========================
4
5 So you want to improve ImplicitCAD. Yay! More help is a good thing.
6
7 As of the time of writing, ImplicitCAD has 3417 lines of code, 896 lines of comments, and 877 blank lines, for a total of 5190 lines spread over 42 files. For a project of ImplicitCAD's scope, that's pretty small, but it's still enough that it can be difficult to find the section we need to change...
8
9 The structure of ImplicitCAD is as follows:
10
11 ```
12 Graphics
13 └── Implicit
14 ├── Export
15 │   ├── Render
16 │   └── Symbolic
17 ├── ExtOpenScad
18 │   └── Util
19 └── ObjectUtil
20 ```
21
22 `Graphics.Implicit.Export` is, as you may guess, where all the export stuff is. `Graphics.Implicit.ExtOpenScad` is the programming language interpreter for the ExtOpenScad language, our extention of openscad. Finally, the graphics engine is defined in `Graphics.Implicit` and `Graphics.Implicit.ObjectUtil`.
23
24 The rest of this file will go through different changes you are likely to want to make and how to implement them.
25
26 Language Changes
27 ----------------
28
29 Most likely, you want to change one of four things:
30
31 * **Expressions**: Expressions are things like `1+2`, `"abc"`, and `[sin(3.14), pi]`. They are defined in `Graphics.Implicit.ExtOpenScad.Expressions`. (Note that `sin` and `pi` are variables, which are defined elsewhere.)
32
33 * **Statements**: Statements are things like variable assignment, for loops, and if statements. For example `for (a = [1,2,3]) echo (a);`. Statements are defined in `Graphics.Implicit.ExtOpenScad.Statements`.
34
35 ```haskell
36 computationStatement = ...
37 ifStatement,
38 forStatement,
39 ...
40
41 ...
42
43 forStatement = (do
44 line <- fmap sourceLine getPosition
45 -- a for loop is of the form:
46 -- for ( vsymb = vexpr ) loopStatements
47 -- eg. for ( a = [1,2,3] ) {echo(a); echo "lol";}
48 -- eg. for ( [a,b] = [[1,2]] ) {echo(a+b); echo "lol";}
49 string "for"
50 many space
51 char '('
52 many space
53 pattern <- patternMatcher
54 many space
55 char '='
56 vexpr <- expression 0
57 char ')'
58 many space
59 loopStatements <- suite
60 ...
61 ```
62
63
64 * **Default Variables**: Like `sin`, `pi`, `sqrt`. These are all defined in ` Graphics.Implicit.ExtOpenScad.Default`. We can just use `toOObj` to convert Haskell values into `OpenscadObj`s and use them as default variable settings. (Small caveat: inputs to `toOObj` can't be polymorphic, so we use a type signature to force it to a certain type.)
65
66 ```haskell
67 defaultFunctions = map (\(a,b) -> (a, toOObj ( b :: ℝ -> ℝ)))
68 [
69 ("sin", sin),
70 ("cos", cos),
71 ("tan", tan),
72 ...
73 ]
74 ```
75
76 * **Default Modules**: Like `sphere` and `linear_extrude`. These are all defined in `Graphics.Implicit.ExtOpenScad.Primitives`.
77
78 ```haskell
79 primitives = [ sphere, cube, square, cylinder, ... ]
80
81 ...
82
83 -- **Exmaple of implementing a module**
84 -- sphere is a module without a suite named sphere,
85 -- this means that the parser will look for this like
86 -- sphere(args...);
87 sphere = moduleWithoutSuite "sphere" $ do
88 example "sphere(3);"
89 example "sphere(r=5);"
90 -- What are the arguments?
91 -- The radius, r, which is a (real) number.
92 -- Because we don't provide a default, this ends right
93 -- here if it doesn't get a suitable argument!
94 r :: ℝ <- argument "r"
95 `doc` "radius of the sphere"
96 -- So what does this module do?
97 -- It adds a 3D object, a sphere of radius r,
98 -- using the sphere implementation in Prim
99 -- (Graphics.Implicit.Primitives)
100 addObj3 $ Prim.sphere r
101
102 ```
103
104 Output Formats
105 --------------
106
107 Formats are defined in files like `Graphics.Implicit.Export.TriangleMeshFormats` (as is the case with STLs), `Graphics.Implicit.Export.PolylineMeshFormats` (as is the case with SVGs).
108
109 Then, in `Graphics.Implicit.Export`:
110
111 ```haskell
112 writeSVG res = writeObject res PolylineFormats.svg
113 writeSTL res = writeObject res TriangleMeshFormats.stl
114 ```
115
116 Rendering Algorithms
117 --------------------
118
119 These are defined in `Graphics.Implicit.Export.Render` and children. `Graphics.Implicit.Export.Render` begins with an outline of how rendering is done:
120
121 ```haskell
122 -- Here's the plan for rendering a cube (the 2D case is trivial):
123
124 -- (1) We calculate midpoints using interpolate.
125 -- This guarentees that our mesh will line up everywhere.
126 -- (Contrast with calculating them in getSegs)
127
128 import Graphics.Implicit.Export.Render.Interpolate (interpolate)
129
130 ...
131 ```
132
133 If you are interested on working on this part of the code, read it. The children are also well documented.
134
135 Graphics Primitives
136 -------------------
137
138 The most complicated part of ImplicitCAD is the actual graphics engine. Before working on it, please familiarize yourself with the theory as described in [Chris' blog post](http://christopherolah.wordpress.com/2011/11/06/manipulation-of-implicit-functions-with-an-eye-on-cad/) (though changes have occured since then).
139
140 The simples way to implement a new primitive is using `implicit`, a contructor that takes an implicit function and boudning box, producing an object. For example, we could have originally defined `sphere` as:
141
142 ```haskell
143 sphere :: ℝ -> SymbolicObj3
144 sphere r = implicit (
145 \(x,y,z) -> sqrt (x^2+y^2+z^2) - r,
146 ((-r, -r, -r), (r, r, r))
147 )
148 ```
149
150 and put it in `Graphics.Implicit.Primitives`. However, to allow more powerful optimizations, meta-inspection, and other goodies, frequently used objects should be put in the `SymbolicObj` definitions in `Graphics.Implicit.Definitions`. For example, `sphere`:
151
152 ```haskell
153 data SymbolicObj3 =
154 Rect3R ℝ ℝ3 ℝ3
155 | Sphere ℝ
156 ...
157 ```
158
159 Then one needs to make the relevant entries in `Graphics.Implicit.ObjectUtil.*`.
160
161 `Graphics.Implicit.ObjectUtil.Box3`:
162
163 ```haskell
164 getBox3 (Sphere r ) = ((-r, -r, -r), (r,r,r))
165 ```
166
167 `Graphics.Implicit.ObjectUtil.GetImplicit3`:
168
169 ```haskell
170 getImplicit3 (Sphere r ) =
171 \(x,y,z) -> sqrt (x**2 + y**2 + z**2) - r
172 ```
173
174
Something went wrong with that request. Please try again.