[{"data":1,"prerenderedAt":2166},["ShallowReactive",2],{"tutorial-mesh-slicing-and-cross-sections-in-cpp":3},{"id":4,"title":5,"author":6,"body":7,"date":2141,"description":2142,"extension":2143,"keywords":2144,"meta":2156,"navigation":148,"ogImage":2157,"path":2158,"published":148,"seo":2159,"stem":2160,"tags":2161,"__hash__":2165},"tutorials\u002Ftutorials\u002Fmesh-slicing-and-cross-sections-in-cpp.md","Fast and Robust Mesh Slicing and Cross-Sections in C++","Žiga Sajovic",{"type":8,"value":9,"toc":2129},"minimark",[10,28,36,40,47,52,55,114,124,128,197,223,227,237,420,426,433,437,444,637,643,650,654,657,828,834,837,945,948,1128,1131,1135,1138,1371,1377,1380,1548,1551,1555,1562,1719,1723,1726,1862,1868,1875,1878,2024,2041,2045,2075,2079,2082,2086,2098,2103,2109,2121,2125],[11,12,13],"note",{},[14,15,16,17,22,23,27],"p",{},"Also available in ",[18,19,21],"a",{"href":20},"\u002Ftutorials\u002Fmesh-slicing-and-cross-sections-in-python","Python"," and ",[18,24,26],{"href":25},"\u002Ftutorials\u002Fmesh-slicing-and-cross-sections-in-javascript","JavaScript",".",[14,29,30,31,35],{},"Slicing a mesh by a plane gives the cross-section: the closed curves where the plane cuts the surface. Stack many parallel slices and you have the layers of a 3D print, or the sections of a survey. In ",[32,33,34],"code",{},"trueform"," a slice is an isocontour. Give each point its signed distance to the plane, and the slice is where that distance is zero. It is header-only C++17. This tutorial covers one slice, a slice by any plane, stacked slices, sections along an axis, and filled sections.",[37,38],"article-cta",{":buttons":39},"[{\"label\":\"trueform\",\"to\":\"\u002Ftrueform\",\"icon\":\"i-lucide-cpu\",\"variant\":\"soft\",\"color\":\"neutral\"},{\"label\":\"GitHub\",\"to\":\"https:\u002F\u002Fgithub.com\u002Fpolydera\u002Ftrueform\",\"icon\":\"i-simple-icons-github\",\"variant\":\"soft\",\"color\":\"neutral\"},{\"label\":\"Documentation\",\"to\":\"https:\u002F\u002Ftrueform.polydera.com\u002Fcpp\u002Fmodules\u002Fiso#isocontours\",\"variant\":\"soft\",\"color\":\"neutral\"},{\"label\":\"Try it live\",\"to\":\"https:\u002F\u002Ftrueform.polydera.com\u002Flive-examples\u002Fcross-section\",\"icon\":\"i-lucide-play\"}]",[14,41,42],{},[43,44],"img",{"alt":45,"src":46},"The Stanford dragon cut into 24 horizontal cross-sections, shown as stacked curves","\u002Fimg\u002Ftutorials\u002Fmesh-slicing.png",[48,49,51],"h2",{"id":50},"install","Install",[14,53,54],{},"Header-only. It needs C++17 and oneTBB. Add it to your project via CMake FetchContent:",[56,57,62],"pre",{"className":58,"code":59,"language":60,"meta":61,"style":61},"language-cmake shiki shiki-themes github-dark","FetchContent_Declare(\n  trueform\n  GIT_REPOSITORY https:\u002F\u002Fgithub.com\u002Fpolydera\u002Ftrueform\n)\nFetchContent_MakeAvailable(trueform)\ntarget_link_libraries(my_app PRIVATE tf::trueform)\n","cmake","",[32,63,64,73,79,85,91,97],{"__ignoreMap":61},[65,66,69],"span",{"class":67,"line":68},"line",1,[65,70,72],{"class":71},"s95oV","FetchContent_Declare(\n",[65,74,76],{"class":67,"line":75},2,[65,77,78],{"class":71},"  trueform\n",[65,80,82],{"class":67,"line":81},3,[65,83,84],{"class":71},"  GIT_REPOSITORY https:\u002F\u002Fgithub.com\u002Fpolydera\u002Ftrueform\n",[65,86,88],{"class":67,"line":87},4,[65,89,90],{"class":71},")\n",[65,92,94],{"class":67,"line":93},5,[65,95,96],{"class":71},"FetchContent_MakeAvailable(trueform)\n",[65,98,100,104,107,111],{"class":67,"line":99},6,[65,101,103],{"class":102},"snl16","target_link_libraries",[65,105,106],{"class":71},"(my_app ",[65,108,110],{"class":109},"svObZ","PRIVATE",[65,112,113],{"class":71}," tf::trueform)\n",[14,115,116,117,123],{},"Also available via conan, nuget, and pip. See the ",[18,118,122],{"href":119,"rel":120},"https:\u002F\u002Ftrueform.polydera.com\u002Fcpp\u002Fgetting-started\u002Finstallation",[121],"nofollow","installation guide"," for all options.",[48,125,127],{"id":126},"loading-the-mesh","Loading the mesh",[56,129,133],{"className":130,"code":131,"language":132,"meta":61,"style":61},"language-cpp shiki shiki-themes github-dark","#include \u003Ctrueform\u002Ftrueform.hpp>\n\nauto mesh_buffer = tf::read_stl(\"part.stl\");\nauto mesh = mesh_buffer.polygons();\n","cpp",[32,134,135,144,150,179],{"__ignoreMap":61},[65,136,137,140],{"class":67,"line":68},[65,138,139],{"class":102},"#include",[65,141,143],{"class":142},"sU2Wk"," \u003Ctrueform\u002Ftrueform.hpp>\n",[65,145,146],{"class":67,"line":75},[65,147,149],{"emptyLinePlaceholder":148},true,"\n",[65,151,152,155,158,161,164,167,170,173,176],{"class":67,"line":81},[65,153,154],{"class":102},"auto",[65,156,157],{"class":71}," mesh_buffer ",[65,159,160],{"class":102},"=",[65,162,163],{"class":109}," tf",[65,165,166],{"class":71},"::",[65,168,169],{"class":109},"read_stl",[65,171,172],{"class":71},"(",[65,174,175],{"class":142},"\"part.stl\"",[65,177,178],{"class":71},");\n",[65,180,181,183,186,188,191,194],{"class":67,"line":87},[65,182,154],{"class":102},[65,184,185],{"class":71}," mesh ",[65,187,160],{"class":102},[65,189,190],{"class":71}," mesh_buffer.",[65,192,193],{"class":109},"polygons",[65,195,196],{"class":71},"();\n",[14,198,199,202,203,206,207,210,211,214,215,218,219,222],{},[32,200,201],{},"tf::read_stl"," returns a ",[32,204,205],{},"tf::polygons_buffer"," that owns the data. ",[32,208,209],{},".polygons()"," is a view on it. ",[32,212,213],{},"tf::read_obj"," works the same way. If your faces and points already live in your own arrays, wrap them with ",[32,216,217],{},"tf::make_polygons(tf::make_faces\u003C3>(faces), tf::make_points\u003C3>(points))",". No copy is made. To follow along without a file, ",[32,220,221],{},"tf::make_sphere_mesh(1.f, 100, 200)"," gives a unit sphere.",[48,224,226],{"id":225},"one-horizontal-slice","One horizontal slice",[14,228,229,230,233,234,27],{},"For a plane ",[32,231,232],{},"z = h",", the field is the height itself. The slice is its isocontour at ",[32,235,236],{},"h",[56,238,240],{"className":130,"code":239,"language":132,"meta":61,"style":61},"tf::buffer\u003Cfloat> height;\nheight.allocate(mesh.points().size());\ntf::parallel_transform(mesh.points(), height,\n                       [](auto pt) { return pt[2]; });\n\nauto slice = tf::make_isocontours(mesh, tf::make_range(height), 0.25f);\n\nfor (auto loop : slice.curves()) {\n  for (auto pt : loop) {\n    \u002F\u002F pt[2] == 0.25\n  }\n}\n",[32,241,242,256,279,295,322,326,363,368,388,401,408,414],{"__ignoreMap":61},[65,243,244,247,250,253],{"class":67,"line":68},[65,245,246],{"class":109},"tf",[65,248,249],{"class":71},"::buffer",[65,251,252],{"class":102},"\u003Cfloat>",[65,254,255],{"class":71}," height;\n",[65,257,258,261,264,267,270,273,276],{"class":67,"line":75},[65,259,260],{"class":71},"height.",[65,262,263],{"class":109},"allocate",[65,265,266],{"class":71},"(mesh.",[65,268,269],{"class":109},"points",[65,271,272],{"class":71},"().",[65,274,275],{"class":109},"size",[65,277,278],{"class":71},"());\n",[65,280,281,283,285,288,290,292],{"class":67,"line":81},[65,282,246],{"class":109},[65,284,166],{"class":71},[65,286,287],{"class":109},"parallel_transform",[65,289,266],{"class":71},[65,291,269],{"class":109},[65,293,294],{"class":71},"(), height,\n",[65,296,297,300,302,306,309,312,315,319],{"class":67,"line":87},[65,298,299],{"class":71},"                       [](",[65,301,154],{"class":102},[65,303,305],{"class":304},"s9osk"," pt",[65,307,308],{"class":71},") { ",[65,310,311],{"class":102},"return",[65,313,314],{"class":71}," pt[",[65,316,318],{"class":317},"sDLfK","2",[65,320,321],{"class":71},"]; });\n",[65,323,324],{"class":67,"line":93},[65,325,149],{"emptyLinePlaceholder":148},[65,327,328,330,333,335,337,339,342,345,347,349,352,355,358,361],{"class":67,"line":99},[65,329,154],{"class":102},[65,331,332],{"class":71}," slice ",[65,334,160],{"class":102},[65,336,163],{"class":109},[65,338,166],{"class":71},[65,340,341],{"class":109},"make_isocontours",[65,343,344],{"class":71},"(mesh, ",[65,346,246],{"class":109},[65,348,166],{"class":71},[65,350,351],{"class":109},"make_range",[65,353,354],{"class":71},"(height), ",[65,356,357],{"class":317},"0.25",[65,359,360],{"class":102},"f",[65,362,178],{"class":71},[65,364,366],{"class":67,"line":365},7,[65,367,149],{"emptyLinePlaceholder":148},[65,369,371,374,377,379,382,385],{"class":67,"line":370},8,[65,372,373],{"class":102},"for",[65,375,376],{"class":71}," (",[65,378,154],{"class":102},[65,380,381],{"class":71}," loop : slice.",[65,383,384],{"class":109},"curves",[65,386,387],{"class":71},"()) {\n",[65,389,391,394,396,398],{"class":67,"line":390},9,[65,392,393],{"class":102},"  for",[65,395,376],{"class":71},[65,397,154],{"class":102},[65,399,400],{"class":71}," pt : loop) {\n",[65,402,404],{"class":67,"line":403},10,[65,405,407],{"class":406},"sAwPA","    \u002F\u002F pt[2] == 0.25\n",[65,409,411],{"class":67,"line":410},11,[65,412,413],{"class":71},"  }\n",[65,415,417],{"class":67,"line":416},12,[65,418,419],{"class":71},"}\n",[14,421,422],{},[43,423],{"alt":424,"src":425},"One horizontal slice through the Stanford dragon at z = 0.25: pink loops where the plane, shown in orange, cuts the surface","\u002Fimg\u002Ftutorials\u002Fsteps\u002Fmesh-slicing-and-cross-sections-1-slice.png",[14,427,428,429,432],{},"The result is a ",[32,430,431],{},"tf::curves_buffer",": points, and one index path per curve. On a closed mesh each curve is a closed loop, and the last id repeats the first. A part with holes or several bodies gives several loops in one slice.",[48,434,436],{"id":435},"slice-by-any-plane","Slice by any plane",[14,438,439,440,443],{},"For a tilted plane, use the signed distance to the plane as the field. ",[32,441,442],{},"tf::distance_f(plane)"," is signed: negative on one side, positive on the other.",[56,445,447],{"className":130,"code":446,"language":132,"meta":61,"style":61},"auto normal = tf::make_unit_vector(1.f, 1.f, 1.f);\nauto origin = tf::make_point(0.f, 0.f, 0.2f);\nauto plane = tf::make_plane(normal, origin);\n\ntf::buffer\u003Cfloat> field;\nfield.allocate(mesh.points().size());\ntf::parallel_transform(mesh.points(), field, tf::distance_f(plane));\n\nauto section = tf::make_isocontours(mesh, tf::make_range(field), 0.f);\n",[32,448,449,487,525,544,548,559,576,601,605],{"__ignoreMap":61},[65,450,451,453,456,458,460,462,465,467,470,472,475,477,479,481,483,485],{"class":67,"line":68},[65,452,154],{"class":102},[65,454,455],{"class":71}," normal ",[65,457,160],{"class":102},[65,459,163],{"class":109},[65,461,166],{"class":71},[65,463,464],{"class":109},"make_unit_vector",[65,466,172],{"class":71},[65,468,469],{"class":317},"1.",[65,471,360],{"class":102},[65,473,474],{"class":71},", ",[65,476,469],{"class":317},[65,478,360],{"class":102},[65,480,474],{"class":71},[65,482,469],{"class":317},[65,484,360],{"class":102},[65,486,178],{"class":71},[65,488,489,491,494,496,498,500,503,505,508,510,512,514,516,518,521,523],{"class":67,"line":75},[65,490,154],{"class":102},[65,492,493],{"class":71}," origin ",[65,495,160],{"class":102},[65,497,163],{"class":109},[65,499,166],{"class":71},[65,501,502],{"class":109},"make_point",[65,504,172],{"class":71},[65,506,507],{"class":317},"0.",[65,509,360],{"class":102},[65,511,474],{"class":71},[65,513,507],{"class":317},[65,515,360],{"class":102},[65,517,474],{"class":71},[65,519,520],{"class":317},"0.2",[65,522,360],{"class":102},[65,524,178],{"class":71},[65,526,527,529,532,534,536,538,541],{"class":67,"line":81},[65,528,154],{"class":102},[65,530,531],{"class":71}," plane ",[65,533,160],{"class":102},[65,535,163],{"class":109},[65,537,166],{"class":71},[65,539,540],{"class":109},"make_plane",[65,542,543],{"class":71},"(normal, origin);\n",[65,545,546],{"class":67,"line":87},[65,547,149],{"emptyLinePlaceholder":148},[65,549,550,552,554,556],{"class":67,"line":93},[65,551,246],{"class":109},[65,553,249],{"class":71},[65,555,252],{"class":102},[65,557,558],{"class":71}," field;\n",[65,560,561,564,566,568,570,572,574],{"class":67,"line":99},[65,562,563],{"class":71},"field.",[65,565,263],{"class":109},[65,567,266],{"class":71},[65,569,269],{"class":109},[65,571,272],{"class":71},[65,573,275],{"class":109},[65,575,278],{"class":71},[65,577,578,580,582,584,586,588,591,593,595,598],{"class":67,"line":365},[65,579,246],{"class":109},[65,581,166],{"class":71},[65,583,287],{"class":109},[65,585,266],{"class":71},[65,587,269],{"class":109},[65,589,590],{"class":71},"(), field, ",[65,592,246],{"class":109},[65,594,166],{"class":71},[65,596,597],{"class":109},"distance_f",[65,599,600],{"class":71},"(plane));\n",[65,602,603],{"class":67,"line":370},[65,604,149],{"emptyLinePlaceholder":148},[65,606,607,609,612,614,616,618,620,622,624,626,628,631,633,635],{"class":67,"line":390},[65,608,154],{"class":102},[65,610,611],{"class":71}," section ",[65,613,160],{"class":102},[65,615,163],{"class":109},[65,617,166],{"class":71},[65,619,341],{"class":109},[65,621,344],{"class":71},[65,623,246],{"class":109},[65,625,166],{"class":71},[65,627,351],{"class":109},[65,629,630],{"class":71},"(field), ",[65,632,507],{"class":317},[65,634,360],{"class":102},[65,636,178],{"class":71},[14,638,639],{},[43,640],{"alt":641,"src":642},"Slice by any plane: the Stanford dragon cut by a tilted plane with normal (1, 1, 1), the section loops in pink","\u002Fimg\u002Ftutorials\u002Fsteps\u002Fmesh-slicing-and-cross-sections-2-plane.png",[14,644,645,646,649],{},"Every curve point lies on the plane. ",[32,647,648],{},"tf::make_unit_vector"," normalizes for you.",[48,651,653],{"id":652},"stacked-slices-for-3d-printing","Stacked slices for 3D printing",[14,655,656],{},"Parallel planes are levels of one field. Pass them all in one call:",[56,658,660],{"className":130,"code":659,"language":132,"meta":61,"style":61},"float layer_height = 0.1f;\nauto [z_min, z_max] = std::minmax_element(height.begin(), height.end());\n\nstd::vector\u003Cfloat> levels;\nfor (float z = *z_min + layer_height \u002F 2; z \u003C *z_max; z += layer_height)\n  levels.push_back(z);\n\nauto layers = tf::make_isocontours(mesh, tf::make_range(height),\n                                   tf::make_range(levels));\n",[32,661,662,680,711,715,728,775,786,790,816],{"__ignoreMap":61},[65,663,664,667,670,672,675,677],{"class":67,"line":68},[65,665,666],{"class":102},"float",[65,668,669],{"class":71}," layer_height ",[65,671,160],{"class":102},[65,673,674],{"class":317}," 0.1",[65,676,360],{"class":102},[65,678,679],{"class":71},";\n",[65,681,682,684,687,689,692,694,697,700,703,706,709],{"class":67,"line":75},[65,683,154],{"class":102},[65,685,686],{"class":71}," [z_min, z_max] ",[65,688,160],{"class":102},[65,690,691],{"class":109}," std",[65,693,166],{"class":71},[65,695,696],{"class":109},"minmax_element",[65,698,699],{"class":71},"(height.",[65,701,702],{"class":109},"begin",[65,704,705],{"class":71},"(), height.",[65,707,708],{"class":109},"end",[65,710,278],{"class":71},[65,712,713],{"class":67,"line":81},[65,714,149],{"emptyLinePlaceholder":148},[65,716,717,720,723,725],{"class":67,"line":87},[65,718,719],{"class":109},"std",[65,721,722],{"class":71},"::vector",[65,724,252],{"class":102},[65,726,727],{"class":71}," levels;\n",[65,729,730,732,734,736,739,741,744,747,750,752,755,758,761,764,766,769,772],{"class":67,"line":93},[65,731,373],{"class":102},[65,733,376],{"class":71},[65,735,666],{"class":102},[65,737,738],{"class":71}," z ",[65,740,160],{"class":102},[65,742,743],{"class":102}," *",[65,745,746],{"class":71},"z_min ",[65,748,749],{"class":102},"+",[65,751,669],{"class":71},[65,753,754],{"class":102},"\u002F",[65,756,757],{"class":317}," 2",[65,759,760],{"class":71},"; z ",[65,762,763],{"class":102},"\u003C",[65,765,743],{"class":102},[65,767,768],{"class":71},"z_max; z ",[65,770,771],{"class":102},"+=",[65,773,774],{"class":71}," layer_height)\n",[65,776,777,780,783],{"class":67,"line":99},[65,778,779],{"class":71},"  levels.",[65,781,782],{"class":109},"push_back",[65,784,785],{"class":71},"(z);\n",[65,787,788],{"class":67,"line":365},[65,789,149],{"emptyLinePlaceholder":148},[65,791,792,794,797,799,801,803,805,807,809,811,813],{"class":67,"line":370},[65,793,154],{"class":102},[65,795,796],{"class":71}," layers ",[65,798,160],{"class":102},[65,800,163],{"class":109},[65,802,166],{"class":71},[65,804,341],{"class":109},[65,806,344],{"class":71},[65,808,246],{"class":109},[65,810,166],{"class":71},[65,812,351],{"class":109},[65,814,815],{"class":71},"(height),\n",[65,817,818,821,823,825],{"class":67,"line":390},[65,819,820],{"class":109},"                                   tf",[65,822,166],{"class":71},[65,824,351],{"class":109},[65,826,827],{"class":71},"(levels));\n",[14,829,830],{},[43,831],{"alt":832,"src":833},"Stacked slices for 3D printing: every layer loop of the Stanford dragon at 0.1 spacing, drawn without the mesh","\u002Fimg\u002Ftutorials\u002Fsteps\u002Fmesh-slicing-and-cross-sections-3-layers.png",[14,835,836],{},"This gives every loop of every layer. The loops do not come back in layer order. Each loop lies at one height, so read its layer from its first point:",[56,838,840],{"className":130,"code":839,"language":132,"meta":61,"style":61},"std::vector\u003Cint> layer_of_loop;\nfor (auto path : layers.paths()) {\n  float z = layers.points()[path.front()][2];\n  layer_of_loop.push_back((int)std::lround((z - levels[0]) \u002F layer_height));\n}\n",[32,841,842,854,870,898,941],{"__ignoreMap":61},[65,843,844,846,848,851],{"class":67,"line":68},[65,845,719],{"class":109},[65,847,722],{"class":71},[65,849,850],{"class":102},"\u003Cint>",[65,852,853],{"class":71}," layer_of_loop;\n",[65,855,856,858,860,862,865,868],{"class":67,"line":75},[65,857,373],{"class":102},[65,859,376],{"class":71},[65,861,154],{"class":102},[65,863,864],{"class":71}," path : layers.",[65,866,867],{"class":109},"paths",[65,869,387],{"class":71},[65,871,872,875,877,879,882,884,887,890,893,895],{"class":67,"line":81},[65,873,874],{"class":102},"  float",[65,876,738],{"class":71},[65,878,160],{"class":102},[65,880,881],{"class":71}," layers.",[65,883,269],{"class":109},[65,885,886],{"class":71},"()[path.",[65,888,889],{"class":109},"front",[65,891,892],{"class":71},"()][",[65,894,318],{"class":317},[65,896,897],{"class":71},"];\n",[65,899,900,903,905,908,911,914,916,918,921,924,927,930,933,936,938],{"class":67,"line":87},[65,901,902],{"class":71},"  layer_of_loop.",[65,904,782],{"class":109},[65,906,907],{"class":71},"((",[65,909,910],{"class":102},"int",[65,912,913],{"class":71},")",[65,915,719],{"class":109},[65,917,166],{"class":71},[65,919,920],{"class":109},"lround",[65,922,923],{"class":71},"((z ",[65,925,926],{"class":102},"-",[65,928,929],{"class":71}," levels[",[65,931,932],{"class":317},"0",[65,934,935],{"class":71},"]) ",[65,937,754],{"class":102},[65,939,940],{"class":71}," layer_height));\n",[65,942,943],{"class":67,"line":93},[65,944,419],{"class":71},[14,946,947],{},"Or slice layer by layer, and keep 2D outlines for a slicer:",[56,949,951],{"className":130,"code":950,"language":132,"meta":61,"style":61},"\u002F\u002F outlines[layer][loop][point] = {x, y}\nstd::vector\u003Cstd::vector\u003Cstd::vector\u003Cstd::array\u003Cfloat, 2>>>> outlines;\n\nfor (float z : levels) {\n  auto layer = tf::make_isocontours(mesh, tf::make_range(height), z);\n  auto &loops = outlines.emplace_back();\n  for (auto loop : layer.curves()) {\n    auto &outline = loops.emplace_back();\n    for (auto pt : loop) outline.push_back({pt[0], pt[1]});\n  }\n}\n",[32,952,953,958,996,1000,1011,1038,1058,1073,1092,1120,1124],{"__ignoreMap":61},[65,954,955],{"class":67,"line":68},[65,956,957],{"class":406},"\u002F\u002F outlines[layer][loop][point] = {x, y}\n",[65,959,960,962,964,966,968,970,972,974,976,978,980,983,986,988,990,993],{"class":67,"line":75},[65,961,719],{"class":109},[65,963,722],{"class":71},[65,965,763],{"class":102},[65,967,719],{"class":109},[65,969,722],{"class":71},[65,971,763],{"class":102},[65,973,719],{"class":109},[65,975,722],{"class":71},[65,977,763],{"class":102},[65,979,719],{"class":109},[65,981,982],{"class":71},"::array",[65,984,985],{"class":102},"\u003Cfloat",[65,987,474],{"class":71},[65,989,318],{"class":317},[65,991,992],{"class":102},">>>>",[65,994,995],{"class":71}," outlines;\n",[65,997,998],{"class":67,"line":81},[65,999,149],{"emptyLinePlaceholder":148},[65,1001,1002,1004,1006,1008],{"class":67,"line":87},[65,1003,373],{"class":102},[65,1005,376],{"class":71},[65,1007,666],{"class":102},[65,1009,1010],{"class":71}," z : levels) {\n",[65,1012,1013,1016,1019,1021,1023,1025,1027,1029,1031,1033,1035],{"class":67,"line":93},[65,1014,1015],{"class":102},"  auto",[65,1017,1018],{"class":71}," layer ",[65,1020,160],{"class":102},[65,1022,163],{"class":109},[65,1024,166],{"class":71},[65,1026,341],{"class":109},[65,1028,344],{"class":71},[65,1030,246],{"class":109},[65,1032,166],{"class":71},[65,1034,351],{"class":109},[65,1036,1037],{"class":71},"(height), z);\n",[65,1039,1040,1042,1045,1048,1050,1053,1056],{"class":67,"line":99},[65,1041,1015],{"class":102},[65,1043,1044],{"class":102}," &",[65,1046,1047],{"class":71},"loops ",[65,1049,160],{"class":102},[65,1051,1052],{"class":71}," outlines.",[65,1054,1055],{"class":109},"emplace_back",[65,1057,196],{"class":71},[65,1059,1060,1062,1064,1066,1069,1071],{"class":67,"line":365},[65,1061,393],{"class":102},[65,1063,376],{"class":71},[65,1065,154],{"class":102},[65,1067,1068],{"class":71}," loop : layer.",[65,1070,384],{"class":109},[65,1072,387],{"class":71},[65,1074,1075,1078,1080,1083,1085,1088,1090],{"class":67,"line":370},[65,1076,1077],{"class":102},"    auto",[65,1079,1044],{"class":102},[65,1081,1082],{"class":71},"outline ",[65,1084,160],{"class":102},[65,1086,1087],{"class":71}," loops.",[65,1089,1055],{"class":109},[65,1091,196],{"class":71},[65,1093,1094,1097,1099,1101,1104,1106,1109,1111,1114,1117],{"class":67,"line":390},[65,1095,1096],{"class":102},"    for",[65,1098,376],{"class":71},[65,1100,154],{"class":102},[65,1102,1103],{"class":71}," pt : loop) outline.",[65,1105,782],{"class":109},[65,1107,1108],{"class":71},"({pt[",[65,1110,932],{"class":317},[65,1112,1113],{"class":71},"], pt[",[65,1115,1116],{"class":317},"1",[65,1118,1119],{"class":71},"]});\n",[65,1121,1122],{"class":67,"line":403},[65,1123,413],{"class":71},[65,1125,1126],{"class":67,"line":410},[65,1127,419],{"class":71},[14,1129,1130],{},"Slicing at the middle of each layer, as above, is the usual choice for print slicers.",[48,1132,1134],{"id":1133},"survey-sections-along-an-axis","Survey sections along an axis",[14,1136,1137],{},"For sections across a road, a riverbed, or a tunnel, slice along the axis. The field is the chainage, the distance along the axis. The stations are its levels.",[56,1139,1141],{"className":130,"code":1140,"language":132,"meta":61,"style":61},"auto direction = tf::make_unit_vector(1.f, 0.f, 0.f);\n\ntf::buffer\u003Cfloat> chainage;\nchainage.allocate(mesh.points().size());\ntf::parallel_transform(mesh.points(), chainage, [&](auto pt) {\n  return tf::dot(pt.as_vector_view(), direction);\n});\n\nstd::vector\u003Cfloat> stations;\nfor (float s = -0.8f; s \u003C= 0.81f; s += 0.2f) stations.push_back(s);\n\nauto sections = tf::make_isocontours(mesh, tf::make_range(chainage),\n                                     tf::make_range(stations));\n",[32,1142,1143,1178,1182,1193,1210,1238,1259,1264,1268,1279,1328,1332,1358],{"__ignoreMap":61},[65,1144,1145,1147,1150,1152,1154,1156,1158,1160,1162,1164,1166,1168,1170,1172,1174,1176],{"class":67,"line":68},[65,1146,154],{"class":102},[65,1148,1149],{"class":71}," direction ",[65,1151,160],{"class":102},[65,1153,163],{"class":109},[65,1155,166],{"class":71},[65,1157,464],{"class":109},[65,1159,172],{"class":71},[65,1161,469],{"class":317},[65,1163,360],{"class":102},[65,1165,474],{"class":71},[65,1167,507],{"class":317},[65,1169,360],{"class":102},[65,1171,474],{"class":71},[65,1173,507],{"class":317},[65,1175,360],{"class":102},[65,1177,178],{"class":71},[65,1179,1180],{"class":67,"line":75},[65,1181,149],{"emptyLinePlaceholder":148},[65,1183,1184,1186,1188,1190],{"class":67,"line":81},[65,1185,246],{"class":109},[65,1187,249],{"class":71},[65,1189,252],{"class":102},[65,1191,1192],{"class":71}," chainage;\n",[65,1194,1195,1198,1200,1202,1204,1206,1208],{"class":67,"line":87},[65,1196,1197],{"class":71},"chainage.",[65,1199,263],{"class":109},[65,1201,266],{"class":71},[65,1203,269],{"class":109},[65,1205,272],{"class":71},[65,1207,275],{"class":109},[65,1209,278],{"class":71},[65,1211,1212,1214,1216,1218,1220,1222,1225,1228,1231,1233,1235],{"class":67,"line":93},[65,1213,246],{"class":109},[65,1215,166],{"class":71},[65,1217,287],{"class":109},[65,1219,266],{"class":71},[65,1221,269],{"class":109},[65,1223,1224],{"class":71},"(), chainage, [",[65,1226,1227],{"class":102},"&",[65,1229,1230],{"class":71},"](",[65,1232,154],{"class":102},[65,1234,305],{"class":304},[65,1236,1237],{"class":71},") {\n",[65,1239,1240,1243,1245,1247,1250,1253,1256],{"class":67,"line":99},[65,1241,1242],{"class":102},"  return",[65,1244,163],{"class":109},[65,1246,166],{"class":71},[65,1248,1249],{"class":109},"dot",[65,1251,1252],{"class":71},"(pt.",[65,1254,1255],{"class":109},"as_vector_view",[65,1257,1258],{"class":71},"(), direction);\n",[65,1260,1261],{"class":67,"line":365},[65,1262,1263],{"class":71},"});\n",[65,1265,1266],{"class":67,"line":370},[65,1267,149],{"emptyLinePlaceholder":148},[65,1269,1270,1272,1274,1276],{"class":67,"line":390},[65,1271,719],{"class":109},[65,1273,722],{"class":71},[65,1275,252],{"class":102},[65,1277,1278],{"class":71}," stations;\n",[65,1280,1281,1283,1285,1287,1290,1292,1295,1298,1300,1303,1306,1309,1311,1313,1315,1318,1320,1323,1325],{"class":67,"line":403},[65,1282,373],{"class":102},[65,1284,376],{"class":71},[65,1286,666],{"class":102},[65,1288,1289],{"class":71}," s ",[65,1291,160],{"class":102},[65,1293,1294],{"class":102}," -",[65,1296,1297],{"class":317},"0.8",[65,1299,360],{"class":102},[65,1301,1302],{"class":71},"; s ",[65,1304,1305],{"class":102},"\u003C=",[65,1307,1308],{"class":317}," 0.81",[65,1310,360],{"class":102},[65,1312,1302],{"class":71},[65,1314,771],{"class":102},[65,1316,1317],{"class":317}," 0.2",[65,1319,360],{"class":102},[65,1321,1322],{"class":71},") stations.",[65,1324,782],{"class":109},[65,1326,1327],{"class":71},"(s);\n",[65,1329,1330],{"class":67,"line":410},[65,1331,149],{"emptyLinePlaceholder":148},[65,1333,1334,1336,1339,1341,1343,1345,1347,1349,1351,1353,1355],{"class":67,"line":416},[65,1335,154],{"class":102},[65,1337,1338],{"class":71}," sections ",[65,1340,160],{"class":102},[65,1342,163],{"class":109},[65,1344,166],{"class":71},[65,1346,341],{"class":109},[65,1348,344],{"class":71},[65,1350,246],{"class":109},[65,1352,166],{"class":71},[65,1354,351],{"class":109},[65,1356,1357],{"class":71},"(chainage),\n",[65,1359,1361,1364,1366,1368],{"class":67,"line":1360},13,[65,1362,1363],{"class":109},"                                     tf",[65,1365,166],{"class":71},[65,1367,351],{"class":109},[65,1369,1370],{"class":71},"(stations));\n",[14,1372,1373],{},[43,1374],{"alt":1375,"src":1376},"Survey sections along an axis: sections across the Stanford dragon at stations every 0.2 along x","\u002Fimg\u002Ftutorials\u002Fsteps\u002Fmesh-slicing-and-cross-sections-4-sections.png",[14,1378,1379],{},"To draw a section, map its points to offset and elevation:",[56,1381,1383],{"className":130,"code":1382,"language":132,"meta":61,"style":61},"auto up = tf::make_unit_vector(0.f, 0.f, 1.f);\nauto side = tf::make_unit_vector(tf::cross(up, direction));\n\nfor (auto curve : sections.curves()) {\n  std::vector\u003Cstd::array\u003Cfloat, 2>> profile;   \u002F\u002F offset, elevation\n  for (auto pt : curve)\n    profile.push_back({tf::dot(pt.as_vector_view(), side),\n                       tf::dot(pt.as_vector_view(), up)});\n}\n",[32,1384,1385,1420,1447,1451,1466,1494,1505,1528,1544],{"__ignoreMap":61},[65,1386,1387,1389,1392,1394,1396,1398,1400,1402,1404,1406,1408,1410,1412,1414,1416,1418],{"class":67,"line":68},[65,1388,154],{"class":102},[65,1390,1391],{"class":71}," up ",[65,1393,160],{"class":102},[65,1395,163],{"class":109},[65,1397,166],{"class":71},[65,1399,464],{"class":109},[65,1401,172],{"class":71},[65,1403,507],{"class":317},[65,1405,360],{"class":102},[65,1407,474],{"class":71},[65,1409,507],{"class":317},[65,1411,360],{"class":102},[65,1413,474],{"class":71},[65,1415,469],{"class":317},[65,1417,360],{"class":102},[65,1419,178],{"class":71},[65,1421,1422,1424,1427,1429,1431,1433,1435,1437,1439,1441,1444],{"class":67,"line":75},[65,1423,154],{"class":102},[65,1425,1426],{"class":71}," side ",[65,1428,160],{"class":102},[65,1430,163],{"class":109},[65,1432,166],{"class":71},[65,1434,464],{"class":109},[65,1436,172],{"class":71},[65,1438,246],{"class":109},[65,1440,166],{"class":71},[65,1442,1443],{"class":109},"cross",[65,1445,1446],{"class":71},"(up, direction));\n",[65,1448,1449],{"class":67,"line":81},[65,1450,149],{"emptyLinePlaceholder":148},[65,1452,1453,1455,1457,1459,1462,1464],{"class":67,"line":87},[65,1454,373],{"class":102},[65,1456,376],{"class":71},[65,1458,154],{"class":102},[65,1460,1461],{"class":71}," curve : sections.",[65,1463,384],{"class":109},[65,1465,387],{"class":71},[65,1467,1468,1471,1473,1475,1477,1479,1481,1483,1485,1488,1491],{"class":67,"line":93},[65,1469,1470],{"class":109},"  std",[65,1472,722],{"class":71},[65,1474,763],{"class":102},[65,1476,719],{"class":109},[65,1478,982],{"class":71},[65,1480,985],{"class":102},[65,1482,474],{"class":71},[65,1484,318],{"class":317},[65,1486,1487],{"class":102},">>",[65,1489,1490],{"class":71}," profile;",[65,1492,1493],{"class":406},"   \u002F\u002F offset, elevation\n",[65,1495,1496,1498,1500,1502],{"class":67,"line":99},[65,1497,393],{"class":102},[65,1499,376],{"class":71},[65,1501,154],{"class":102},[65,1503,1504],{"class":71}," pt : curve)\n",[65,1506,1507,1510,1512,1515,1517,1519,1521,1523,1525],{"class":67,"line":365},[65,1508,1509],{"class":71},"    profile.",[65,1511,782],{"class":109},[65,1513,1514],{"class":71},"({",[65,1516,246],{"class":109},[65,1518,166],{"class":71},[65,1520,1249],{"class":109},[65,1522,1252],{"class":71},[65,1524,1255],{"class":109},[65,1526,1527],{"class":71},"(), side),\n",[65,1529,1530,1533,1535,1537,1539,1541],{"class":67,"line":370},[65,1531,1532],{"class":109},"                       tf",[65,1534,166],{"class":71},[65,1536,1249],{"class":109},[65,1538,1252],{"class":71},[65,1540,1255],{"class":109},[65,1542,1543],{"class":71},"(), up)});\n",[65,1545,1546],{"class":67,"line":390},[65,1547,419],{"class":71},[14,1549,1550],{},"If the sections are not parallel, for example along a curved alignment, slice once per plane with the signed-distance field from the previous section.",[48,1552,1554],{"id":1553},"filled-cross-sections","Filled cross-sections",[14,1556,1557,1558,1561],{},"A closed loop on a plane is a polygon. ",[32,1559,1560],{},"tf::triangulated"," fills it. Each loop is filled on its own, so a slice through a part with a hole gives two filled disks, not a ring:",[56,1563,1565],{"className":130,"code":1564,"language":132,"meta":61,"style":61},"auto equator = tf::make_isocontours(mesh, tf::make_range(height), 0.f);\nauto cap = tf::triangulated(\n    tf::make_polygons(equator.paths(), equator.points()));\n\nfloat area = 0.f;\nfor (auto triangle : cap.polygons()) area += tf::area(triangle);\n\u002F\u002F close to pi for the unit sphere's equator\n\ntf::write_stl(cap.polygons(), \"section.stl\");\n",[32,1566,1567,1598,1617,1640,1644,1660,1688,1693,1697],{"__ignoreMap":61},[65,1568,1569,1571,1574,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594,1596],{"class":67,"line":68},[65,1570,154],{"class":102},[65,1572,1573],{"class":71}," equator ",[65,1575,160],{"class":102},[65,1577,163],{"class":109},[65,1579,166],{"class":71},[65,1581,341],{"class":109},[65,1583,344],{"class":71},[65,1585,246],{"class":109},[65,1587,166],{"class":71},[65,1589,351],{"class":109},[65,1591,354],{"class":71},[65,1593,507],{"class":317},[65,1595,360],{"class":102},[65,1597,178],{"class":71},[65,1599,1600,1602,1605,1607,1609,1611,1614],{"class":67,"line":75},[65,1601,154],{"class":102},[65,1603,1604],{"class":71}," cap ",[65,1606,160],{"class":102},[65,1608,163],{"class":109},[65,1610,166],{"class":71},[65,1612,1613],{"class":109},"triangulated",[65,1615,1616],{"class":71},"(\n",[65,1618,1619,1622,1624,1627,1630,1632,1635,1637],{"class":67,"line":81},[65,1620,1621],{"class":109},"    tf",[65,1623,166],{"class":71},[65,1625,1626],{"class":109},"make_polygons",[65,1628,1629],{"class":71},"(equator.",[65,1631,867],{"class":109},[65,1633,1634],{"class":71},"(), equator.",[65,1636,269],{"class":109},[65,1638,1639],{"class":71},"()));\n",[65,1641,1642],{"class":67,"line":87},[65,1643,149],{"emptyLinePlaceholder":148},[65,1645,1646,1648,1651,1653,1656,1658],{"class":67,"line":93},[65,1647,666],{"class":102},[65,1649,1650],{"class":71}," area ",[65,1652,160],{"class":102},[65,1654,1655],{"class":317}," 0.",[65,1657,360],{"class":102},[65,1659,679],{"class":71},[65,1661,1662,1664,1666,1668,1671,1673,1676,1678,1680,1682,1685],{"class":67,"line":99},[65,1663,373],{"class":102},[65,1665,376],{"class":71},[65,1667,154],{"class":102},[65,1669,1670],{"class":71}," triangle : cap.",[65,1672,193],{"class":109},[65,1674,1675],{"class":71},"()) area ",[65,1677,771],{"class":102},[65,1679,163],{"class":109},[65,1681,166],{"class":71},[65,1683,1684],{"class":109},"area",[65,1686,1687],{"class":71},"(triangle);\n",[65,1689,1690],{"class":67,"line":365},[65,1691,1692],{"class":406},"\u002F\u002F close to pi for the unit sphere's equator\n",[65,1694,1695],{"class":67,"line":370},[65,1696,149],{"emptyLinePlaceholder":148},[65,1698,1699,1701,1703,1706,1709,1711,1714,1717],{"class":67,"line":390},[65,1700,246],{"class":109},[65,1702,166],{"class":71},[65,1704,1705],{"class":109},"write_stl",[65,1707,1708],{"class":71},"(cap.",[65,1710,193],{"class":109},[65,1712,1713],{"class":71},"(), ",[65,1715,1716],{"class":142},"\"section.stl\"",[65,1718,178],{"class":71},[48,1720,1722],{"id":1721},"working-with-results","Working with results",[14,1724,1725],{},"To keep the solid part between two planes as a mesh, use isobands. They cut the mesh along the slices:",[56,1727,1729],{"className":130,"code":1728,"language":132,"meta":61,"style":61},"std::array\u003Cfloat, 2> cuts{-0.2f, 0.2f};\nstd::array\u003Cint, 1> keep{1};\nauto [slab, labels, face_labels] = tf::make_isobands(\n    mesh, tf::make_range(height), tf::make_range(cuts),\n    tf::make_range(keep));\n\ntf::write_obj(slab.polygons(), \"slab.obj\");\n",[32,1730,1731,1764,1786,1804,1826,1837,1841],{"__ignoreMap":61},[65,1732,1733,1735,1737,1739,1741,1743,1746,1749,1751,1753,1755,1757,1759,1761],{"class":67,"line":68},[65,1734,719],{"class":109},[65,1736,982],{"class":71},[65,1738,985],{"class":102},[65,1740,474],{"class":71},[65,1742,318],{"class":317},[65,1744,1745],{"class":102},">",[65,1747,1748],{"class":71}," cuts{",[65,1750,926],{"class":102},[65,1752,520],{"class":317},[65,1754,360],{"class":102},[65,1756,474],{"class":71},[65,1758,520],{"class":317},[65,1760,360],{"class":102},[65,1762,1763],{"class":71},"};\n",[65,1765,1766,1768,1770,1773,1775,1777,1779,1782,1784],{"class":67,"line":75},[65,1767,719],{"class":109},[65,1769,982],{"class":71},[65,1771,1772],{"class":102},"\u003Cint",[65,1774,474],{"class":71},[65,1776,1116],{"class":317},[65,1778,1745],{"class":102},[65,1780,1781],{"class":71}," keep{",[65,1783,1116],{"class":317},[65,1785,1763],{"class":71},[65,1787,1788,1790,1793,1795,1797,1799,1802],{"class":67,"line":81},[65,1789,154],{"class":102},[65,1791,1792],{"class":71}," [slab, labels, face_labels] ",[65,1794,160],{"class":102},[65,1796,163],{"class":109},[65,1798,166],{"class":71},[65,1800,1801],{"class":109},"make_isobands",[65,1803,1616],{"class":71},[65,1805,1806,1809,1811,1813,1815,1817,1819,1821,1823],{"class":67,"line":87},[65,1807,1808],{"class":71},"    mesh, ",[65,1810,246],{"class":109},[65,1812,166],{"class":71},[65,1814,351],{"class":109},[65,1816,354],{"class":71},[65,1818,246],{"class":109},[65,1820,166],{"class":71},[65,1822,351],{"class":109},[65,1824,1825],{"class":71},"(cuts),\n",[65,1827,1828,1830,1832,1834],{"class":67,"line":93},[65,1829,1621],{"class":109},[65,1831,166],{"class":71},[65,1833,351],{"class":109},[65,1835,1836],{"class":71},"(keep));\n",[65,1838,1839],{"class":67,"line":99},[65,1840,149],{"emptyLinePlaceholder":148},[65,1842,1843,1845,1847,1850,1853,1855,1857,1860],{"class":67,"line":365},[65,1844,246],{"class":109},[65,1846,166],{"class":71},[65,1848,1849],{"class":109},"write_obj",[65,1851,1852],{"class":71},"(slab.",[65,1854,193],{"class":109},[65,1856,1713],{"class":71},[65,1858,1859],{"class":142},"\"slab.obj\"",[65,1861,178],{"class":71},[14,1863,1864],{},[43,1865],{"alt":1866,"src":1867},"Slab between two planes: the part of the Stanford dragon between z = -0.2 and z = 0.2 kept with isobands, in orange, rims in pink","\u002Fimg\u002Ftutorials\u002Fsteps\u002Fmesh-slicing-and-cross-sections-5-slab.png",[14,1869,1870,1871,1874],{},"The slab is open at the cuts. ",[32,1872,1873],{},"face_labels"," maps each slab face back to its source face.",[14,1876,1877],{},"To split the mesh in two at a plane, embed the slice and split by band:",[56,1879,1881],{"className":130,"code":1880,"language":132,"meta":61,"style":61},"std::array\u003Cfloat, 1> at{0.f};\nauto [halves, half_labels, half_face_labels] = tf::embedded_isocurves(\n    mesh, tf::make_range(height), tf::make_range(at));\n\nauto [pieces, piece_labels] =\n    tf::split_into_components(halves.polygons(), half_labels);\ntf::write_stl(pieces[0].polygons(), \"below.stl\");\ntf::write_stl(pieces[1].polygons(), \"above.stl\");\n",[32,1882,1883,1906,1924,1945,1949,1959,1976,2001],{"__ignoreMap":61},[65,1884,1885,1887,1889,1891,1893,1895,1897,1900,1902,1904],{"class":67,"line":68},[65,1886,719],{"class":109},[65,1888,982],{"class":71},[65,1890,985],{"class":102},[65,1892,474],{"class":71},[65,1894,1116],{"class":317},[65,1896,1745],{"class":102},[65,1898,1899],{"class":71}," at{",[65,1901,507],{"class":317},[65,1903,360],{"class":102},[65,1905,1763],{"class":71},[65,1907,1908,1910,1913,1915,1917,1919,1922],{"class":67,"line":75},[65,1909,154],{"class":102},[65,1911,1912],{"class":71}," [halves, half_labels, half_face_labels] ",[65,1914,160],{"class":102},[65,1916,163],{"class":109},[65,1918,166],{"class":71},[65,1920,1921],{"class":109},"embedded_isocurves",[65,1923,1616],{"class":71},[65,1925,1926,1928,1930,1932,1934,1936,1938,1940,1942],{"class":67,"line":81},[65,1927,1808],{"class":71},[65,1929,246],{"class":109},[65,1931,166],{"class":71},[65,1933,351],{"class":109},[65,1935,354],{"class":71},[65,1937,246],{"class":109},[65,1939,166],{"class":71},[65,1941,351],{"class":109},[65,1943,1944],{"class":71},"(at));\n",[65,1946,1947],{"class":67,"line":87},[65,1948,149],{"emptyLinePlaceholder":148},[65,1950,1951,1953,1956],{"class":67,"line":93},[65,1952,154],{"class":102},[65,1954,1955],{"class":71}," [pieces, piece_labels] ",[65,1957,1958],{"class":102},"=\n",[65,1960,1961,1963,1965,1968,1971,1973],{"class":67,"line":99},[65,1962,1621],{"class":109},[65,1964,166],{"class":71},[65,1966,1967],{"class":109},"split_into_components",[65,1969,1970],{"class":71},"(halves.",[65,1972,193],{"class":109},[65,1974,1975],{"class":71},"(), half_labels);\n",[65,1977,1978,1980,1982,1984,1987,1989,1992,1994,1996,1999],{"class":67,"line":365},[65,1979,246],{"class":109},[65,1981,166],{"class":71},[65,1983,1705],{"class":109},[65,1985,1986],{"class":71},"(pieces[",[65,1988,932],{"class":317},[65,1990,1991],{"class":71},"].",[65,1993,193],{"class":109},[65,1995,1713],{"class":71},[65,1997,1998],{"class":142},"\"below.stl\"",[65,2000,178],{"class":71},[65,2002,2003,2005,2007,2009,2011,2013,2015,2017,2019,2022],{"class":67,"line":370},[65,2004,246],{"class":109},[65,2006,166],{"class":71},[65,2008,1705],{"class":109},[65,2010,1986],{"class":71},[65,2012,1116],{"class":317},[65,2014,1991],{"class":71},[65,2016,193],{"class":109},[65,2018,1713],{"class":71},[65,2020,2021],{"class":142},"\"above.stl\"",[65,2023,178],{"class":71},[14,2025,2026,2027,2031,2032,2036,2037,27],{},"Slicing works for any scalar field, not only planes. See ",[18,2028,2030],{"href":2029},"\u002Ftutorials\u002Fisocontours-on-a-triangle-mesh-in-cpp","isocontours on a triangle mesh",". To cut a mesh by another mesh, use ",[18,2033,2035],{"href":2034},"\u002Ftutorials\u002Fmesh-intersection-curves-in-cpp","intersection curves"," or ",[18,2038,2040],{"href":2039},"\u002Ftutorials\u002Ffast-mesh-booleans-in-cpp","booleans",[48,2042,2044],{"id":2043},"related-tutorials","Related tutorials",[2046,2047,2048,2055,2062,2068],"ul",{},[2049,2050,2051,2054],"li",{},[18,2052,2053],{"href":2029},"Fast and Robust Isocontours on a Triangle Mesh in C++"," — curves and bands of equal value on a scalar field.",[2049,2056,2057,2061],{},[18,2058,2060],{"href":2059},"\u002Ftutorials\u002Fconstrained-delaunay-triangulation-in-cpp","Fast and Exact Constrained Delaunay Triangulation in C++"," — triangulate points and outlines, with holes and constraints.",[2049,2063,2064,2067],{},[18,2065,2066],{"href":2034},"Fast and Exact Mesh Intersection Curves in C++"," — exact curves where two or more meshes cross.",[2049,2069,2070,2074],{},[18,2071,2073],{"href":2072},"\u002Ftutorials\u002Ffast-connected-components-in-cpp","Fast Connected Components in C++"," — split a mesh into parts and find its boundary loops.",[48,2076,2078],{"id":2077},"performance","Performance",[14,2080,2081],{},"A slice is an isocontour, so the isocontour benchmark is the slicing benchmark. We measured on the Stanford dragon, against VTK and libigl.",[2083,2084],"headline-numbers",{":items":2085},"[{\"value\":\"5.9ms\",\"label\":\"Isocontours\",\"detail\":\"1,025,766 polygons (VTK: 236.2 ms)\"},{\"value\":\"11.6ms\",\"label\":\"Many levels\",\"detail\":\"480,868 polygons (VTK: 336.6 ms)\"},{\"value\":\"40×\",\"label\":\"Faster than VTK\",\"detail\":\"Isocontours, 1,025,766 polygons\"}]",[14,2087,2088,2093,2094],{},[65,2089,2092],{"className":2090},[2091],"tag-pill","Apple M4 Max"," ",[65,2095,2097],{"className":2096},[2091],"16 threads",[2099,2100],"data-table",{":headers":2101,":highlight":318,":rows":2102},"[\"Operation\",\"Mesh\",\"trueform\",\"VTK\",\"libigl\"]","[[\"Isocontours\",\"1,025,766 polygons\",\"5.9 ms\",\"236.2 ms (40×)\",\"736.9 ms (124×)\"],[\"Isocontours, many levels\",\"480,868 polygons\",\"11.6 ms\",\"336.6 ms (29×)\",\"963.2 ms (83×)\"],[\"Embedded isobands\",\"1,025,766 polygons\",\"18.2 ms\",\"740.6 ms (41×)\",\"no equivalent\"]]",[14,2104,2105],{},[43,2106],{"alt":2107,"src":2108},"Benchmark chart: trueform against other C++ libraries, isocontours","\u002Fimg\u002Falgorithms\u002Fbenchmark-isocontours-cpp-2026.png",[14,2110,2111,2115,2116],{},[18,2112,2114],{"href":2113},"\u002Ftrueform\u002Fbenchmarks","Full benchmarks"," · ",[18,2117,2120],{"href":2118,"rel":2119},"https:\u002F\u002Ftrueform.polydera.com\u002Fcpp\u002Fmodules\u002Fiso#isocontours",[121],"Documentation",[2122,2123],"cite-as",{"author":2124,"title":5},"Sajovic, {\\v{Z}}iga",[2126,2127,2128],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":61,"searchDepth":75,"depth":75,"links":2130},[2131,2132,2133,2134,2135,2136,2137,2138,2139,2140],{"id":50,"depth":75,"text":51},{"id":126,"depth":75,"text":127},{"id":225,"depth":75,"text":226},{"id":435,"depth":75,"text":436},{"id":652,"depth":75,"text":653},{"id":1133,"depth":75,"text":1134},{"id":1553,"depth":75,"text":1554},{"id":1721,"depth":75,"text":1722},{"id":2043,"depth":75,"text":2044},{"id":2077,"depth":75,"text":2078},"2026-10-31","Slice a triangle mesh by planes in C++. One cross-section, any tilted plane, stacked layers for 3D printing, survey sections along an axis, and filled sections. Header-only, C++17. 5.9 ms on 1M polygons.","md",[2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155],"mesh slicing C++","slice mesh by plane C++","mesh cross-section C++","plane mesh intersection C++","3D printing slicer C++","STL slicing C++","survey cross-sections mesh","VTK vtkCutter alternative","CGAL Polygon_mesh_slicer alternative","libigl isolines alternative","MeshLib planar section alternative",{},"\u002Fimg\u002Fog\u002Ftutorials\u002Fmesh-slicing-and-cross-sections-in-cpp.png","\u002Ftutorials\u002Fmesh-slicing-and-cross-sections-in-cpp",{"title":5,"description":2142},"tutorials\u002Fmesh-slicing-and-cross-sections-in-cpp",[2162,2163,2164],"c++","slicing","tutorial","PnX6oGVv6ml4V5MuNXmSZCj89WRqmUBHJ-i2S7cbj88",1793517811885]