protected virtual ToolpathPreviewJoint GenerateMiterJoint(Segment3d segmentBefore, Segment3d segmentAfter, TPrintVertex printVertex, ToolpathPreviewMesh mesh)
        {
            var averageDirection = (segmentBefore.Direction + segmentAfter.Direction).Normalized;
            var scaleFactor      = 1 / segmentBefore.Direction.Dot(averageDirection);

            var frame = new Frame3f(printVertex.Position);

            frame.AlignAxis(1, ToVector3f(averageDirection));

            var joint = new ToolpathPreviewJoint();

            joint.InTop = joint.OutTop = mesh.AddVertex(vertexFactory(printVertex,
                                                                      frame.FromFrameP(DiamondCrossSection.Top(printVertex.Dimensions)), brightnessMax));

            joint.InRight = joint.OutRight = mesh.AddVertex(vertexFactory(printVertex,
                                                                          frame.FromFrameP(DiamondCrossSection.Right(printVertex.Dimensions)), brightnessMin));

            joint.InBottom = joint.OutBottom = mesh.AddVertex(vertexFactory(printVertex,
                                                                            frame.FromFrameP(DiamondCrossSection.Bottom(printVertex.Dimensions)), brightnessMax));

            joint.InLeft = joint.OutLeft = mesh.AddVertex(vertexFactory(printVertex,
                                                                        frame.FromFrameP(DiamondCrossSection.Left(printVertex.Dimensions)), brightnessMin));

            return(joint);
        }
        public ToolpathPreviewMesh Generate(LinearToolpath3 <TPrintVertex> toolpath, Func <TPrintVertex, Vector3d, float, ToolpathPreviewVertex> vertexFactory)
        {
            this.vertexFactory = vertexFactory;

            var mesh = new ToolpathPreviewMesh();

            var joints = new ToolpathPreviewJoint[toolpath.VertexCount];

            Segment3d?segmentBeforeJoint = null;

            for (int i = 0; i < toolpath.VertexCount; i++)
            {
                Segment3d?segmentAfterJoint = null;

                if (i < toolpath.VertexCount - 1)
                {
                    segmentAfterJoint = new Segment3d(toolpath[i].Position, toolpath[i + 1].Position);
                }

                if (segmentBeforeJoint == null || segmentAfterJoint == null)
                {
                    joints[i] = GenerateButtJoint(segmentBeforeJoint, segmentAfterJoint, toolpath[i], mesh);
                }
                else
                {
                    var angleRad = SignedAngleRad(segmentBeforeJoint.Value.Direction.xy, segmentAfterJoint.Value.Direction.xy);

                    if (Math.Abs(angleRad) > miterThreshold)
                    {
                        joints[i] = GenerateBevelJoint(segmentBeforeJoint.Value, segmentAfterJoint.Value, toolpath[i], mesh);
                    }
                    else
                    {
                        joints[i] = GenerateMiterJoint(segmentBeforeJoint.Value, segmentAfterJoint.Value, toolpath[i], mesh);
                    }
                }

                segmentBeforeJoint = segmentAfterJoint;
            }

            AddEdges(joints, mesh);

            return(mesh);
        }