C# 如何绘制三维图形来表示空间中的对象

C# 如何绘制三维图形来表示空间中的对象,c#,plot,charts,3d,C#,Plot,Charts,3d,我有一个机器人,可以输出x,y,z在空间中的位置。我的问题是,我只能使用图表在windows窗体中找到2D绘图 我想在3D空间里画我的机器人。我能用什么工具 类似于此: 我需要一个免费的软件解决方案 编辑: 我的2D图形atm: chart1.ChartAreas[0].AxisX.Minimum = 0; chart1.ChartAreas[0].AxisX.Maximum = 12; chart1.ChartAreas[0].AxisX.In

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

我想在3D空间里画我的机器人。我能用什么工具

类似于此:

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

编辑:

我的2D图形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);

编辑:

您是正确的,在图表控件中没有正确的方法使用真实的z轴

不过它确实有一个3D风格,可以用于一个相当不错的图表区域

不过,您必须在代码中绘制图形,因为内置的z轴只支持图表中的
系列
中的尽可能多或尽可能少的离散值

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

相反,您可以这样做:

  • 将每个数据点的z值与Y值一起存储在YValues数组中
  • 为此,您需要一个支持多个Y值的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);
}
如果此绘制事件发生,我们将按照自己喜欢的方式绘制数据。以下是直线或点:

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!
}
private void chart1_PostPaint(对象发送方,ChartPaintEventArgs e)
{
Chart Chart=发送者作为图表;
如果(chart.Series.Count<1)返回;
if(chart.Series[0].Points.Count<1)返回;
ChartArea ca=chart.ChartAreas[0];
e、 ChartGraphics.Graphics.SmoothingMode=SmoothingMode.AntiAlias;
列表数据=新列表();
foreach(图表中的系列s.系列)
添加(GetPointsFrom3D(ca,s,s.Points.ToList(),e.ChartGraphics));
renderLines(数据,e.ChartGraphics.Graphics,chart,true);//选择一个!
renderPoints(数据,例如ChartGraphics.Graphics,chart,6);//选择一个!
}
坐标系使用轴方法计算:

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();
}
列出GetPointsFrom3D(ChartArea ca,系列s,
列出数据点,图表(cg)
{
var p3t=dPoints.Select(x=>newpoint3d((float)ca.axix.ValueToPosition(x.XValue)),
(浮动)约轴值位置(x.Y值[0]),
(float)ca.AxisY.ValueToPosition(x.y值[1])).ToArray();
ca.TransformPoints(p3t.ToArray());
返回p3t.Select(x=>cg.GetAbsolutePoint(新点f(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);
    }
}
void渲染线(列表数据、图形、图表、布尔曲线)
{
对于(int i=0;i1)
使用(画笔=新画笔(Color.FromArgb(64,chart.Series[i].Color),2.5f))
if(curves)graphics.DrawCurve(画笔,数据[i].ToArray());
else graphics.DrawLines(画笔,数据[i].ToArray());
}
}
无效渲染点(列表数据、图形、图表、浮动宽度)
{
对于(int s=0;s
也可以对网格或区域等其他绘图例程进行编码。。只需使用用户GDI+方法添加新例程,如DrawCurve或FillPolygon,甚至DrawImage

您可以为不同的视图设置
ChartArea.Area3DStyle.Rotation
ChartArea.Area3DStyle.Indeption
,如动画中所示

Edit我已经更新了
PostPaint
方法来最小化依赖关系


您是对的,在图表控件中没有正确的方法使用真实的z轴

不过它确实有一个3D风格,可以用于一个相当不错的图表区域

不过,您必须在代码中绘制图形,因为内置的z轴只支持图表中的
系列
中的尽可能多或尽可能少的离散值

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

相反,您可以这样做:

  • 将每个数据点的z值与Y值一起存储在YValues数组中
  • 为此,您需要一个支持多个Y值的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);
}
如果此绘制事件发生,我们将按照自己喜欢的方式绘制数据。以下是直线或点:

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!
}
private void chart1_PostPaint(对象发送方,ChartPaintEventArgs e)
{
Chart Chart=发送者作为图表;
如果(chart.Series.Count<1)返回;
if(chart.Series[0].Points.Count<1)返回;
ChartArea ca=chart.ChartAreas[0];
e、 ChartGraphics.Graphics.SmoothingMode=SmoothingMode.AntiAlias;
列表数据=新列表();
foreach(图表中的系列s.系列)
添加(GetPointsFrom3D(ca,s,s.Points.ToList(),e.ChartGraphics));
renderLines(数据,e.ChartGraphics.Graphics,chart,true);//选择一个!
renderPoints(数据,例如ChartGraphics.Graphics,chart,6);//选择一个!
}
坐标系使用轴方法计算:

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();
}
列出GetPointsFrom3D(ChartArea ca,系列s,
列出数据点,图表(cg)
{
var p3t=dPoints.Select(x=>newpoint3d((float)ca.axix.ValueToPosition(x.XValue)),
(浮动)约轴值位置(x.Y值[0]),
(float)ca.AxisY.ValueToPosition(x.y值[1])).ToArray();
ca.TransformPoints(p3t.ToArray());
返回p3t.Select(x=>cg.GetAbsolutePoint(新