7
$\begingroup$

In Python there are very easy to use and efficient libraries for surface parametrization (for instance igl). I wonder if in Mathematica we have a ready-made implementation.

The parametrization is typically given as a UV list $\{\{u_1,v_1\},\{u_2,v_2\},\cdots\}$.

Some sample data for a particular parametrization I am working with is here, with the surface points, the triangle list and the parametrization:

enter image description here enter image description here


For completeness I include the python code that generates the plot:

 import igl import numpy as np from meshplot import plot, subplot, interact vertices = np.loadtxt(r'C:\path\theX.csv',delimiter=',') faces = np.loadtxt(r'C:\path\theT.csv',delimiter=',')-1 param = np.loadtxt(r'C:\path\theUV.csv',delimiter=',') plot(vertices,faces, uv=param,shading={"wireframe": False, "flat": False}) 

$\endgroup$
11
  • 1
    $\begingroup$ BSplineSurface reference.wolfram.com/language/ref/… Might work for you, or you can use Interpolation for x[u,v], y[u,v] and z[u,v] and plot with ParametricPlot3D $\endgroup$ Commented Jul 25 at 16:13
  • 1
    $\begingroup$ @CraigCarter thanks, although I'd like to avoid interportations and rather handle completely discrete surfaces. $\endgroup$ Commented Jul 25 at 20:58
  • 3
    $\begingroup$ One thing to keep in mind when formulating questions on this site is that generally few of the experts in Mathematica are also experts in the OP's field. I'm confused: "Parametrization" and "completely discrete surface" are at odds. To me, a parametrization of a surface is a continuous function $(x,y,z)=f(u,v)$ that approximates the target surface typically by interpolation or by fitting. Apparently that is not what you want. You want a "UV list", which appears to be a discrete list of ordered pairs of real numbers. It seems impossible to define a surface this way without a function $f(u,v)$. $\endgroup$ Commented Jul 27 at 15:50
  • $\begingroup$ Weekends are often slow, so maybe someone who knows of such a package will turn up in a couple of days. If not, two things that you might attempt: (1) Calling python from Mma. (2) Translating the python code to Mma, which seems like it would be a great benefit to others. $\endgroup$ Commented Jul 27 at 15:50
  • $\begingroup$ @MichaelE2 Yes, I'm abusing a bit because this is standard language in computational differential geometry. If you're interested you can check the link to the python igl package where in a couple of paragraphs a 'parametrization' is defined in the discrete sense, but it is roughly the same that you mention. $\endgroup$ Commented Jul 27 at 16:03

3 Answers 3

7
+100
$\begingroup$

Update with UV data

I believe the checkerboard pattern is now correct just OP pattern is in a different rotation angle.

uv = Import["C:\\Users\\VV\\Downloads\\theUV.csv"]; pt = Import["C:\\Users\\VV\\Downloads\\theX.csv"]; ix = Interpolation[Transpose[{pt[[All, {1, 2}]], uv[[All, 1]]}], InterpolationOrder -> 1]; iy = Interpolation[Transpose[{pt[[All, {1, 2}]], uv[[All, 2]]}], InterpolationOrder -> 1]; ListPlot3D[pt, ViewPoint -> Top, BoxRatios -> Automatic, MeshFunctions -> ({ix[#1, #2] &, iy[#1, #2] &}), Mesh -> 18, MeshShading -> {{Black, Yellow}, {Yellow, Black}}, Method -> {"RotationControl" -> "ArcBall"}, Boxed -> False, Axes -> False] 

enter image description here

Original answer without using UV data

You can use ListPlot3D with MeshFunctions, MeshShading and Mesh to create the checkerboard pattern. No need for any UV data.

(* add your path to the files *) tr = Import["theT.csv"]; pt = Import["theX.csv"]; Graphics3D[{FaceForm[None], Triangle /@ (pt[[#]] & /@ tr)}, ViewPoint -> Top, Boxed -> False]; ListPlot3D[pt, ViewPoint -> Top, BoxRatios -> Automatic, MeshFunctions -> {#2 + #1 &, #2 - #1 &}, Mesh -> 15, MeshShading -> {{Black, Yellow}, {Yellow, Black}}]; Show[%%, %] 

enter image description here

enter image description here

$\endgroup$
7
  • $\begingroup$ Thanks, this is useful. However it's not the same for two reasons. (1) If we look carefully your checkerboard pattern is not perfect, in the sense that the distances of all the edges are supposed to be the same. Such a Chebyshev net, as is called, is generated with the parametrization data. (2) I'm not sure how easily we can extract here the quad mesh spanned by the checkerboard pattern. $\endgroup$ Commented Jul 27 at 19:57
  • $\begingroup$ @DanielCastro Why do you assume lengths of black squares should be the same? If you look at the igl link in your OP, in the first image of a camel head we see huge black square in the tip of the nose of the camel while squares on its neck are very small. $\endgroup$ Commented Jul 27 at 20:02
  • $\begingroup$ True, they are using different parametrizations. I am using a "Chebyshev parametrization" which explicitly enforces the aforementioned property. Of course I did not do that implementation, the credit goes to these guys: youtu.be/eza70O2avZ4?si=tK8LZgFZUAMoRihy $\endgroup$ Commented Jul 27 at 20:05
  • $\begingroup$ This is cool, thanks. There are some minor defects on the sides, I suppose this is due to the interpolation, right ? $\endgroup$ Commented Jul 28 at 9:50
  • $\begingroup$ @DanielCastro It is either a bug in ListPlot3D or a consequence of an interpolation algorithm they use in ListPlot3D which is not perfect. I can not do anything about it. $\endgroup$ Commented Jul 28 at 10:04
5
$\begingroup$

We can call libigl in Python through ExternalEvaluate:

$igl = StartExternalSession[ Association["System" -> "Python", "Evaluator" -> <|"Dependencies" -> {"libigl"}, "EnvironmentName" -> "iglenv"|>]]; ExternalEvaluate[$igl, " import igl import numpy as np import os def compute_uv(filename: str) -> np.ndarray: V, F = igl.read_triangle_mesh(filename) bnd = igl.boundary_loop(F) b = np.array([bnd[0], bnd[len(bnd) // 2]]) bc = np.array([[0.0, 0.0], [1.0, 0.0]]) UV = igl.lscm(V, F, b, bc) return UV[0] "]; 

Right now we have to pass in a file. I tried doing stuff like

def compute_uv(V: np.array, F: np.array) -> np.array:

but I couldn't figure out how to pass in arrays to python as the right type.

vertices = Import["/Users/ghurst/Downloads/theX.csv"]; triangles = Import["/Users/ghurst/Downloads/theT.csv"]; Export["temp.obj", MeshRegion[pts, Polygon[triangles]]]; 

And now we get the uv data and plot:

uvs = Normal[ExternalEvaluate[$igl, "compute_uv('temp.obj')"]]; texture = ImageResize[Image[Table[Mod[i + j, 2], {i, 8}, {j, 8}]], Scaled[30], Resampling -> "Nearest"]; Graphics3D[{Texture[texture], EdgeForm[], GraphicsComplex[ vertices, Polygon[triangles], VertexTextureCoordinates -> uvs ]}, Lighting -> "Accent", Boxed -> False, ViewVertical -> {0, 1, 0}, ViewPoint -> {0, 0, 4} ] 
$\endgroup$
2
  • $\begingroup$ Wow, impressive, thanks. Actually all that I'm doing in python is "import igl import scipy as sp import numpy as np from meshplot import plot, subplot, interact vertices = np.loadtxt(r'C:\path\theX.csv',delimiter=',') faces = np.loadtxt(r'C:\path\theT.csv',delimiter=',')-1 param = np.loadtxt(r'C:\path\theUV.csv',delimiter=',') plot(vertices,faces, uv=param,shading={"wireframe": False, "flat": False})" $\endgroup$ Commented Jul 30 at 21:09
  • $\begingroup$ @cvgmt Thanks. Please see edit. $\endgroup$ Commented Jul 31 at 13:41
3
$\begingroup$

You can combine the data into MeshRegion (a.k.a. simplicial complex) as follows:

pts = Import["path-to-the/theX.csv"]; triangles = Import["path-to-the/theT.csv"]; MeshRegion[pts, Triangle /@ triangles] 

picture

$\endgroup$
1
  • 1
    $\begingroup$ Thanks, but this is not what I'm looking for. The important thing is the parametrization (see that checkerboard pattern in the attached picture?) $\endgroup$ Commented Jul 27 at 13:55

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.