FuncViz examples
Generalized bitree/quadtree/octree library
Loading...
Searching...
No Matches
surface_with_normals.cpp
Go to the documentation of this file.
1// -*- Mode:C++; Coding:us-ascii-unix; fill-column:158 -*-
2/*******************************************************************************************************************************************************.H.S.**/
3/**
4 @file surface_with_normals.cpp
5 @author Mitch Richling http://www.mitchr.me/
6 @date 2024-07-13
7 @brief Simple surface function graph.@EOL
8 @std C++23
9 @copyright
10 @parblock
11 Copyright (c) 2024, Mitchell Jay Richling <http://www.mitchr.me/> All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
14
15 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
16
17 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19
20 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software
21 without specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 DAMAGE.
29 @endparblock
30 @filedetails
31
32 Surface normals may be used by many visualization tools to render smoother results. In this example we demonstrate:
33
34 - How to compute a surface gradient for a function plot
35 - How to unitize the gradient into a surface normal
36 - How to add the normal to the sample data stored by a MRPTree
37 - How to include normals in the cell complex
38 - How to increase sampling with a SDF function
39 - How to increase sampling near humps by testing derivatives
40 - How to balance a tree
41 - How to dump a cell complex into various file types
42*/
43/*******************************************************************************************************************************************************.H.E.**/
44/** @cond exj */
45
46////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
47#include "MR_rect_tree.hpp"
48#include "MR_cell_cplx.hpp"
49#include "MR_rt_to_cc.hpp"
50
51////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
52typedef mjr::tree15b2d5rT tt_t;
53typedef mjr::MRccT5 cc_t;
54typedef mjr::MR_rt_to_cc<tt_t, cc_t> tc_t;
55
56////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
57tt_t::rrpt_t damp_cos_wave(tt_t::drpt_t xvec) {
58 double x = xvec[0];
59 double y = xvec[1];
60 double d = x*x+y*y;
61 double m = std::exp(-d/4);
62 double s = std::sqrt(d);
63 double z = m*cos(4*s);
64 double dx = -(cos((4 * s)) * s + 4 * sin( (4 * s))) * x * exp(-x * x / 2 - y * y / 2);
65 double dy = -(cos((4 * s)) * s + 4 * sin( (4 * s))) * y * exp(-x * x / 2 - y * y / 2);
66 double dd = -m*(cos(4*s)*s+8*sin(4*s));
67 if (s>1.0e-5) {
68 dx = dx / s;
69 dy = dy / s;
70 dd = dd / (4 * s);
71 } else {
72 dx = 1;
73 dy = 1;
74 dd = 1;
75 }
76 double nm = std::sqrt(1+dx*dx+dy*dy);
77 return {z, -dx/nm, -dy/nm, 1/nm, dd};
78}
79
80////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
81double circle_sdf(double r, tt_t::drpt_t xvec) {
82 double x = xvec[0];
83 double y = xvec[1];
84 double m = x*x+y*y;
85 return (r*r-m);
86}
87
88////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89int main() {
90 tt_t tree({-2.1, -2.1},
91 { 2.1, 2.1});
92 cc_t ccplx;
93
94 // Make a few samples on a uniform grid
95 tree.refine_grid(2, damp_cos_wave);
96
97 // The humps need extra samples. We know where they are, and we could sample on them with an SDF like this:
98 // for(double i: {0, 1, 2, 3}) {
99 // double r = i*std::numbers::pi/4;
100 // tree.refine_leaves_recursive_cell_pred(6, damp_cos_wave, [&tree, r](int i) { return (tree.cell_cross_sdf(i, std::bind_front(circle_sdf, r))); });
101 // }
102
103 // Alternately, we can test the derivative values to identify the humps
104 // tree.refine_leaves_recursive_cell_pred(6, damp_cos_wave, [&tree](tt_t::diti_t i) { return tree.cell_cross_range_level(i, 1, 0.0); });
105 // tree.refine_leaves_recursive_cell_pred(6, damp_cos_wave, [&tree](tt_t::diti_t i) { return tree.cell_cross_range_level(i, 2, 0.0); });
106
107 // Lastly we can use the directional derivative radiating from the origin
108 tree.refine_leaves_recursive_cell_pred(6, damp_cos_wave, [&tree](tt_t::diti_t i) { return tree.cell_cross_range_level(i, 4, 0.0); });
109
110 // Balance the three to the traditional level of 1 (no cell borders a cell more than half it's size)
111 tree.balance_tree(1, damp_cos_wave);
112
113 tree.dump_tree(5);
114
115 tc_t::construct_geometry_fans(ccplx,
116 tree,
117 2,
118 {{tc_t::val_src_spc_t::FDOMAIN, 0},
119 {tc_t::val_src_spc_t::FDOMAIN, 1},
120 {tc_t::val_src_spc_t::FRANGE, 0}});
121
122 // Note we use the single argument version of create_named_datasets() because we don't want to name elements 3, 4, & 5 (the components of the normal
123 // Note if we had placed the ddiv component right after z, then we could have used the two argument version...
124 ccplx.set_data_name_to_data_idx_lst({{"x", {0}},
125 {"y", {1}},
126 {"z=f(x,y)", {2}},
127 {"ddiv", {6}},
128 {"NORMALS", {3,4,5}}});
129
130 ccplx.dump_cplx(5);
131
132 ccplx.write_legacy_vtk("surface_with_normals.vtk", "surface_with_normals");
133 ccplx.write_xml_vtk( "surface_with_normals.vtu", "surface_with_normals");
134 ccplx.write_ply( "surface_with_normals.ply", "surface_with_normals");
135}
136/** @endcond */
int main()