6
$\begingroup$

I have the following region:

curve = BSplineCurve[{{0, 0}, {1, -.5}, {2, .5}, {1, 2}, {0, 
    1}, {-1, .5}}, SplineClosed -> True];
reg = Region@BoundaryDiscretizeGraphics@curve;

and the function (over that region):

f[x_,y_]=Sin[x y+2];

How do I generate a 3D plot of the surface given by $(x,y,f(x,y))$ with a grid of unitary normal vectors, only on the region reg?

$\endgroup$

1 Answer 1

11
$\begingroup$
curve = BSplineCurve[{{0, 0}, {1, -.5}, {2, .5}, {1, 2}, {0, 
     1}, {-1, .5}}, SplineClosed -> True];

bdg = BoundaryDiscretizeGraphics[curve];

f[x_, y_] = Sin[x y + 2];

p3d = Plot3D[f[x, y], {x, y} ∈ bdg, 
  Mesh -> None, BoxRatios -> 1, PlotRangePadding -> Scaled[.15]]

enter image description here

You can post-process p3d to add

1. normal lines at the center of each polygon:

Normal[p3d] /. p : Polygon[c_, ___, VertexNormals -> vn_, ___] :>
   {p, Black, Line[{Mean[c], Mean[c] + Mean[vn]/3}]}

enter image description here

2. normal lines at polygon vertices:

Normal[p3d] /. p : Polygon[c_, ___, VertexNormals -> vn_, ___] :> 
  {p, Black, MapThread[Line[{##}] &, {c, c + vn/3}]}

enter image description here

To compare the two methods use an input plot produced with MaxRecursion -> 0 and a small value for PlotPoints:

p3dB = Plot3D[f[x, y], {x, y} ∈ bdg, Mesh -> None, 
   BoxRatios -> 1, PlotPoints -> 1, MaxRecursion -> 0, 
   PlotStyle -> EdgeForm[{Gray, Thin}], 
   PlotRangePadding -> Scaled[.15]];

Row[Show[#, ImageSize -> 400] & /@ 
  {Normal[p3dB] /. p : Polygon[c_, ___, VertexNormals -> vn_, ___] :> 
    {p, Black, Line[{Mean[c], Mean[c] + Mean[vn]/3}]},
   Normal[p3dB] /. p : Polygon[c_, ___, VertexNormals -> vn_, ___] :> 
    {p, Black, MapThread[Line[{##}] &, {c, c + vn/3}]}}]

enter image description here

Alternatively, you can use the function normalsShow from VertexNormals >> Applications:

normalsShow[g_Graphics3D] :=  Module[{pl, vl, n},
   {pl, vl} = First@Cases[g, GraphicsComplex[pl_, prims_, VertexNormals -> vl_, 
        opts___?OptionQ] :> {pl, vl}, Infinity];
   n = Length[pl];
   Show[g, 
    Graphics3D[GraphicsComplex @@ {Join[pl, pl + vl/3], 
      {Black, Line[Table[{i, i + n}, {i, n}]]}}]]
   ];


normalsShow @ p3d

enter image description here

$\endgroup$
4
  • $\begingroup$ Thank you for your great answer, however when adding in the option ColorFunction -> "FallColors" in the p3d definition the normal vectors won't show up, do you know how to deal with this? $\endgroup$
    – Lilla
    Apr 20, 2020 at 19:41
  • 1
    $\begingroup$ @Leonardo, try replacing Polygon[c_, VertexNormals -> vn_] with Polygon[c_, ___, VertexNormals -> vn_, ___]? $\endgroup$
    – kglr
    Apr 20, 2020 at 19:49
  • $\begingroup$ Solved, perfect. $\endgroup$
    – Lilla
    Apr 20, 2020 at 19:53
  • $\begingroup$ @kglr I just asked a related question here: mathematica.stackexchange.com/questions/246462/…. Could you please tell me how to get a list of the normal vectors only along the boundary? And plot them as well (along with the surface). $\endgroup$
    – ap21
    May 22, 2021 at 3:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.