【问题标题】:How to plot a 3D Graph to represent an object in space如何绘制 3D 图形以表示空间中的对象
【发布时间】:2016-10-25 16:05:09
【问题描述】:

我有一个输出空间中 x,y,z 位置的机器人。我的问题是我只能使用图表在 windows 窗体中找到 2D 绘图。

我想在 3D 空间中绘制我的机器人。有什么工具可以用吗??

类似的东西:

我需要一个免费的软件解决方案

编辑:

我的二维图 atm:

        chart1.ChartAreas[0].AxisX.Minimum = 0;
        chart1.ChartAreas[0].AxisX.Maximum = 12;
        chart1.ChartAreas[0].AxisX.Interval = 1;

        chart1.ChartAreas[0].AxisY.Minimum = 0;
        chart1.ChartAreas[0].AxisY.Maximum = 7;
        chart1.ChartAreas[0].AxisY.Interval = 1;

        //example
        posicao_atual_master.X = 10;
        posicao_atual_master.Y = 5;




         chart1.Series[0].Points.Clear();
        chart1.Series[0].Points.AddXY(posicao_atual_master.X, posicao_atual_master.Y);

设计师:

// chart1
        // 
        chartArea1.AxisX.MajorGrid.Enabled = false;
        chartArea1.AxisX.MajorTickMark.Enabled = false;
        chartArea1.AxisY.MajorGrid.Enabled = false;
        chartArea1.AxisY.MajorTickMark.Enabled = false;
        chartArea1.Name = "ChartArea1";
        chartArea1.Position.Auto = false;
        chartArea1.Position.Height = 100F;
        chartArea1.Position.Width = 90F;
        this.chart1.ChartAreas.Add(chartArea1);
        legend1.BackColor = System.Drawing.Color.Transparent;
        legend1.BorderColor = System.Drawing.Color.Transparent;
        legend1.Font = new System.Drawing.Font("Microsoft Sans Serif", 4F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Millimeter, ((byte)(1)), true);
        legend1.IsTextAutoFit = false;
        legend1.Name = "legen";
        legend1.TableStyle = System.Windows.Forms.DataVisualization.Charting.LegendTableStyle.Tall;
        this.chart1.Legends.Add(legend1);
        this.chart1.Location = new System.Drawing.Point(543, 49);
        this.chart1.Name = "chart1";
        series1.ChartArea = "ChartArea1";
        series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
        series1.Color = System.Drawing.Color.Transparent;
        series1.Legend = "legen";
        series1.MarkerBorderColor = System.Drawing.Color.Black;
        series1.MarkerImage = "C:\\Users\\Tiago\\Desktop\\CODIGO_TESE_FINAL_BACKUP1408_BOM\\C# - AR.Drone SDK\\AR.Dron" +
"e\\icone_drone_verde.png";
        series1.MarkerImageTransparentColor = System.Drawing.Color.Red;
        series1.Name = "Master";
        series2.ChartArea = "ChartArea1";
        series2.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point;
        series2.Legend = "legen";
        series2.MarkerImage = "C:\\Users\\Tiago\\Desktop\\CODIGO_TESE_FINAL_BACKUP1408_BOM\\Fotos dos Relatórios\\icon" +
"e_drone_vermelho.png";
        series2.Name = "Slave";
        this.chart1.Series.Add(series1);
        this.chart1.Series.Add(series2);
        this.chart1.Size = new System.Drawing.Size(1159, 359);
        this.chart1.TabIndex = 7;
        this.chart1.Text = "chart1";
        this.chart1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseDown);
        this.chart1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseMove);
        this.chart1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.chart1_MouseUp);

编辑:IMAGE

【问题讨论】:

  • 不是重复的。 ILNumerics 不是免费工具。
  • 可以使用图表控件和一些数学运算。到目前为止你能展示你的代码吗?
  • 自 2011 年以来,ILNumerics 已在专有许可下出售,起价为 89 欧元(月付)或 1.300 欧元(年付)。 1300 欧元在太空中绘制一个机器人......是的,不。
  • 没问题。我会发帖的。

标签: c# plot charts 3d


【解决方案1】:

你是对的,在 Chart 控件中没有正确的方法来使用真正的 z 轴。

虽然它确实具有 3D 样式,但可以用于相当不错的 ChartArea。

您必须在代码中绘制图形,因为内置的 z 轴只支持与图表中 Series 一样多或更少的离散值。

这对于某些东西来说是可以的,比如颜色立方体,但是当你需要任意数据值时它就不行了。

您可以这样做:

  • 将每个数据点的 z 值与 Y 值一起存储在 YValues 数组中。
  • 为此,您需要一个支持多个 YValue 的 ChartType
  • 编写 xxxPaint 事件之一以绘制图形
  • 为此,您需要将值转换为像素

首先我们准备图表。许多细节取决于您的需求;

void prepare3dChart(Chart chart, ChartArea ca)
{
    ca.Area3DStyle.Enable3D = true;  // set the chartarea to 3D!
    ca.AxisX.Minimum = -250;
    ca.AxisY.Minimum = -250;
    ca.AxisX.Maximum = 250;
    ca.AxisY.Maximum = 250;
    ca.AxisX.Interval = 50;
    ca.AxisY.Interval = 50;
    ca.AxisX.Title = "X-Achse";
    ca.AxisY.Title = "Y-Achse";
    ca.AxisX.MajorGrid.Interval = 250;
    ca.AxisY.MajorGrid.Interval = 250;
    ca.AxisX.MinorGrid.Enabled = true;
    ca.AxisY.MinorGrid.Enabled = true;
    ca.AxisX.MinorGrid.Interval = 50;
    ca.AxisY.MinorGrid.Interval = 50;
    ca.AxisX.MinorGrid.LineColor = Color.LightSlateGray;
    ca.AxisY.MinorGrid.LineColor = Color.LightSlateGray;

    // we add two series:
    chart.Series.Clear();
    for (int i = 0; i < 2; i++)
    {
        Series s = chart.Series.Add("S" + i.ToString("00"));
        s.ChartType = SeriesChartType.Bubble;   // this ChartType has a YValue array
        s.MarkerStyle = MarkerStyle.Circle;
        s["PixelPointWidth"] = "100";
        s["PixelPointGapDepth"] = "1";
    }
    chart.ApplyPaletteColors();

    addTestData(chart);
}

这里我们添加一些测试数据:

void addTestData(Chart chart)
{
    Random rnd = new Random(9);
    for (int i = 0; i < 100; i++)
    {
        double x = Math.Cos(i/10f )*88 + rnd.Next(5);
        double y = Math.Sin(i/11f)*88 + rnd.Next(5);
        double z = Math.Sqrt(i*2f)*88 + rnd.Next(5);

        AddXY3d( chart.Series[0], x, y, z);
        AddXY3d( chart.Series[1], x-111, y-222, z);
    }
}

DataPoints 与此例程一起添加:

int AddXY3d(Series s, double xVal, double yVal, double zVal)
{
    int p = s.Points.AddXY(xVal, yVal, zVal);
    // the DataPoint are transparent to the regular chart drawing:
    s.Points[p].Color = Color.Transparent;
    return p;
}

如果这个 Paint 事件我们按照我们喜欢的方式绘制数据。以下是线或点:

private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
    Chart chart = sender as Chart;

    if (chart .Series.Count < 1) return;
    if (chart .Series[0].Points.Count < 1) return;

    ChartArea ca = chart .ChartAreas[0];
    e.ChartGraphics.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

    List<List<PointF>> data = new List<List<PointF>>();
    foreach (Series s in chart .Series)
        data.Add(GetPointsFrom3D(ca, s, s.Points.ToList(), e.ChartGraphics));

    renderLines(data, e.ChartGraphics.Graphics, chart , true);  // pick one!
    renderPoints(data, e.ChartGraphics.Graphics, chart , 6);   // pick one!
}

坐标是使用轴方法计算的:

List<PointF> GetPointsFrom3D(ChartArea ca, Series s, 
                             List<DataPoint> dPoints, ChartGraphics cg)
{
    var p3t = dPoints.Select(x => new Point3D((float)ca.AxisX.ValueToPosition(x.XValue),
        (float)ca.AxisY.ValueToPosition(x.YValues[0]),
        (float)ca.AxisY.ValueToPosition(x.YValues[1]))).ToArray();
    ca.TransformPoints(p3t.ToArray());

    return p3t.Select(x => cg.GetAbsolutePoint(new PointF(x.X, x.Y))).ToList();
}

实际的绘图发生在这些例程中;一个画线,另一个画点:

void renderLines(List<List<PointF>> data, Graphics graphics, Chart chart, bool curves)
{
    for (int i = 0; i < chart.Series.Count; i++)
    {
      if (data[i].Count > 1)
         using (Pen pen = new Pen(Color.FromArgb(64, chart.Series[i].Color), 2.5f))
            if (curves) graphics.DrawCurve(pen, data[i].ToArray());
            else graphics.DrawLines(pen, data[i].ToArray());
    }
}

void renderPoints(List<List<PointF>> data, Graphics graphics, Chart chart, float width)
{
    for (int s = 0; s < chart.Series.Count; s++)
    {
        Series S = chart.Series[s];
        for (int p = 0; p < S.Points.Count; p++)
            using (SolidBrush brush = new SolidBrush(Color.FromArgb(64, S.Color)))
                graphics.FillEllipse(brush, data[s][p].X-width/2, 
                                     data[s][p].Y-width/2,width, width);
    }
}

也可以对网格或区域等其他绘图例程进行编码。只需使用用户 GDI+ 方法(如 DrawCurve 或 FillPolygon 甚至 DrawImage)添加新例程。

您可以为不同的视图设置ChartArea.Area3DStyle.RotationChartArea.Area3DStyle.Inclination,如动画所示。

编辑我已更新 PostPaint 方法以最小化依赖关系。

【讨论】:

  • 谢谢。如果你能提供一些代码,因为我不太擅长 C# WindowsForms。
  • 顺便说一句,你可以看到我使用 MarkerImage 来绘制无人机图像而不是点。你认为我可以用你的方法做类似的事情吗?
  • 代码使用所有常规的 GDI+ 方法,所以,是的,它可以绘制您用于标记的图像。但是画很多会聚集结果..
  • 好的,谢谢。您是否曾尝试将值从 Visual Studio 发送到 Matlab 并使用 Matlab 绘图?请提供代码。如果你想开发这个简单的图表来代表太空中的机器人,我可以付钱给你。
  • 不,就是这样,一切都是为了提供帮助的乐趣。而且,不,我不做 MatLab。我会待上一两个小时。稍后我会发布代码..
猜你喜欢
  • 2020-03-12
  • 2013-10-05
  • 2016-07-28
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多