Catmull–Clark subdivision surface: Difference between revisions

(→‎{{header|Mathematica}}: added images illustrating the resulting impilmentation)
Line 414:
=== Another implementation ===
Another implementation which should work with holes, but has only been tested on a cube
{{works with|OCaml|4.02+}}
<lang OCaml>type point = { x: float; y : float; z : float }
let zero = { x = 0.0; y = 0.0; z = 0.0 }
let add a b = { x = a.x+.b.x; y = a.y+.b.y; z = a.z+.b.z }
let mul a k = { x = a.x*.k; y = a.y*.k; z= a.z*.k }
let div p k = mul p (1.0/.k)
let fsgn x y = if x < y then -1 else if x > y then 1 else 0
let cmp a b = if a.x=b.x then if a.y=b.y then fsgn b.z a.z else fsgn b.y a.y else fsgn b.x a.x
 
type face = Face of point list
type edge = Edge of point*point
let ecmp (Edge (p1,p2)) (Edge (p3,p4)) = let sgn = cmp p1 p3 in if sgn = 0 then cmp p2 p4 else sgn
 
let make_edge a b = ifEdge cmp(min a b, <max 0 then Edge (b,a) else Edge (a,b)
let make_face a b c d = Face [a;b;c;d]
 
let centroid plist = div (List.fold_left add {x=0.0;y=0.0;z=0.0}zero plist) (float (List.length plist))
let mid_edge (Edge (p1,p2)) = div (add p1 p2) 2.0
let face_point (Face pl) = centroid pl
let point_in_face p (Face pl) = List.mem p pl
let point_in_edge p (Edge (p1,p2)) = (p = p1 || p = p2)
let edge_in_face (Edge (p1,p2)) (Face pl)f = (List.mempoint_in_face p1 plf && List.mempoint_in_face p2 pl)f
 
let border_edge faces e =
Line 448 ⟶ 447:
let v_faces = List.filter (point_in_face p) faces in
let n = List.length v_faces in
let is_border = n !=<> (List.length v_edges) in
if is_border then
let border_mids = List.map mid_edge (List.filter (border_edge faces) v_edges) in
Line 454 ⟶ 453:
centroid (p :: border_mids)
else
let avg_face = centroid (List.map face_point v_faces) in
let avg_mid = centroid (List.map mid_edge v_edges) in
div (add (add (mul p (float(n-3))) avg_face) (mul avg_mid 2.0)) (float n)
 
let iter_edges fedges_of_face (Face pl) =
let rec next acc = function
| [] -> ()invalid_arg "empty face"
| a :: [] -> fList.rev (make_edge a (List.hd pl) :: acc)
| a :: (b :: c_ as xs) -> fnext (make_edge a b; next (b::c acc) xs in
next [] pl;;
 
let catmull_clark faces =
let module EdgeSet = Set.Make(struct type t = edge let compare = ecmpcompare end) in
let esetedges = refEdgeSet.elements (EdgeSet.emptyof_list (List.concat (List.map edges_of_face faces))) in
let add_edge a b = eset := EdgeSet.add (make_edge a b) !eset in
let edges = (List.iter (iter_edges add_edge) faces; EdgeSet.elements !eset) in
let new_faces = ref [] in
let mod_face ((Face pl) as face) =
let fp = face_point face in
let ep = refList.map [](edge_point infaces) (edges_of_face face) in
iter_edgeslet (fune_tl a b -> ep := (edge_point facesList.hd (make_edge a b))::List.rev !ep) face;in
let e_tlvl = List.hdmap (List.revmod_vertex !epfaces edges) pl in
let vadd_facet (e', acc) v e = List.mape, (mod_vertexmake_face facese' edges)v ple fp :: acc) in
let rec_, add_facetnew_faces e= vlList.fold_left2 el =add_facet (match (vle_tl,el []) withvl ep in
List.rev new_faces in
| (h1::t1),(h2::t2) ->
List.concat (List.itermap mod_face faces; !new_faces)
new_faces := (make_face e h1 h2 fp) :: !new_faces;
add_facet h2 t1 t2
| ([],[]) -> ()
| _ -> failwith "vertex/edge mismatch") in
add_facet e_tl v' !ep) in
(List.iter mod_face faces; !new_faces)
 
let show_faces fl =
let pr_point p = Printf.printf " (%.4f, %.4f, %.4f)" p.x p.y p.z in
let pr_face (Face( pl)) = print_string "Face:"; List.iter pr_point pl; print_string "\n" in
(print_string "surface {\n"; List.iter pr_face fl; print_string "}\n")
 
Line 508 ⟶ 499:
}
surface {
Face: (-0.00007500, 0.75000000, -0.7500) (-0.5556, -0.5556, -0.5556) (-0.7500, -0.00007500, 0.75000000) (0-1.0000, 0.0000, 10.0000)
Face: (-0.7500, -0.00007500, 0.75000000) (-0.5556, -0.5556, 0.5556) (-0.00007500, 0.75000000, 0.7500) (0-1.0000, 0.0000, 10.0000)
Face: (-0.00007500, -0.75000000, 0.7500) (-0.5556, 0.5556, 0.5556) (-0.7500, 0.00007500, 0.75000000) (0-1.0000, 0.0000, 10.0000)
Face: (-0.7500, 0.00007500, 0.75000000) (-0.5556, -0.5556, -0.5556) (-0.00007500, -0.75000000, -0.7500) (0-1.0000, 0.0000, 10.0000)
Face: (0.00007500, 0.75000000, -0.7500) (0.5556, -0.5556, -0.5556) (-0.7500, -0.00007500, -0.75000000) (01.0000, 0.0000, -10.0000)
Face: (0.7500, -0.00007500, -0.75000000) (0.5556, -0.5556, -0.5556) (0.00007500, 0.75000000, -0.7500) (01.0000, 0.0000, -10.0000)
Face: (0.00007500, -0.75000000, -0.7500) (-0.5556, 0.5556, -0.5556) (0.7500, 0.00007500, -0.75000000) (01.0000, 0.0000, -10.0000)
Face: (-0.7500, 0.00007500, -0.75000000) (-0.5556, -0.5556, -0.5556) (0.00007500, -0.75000000, -0.7500) (01.0000, 0.0000, -10.0000)
Face: (-0.7500, -0.7500, 0.0000) (-0.5556, -0.5556, -0.5556) (0.0000, -0.7500, -0.7500) (0.0000, -1.0000, 0.0000)
Face: (0.0000, -0.7500, -0.7500) (0.5556, -0.5556, -0.5556) (0.7500, -0.7500, 0.0000) (0.0000, -1.0000, 0.0000)
Face: (-0.7500, -0.7500, 0.0000) (0.5556, -0.5556, -0.5556) (0.0000, -0.7500, 0.7500) (0.0000, -1.0000, 0.0000)
Face: (0.0000, -0.7500, -0.7500) (-0.5556, -0.5556, -0.5556) (-0.7500, -0.7500, 0.0000) (0.0000, -1.0000, 0.0000)
Face: (-0.7500, -0.7500, 0.0000) (-0.5556, -0.5556, -0.5556) (0.0000, -0.7500, -0.7500) (0.0000, -1.0000, 0.0000)
Face: (0.0000, -0.7500, -0.7500) (0.5556, -0.5556, -0.5556) (0.7500, -0.7500, 0.0000) (0.0000, -1.0000, 0.0000)
Face: (-0.7500, -0.7500, 0.0000) (0.5556, -0.5556, -0.5556) (0.0000, -0.7500, 0.7500) (0.0000, -1.0000, 0.0000)
Face: (0.0000, -0.7500, -0.7500) (-0.5556, -0.5556, -0.5556) (-0.7500, -0.7500, 0.0000) (0.0000, -1.0000, 0.0000)
Face: (0.75000000, -0.00007500, -0.7500) (-0.5556, -0.5556, -0.5556) (-0.7500, -0.75000000, -0.00007500) (10.0000, 0.0000, 0-1.0000)
Face: (-0.7500, 0.75000000, -0.00007500) (-0.5556, 0.5556, -0.5556) (0.75000000, 0.00007500, -0.7500) (10.0000, 0.0000, 0-1.0000)
Face: (0.75000000, 0.00007500, -0.7500) (0.5556, -0.5556, -0.5556) (0.7500, 0.75000000, -0.00007500) (10.0000, 0.0000, 0-1.0000)
Face: (0.7500, -0.75000000, -0.00007500) (0.5556, -0.5556, -0.5556) (0.75000000, -0.00007500, -0.7500) (10.0000, 0.0000, 0-1.0000)
Face: (-0.75000000, -0.00007500, 0.7500) (-0.5556, -0.5556, -0.5556) (-0.7500, -0.75000000, 0.00007500) (-10.0000, 0.0000, 01.0000)
Face: (-0.7500, 0.75000000, 0.00007500) (-0.5556, 0.5556, 0.5556) (-0.75000000, 0.00007500, 0.7500) (-10.0000, 0.0000, 01.0000)
Face: (-0.75000000, 0.00007500, -0.7500) (-0.5556, -0.5556, 0.5556) (-0.7500, 0.75000000, 0.00007500) (-10.0000, 0.0000, 01.0000)
Face: (-0.7500, -0.75000000, 0.00007500) (-0.5556, -0.5556, -0.5556) (-0.75000000, -0.00007500, -0.7500) (-10.0000, 0.0000, 01.0000)
}</pre>
 
Anonymous user