I’m using C# to try to find the lowest and highest face of a given brep, as measured by their centroid z value.
@DavidRutten posted this as a scripted VB component for GH:
Private Sub RunScript(ByVal B As Brep, ByRef lowest As Object, ByRef highest As Object)
'Validate input
If (B Is Nothing) Then Return
'We'll iterate over all the faces and simultaneously remember the lowest and highest so far.
Dim lowPoint As Double = Double.MaxValue
Dim highPoint As Double = Double.MinValue
For Each face As BrepFace In B.Faces
'Convert the Face to a new Brep.
Dim faceBrep As Brep = face.DuplicateFace(True)
'Compute the Area Mass Properties of the brep
Dim ap As AreaMassProperties = AreaMassProperties.Compute(faceBrep)
'If the Area centroid is a new low, assign the brep to the lowest output.
If (ap.Centroid.Z < lowPoint) Then
lowPoint = ap.Centroid.Z
lowest = faceBrep
End If
'If the Area centroid is a new high, assign the brep to the highest output.
If (ap.Centroid.Z > highPoint) Then
highPoint = ap.Centroid.Z
highest = faceBrep
End If
Next
End Sub
I’ve tried to replicate a command in C#, but only got so far. I’m looking for help to complete the following code. I’m certain I’m not using the if/else statements correctly (just started learning c# 3 weeks ago):
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
ObjRef obj_ref;
var rc = RhinoGet.GetOneObject("Select brep", false, ObjectType.Brep, out obj_ref);
if (rc != Result.Success)
return rc;
var brep = obj_ref.Brep();
//double lowpoint = double.MaxValue;
//double highpoint = double.MinValue;
foreach (var face in brep.Faces)
{
var faceBrep = face.DuplicateFace(true);
//if (ap.Centroid.Z < lowPoint)
//lowPoint = ap.Centroid.Z
//lowest = faceBrep
//else (ap.Centroid.Z > highPoint)
//highPoint = ap.Centroid.Z
//highest = faceBrep
Point3d ap = AreaMassProperties.Compute(faceBrep).Centroid;
TextDot textdot = new TextDot("hello", ap);
doc.Objects.AddTextDot(textdot);
}
return Result.Success;
}
Here is where I’m at now. I’d like to label the top faces in the order that they’ve been selected. To do this I don’t think I can use a foreach loop, can I?
And are you able to use the .SetUserString method on BrepFaces?
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
const ObjectType geometryFilter = ObjectType.Brep;
GetObject go = new GetObject();
go.GetMultiple(1, 0);
go.GeometryFilter = geometryFilter;
//I'D LIKE TO HAVE THE TOP FACES LABELED WITH THEIR ORDER OF SELECTION, SO NEED TO USE A 'PROPER' ITERATOR INSTEAD OF foreach, CORRECT?
//for (var i = 0; i < --HOW TO MAKE A LIST FROM GetObject??-- .Count; i++)
foreach (var i in go.Objects())
{
ObjectAttributes attributes = new ObjectAttributes();
attributes.ObjectColor = Color.CadetBlue;
var brep = i.Brep();
var rhino_object = i.Object();
var current_layer_index = doc.Layers.CurrentLayerIndex;
rhino_object.Attributes.LayerIndex = current_layer_index;
rhino_object.Attributes.Name = "CLT";
var defaultkey = "key";
var defaultval = "value";
rhino_object.Attributes.SetUserString(defaultkey, defaultval);
rhino_object.CommitChanges();
var format = string.Format("F{0}", doc.DistanceDisplayPrecision);
if (brep != null)
RhinoApp.WriteLine("Faces:{0}, Area:{1}, Volume:{2}",
brep.Faces.Count,
brep.GetArea().ToString(format),
brep.GetVolume().ToString(format)
);
BrepFace topFace = brep.Faces.OrderByDescending(f => AreaMassProperties.Compute(f).Centroid.Z).ToList()[0];
doc.Objects.AddSurface(topFace);
Point3d center = AreaMassProperties.Compute(topFace).Centroid;
//HOW TO ASSIGN USER STRINGS TO BREPFACES? ERROR SAYS THAT THERE IS NO ACCESSIBLE EXTENSION METHOD...
//topFace.Attributes.SetUserString(defaultkey, defaultval);
//topFace.CommitChanges();
//var str = string.Format("Face #", i.ToString());
//TextDot dot = new TextDot(str, center[i]);
//doc.Objects.AddTextDot(dot,attributes);
TextDot textdot = new TextDot("Top Face", center);
doc.Objects.AddTextDot(textdot, attributes);
}
return Result.Success;
I dont think you can label BrepFaces individually, since the UserText is part of the Rhino object while the BrepFace is part of geometry(Brep, Curve etc). There is a differentiation between geometry and the meta information saved in the object, which contains both information and geometry.
That said, you can add the face itself to the document as a single-faced brep, place a textdot on the centroid or maybe save the face id as a userstring to the brep object and get it from there.
Objects() returns an array. .Count is for lists, .Length is for arrays
Looks like I may have mispoken. If you look at the example I referenced above, I’m attaching user data to the underlying surface of a BrepFace. See if that works any better.