With the code below I created a function to draw a 3D chain model in C# using the helix toolkit. This works exactly how I wanted to but... now I'm breaking my head around a good approach to draw the chainlinks in specific direction, from a startpoint to a endpoint, but I didn't come much further the last week. I know I need to work with vector multiplication or scalars but I need some guidance to right topic to solve my problem.
using HelixToolkit.SharpDX.Core;
using HelixToolkit.Wpf.SharpDX;
using SharpDX;
namespace RapiD.Geometry.Models
{
public partial class ChainLink3D : GeometryBase3D
{
[ObservableProperty]
float radius;
[ObservableProperty]
float width;
[ObservableProperty]
float diameter;
[ObservableProperty]
float length;
[ObservableProperty]
int copies;
[ObservableProperty]
ObservableCollection<Element3D> elements;
public ChainLink3D(float diameter, float width, float length, int copies)
{
this.width = width;
this.length = length;
this.diameter = diameter;
this.copies = copies;
this.elements= new ObservableCollection<Element3D>();
OriginalMaterial = PhongMaterials.Chrome;
DrawChainLink();
}
public void DrawChainLink()
{
MeshBuilder meshBuilder = new MeshBuilder();
float radius = (width - diameter) / 2;
float trans = 0f;
float translate = length + (radius * 2) - diameter;
float yoffset = 0;
int segments = 10;
float interval = 180 / segments;
int numOfCopies = copies;
float startPoint = radius - (diameter / 2);
float endPoint = -length -radius + (diameter / 2);
Vector3 startVector = new Vector3(-300, 200f, 0);
Vector3 endVector = new Vector3(300, 500, 0);
Vector3 direction = Vector3.Normalize (endVector - startVector);
//The for loop is drawing the chainlink
for (int j = 0; j < numOfCopies; j++)
{
List<Vector3> single_chain_link = new List<Vector3>();
for (float i = 0; i <= 360; i += interval)
{
if (i > 180)
yoffset = -length;
else
yoffset = 0;
float a = i * MathF.PI / 180;
float x = radius * MathF.Cos(a);
float y = radius * MathF.Sin(a) + yoffset + trans;
Vector3 vec = new Vector3(x, y, 0);
//Rotates every second chainlink
if (j % 2 == 1)
vec =new Vector3(0, y, x);
vec += startVector;
//vec *= direction;
single_chain_link.Add(vec);
}
// this three are a reference for a new example direction in which I want to draw the chain link to
meshBuilder.AddSphere(Vector3.Zero, 5, 10, 10);
meshBuilder.AddSphere(startVector, 5, 10, 10);
meshBuilder.AddSphere(endVector, 5, 10, 10);
meshBuilder.AddTube(single_chain_link, diameter, 10, true);
meshBuilder.AddArrow(new Vector3(0, startPoint + trans, 0), new Vector3(0, endPoint + trans, 0), 2, 10);
elements.Add(new Element3D(new Vector3(0, startPoint + trans, 0), new Vector3(0, endPoint + trans, 0)));
//single_chain_link.OrderByDescending(x => x.X);
MeshGeometry = meshBuilder.ToMeshGeometry3D();
trans -= translate;
}
}
}
}
I did successfully draw the chain form a specific startpoint, but I want to draw the elements from the given startpoint to a endposition.
You should be using a transformation to rotate and/or move your model to the correct orientation.
To create a rotation matrix from a direction it is useful to know some linear algebra. Notably that the cross product between two vectors result in a vector orthogonal to both. And that a rotation matrix is not really anything more than three ortogonal axes. So you can do something like the following pseudo code
If you are using System.Numerics there is the Matrix4x4.CreateLookAt that does more or less this.
Once you have a matrix you can just transform your model to rotate it in whatever direction you want. Note that it is common, at least for me, to mix up directions and end up with something that is of by 90 degrees, or some other error. It does not help that different libraries can use some different conventions. My best solution is to do things in small steps and verify that the result is as you expect it to be.