Skip to content

Commit

Permalink
Merge pull request #45 from oberbichler/feature/multipatch
Browse files Browse the repository at this point in the history
Multipatch support
  • Loading branch information
oberbichler authored Mar 8, 2021
2 parents b653b56 + 5864ce6 commit b068b67
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 52 deletions.
56 changes: 40 additions & 16 deletions Bowerbird/Components/PathfinderComponents/ConstructPathfinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,28 @@ protected override void SolveInstance(IGH_DataAccess DA)
if (!DA.GetData(3, ref stepSize)) return;
if (!DA.GetData(4, ref maxPoints)) return;

BrepFace face;

if (brep.Faces.Count > 1)
throw new Exception("Multipatches not yet supported");
{
if (StartPointType == StartPointTypes.UV)
throw new Exception("UV coordinates not supported for multipatches");

brep.ClosestPoint((Point3d)startingPoint, out var _, out var ci, out var _, out var _, 0, out var _);

if (ci.ComponentIndexType == ComponentIndexType.BrepFace)
face = brep.Faces[ci.Index];
else if (ci.ComponentIndexType == ComponentIndexType.BrepEdge)
{
var edge = brep.Edges[ci.Index];
var faceIndex = edge.AdjacentFaces()[0];
face = brep.Faces[faceIndex];
}
else
throw new Exception();
}
else
face = brep.Faces[0];


// --- Execute
Expand All @@ -57,19 +77,20 @@ protected override void SolveInstance(IGH_DataAccess DA)

brep = brep.DuplicateBrep();

var face = brep.Faces[0];

// normalize parameter space. This allows hard-coded tolerances.
face.SetDomain(0, new Interval(0, 1)).AssertTrue();
face.SetDomain(1, new Interval(0, 1)).AssertTrue();
// Normalize parameter space. This allows hard-coded tolerances.
foreach (var f in brep.Faces)
{
f.SetDomain(0, new Interval(0, 1)).AssertTrue();
f.SetDomain(1, new Interval(0, 1)).AssertTrue();
}

var surface = face.UnderlyingSurface();

Vector2d uv;

if (StartPointType == StartPointTypes.UV)
{
// convert UV to normalized parameter space
// Convert UV to normalized parameter space
var u = face.Domain(0).NormalizedParameterAt(startingPoint.X);
var v = face.Domain(1).NormalizedParameterAt(startingPoint.Y);

Expand All @@ -82,7 +103,8 @@ protected override void SolveInstance(IGH_DataAccess DA)
{
var sample = (Point3d)startingPoint;

face.ClosestPoint(sample, out double u, out double v);
if (!face.ClosestPoint(sample, out double u, out double v))
throw new Exception("Projection failed");

// If untrimmed CP is outside boundaries -> compute boundary CP
if (face.IsPointOnFace(u, v) == PointFaceRelation.Exterior)
Expand Down Expand Up @@ -129,20 +151,22 @@ protected override void SolveInstance(IGH_DataAccess DA)

if (path.Type.HasFlag(Path.Types.First))
{
var pathfinder = Pathfinder.Create(path, face, uv, false, stepSize, tolerance, maxPoints);

var curve = new PolylineCurve(pathfinder.Parameters);
foreach (var pathfinder in Pathfinder.Create(path, face, uv, false, stepSize, tolerance, maxPoints))
{
var curve = new PolylineCurve(pathfinder.Parameters);

curves.Add(CurveOnSurface.Create(surface, curve));
curves.Add(CurveOnSurface.Create(pathfinder.Face.UnderlyingSurface(), curve));
}
}

if (path.Type.HasFlag(Path.Types.Second))
{
var pathfinder = Pathfinder.Create(path, face, uv, true, stepSize, tolerance, maxPoints);

var curve = new PolylineCurve(pathfinder.Parameters);
foreach (var pathfinder in Pathfinder.Create(path, face, uv, true, stepSize, tolerance, maxPoints))
{
var curve = new PolylineCurve(pathfinder.Parameters);

curves.Add(CurveOnSurface.Create(surface, curve));
curves.Add(CurveOnSurface.Create(pathfinder.Face.UnderlyingSurface(), curve));
}
}

// --- Output
Expand Down
3 changes: 3 additions & 0 deletions Bowerbird/Curvature/CurveOnSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ public Curve ToCurve(double tolerance)
{
var curve = Surface.Pushup(Curve, tolerance);

if (curve == null)
return null;

return curve.IsValid ? curve : null;
}

Expand Down
4 changes: 4 additions & 0 deletions Bowerbird/Curvature/IBoundary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ namespace Bowerbird.Curvature
{
interface IBoundary
{
BrepFace AdjacentFace { get; }

Vector3d AdjacentTangent { get; }

bool Clip(Vector2d a, ref Vector2d b);
}
}
144 changes: 120 additions & 24 deletions Bowerbird/Curvature/Pathfinder.cs
Original file line number Diff line number Diff line change
@@ -1,55 +1,147 @@
using Rhino.Geometry;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Bowerbird.Curvature
{
public class Pathfinder
{
public BrepFace Face { get; private set; }

public List<Point3d> Parameters { get; private set; }

public List<Point3d> Points { get; private set; }

public Pathfinder(List<Point3d> parameters, List<Point3d> points)
public Pathfinder(BrepFace face, List<Point3d> parameters, List<Point3d> points)
{
Face = face;
Parameters = parameters;
Points = points;
}

public static Pathfinder Create(Path path, BrepFace face, Vector2d uv, bool type, double stepSize, double tolerance, int maxPoints)
struct Task
{
var parameters = new List<Point3d>();
var points = new List<Point3d>();
public Task(BrepFace face, Vector2d parameter, Point3d location, Vector3d direction)
{
Face = face;
Parameter = parameter;
Location = location;
Direction = direction;
}

public BrepFace Face;

public Vector2d Parameter;

parameters.Add(new Point3d(uv.X, uv.Y, 0));
points.Add(face.PointAt(uv.X, uv.Y));
public Point3d Location;

var direction = path.InitialDirection(face, uv, type);
public Vector3d Direction;
}

if (direction.IsZero)
return new Pathfinder(parameters, points);
private static void AddTask(Queue<Task> tasks, BrepFace adjacentFace, Point3d location, Vector3d direction)
{
if (adjacentFace == null || !adjacentFace.ClosestPoint(location, out var newU, out var newV))
return;

IBoundary boundary;
var uv = new Vector2d(newU, newV);
tasks.Enqueue(new Task(adjacentFace, uv, location, direction));
}

public static List<Pathfinder> Create(Path path, BrepFace face, Vector2d uv, bool type, double stepSize, double tolerance, int maxPoints)
{
var tasks = new Queue<Task>();
var results = new List<Pathfinder>();

if (face.IsSurface)
// Initial face
{
var surface = face.UnderlyingSurface();
boundary = UntrimmedBoundary.Create(surface);
var parameters = new List<Point3d>();
var points = new List<Point3d>();

parameters.Add(new Point3d(uv.X, uv.Y, 0));
points.Add(face.PointAt(uv.X, uv.Y));

var direction = path.InitialDirection(face, uv, type);

if (direction.IsZero)
return new List<Pathfinder>();

IBoundary boundary;

if (face.IsSurface)
boundary = UntrimmedBoundary.Create(face);
else
boundary = TrimmedBoundary.Create(face);

// First branch
{
var endDirection = FindPath(parameters, points, path, face, uv, direction, boundary, stepSize, tolerance, maxPoints);

results.Add(new Pathfinder(face, parameters, points));

var endLocation = points[points.Count - 1];
var adjacentFace = boundary.AdjacentFace;

AddTask(tasks, adjacentFace, endLocation, endDirection);
}

parameters.Reverse();
points.Reverse();

// Second branch
{
var endDirection = FindPath(parameters, points, path, face, uv, -direction, boundary, stepSize, tolerance, maxPoints);

results.Add(new Pathfinder(face, parameters, points));

var endLocation = points[points.Count - 1];
var adjacentFace = boundary.AdjacentFace;

AddTask(tasks, adjacentFace, endLocation, endDirection);
}

maxPoints -= points.Count;
}
else
boundary = TrimmedBoundary.Create(face);

FindPath(parameters, points, path, face, uv, direction, boundary, stepSize, tolerance, maxPoints);
// Adjacent faces

while (tasks.Count != 0)
{
var task = tasks.Dequeue();

var parameters = new List<Point3d>();
var points = new List<Point3d>();

parameters.Add(new Point3d(task.Parameter.X, task.Parameter.Y, 0));
points.Add(task.Location);

parameters.Reverse();
points.Reverse();
IBoundary boundary;

FindPath(parameters, points, path, face, uv, -direction, boundary, stepSize, tolerance, maxPoints);
if (task.Face.IsSurface)
boundary = UntrimmedBoundary.Create(task.Face);
else
boundary = TrimmedBoundary.Create(task.Face);

return new Pathfinder(parameters, points);
var endDirection = FindPath(parameters, points, path, task.Face, task.Parameter, task.Direction, boundary, stepSize, tolerance, maxPoints);

// Skip empty paths
if (points.Count < 2)
continue;

results.Add(new Pathfinder(task.Face, parameters, points));

var endLocation = points[points.Count - 1];
var adjacentFace = boundary.AdjacentFace;

AddTask(tasks, adjacentFace, endLocation, endDirection);

maxPoints -= points.Count;
}

return results;
}

private static void FindPath(List<Point3d> parameters, List<Point3d> points, Path path, Surface surface, Vector2d uv, Vector3d direction, IBoundary boundary, double stepSize, double tolerance, int maxPoints)
private static Vector3d FindPath(List<Point3d> parameters, List<Point3d> points, Path path, Surface surface, Vector2d uv, Vector3d direction, IBoundary boundary, double stepSize, double tolerance, int maxPoints)
{
var tolerance2 = tolerance * tolerance;

Expand Down Expand Up @@ -91,13 +183,15 @@ private static void FindPath(List<Point3d> parameters, List<Point3d> points, Pat

// Update direction

direction = x - points[points.Count - 1];
var newDirection = x - points[points.Count - 1];

// Break if no progress in geometry space

if (direction.SquareLength < tolerance2)
if (newDirection.SquareLength < tolerance2)
break;

direction = newDirection;

// Add point

parameters.Add(new Point3d(uv.X, uv.Y, 0));
Expand All @@ -108,6 +202,8 @@ private static void FindPath(List<Point3d> parameters, List<Point3d> points, Pat
if (isBoundary)
break;
}

return direction;
}
}
}
4 changes: 4 additions & 0 deletions Bowerbird/Curvature/PrincipalCurvature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ public bool Compute(Surface surface, double u, double v)
D1 = K12 * A1 + (K1 - K11) * A2;
D1 /= D1.Length;

Debug.Assert(D1.IsValid);

D2 = (K2 - K22) * A1 + K21 * A2;
D2 /= D2.Length;

Debug.Assert(D1.IsValid);

return true;
}

Expand Down
15 changes: 6 additions & 9 deletions Bowerbird/Curvature/TrimmedBoundary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class TrimmedBoundary : IBoundary

public BrepFace AdjacentFace { get; private set; }

public Vector3d AdjacentTangent { get; private set; }

private TrimmedBoundary(BrepFace face)
{
_face = face;
Expand Down Expand Up @@ -47,16 +49,11 @@ public bool Clip(Vector2d a, ref Vector2d b)

BoundingEdge = trim.Edge;

foreach (var adjacentFaceIndex in trim.Edge.AdjacentFaces())
{
// Skip current face
if (adjacentFaceIndex == _face.FaceIndex)
continue;
var adjacentFaces = trim.Edge.AdjacentFaces();

AdjacentFace = adjacentFaces.Length == 1 ? null : _face.Brep.Faces[adjacentFaces[0] == _face.FaceIndex ? adjacentFaces[1] : adjacentFaces[0]];

// Take first adjacent face (assuming Edge.FaceCount = 1 or 2)
AdjacentFace = trim.Brep.Faces[adjacentFaceIndex];
break;
}
AdjacentTangent = trim.TangentAt(intersection.ParameterA);

return true;
}
Expand Down
Loading

0 comments on commit b068b67

Please sign in to comment.