Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

This page documents the main differences between the D port and the original OpenMesh.

Of course the port makes all the standard changes involved in porting a library from C++ to D. Other than what is listed here, the D port pretty much follows the original API. The detailed API documentation for all the members of a typical mesh can be found on these three pages:

The rest of the page is organized as follows: after a quick overview, the details of some of the less obvious changes are given.

Quick Overview

This is a brief overview of most of the syntax and API changes required to port an OpenMesh/C++ program to OpenMesh/D. (There are of course all the usual porting issues as well.)

  • include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh> --> import OpenMesh.Core.Mesh.PolyMesh_ArrayKernelT;
  • Point& Mesh::point(VertexHandle) --> Point Mesh.point(VertexHandle) or Point* Mesh.point_ptr(VertexHandle)
  • StatusInfo& Mesh::status(VertexHandle) --> StatusInfo Mesh.status(VertexHandle) or StatusInfo* Mesh::status_ptr(VertexHandle)
    • status overloads are handled similarly for all handle types.
    • The D port also has vstatus,hstatus,estatus,fstatus variants (and their _ptr flavors) which are not overloaded.
  • is_valid_handle(VertexHandle) --> ok as-is, but the D port also has variants specific to particular handle types: is_valid_vhandle, is_valid_hhandle, is_valid_ehandle, is_valid_fhandle.
  • while(; circulator; ++circulator) --> while(; circulator.is_active; ++circulator)
  • In D a VectorT!(Scalar,N) has .x .y and .z properties as appropriate for the cases where N<=3.
  • *mesh1 = *mesh2 --> mesh1 = mesh2.dup (meaning use .dup for classes instead of C++'s copy semantics).

Details about certain Changes

Const

The D port uses D 1.x and therefore there is no const. However, occurrences of const in the API have mostly been preserved in the source code as comments (/*const*/) to aid in future porting someday to a D with const.

Also all the const-flavored iterators and circulators have been retained to make porting easier; however in the current D port they are identical to their non-const counterparts. So for example VertexVertexIterT and ConstVertexVertexIterT are the same thing in D.

Reference return values

Since D doesn't allow references to be returned from functions, the D port replaces returned references with return-by-value and return-by-pointer. Specifically, In C++ many OpenMesh mesh functions were of the form

C++:

Point& point(VertexHandle);

In D such functions have been split into a pair

D:

   Point point(VertexHandle);
   Point* point_ptr(VertexHandle);

Most often the _ptr variety is what you want, unless you know that

  1. you don't want to modify the mesh's copy of the value and
  2. the return value is small-ish (meaning return-by-value will be efficient)

Iterators and Circulators

The second group of changes is to the iterators and circulators. The iterators/circulators remain value types (structs) in the D port.

Use iter.val or iter.ptr instead of *iter

Since D has no equivalent for operator*, the D port uses properties to dereference an iterator. The .val attribute dereferences by value and .ptr returns a pointer to the item referred to by the iterator.

Use of iter.handle must be explicit

The original C++ included implicit conversions to the iterator's handle_type. For circulators there was additionally an implicit conversion to bool to indicate when one cycle has been completed. D doesn't have implicit conversions so those have been replaced with explicit attributes, .handle and .is_active.

C++:

   VertexVertexIterT<Mesh> v_it = mesh.vv_iter();
   for(; v_it; ++v_it) {
       Point p = mesh.point(v_it);
       ...
   }

D:

   auto v_it = mesh.vv_iter;
   for(; v_it.is_active; ++v_it) {
       Point p = mesh.point(v_it.handle);
       ...
   }

foreach also works

Foreach on iterators and circulators gives you sequential access to the .handle property of the iterator. Modification of the handle is forbidden, but modification of the attributes accessed through those handles should be ok (e.g. changing the Point associated with a vertex handle is fine).

C++:

   VertexVertexIterT<Mesh> v_it = mesh.vv_iter();
   for(; v_it; ++v_it) {
       mesh.point(v_it)[0] += 0.1;
       ...
   }

D:

   foreach(vh; mesh.vv_iter) {
       mesh.point_ptr(vh).x += 0.1;
       ...
   }

Excessive Overloading

In the C++ version some methods like status and is_valid_handle have overloads for all four handle types (VertexHandle , HalfedgeHandle, EdgeHandle, and FaceHandle). In my opinion this makes the code harder to maintain and more error prone. When you've got several handle variables sitting around it's easy to accidentally pass the wrong one.

Example:

   foreach(h_it; mesh.halfedges_begin) {
      HalfedgeHandle hh = h_it.handle;
      VertexHandle vh = mesh.from_vertex_handle(hh);
      mesh.status_ptr(hh).set_tagged = true; //oops should have been vh!
   }

With all the overloads, this will pass by unnoticed by the compiler. So instead I've provided handle-specific versions of these functions. Since you know you're trying to access the vertex status when you write that code, you can make that explicit by using vstatus_ptr instead of the generic status_ptr. Then the above code will generate a compilation error as hoped for. If you're writing more generic handle manipulation code, then the overloads are still there for that.