This file is archived and only kept for reference - DO NOT edit
This document contains a growing number of SVG example code. Each demo is defined in its own namespace and can be loaded from the REPL via:
(load-file "examples/svg/ex01.clj") ;; etc...
In the example below we construct three circles, compute their points of intersection and then visualize the result in SVG:
(ns thi.ng.geom.examples.svg.ex01
(:require
[thi.ng.math.core :as m]
[thi.ng.geom.core :as g]
[thi.ng.geom.circle :as c]
[thi.ng.geom.svg.core :as svg]
[thi.ng.geom.svg.adapter :as adapt]
[thi.ng.color.core :as col]))
(defn labeled-dot
[p label] (list (c/circle p 3) (svg/text (m/+ p 10 0) label)))
;; This scene defines 2 circles and their intersection points
(def scene
(let [c1 (c/circle 50 150 50)
c2 (c/circle 250 150 50)
c3 (c/circle 150 150 100)
[a b] (g/intersect-shape c1 c3)
[c d] (g/intersect-shape c2 c3)]
(svg/svg
{:width 300 :height 300}
(svg/group
{:fill "yellow"}
;; these circles inherit all attributes from parent group
c1 c2
;; we can use metadata to override specific attribs per shape
;; here we also demonstrate automatic color attrib conversion
(with-meta c3 {:fill (col/rgba 0 1 1 0.25) :stroke (col/hsva 0 1 1)}))
(svg/group
{:fill "#000"
:font-family "Arial, sans-serif"
:font-size 10}
(mapcat labeled-dot [a b c d] ["A" "B" "C" "D"])))))
(->> scene
(adapt/all-as-svg) ;; transform all scene elements
(svg/serialize) ;; serialize as SVG XML string
(spit "svgdemo01-circles.svg")) ;; write to disk
(ns thi.ng.geom.examples.svg.ex02
(:require
[thi.ng.geom.core :as g]
[thi.ng.geom.matrix :as mat]
[thi.ng.geom.mesh.io :as mio]
[thi.ng.geom.svg.core :as svg]
[thi.ng.geom.svg.shaders :as shader]
[thi.ng.geom.svg.renderer :as render]
[thi.ng.math.core :as m]
[clojure.java.io :as io]))
(def width 640)
(def height 480)
(def model (-> (mat/matrix44) (g/rotate-x m/HALF_PI) (g/rotate-z m/SIXTH_PI)))
(def view (apply mat/look-at (mat/look-at-vectors 0 0 -2 0 0 0)))
(def proj (mat/perspective 60 (/ width height) 0.1 2))
(def mvp (->> model (m/* view) (m/* proj)))
(def col-tx (g/rotate-x (mat/matrix44) (- m/HALF_PI)))
(def shader
(shader/shader
{:fill (shader/phong
{:model model
:view view
:light-pos [0 -2 1]
:light-col [1 1 1]
:diffuse (shader/normal-rgb col-tx)
:ambient [0.1 0.1 0.2]
:specular 1.0
:shininess 6.0})
:uniforms {:stroke "black" :stroke-width 0.25}
:flags {:solid true}}))
(def mesh
(with-open [in (io/input-stream "dev-resources/suzanne.stl")]
(-> in
(mio/wrapped-input-stream)
(mio/read-stl)
(g/center)
(g/scale 0.85))))
(defn render-svg
[path mesh mvp width height]
(let [screen (mat/viewport-matrix width height)]
(->> (svg/svg
{:width width :height height}
(render/mesh mesh mvp screen shader))
(svg/serialize)
(spit path))))
(render-svg "svgdemo02-suzanne.svg" mesh mvp width height)
Diffuse: Normal XYZ > RGB | Diffuse: Normal XYZ > RGB | Diffuse: Normal XYZ > RGB |
Ambient: [0.1 0.1 0.1] | Ambient: [0.05 0.05 0.2] | |
Specular: [0.8 0.8 0.8] | ||
Lighting: N/A | Lighting: Lambert | Lighting: Blinn-Phong |
(ns thi.ng.geom.examples.svg.ex03
(:require
[thi.ng.geom.core :as g]
[thi.ng.geom.vector :refer [vec3]]
[thi.ng.geom.matrix :as mat]
[thi.ng.geom.circle :as c]
[thi.ng.geom.polygon :as p]
[thi.ng.geom.gmesh :as gm]
[thi.ng.geom.mesh.subdivision :as sd]
[thi.ng.geom.svg.core :as svg]
[thi.ng.geom.svg.shaders :as shader]
[thi.ng.geom.svg.renderer :as render]
[thi.ng.math.core :as m]))
(def width 640)
(def height 480)
(def model (g/rotate-y (mat/matrix44) m/SIXTH_PI))
(def view (apply mat/look-at (mat/look-at-vectors 0 1.75 0.75 0 0 0)))
(def proj (mat/perspective 60 (/ width height) 0.1 10))
(def mvp (->> model (m/* view) (m/* proj)))
(def diffuse (shader/normal-rgb (g/rotate-y (mat/matrix44) m/PI)))
(def uniforms {:stroke "white" :stroke-width 0.25})
(def shader-diffuse
(shader/shader
{:fill diffuse
:uniforms uniforms
:flags {:solid true}}))
(def shader-lambert
(shader/shader
{:fill (shader/lambert
{:view view
:light-dir [-1 0 1]
:light-col [1 1 1]
:diffuse diffuse
:ambient 0.1})
:uniforms uniforms
:flags {:solid true}}))
(def shader-phong
(shader/shader
{:fill (shader/phong
{:model model
:view view
:light-pos [-1 2 1]
:light-col [1 1 1]
:diffuse diffuse
:ambient [0.05 0.05 0.2]
:specular 0.8
:shininess 8.0})
:uniforms uniforms
:flags {:solid true}}))
(defn ring
[res radius depth wall]
(-> (c/circle radius)
(g/as-polygon res)
(g/extrude-shell {:depth depth :wall wall :inset -0.1 :mesh (gm/gmesh)})
(g/center)))
(def mesh
(->> [[1 0.25 0.15] [0.75 0.35 0.1] [0.5 0.5 0.05] [0.25 0.75 0.05]]
(map (partial apply ring 40))
(reduce g/into)
(sd/catmull-clark)
(sd/catmull-clark)))
;; 2d text label w/ projected anchor point
(defn label-3d
[p mvp screen [l1 l2]]
(let [p' (mat/project-point p mvp screen)
p2' (mat/project-point (m/+ p 0 0 0.2) mvp screen)
p3' (m/+ p2' 100 0)]
(svg/group
{:fill "black"
:font-family "Arial"
:font-size 12
:text-anchor "end"}
(svg/circle p' 2 nil)
(svg/line-strip [p' p2' p3'] {:stroke "black"})
(svg/text (m/+ p3' 0 -5) l1 {})
(svg/text (m/+ p3' 0 12) l2 {:font-weight "bold"}))))
(defn render-svg
[path mesh mvp shader width height labels]
(let [screen (mat/viewport-matrix width height)
max-z (/ 0.75 2)]
(->> (svg/svg
{:width width :height height}
(render/mesh mesh mvp screen shader)
(label-3d (vec3 0 0 max-z) mvp screen labels))
(svg/serialize)
(spit path))))
(render-svg "svgdemo03-diffuse.svg"
mesh mvp shader-diffuse width height
["Shader" "Normal/RGB"])
(render-svg "svgdemo03-lambert.svg"
mesh mvp shader-lambert width height
["Shader" "Lambert"])
(render-svg "svgdemo03-phong.svg"
mesh mvp shader-phong width height
["Shader" "Blinn-Phong"])
(ns thi.ng.geom.examples.svg.ex04
(:require
[thi.ng.geom.core :as g]
[thi.ng.geom.vector :refer [vec2]]
[thi.ng.geom.svg.core :as svg]
[thi.ng.color.core :as col]
[thi.ng.math.core :as m]
[thi.ng.math.macros :as mm]))
(defn spiral
[center start end r1 r2 steps]
(map
(fn [r theta] (m/+ (g/as-cartesian (vec2 r theta)) center))
(range r1 r2 (mm/subdiv r2 r1 steps))
(range start end (mm/subdiv end start steps))))
(def rainbow-gradient (map (fn [h] [h (col/hsva h 1 1)]) (m/norm-range 12)))
(->> (svg/svg
{:width 300 :height 300}
(svg/defs
(apply svg/radial-gradient "rainbow" {} rainbow-gradient))
(svg/line-strip
(spiral [150 150] 0 (* 6 m/TWO_PI) 0 140 300)
(assoc svg/stroke-round
:stroke "url(#rainbow)"
:stroke-width 10)))
(svg/serialize)
(spit "svgdemo04-spiral.svg"))
(ns thi.ng.geom.examples.svg.ex05
(:require
[thi.ng.geom.core :as g]
[thi.ng.geom.vector :refer [vec2]]
[thi.ng.geom.matrix :refer [M32]]
[thi.ng.geom.svg.core :as svg]
[thi.ng.color.core :as col]
[thi.ng.math.core :as m]
[thi.ng.math.macros :as mm]))
(defn spiral
[center start end r1 r2 steps]
(map
(fn [r theta] (m/+ (g/as-cartesian (vec2 r theta)) center))
(range r1 r2 (mm/subdiv r2 r1 steps))
(range start end (mm/subdiv end start steps))))
(def rainbow-gradient (map (fn [h] [h (col/hsva h 1 1)]) (m/norm-range 12)))
(->> (svg/svg
{:width 600 :height 300}
(svg/defs
(apply svg/radial-gradient "rainbow-rad" {} rainbow-gradient)
(apply svg/linear-gradient "rainbow-lin" {} rainbow-gradient)
(svg/line-strip
(spiral [0 0] 0 (* 6 m/TWO_PI) 0 140 300)
(assoc svg/stroke-round :id "spiral")))
(svg/instance
"spiral"
{:transform (-> M32 (g/translate (vec2 150 150)))
:stroke "url(#rainbow-rad)"
:stroke-width 10})
(svg/instance
"spiral"
{:transform (-> M32 (g/translate (vec2 450 150)) (g/rotate m/PI))
:stroke "url(#rainbow-lin)"
:stroke-width 5}))
(svg/serialize)
(spit "svgdemo05-instancing.svg"))
(ns thi.ng.geom.examples.svg.ex06
(:require
[thi.ng.geom.core :as g]
[thi.ng.geom.matrix :refer [M32]]
[thi.ng.geom.line :as l]
[thi.ng.geom.svg.core :as svg]
[thi.ng.geom.svg.adapter :as adapt]))
(def arrow (svg/arrow-head 15 0.2 false))
;; compose decorators
(def labeler
(svg/comp-decorators
(svg/arrow-head 10 0.25 true {:fill "red"})
(svg/line-label {:fill "black" :stroke "none"})))
(->> (svg/svg
{:width 300 :height 300 :font-family "Arial" :font-size 12}
;; option 1: use line-strip-decorated
(svg/line-strip-decorated
[[5 0] [5 295] [300 295]]
arrow nil arrow
{:stroke "blue"})
;; option 2: attach decorators as metadata
(with-meta
(l/linestrip2 [[10 290] [100 150] [200 200] [290 10]])
{:stroke "red"
:stroke-dasharray "5 5"
:__segment labeler
:__label ["Jan 2014" "Feb 2014" "Mar 2014"]}))
(adapt/all-as-svg)
(svg/serialize)
(spit "svgdemo06-decorators.svg"))