Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapting a mesh to a 3D Curve #3729

Open
Doomerdinger opened this issue Nov 21, 2024 · 1 comment
Open

Adapting a mesh to a 3D Curve #3729

Doomerdinger opened this issue Nov 21, 2024 · 1 comment

Comments

@Doomerdinger
Copy link

I am attempting to deform a mesh such that it connects with a line in 3D space, with some constraints.
For context if anyone is familiar with the dental domain, I am trying to attach a tooth to a margin line.

Currently I am selecting/and or creating vertices on the mesh and dragging them to points on the line, applying a laplacian deformation.
I won't get in to how I select the points on the mesh or how I determine exactly where I am dragging them to, but I can if that information seems like it may be relevant.

Image
My current modifications. You can see a large amount of concavity in this region.
Image
The input mesh I am modifying.
Image
An example of what may be closer to ideal. The mesh maintains a more convex shape where possible, before ultimately becoming concave because the line in space I am fitting to forces it.

Before I continue down the path of something more custom, any chance there are existing tips/tricks/examples to push my results more to what I desire?

@Grantim
Copy link
Contributor

Grantim commented Nov 22, 2024

Hello!

One thing you can try is to use FreeFormBestFit

/// Class to accumulate source and target points for free form alignment
/// Calculates best Free Form transform to fit given source->target deformation
/// origin ref grid as box corners ( resolution parameter specifies how to divide box )
class MRMESH_CLASS FreeFormBestFit
{
public:
/// initialize the class, compute cached values and reserve space for matrices
MRMESH_API FreeFormBestFit( const Box3d& box, const Vector3i& resolution = Vector3i::diagonal( 2 ) );
/// add pair of source and target point to accumulator
MRMESH_API void addPair( const Vector3d& src, const Vector3d& tgt, double w = 1.0 );
void addPair( const Vector3f& src, const Vector3f& tgt, float w = 1.0f ) { addPair( Vector3d( src ), Vector3d( tgt ), double( w ) ); }

To construct this class you need to path "tooth" bounding box and resolution of free form transformer

Then you need to add pairs of points to fit, I suggest you to make Polyline3 from "margin" line

/// polyline that stores points of type V
/// \ingroup PolylineGroup
template<typename V>
struct Polyline
{
public:
PolylineTopology topology;
Vector<V, VertId> points;
Polyline() = default;
/// creates polyline from 2D contours, 3D polyline will get zero z-component
MRMESH_API Polyline( const Contours2f& contours );
/// creates polyline from 3D contours, 2D polyline will lose z-component
MRMESH_API Polyline( const Contours3f& contours );

And project vertices of the polyline on mesh with

/**
* \brief computes the closest point on mesh (or its region) to given point
* \param upDistLimitSq upper limit on the distance in question, if the real distance is larger than the function exits returning upDistLimitSq and no valid point
* \param xf mesh-to-point transformation, if not specified then identity transformation is assumed
* \param loDistLimitSq low limit on the distance in question, if a point is found within this distance then it is immediately returned without searching for a closer one
* \param validFaces if provided then only faces from there will be considered as projections
* \param validProjections if provided then only projections passed this test can be returned
*/
[[nodiscard]] MRMESH_API MeshProjectionResult findProjection( const Vector3f & pt, const MeshPart & mp,
float upDistLimitSq = FLT_MAX,
const AffineXf3f * xf = nullptr,
float loDistLimitSq = 0,
const FacePredicate & validFaces = {},
const std::function<bool(const MeshProjectionResult&)> & validProjections = {} );

So for each point of "margin" you will have corresponding point on "tooth".

Add these pairs to FreeFormBestFit and find best transformation:

/// finds best grid points positions to align source points to target points
[[nodiscard]] MRMESH_API std::vector<Vector3f> findBestDeformationReferenceGrid();

Then you need to apply it to "tooth" like this (it is example in python, but c++ code should be similar)

// Class for deforming mesh using trilinear interpolation
class FreeFormDeformer
{
public:
// Only set mesh ref
MRMESH_API FreeFormDeformer( VertCoords& coords, const VertBitSet& valid );
// Parallel calculates all points normed positions
// sets ref grid by initialBox, if initialBox is invalid use mesh bounding box instead
MRMESH_API void init( const Vector3i& resolution = Vector3i::diagonal( 2 ), const Box3f& initialBox = Box3f() );
// Updates ref grid point position
MRMESH_API void setRefGridPointPosition( const Vector3i& coordOfPointInGrid, const Vector3f& newPos );
// Gets ref grid point position
MRMESH_API const Vector3f& getRefGridPointPosition( const Vector3i& coordOfPointInGrid ) const;
// Parallel apply updated grid to all mesh points
// ensure updating render object after using it
MRMESH_API void apply() const;

void setAllRefGridPositions( const std::vector<Vector3f>& refPoints ) { refPointsGrid_ = refPoints; }

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants