Brep Centroid without using AreaMassProperties

Dear forum,

After some debugging I have come to realise that computing the centroid of a brep using

AreaMassProperties.Compute

takes a lot of time, even though I only set firstMoment to true.

I am wondering if there is an alternative way to AreaMassProperties for getting the centroid of a brep? The Brep is very spatial, thus using the bounding box is not an option.

Thanks,
david

As Plan B : Try converting the Brep(s) to Mesh(es) and then use something like this:

public Point3d MeshCentroid(Mesh M){
    M.Faces.ConvertQuadsToTriangles();

    double meshVolume = 0;
    Point3d temp = new Point3d (0, 0, 0);

    var MTV = M.TopologyVertices;
    var MF = M.Faces;

    for(int i = 0; i < MF.Count;i++){
      int[] adjV = MTV.IndicesFromFace(i);
      Point3d[] V = new Point3d[adjV.Length];
      for(int j = 0; j < adjV.Length;j++) V[j] = MTV[adjV[j]];

      Point3d center = (V[0] + V[1] + V[2]) / 4;
      double volume = DotProduct((Vector3d) V[0], CrossProduct((Vector3d) V[1], (Vector3d) V[2])) / 6;
      meshVolume += volume;
      temp += center * volume;
    }

    return temp / meshVolume;
  }

  public double DotProduct(Vector3d v1, Vector3d v2){
    double dot = (v1.X * v2.X) + (v1.Y * v2.Y) + (v1.Z * v2.Z);
    return dot;
  }

  public Vector3d CrossProduct(Vector3d V1, Vector3d V2){
    Vector3d cross = new Vector3d (
      (V1.Y * V2.Z - V1.Z * V2.Y),
      (V1.Z * V2.X - V1.X * V2.Z),
      (V1.X * V2.Y - V1.Y * V2.X));
    return cross;
  }

Hi @DavAndLar,

Use the à la carte version of AreaMassProperties.Compute. Specify true for area and firstMoments, false for the other moments.

– Dale

Hi @dale, that’s what I’m doing atm. However, I found that it was even ok specify false for area. But still, it takes a while to compute, that’s why I was looking for an alternative.

best,
david

I tried your code @PeterFotiadis and it returns a Null Point. Any idea of why that is?

-david

Quite strange (given a valid and manifold Mesh as a result from converting a valid and manifold Brep). Anyway post (in R5 format) the input Brep (or Breps).

Atm I’m just trying out the code on a planar rectangle, i.e. no fancy Brep to be shared.

This is how I’ve implemented the code:

private void RunScript(Brep x, ref object a)
    {

        Mesh[] myMesh = Rhino.Geometry.Mesh.CreateFromBrep(x);
        a = MeshCentroid(myMesh[0]);
    }

    public Point3d MeshCentroid(Mesh M){
    M.Faces.ConvertQuadsToTriangles();

    double meshVolume = 0;
    Point3d temp = new Point3d (0, 0, 0);

    var MTV = M.TopologyVertices;
    var MF = M.Faces;

    for(int i = 0; i < MF.Count;i++){
      int[] adjV = MTV.IndicesFromFace(i);
      Point3d[] V = new Point3d[adjV.Length];
      for(int j = 0; j < adjV.Length;j++) V[j] = MTV[adjV[j]];

      Point3d center = (V[0] + V[1] + V[2]) / 4;
      double volume = DotProduct((Vector3d) V[0], CrossProduct((Vector3d) V[1], (Vector3d) V[2])) / 6;
      meshVolume += volume;
      temp += center * volume;
    }

    return temp / meshVolume;
  }

  public double DotProduct(Vector3d v1, Vector3d v2){
    double dot = (v1.X * v2.X) + (v1.Y * v2.Y) + (v1.Z * v2.Z);
    return dot;
  }

  public Vector3d CrossProduct(Vector3d V1, Vector3d V2){
    Vector3d cross = new Vector3d (
      (V1.Y * V2.Z - V1.Z * V2.Y),
      (V1.Z * V2.X - V1.X * V2.Z),
      (V1.X * V2.Y - V1.Y * V2.X));
    return cross;
  }

Code provided works on closed Meshes (i.e. where Volume has meaning). Spot the meshVolume - as double - used.