What does this 'do' syntax mean?

I found the following example in the README for the Meshing package

using Meshing
using GeometryTypes
using LinearAlgebra: dot, norm
using FileIO

# generate an SDF of a sphere
sdf_sphere = SignedDistanceField(HyperRectangle(Vec(-1,-1,-1.),Vec(2,2,2.))) do v
    sqrt(sum(dot(v,v))) - 1 # sphere
end

m = GLNormalMesh(sdf_sphere, MarchingCubes())

save("sphere.ply",m)

I am trying to work out what that SignedDistanceField(...) do ... end syntax means. It seems that this code samples the function sqrt(sum(dot(v,v))) - 1 at intervals of 0.1, but what Julia syntax is being used to accomplish this?

More specifically, for SignedDistanceField, how does one change the resolution to something other than 0.1? I looked at the documentation for SignedDistanceField (in the GeometryTypes package), but unfortunately it’s not much help:

  A SignedDistanceField is a uniform sampling of an implicit function. The bounds field corresponds to the sampling
  space intervals on each axis. The data field represents the value at each point whose exact location can be
  rationalized from bounds. The type is parameterized by:

    β€’    N - The dimensionality of the sampling space.

    β€’    SpaceT - the type of the space where we will uniformly sample.

    β€’    FieldT - the type resulting from evaluation of the implicit function.

  Note that decoupling the space and field types is useful since geometry can be formulated with integers and distances
  can be measured with floating points.

  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

  Construct a SignedDistanceField by sampling a function over the bounds at the specified resolution (default = 0.1).
  Note that the sampling grid must be regular, so a new HyperRectangle will be generated for the SignedDistanceField
  that may have larger maximum bounds than the input HyperRectangle. The default Field type is Float64, but this can be
  changed with the fieldT argument.

It mentions that the default resolution but doesn’t mention how to change it.

2 Likes

Have a look at https://docs.julialang.org/en/v1/manual/functions/index.html#Do-Block-Syntax-for-Function-Arguments-1. The do syntax basically just passes an anonymous function as the first argument to the function.

3 Likes

Here is a trivial example:

my_function(f, container) = begin
    for element in container
        f(element)
    end
    return nothing
end

my_function([1,2,3]) do x  # equivlent to my_function(print, [1,2,3])
    print(x)
end

Instead of specifying (x)->print(x) as an argument of my_function, with the do synatx one can write (generally larger) functions that operate on the rest of the arguments in the signature (in this case, the argument container)

10 Likes

Maybe this is obvious from the other replies, but the do syntax plays no part in (directly) determining the resolution.

I’ve never used this package but these lines from the tests file of Meshing, seem to indicate that you can specify a different resolution with the third argument to SignedDistanceField. So in the example you cite, you could write the following to change the resolution to 0.025.

resolution = 0.025
sdf_sphere = SignedDistanceField(HyperRectangle(Vec(-1,-1,-1.),Vec(2,2,2.)),resolution) do v
    sqrt(sum(dot(v,v))) - 1 # sphere
end

This is because, with the do syntax, the first argument is the body of code after do, and the second, third, etc… are specified as the arguments before do. So you could, equivalently, write the following:

sdf_sphere = SignedDistanceField(v -> sqrt(sum(dot(v,v))) - 1,
    HyperRectangle(Vec(-1,-1,-1.),Vec(2,2,2.)),0.025)

I often find that I can identify missing functionality of an undocumented feature just be reading through tests/runtests.jl, as that generally has to demonstrate most of the intended use cases of a package. That’s how I figured out the answer to your question, in this case.

2 Likes