Skip to content

Instantly share code, notes, and snippets.

@joe-warren
Last active January 22, 2025 02:37
Show Gist options
  • Save joe-warren/abf41560c187fb39cb424e0e75ca6b3e to your computer and use it in GitHub Desktop.
Save joe-warren/abf41560c187fb39cb424e0e75ca6b3e to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
import qualified Waterfall
import Linear
import Control.Lens ((^.), (.~))
import Data.Function ((&))
import Waterfall.SVG (parsePath)
import Control.Monad (sequence)
import Data.Either (fromRight)
-- This code makes heavy use of a module called "Waterfall.SVG"
-- I plan on including this into the opencascade-hs monorepo, however need to clean it up first
-- Until I've done so, running this will be moderately difficult
-- print two of these, one of them mirrored, and then glue them back to back
-- to get a more symetrical ornament
blobfishLogo :: Waterfall.Solid
blobfishLogo =
let fromPaths h = mconcat . fmap (Waterfall.prism h . Waterfall.fromPath) . mconcat . fromRight (error "bad path") . traverse parsePath
outerPath =
["m 17.218114,49.338036 c 0.238335,-2.798139 2.269297,-6.369214 4.978501,-8.673645 1.433798,-1.219579 4.763468,-2.594095 8.19962,-2.821158 3.436153,-0.227063 7.371077,1.883077 10.109838,4.794609 2.738762,2.911532 2.795879,4.294033 3.732882,7.56037 0.836009,0.368529 1.730346,0.402379 2.25933,2.205782 0.650047,2.216127 -2.025726,5.306277 -3.222797,5.201234 -1.176752,1.056308 -2.833491,2.474228 -5.661439,2.512677 -2.827948,0.03845 -4.229676,-1.582493 -5.845724,-1.71041 -1.616048,-0.127917 -2.423022,0.67068 -3.731985,0.617363 -1.308963,-0.05332 -2.637131,-0.976095 -3.955464,-0.990455 -1.318333,-0.01436 -2.336644,1.150172 -4.390725,0.569669 -1.553869,-0.439139 -2.256624,-2.925159 -2.256624,-2.925159 0,0 -0.657619,0.101546 -1.423828,-0.514475 -0.766209,-0.616021 -2.075721,-2.074519 -1.663024,-3.794424 0.412697,-1.719906 2.871439,-2.031978 2.871439,-2.031978 z"
]
leftFin =
["m 18.801102,53.551571 c -0.397811,0.337705 -0.802384,0.349209 -1.358124,1.160482 0,0 -2.552174,-0.838306 -1.861502,-3.073586 0.418007,-1.352832 2.929731,-1.395312 2.929731,-1.395312 z"
]
center =
["m 18.359296,51.957311 c -0.206229,-3.295991 1.175757,-7.04399 3.427658,-9.459569 2.117155,-2.271039 5.506634,-3.43887 8.609281,-3.555272 4.423474,-0.165956 8.521494,2.629913 10.689677,6.641573 1.27432,2.357798 1.827715,5.039056 1.509554,7.700235 -0.327363,2.738152 -0.857437,4.858515 -5.894706,5.655794 -1.736388,0.274829 -3.308943,-1.863149 -5.059072,-2.029352 -1.140629,-0.108321 -1.998628,0.615125 -3.143669,0.57452 -1.284158,-0.04554 -2.480811,-0.779762 -3.76561,-0.800381 -1.215739,-0.01951 -2.679106,1.208554 -3.779192,0.690661 -1.811653,-0.852881 -2.468878,-3.419746 -2.593921,-5.418209 z"
]
rightFin =
[ "m 38.466855,51.815976 c 0.921724,1.158085 1.675101,2.188029 4.348946,4.679775 2.027978,-1.170854 2.710204,-2.784309 2.243101,-4.006993 -0.705822,-1.84755 -4.352036,-2.293646 -5.326149,-1.98199 -0.598556,0.1915 -1.265898,1.309208 -1.265898,1.309208 z"
]
face =
[ "M 25.831835 45.230447 C 25.65013 45.525794 25.46349 45.848641 25.2975 46.194212 A 2.4694452 2.4743323 0 0 0 23.861412 45.732225 A 2.4694452 2.4743323 0 0 0 21.392312 48.206492 A 2.4694452 2.4743323 0 0 0 23.861412 50.68076 A 2.4694452 2.4743323 0 0 0 25.332124 50.192418 C 25.485682 50.429518 25.672837 50.663377 25.898497 50.890566 C 26.255767 51.250258 26.657594 51.50185 27.077753 51.66933 C 23.160288 52.372011 20.590294 54.713072 20.590294 54.713072 L 21.149433 55.215884 C 21.149433 55.215884 24.567513 53.01464 28.828034 52.706476 C 33.130367 52.39529 38.887885 56.140892 38.887885 56.140892 L 39.3199 55.668569 C 39.3199 55.668569 34.803871 52.276407 30.519921 51.594399 C 30.647584 51.546694 30.768935 51.496048 30.882689 51.443504 C 31.298022 51.251661 31.608792 51.063051 31.808731 50.794965 L 31.207217 50.345897 C 31.168867 50.397317 30.918511 50.601771 30.568496 50.763442 C 30.218484 50.925114 29.763132 51.071912 29.275552 51.146365 C 28.300393 51.295273 27.225101 51.162164 26.429731 50.3614 C 25.600992 49.527043 25.428264 48.72994 25.529527 47.925889 C 25.630792 47.121841 26.045039 46.314835 26.470555 45.623188 L 25.831835 45.230447 z"
, "m 36.864544,48.244328 c 0,1.402253 -1.283265,2.796067 -2.571088,2.796067 -1.287825,0 -2.679753,-1.301276 -2.679753,-2.703529 10e-7,-1.402253 1.418988,-2.796325 2.706812,-2.796325 1.287824,0 2.544029,1.301534 2.544029,2.703787 z"
]
glints =
[ "m 24.997777,46.847293 c -0.245583,0.602332 -0.293329,1.433777 -0.230685,2.044382 -0.291116,-0.750768 -0.894501,-1.934243 -1.557937,-2.314524 0.854491,-0.27642 1.327725,-0.07877 1.788622,0.270142 z"
, "m 35.565173,46.671185 c 0.377929,0.433036 0.543038,1.039082 0.405482,1.334483 -0.202047,0.433897 -0.7173,0.669147 -1.083671,0.62109 -0.291116,-0.750768 -0.773852,-1.66702 -1.437288,-2.047301 0.684146,-0.587035 1.73537,-0.343803 2.115477,0.09173 z"
]
eyes =
[ "M 23.913089 44.861477 C 22.100326 44.861477 20.660574 46.271363 20.660574 48.157917 C 20.660574 50.044471 22.087924 51.375809 23.900686 51.375808 C 24.796831 51.375808 25.56042 51.050673 26.103653 50.493691 C 25.516457 49.924667 25.157457 49.118013 25.157457 48.171353 C 25.157457 47.217696 25.525267 46.385835 26.12329 45.796304 C 25.582316 45.211377 24.816566 44.861478 23.913089 44.861477 z"
, "m 37.628795,48.290466 a 3.2822986,3.4159122 0 0 1 -3.282298,3.415912 3.2822986,3.4159122 0 0 1 -3.282299,-3.415912 3.2822986,3.4159122 0 0 1 3.282299,-3.415912 3.2822986,3.4159122 0 0 1 3.282298,3.415912 z"
]
cutMainHole = (`Waterfall.difference` Waterfall.translate (unit _z) (fromPaths 3 (leftFin <> center <> rightFin)))
cutGlints = (`Waterfall.difference` Waterfall.translate (unit _z ^* 2) (fromPaths 3 glints))
in fromPaths 3 outerPath
& cutMainHole
& (<> fromPaths 1.5 center)
& (<> fromPaths 2 rightFin)
& (<> fromPaths 3 face)
& (<> fromPaths 2 eyes)
& cutGlints
& Waterfall.mirror (unit _x)
circle :: Waterfall.Path2D
circle = Waterfall.pathFrom (unit _x)
[ Waterfall.arcViaTo (unit _y) (negate $ unit _x)
, Waterfall.arcViaTo (negate $ unit _y) (unit _x)
]
ornament :: Waterfall.Solid
ornament =
let
com = Waterfall.centerOfMass blobfishLogo
Just (lo, _hi) = Waterfall.axisAlignedBoundingBox blobfishLogo
rawHoop = Waterfall.sweep (Waterfall.fromPath2D . Waterfall.uScale2D 3 $ circle) (Waterfall.fromPath circle)
hoopClipped = rawHoop `Waterfall.intersection` (Waterfall.centeredCube & Waterfall.translate (unit _z ^* 0.5) & Waterfall.uScale 10)
hoopPositioned = hoopClipped
& Waterfall.translate (unit _x ^* (com ^. _x))
& Waterfall.translate (unit _y ^* (lo ^. _y))
in hoopPositioned <> blobfishLogo
main :: IO ()
main = do
Waterfall.writeSTL 0.1 "blobfish-ornament.stl" ornament
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment