首页 > 其他分享 >Eyeshot:使用 MultiFastMesh 进行 EDM 仿真

Eyeshot:使用 MultiFastMesh 进行 EDM 仿真

时间:2024-04-05 13:33:51浏览次数:32  
标签:Vector3D MultiFastMesh EDM Eyeshot int step steps new data

使用 MultiFastMesh 进行 EDM 仿真

在本文中,使用Eyeshot探索新的MultiFastMesh实体在现实场景中的实际应用,特别关注为线切割 EDM 模拟创建快速高效的 3D 可视化。

在深入了解详细信息之前,我们强烈建议您阅读有关 MultiFastMesh 的介绍性文章。

MultiFastMesh提供了一种将代表每个模拟步骤的所有网格体批处理为单个实体的方法,同时提供了切换各个子网格体可见性的可能性。这使我们能够将所有网格分组为一个实体,并随着模拟的进行逐渐打开每个子网格的可见性。

在这里,您将找到继承自MultiFastMesh 且专门用于显示线切割 EDM 模拟的实体的实现。

public class EdmSimMesh : MultiFastMesh
{
    #region Static Utils
    private static void WriteVertex(float[] vertices, int offset, Point3D point)
    {
        vertices[offset + 0] = (float)point.X;
        vertices[offset + 1] = (float)point.Y;
        vertices[offset + 2] = (float)point.Z;
    }
    private static void WriteNormal(float[] normals, int offset, Vector3D normal)
    {
        normals[offset + 0] = (float)normal.X;
        normals[offset + 1] = (float)normal.Y;
        normals[offset + 2] = (float)normal.Z;
    }
    private static Vector3D ComputeNormal(Vector3D tu, Vector3D tv)
    {
        Vector3D n;
        n = Vector3D.Cross(tu, tv);
        n.Normalize();
        return n;
    }

    private static void ComputeNormal(
        Line prev, Line step, Line next,
        out Vector3D normalAtStartPoint,
        out Vector3D normalAtEndPoint
    )
    {
        // Computes the normal at the start and end point
        // of a step (a line) given its prev and next step.

        if (step != null && prev != null && next != null)
        {
            Vector3D s0 = (step.StartPoint - prev.StartPoint).AsVector;
            s0.Normalize();
            Vector3D e0 = (next.StartPoint - step.StartPoint).AsVector;
            e0.Normalize();
            Vector3D v0 = (s0 + e0);
            v0.Normalize();

            Vector3D s1 = (step.EndPoint - prev.EndPoint).AsVector;
            s1.Normalize();
            Vector3D e1 = (next.EndPoint - step.EndPoint).AsVector;
            e1.Normalize();
            Vector3D v1 = (s1 + e1);
            v1.Normalize();

            normalAtStartPoint = ComputeNormal(v0, (step.EndPoint - step.StartPoint).AsVector);
            normalAtEndPoint = ComputeNormal(v1, (step.EndPoint - step.StartPoint).AsVector);

        }
        else// TODO
        {
            normalAtStartPoint = Vector3D.AxisX;
            normalAtEndPoint = Vector3D.AxisX;
        }
    }

    private static MultiFastMesh BuildFastMeshes(IList<Line> steps)
    {
        // Builds a mesh from a list of steps (lines)
        // as a continuous strip.

        float[] vertices = new float[steps.Count * 3 * 2]; // 2 vertices per line, 3 components per vertex
        float[] normals = new float[steps.Count * 3 * 2];
        int[] triangles = new int[(steps.Count - 1) * 2 * 3];

        for (int i = 0; i < steps.Count; i++)
        {
            int vertIdx0 = i * 3 * 2 + 0;
            int vertIdx1 = i * 3 * 2 + 3;

            // Copy the line's vertices
            WriteVertex(vertices, vertIdx0, steps[i].StartPoint);
            WriteVertex(vertices, vertIdx1, steps[i].EndPoint);

            ComputeNormal(
                i > 0 ? steps[i - 1] : null,
                steps[i],
                i >= steps.Count - 1 ? null : steps[i + 1],
                out Vector3D n0, out Vector3D n1);

            WriteNormal(normals, vertIdx0, n0);
            WriteNormal(normals, vertIdx1, n1);
        }

        for (int i = 0; i < steps.Count - 1; i++)
        {
            // Build 2 tris (ccw)
            triangles[i * 6 + 0] = (i + 0) * 2 + 0;
            triangles[i * 6 + 1] = (i + 1) * 2 + 1;
            triangles[i * 6 + 2] = (i + 0) * 2 + 1;

            triangles[i * 6 + 3] = (i + 0) * 2 + 0;
            triangles[i * 6 + 4] = (i + 1) * 2 + 0;
            triangles[i * 6 + 5] = (i + 1) * 2 + 1;
        }

        /* IMPORTANT */
        /* --------------------------------------------
         A MultiFastMesh allows ranged drawing: 
         you can specify color and visibility
         for different portions of the mesh.
         To achieve that, we must specify the 
         list of `sub-meshes`: here we are 
         saying that each quad of the strip
         we just built is a sub-mesh, for a total
         of steps.Count - 1 sub-meshes.
         With this setup, we can later ask
         the MultiFastMesh to draw only the
         sub-meshes corresponding to steps [0, N] to 
         show only the first N movements.
        -------------------------------------------- */

        IntInterval[] subMeshes = new IntInterval[steps.Count - 1];
        for (int i = 0; i < subMeshes.Length; i++)
        {
            // a sub-mesh is defined as a range of 
            // indices in the triangles array:
            // sub-mesh[i] goes from index i*6 to (i+1)*6 (2 tris)
            subMeshes[i] = new IntInterval(i * 6 + 0, i * 6 + 5);
        }

        return new MultiFastMesh(vertices, normals, triangles, subMeshes);
    }

    #endregion

    private const double PI = 3.14159265359;

    private int _currentStep = 0;
    private int _stepCount = 0;
    private Line[] _steps = null;

    public Color BaseColor = System.Drawing.Color.Gray;
    public Color HighlightColor = System.Drawing.Color.OrangeRed;

    // Used to draw some extras such as two cones
    // at the start and the end of the cutting wire
    private FastMesh _myPrivateMesh = null;
    private Point3D[] _myPoints = null;
    private Vector3D[] _myNormals = null;

    private void InitPrivateMesh(double lineLen)
    {
        Mesh cone0 = Mesh.CreateCone(lineLen * 0.1, 0.0001, Point3D.Origin, Point3D.Origin + Vector3D.AxisZ * 0.25 * lineLen, 6);
        Mesh cone1 = Mesh.CreateCone(lineLen * 0.1, 0.0001, Point3D.Origin, Point3D.Origin + Vector3D.AxisZ * 0.25 * lineLen, 6);

        cone0.Translate(0, 0, -0.5 * lineLen - 0.25 * lineLen);
        cone1.Rotate(PI, Vector3D.AxisX);
        cone1.Translate(0, 0, 0.5 * lineLen + 0.25 * lineLen);

        cone0.MergeWith(cone1, false, false);

        _myPrivateMesh = cone0.ConvertToFastMesh(false);
        _myPoints = new Point3D[_myPrivateMesh.PointArray.Length / 3];
        _myNormals = new Vector3D[_myPrivateMesh.NormalArray.Length / 3];

        for (int i = 0; i < _myPrivateMesh.PointArray.Length; i += 3)
        {
            _myPoints[i / 3] = new Point3D
            (
                _myPrivateMesh.PointArray[i + 0],
                _myPrivateMesh.PointArray[i + 1],
                _myPrivateMesh.PointArray[i + 2]
            );

            // one normal per vertex
            _myNormals[i / 3] = new Vector3D
            (
                _myPrivateMesh.NormalArray[i + 0],
                _myPrivateMesh.NormalArray[i + 1],
                _myPrivateMesh.NormalArray[i + 2]
            );
        }
    }

    /// <summary>
    /// Standard constructor.
    /// </summary>
    /// <param name="steps">A list of ordered cutting steps. Each line defines the position of the wire at that step.</param>
    /// <param name="baseColor">The color applied to the simulation mesh or null if the default color should be used. </param>
    /// <param name="highlightColor">The color applied to the latest step represented by the simulation mesh or null if the default color should be used.</param>
    public EdmSimMesh(IList<Line> steps, Color? baseColor, Color? highlightColor) : base(BuildFastMeshes(steps))
    {
        _stepCount = steps.Count;
        _steps = steps.ToArray();

        if (baseColor.HasValue) BaseColor = baseColor.Value;
        if (highlightColor.HasValue) HighlightColor = highlightColor.Value;

        InitPrivateMesh(steps.First().Length() * 2.5);
        MoveToStep(_stepCount - 1);
    }

    /// <summary>
    /// Moves the simulation to step <paramref name="n"/>, showing the result
    /// of the cutting process from step 0 to the specified step.
    /// </summary>
    /// <param name="n"> The index of the step.</param>
    public void MoveToStep(int n)
    {
        if (n < 0) throw new ArgumentException("Invalid step: step index must be positive or 0", nameof(n));
        n = Math.Min(_stepCount - 1, n);
        _currentStep = n;

        if (n == 0)
        {
            SubMeshIntervals = new List<SubMeshInterval>{ };
        }
        else if (n == 1)
        {
            SubMeshIntervals = new List<SubMeshInterval> { new SubMeshInterval(0, 0, HighlightColor) };
        }
        else
        {
            SubMeshIntervals = new List<SubMeshInterval>
            {
                new SubMeshInterval(0, n - 2, BaseColor),
                new SubMeshInterval(n - 1, n - 1, HighlightColor)
            };
        }

    }

    private void DrawEdmWire(DrawParams data, Line l)
    {
        // Draws a line representing the cutting wire
        // and 2 cones at the start and end of the wire.
        Line myl = (Line)l.Clone();
        myl.Scale(myl.MidPoint, 2.5);

        // Draw the cutting wire
        data.RenderContext.PushShader();

        data.RenderContext.SetColorWireframe(HighlightColor);
        float prev = data.RenderContext.SetLineSize(4.0f, true, false);
        data.RenderContext.DrawLine(myl.StartPoint, myl.EndPoint);
        data.RenderContext.SetLineSize(prev);

        // Draw the cones
        var transform = new Align3D(Plane.XY, new Plane(l.MidPoint, l.Tangent));

        data.RenderContext.SetShader(shaderType.NoLights);

        // Far from the optimal approach, 
        // however, the amount of vertices is
        // really low...
        data.RenderContext.DrawTriangles(

        _myPoints.Select(p =>
        {
            Point3D newP = (Point3D)p.Clone();
            newP.TransformBy(transform);
            return newP;
        }).ToArray()

        , _myNormals.Select(p =>
        {
            Vector3D newP = (Vector3D)p.Clone();
            newP.TransformBy(transform);
            return newP;
        }).ToArray());

        data.RenderContext.PopShader();
    }

    private bool _suspendExtras = false;

    public override void Draw(DrawParams data)
    {
        base.Draw(data);

        // Don't show the cutting wire in the 
        // planar reflections
        _suspendExtras |= data.PlanarReflections;

        if (!_suspendExtras)
            DrawEdmWire(data, _steps[_currentStep]);

        _suspendExtras = false;

    }
    public override void DrawForShadow(RenderParams data)
    {
        _suspendExtras = true;
        base.DrawForShadow(data);
        _suspendExtras = false;
    }

    public override void DrawForSelection(DrawForSelectionParams data)
    {
        _suspendExtras = true;
        base.DrawForSelection(data);
        _suspendExtras = false;
    }

    public override void DrawSelected(DrawParams data)
    {
        _suspendExtras = true;
        base.DrawSelected(data);
        _suspendExtras = false;
    }
}
 

以下是一个小示例,展示了如何使用EdmSimMesh:

// some settings to improve performance
design1.Rendered.ShadowMode = shadowType.None;
design1.Rendered.SilhouettesDrawingMode = silhouettesDrawingType.Never;

// Creating some geometry to build the EdmMeshes
// -----------------------------------------------------------------------------
Brep stock = Brep.CreateBox(6, 3, 1);
stock.Translate(-1.5, -1.5, 0);

Region r1 = new Region(new Circle(Plane.XY, Point2D.Origin, 1));
Region r2 = new Region(CompositeCurve.CreateRoundedRectangle(2.5, 0.7, 0.3, true));
r2.Translate(1.75, 0, 0);

Region rBot = devDept.Eyeshot.Entities.Region.Union(r1, r2)[0];
rBot.Regen(0.001);

Region rTop = (Region) rBot.Clone();
rTop.Translate(0, 0, 1);
rTop.Regen(0.001);

// Decrease/increase the argument of GetPointsByLength to
// increase/decrease the number of steps.
double subdv = 0.1;
LinearPath topPath = new LinearPath(rTop.ContourList[0].GetPointsByLength(subdv));
LinearPath botPath = new LinearPath(rBot.ContourList[0].GetPointsByLength(subdv));
topPath.LineWeight = 4.0f;
botPath.LineWeight = 4.0f;
topPath.LineWeightMethod = colorMethodType.byEntity;
botPath.LineWeightMethod = colorMethodType.byEntity;
botPath.Scale(1.3, 1.3, 1);
rBot.Scale(1.3, 1.3, 1);

List<Line> lines = new List<Line>();
for (int i = 0; i < topPath.Vertices.Length; i++)
{
    lines.Add(new Line(botPath.Vertices[i], topPath.Vertices[i]));
}
// -----------------------------------------------------------------------------

// Adding the entities to the scene
EdmSimMesh edmMesh = new EdmSimMesh(lines, Color.CadetBlue, Color.Magenta);
design1.Entities.Add(edmMesh, Color.FromArgb(255, Color.Black));
design1.Entities.Add(topPath, Color.FromArgb(160, Color.Aquamarine));
design1.Entities.Add(botPath, Color.FromArgb(160, Color.Aquamarine));
design1.Entities.Add(stock, Color.FromArgb(60, Color.DarkGray));

// You can download QuickForms (released by devDept) from NuGet.
QuickForm qkf = new QuickForm();

qkf.AddTrackBar("Step", 0, lines.Count - 1, 1, d =>
{
    int i = (int)d;
    edmMesh.MoveToStep(i);
    design1.Invalidate();
});

qkf.Show();
 

标签:Vector3D,MultiFastMesh,EDM,Eyeshot,int,step,steps,new,data
From: https://blog.csdn.net/john_dwh/article/details/137253937

相关文章

  • CAD开发不二之选:Eyeshot 2024 SDK
    ProductDesignTheprocessofcreatingnewproductsordevelopingdesigninnovationsforenhancedproductperformance.Thedesignprocessincludesconceptualization,simulation,optimization,anddesignfinalizationpriortomanufacturing.Theirevolving......
  • EDM营销文案的撰写技巧?如何提升转化率?
    EDM营销文案与SEO策略如何结合?怎么写有效营销邮件?EDM仍然是一种高效且经济的推广手段。撰写优质的EDM营销文案,不仅可以提升品牌形象,还能有效促进销售转化。那么,如何撰写出引人入胜的EDM营销文案呢?AokSend来介绍一些实用的撰写技巧。EDM营销文案:定位风格不同的受众群体有不......
  • Ant Design 设置必填属性的一个坑!Objects are not valid as a React child (found: ob
    1、刚开始,我是用第一种方式。通过一个变量,来设置必填属性的提示值 显示是没有问题的。但是点击ModalForm确认按钮时,报错ObjectsarenotvalidasaReactchild(found:objectwithkeys{requiredMsg}).Ifyoumeanttorenderacollectionofchildren,useanarray......
  • 工业相机里面图像数据格式mono8,packetedmono10是什么意思,还有color是什么意思?
    mono8,即存储下来的图像为单色,8Bit的图片,一般是bmp,jpeg等。packedmono10,即存储下来的图片为单色,10Bit的图片,但是一般都是存储为16Bit图片,packed存储即将10Bit的数据以16Bit的方式填充,剩余的本应填充为0的6个bit被下一帧图片数据填充,这****样做可以减少数据量和数据冗余度,节省空......
  • Sitecore 通过 AutomatedMessage 发送邮件
    lasted:https://doc.sitecore.com/xp/en/users/exm/103/email-experience-manager/the-email-campaign-builder.htmlpublicstaticvoidSendEXMEmail(){ //发送人的名称 vartoUserName="Abigail"; //发送人的邮件 vartoEmail="[email protected]"; ......
  • SortedMap、NavigableMap、TreeMap介绍和使用
    SortedMap、NavigableMap、TreeMap介绍和使用SortedMap接口:SortedMap是一个接口,继承自Map接口,它定义了对键值对按照键的自然顺序或自定义顺序进行排序的功能。SortedMap中的键值对是按照键的顺序排列的,因此可以根据键的顺序进行范围查找和遍历操作。SortedMap接口提供了一......
  • IfcDerivedMeasureValue
    IfcDerivedMeasureValue  TypedefinitionIfcDerivedMeasureValue isaselecttypeforselectingbetweenderivedmeasuretypes.SELECTIfcAbsorbedDoseMeasureIfcAccelerationMeasureIfcAngularVelocityMeasureIfcAreaDensityMeasureIfcCompoundPlaneAngleMeas......
  • redmine获取cookie和其他系统实现单点登录
    前言最近有个需求,需要将我们一个平台对接到redmine,让用户可以通过这个平台直接在redmine提工单,需要实现免登录跳转。首先是想到去查redmine有无相应的单点登录功能,查到redmine是有LDAP认证功能的,解决方案LDAP认证Redmine支持通过LDAP(轻量级目录访问协议)实现用户认证,这使......
  • EDM 营销 平台有哪些?3款系统大分析
    在当今数字营销的激烈竞争中,EDM(ElectronicDirectMail)营销平台成为了企业获取客户和推广产品的重要渠道之一。随着市场需求的不断增长,各种EDM营销平台如雨后春笋般涌现,企业在选择合适的平台时往往面临诸多挑战。本文将针对EDM营销平台进行深入分析,探讨其中的3款系统,帮助企业在众多......
  • 强烈推荐邮件营销系统——蜂邮EDM
    邮件营销系统的重要性邮件营销系统在现代企业中扮演着至关重要的角色。蜂邮EDM作为一款强大的邮件营销系统,为企业提供了全方位的解决方案。无论是大型企业还是初创公司,都可以通过蜂邮EDM实现精准营销和客户沟通。蜂邮EDM的功能特点蜂邮EDM拥有丰富的功能特点,使得邮件营销变得更加高......