here is the full code in C# script in grasshopper ,

reverseface direction test.gh (11.3 KB) surface direction test.3dm (126.6 KB)

```
// list of points to anchor the vectors in the middle of the face
List<Point3d> a = new List<Point3d>();
// list of the vectors in U-direction of the face
List<Vector3d> b = new List<Vector3d>();
// surface derivetives
Vector3d[] d;
// point at the mid of the domain
Point3d p;
List<Brep> breps = new List<Brep>();
foreach (BrepFace f in x.Faces)
{
// extract the boundary
var c = f.Loops[0].To3dCurve();
// find the center of the boundary
var amp = AreaMassProperties.Compute(c, 0.01);
// evaluatet the face in the middle
double u = f.Domain(0).Mid;
double v = f.Domain(1).Mid;
f.Evaluate(u, v, 1, out p, out d);
// normal of the face (face is assumed to be planar)
Vector3d norm = f.NormalAt(u, v);
if (norm.IsParallelTo(top, Rhino.RhinoDoc.ActiveDoc.ModelAngleToleranceRadians) != 0)
{
//do not change the faces that are perpendicular to the 'top' vector
breps.Add(f.DuplicateFace(false));
continue;
}
// we need the U direction of the face to be consisten with the input vecotr 'top'
// top vector is Z axis of the CNC XY plane
Vector3d currectU = Vector3d.CrossProduct(top, norm);
// if the face U-vector is not in the same direction of the milling direction then
// reverse the face U direction
if (currectU * d[0] < 0)
{
// surface with reverse U
var s = f.Reverse(0, true);
// create a new trimmed surface with the boundary of the f and surface s
Brep bf = Brep.CreateTrimmedSurface(f, s, 0.01);
// add bf to the list
breps.Add(bf);
}else{
// U-direction of the face was OK! so we add the face to the list
breps.Add(f.DuplicateFace(false));
}
// save center point to list a
a.Add(amp.Centroid);
// save the original u-vector in list b
b.Add(d[0]);
}
// pass the data to output
A = a;
B = b;
C = breps;
```