C#用GDI+解析Json文件绘制Chart

图片 1

  1. g2o20160430下的csparse文件夹内的CMakeLists.txt

    cmake_minimum_required(VERSION 2.6)

    PROJECT(csparse)

    SET(CMAKE_C_FLAGS_RELEASE “-O3 -DNDEBUG”)
    #设置 G2O_LGPL_LIB_TYPE STATIC如果想创建静态的csparse库

    ADD_LIBRARY(csparse ${G2O_LGPL_LIB_TYPE} cs_add.c cs_amd.c cs_chol.c cs_cholsol.c cs_compress.c cs_counts.c cs_cumsum.c cs_dfs.c cs_dmperm.c cs_droptol.c cs_dropzeros.c
    cs_dupl.c cs_entry.c cs_ereach.c cs_etree.c cs_fkeep.c cs_gaxpy.c cs_happly.c cs_house.c cs_ipvec.c cs_leaf.c cs_load.c cs_lsolve.c cs_ltsolve.c cs_lu.c cs_lusol.c
    cs_malloc.c cs_maxtrans.c cs_multiply.c cs_norm.c cs_permute.c cs_pinv.c cs_post.c cs_print.c cs_pvec.c cs_qr.c cs_qrsol.c cs_randperm.c cs_reach.c cs_scatter.c cs_scc.c
    cs_schol.c cs_spsolve.c cs_sqr.c cs_symperm.c cs_tdfs.c cs_transpose.c cs_updown.c cs_usolve.c cs_util.c cs_utsolve.c cs_api.h )

    SET_TARGET_PROPERTIES(csparse PROPERTIES OUTPUT_NAME ${LIB_PREFIX}ext_csparse)
    IF (UNIX)
    TARGET_LINK_LIBRARIES(csparse m)
    ENDIF()
    #输出路径
    INSTALL(TARGETS csparse
      RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
      LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
      ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib )
    #安装路径
    FILE(GLOB headers “${CMAKE_CURRENT_SOURCE_DIR}/.h” “${CMAKE_CURRENT_SOURCE_DIR}/.hpp”)
    INSTALL(FILES ${headers} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/EXTERNAL/csparse)

    # Set up the variables
    SET(CSPARSE_LIBRARY “$”)
    SET(CSPARSE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH “Include directory for CSparse” FORCE)
    SET(CSPARSE_LIBRARY ${CSPARSE_LIBRARY} CACHE FILEPATH “CSparse library” FORCE)

    #SET(CSPARSE_FOUND TRUE PARENT_SCOPE)
    #MESSAGE(“CSPARSE_LIBRARY = ${CSPARSE_LIBRARY}”)
    #MESSAGE(“CSPARSE_INCLUDE_DIR = ${CSPARSE_INCLUDE_DIR}”)

0 序

开始用 HTC Vive
做项目,由于
OpenVR
并没有提供用于 Unity3D 的 C♯ 文档(只提供了C++ API
文档),所以想写一个“第三方”的
OpenVR C♯ API 文档,借此机会提高姿势和水平。

由于作者的水平相当低,可想而知接下来一定会遇到众多问题,望读者海涵,如果有什么写得不对的地方请一定指出并往死里喷我,教我人生的经验。虽然我认为没人会读这东西。

图片 2图片 3

 

1 对于OpenVR的初步认识

OpenVR 是由 Valve 公司开发的一套 VR 设备通用 API ,换而言之不管是
Oculus Rift 或 HTC Vive 甚至是其他 VR 设备,都不再需要使用产商提供的
SDK
就可以进行开发,有种打算一统天下的范儿。这套 API
并未开源所以具体实现未知。(由于 Vive 和 Oculus Rift
的原理看似一样但是其实对于画面的处理大相径庭,根据我大胆的瞎猜,我认为这套
API 只是帮我们在原先设备产商提供的 SDK
上又实现了一个能够通过统一接口访问的抽象层来,应该不是什么黑科技大概

OpenVR 文件夹的结构大致如下:

openvr
    bin                用于各平台的dll、pdb文件
    headers            用于 C++(.h) 和 C♯(.cs) 的头文件
                       (是根据本文件夹下的 openvr_api.json 自动生成的,不要手动编辑)
    lib                用于各平台的lib文件
    samples            C++、Unity 范例
    unity_package    用于 Unity 的 Package

unity_package 是之后研究的重点。

using System.Collections.Generic;
namespace Chart
{
    public class Program
    {
        static void Main(string[] args)
        {
            Chart chart = new Chart();
            ChartType chartType = ChartType.Histogram;
            string path = @"....JSON.json";
            DataSource dataSource = new JsonDataSource();
            List<Composition> Compositions = dataSource.GetDataList(path);
            chart.Compositions.AddRange(Compositions);
            chart.Draw(chartType);
            chart.Save();
        }
    }
}

2 OpenVR Unity Package

OpenVR Unity Package 包含以下脚本内容:

  • Plugins
    • openvr_api.cs
  • SteamVR
    • Editor
      • SteamVR_Editor.cs
      • SteamVR_RenderModelEditor.cs
      • SteamVR_Settings.cs
      • SteamVR_SkyboxEditor.cs
      • SteamVR_Update.cs
    • Scripts
      • SteamVR.cs
      • SteamVR_Camera.cs
      • SteamVR_CameraFlip.cs
      • SteamVR_CameraMask.cs
      • SteamVR_Controller.cs
      • SteamVR_ControllerManager.cs
      • SteamVR_Ears.cs
      • SteamVR_ExternalCamera.cs
      • SteamVR_Fade.cs
      • SteamVR_Frustum.cs
      • SteamVR_GameView.cs
      • SteamVR_IK.cs
      • SteamVR_LoadLevel.cs
      • SteamVR_Menu.cs
      • SteamVR_Overlay.cs
      • SteamVR_PlayArea.cs
      • SteamVR_Render.cs
      • SteamVR_RenderModel.cs
      • SteamVR_Skybox.cs
      • SteamVR_SphericalProjection.cs
      • SteamVR_Stats.cs
      • SteamVR_Status.cs
      • SteamVR_StatusText.cs
      • SteamVR_TestController.cs
      • SteamVR_TrackedObject.cs
      • SteamVR_UpdatePoses.cs
      • SteamVR_Utils.cs
    • Extras
      • SteamVR_GazeTracker.cs
      • SteamVR_LaserPointer.cs
      • SteamVR_Teleporter.cs
      • SteamVR_TestThrow.cs
      • SteamVR_TrackedController.cs

事实上,只有 Plugins 中的 open_api.cs 是直接与 OpenVR
打交道的,是它把 OpenVR 所有的 API
都暴露出来,并且声明了一些用于与其进行交换的数据结构。

Scripts 下是官方为我们实现的一些能够处理 OpenVR
中的原始数据的方法,和能够方便的在 Unity
中调用的方法,官方的说法是“推荐我们修改并提出反馈”(You are encouraged
to modify these to suit your project’s unique needs, and provide
feedback
),当然,我们这次的主题是看懂它,所以不作修改就我这水平,能看懂就不错了

用过Unity的都知道 Editor 下是一些编辑器脚本,Extras
下是一些简单的应用,所以就不多提了。不过值得一说的是,Valve
还写了一个自动检测 Project Settings
等设置是否有问题且能够一键自动配置的编辑器扩展工具,简直比 Oculus
高到不知道哪里去了

至于详细内容请参看 readme 此处不再叙述。


下一篇,我们主要研究 openvr_api.cs,了解 class OpenVR{} 中的方法。

Program.cs

 

图片 4图片 5

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace Chart
{
    public class Chart
    {
        private Bitmap bmp = new Bitmap(600, 600);
        List<Composition> composition = new List<Composition>();
        public List<Composition> Compositions { get { return composition; } }
        private float width;

        private float Width
        {
            get
            {
                int sum = 0;
                foreach (var composition in Compositions)
                {
                    sum += composition.DataPoints.Count + 1;
                }
                width = (float)420 / sum;
                return width;
            }
        }

        public void Draw(ChartType chartType)
        {
            Series series;

            switch (chartType)
            {
                case ChartType.LineChart:
                    series = new LineSeries();
                    break;

                case ChartType.Histogram:
                    series = new HistogramSeries();
                    break;

                case ChartType.PieChart:
                    series = new PieSeries();
                    break;

                default:
                    throw new ArgumentOutOfRangeException("Nonexistent ChartType!");
            }

            foreach (var comPosition in Compositions)
            {
                series.Legend.Add(comPosition.Name);
            }

            Platform platform = new Windows(bmp);

            series.Draw(Width, platform, Compositions);
        }

        public void Save()
        {
            bmp.Save(@"....1.bmp");
            Process.Start(@"....1.bmp");
        }
    }
}

Chart.cs

图片 6图片 7

using System.Collections;
using System.Collections.Generic;
using System.Drawing;
namespace Chart
{
    public abstract class Series
    {
        ArrayList legend = new ArrayList();
        public ArrayList Legend { get { return legend; } set { } }

        protected PointF PointFormLarge;
        protected PointF PointFormSmall;

        private void DrawChart(Platform g)
        {
            g.FillRectangle(g.WBrush, 20, 20, 580, 500);
        }

        protected abstract void DrawCore(float width, Platform g, List<Composition> Compositions);

        public void Draw(float width, Platform g, List<Composition> Compositions)
        {
            PointFormLarge = new PointF(width * Compositions.Count + width, 0);
            PointFormSmall = new PointF(width, 0);
            DrawChart(g);
            DrawCore(width, g, Compositions);
        }
    }
}

Series.cs

图片 8图片 9

using System.Collections.Generic;
using System.Drawing;
using System;
namespace Chart
{
    public class HistogramSeries : Series
    {

        private void DrawAxes(Platform g)
        {
            g.DrawLine(g.Rpen, new Point(100, 40), new Point(100, 420));
            g.DrawLine(g.Rpen, new Point(100, 40), new Point(90, 50));
            g.DrawLine(g.Rpen, new Point(100, 40), new Point(110, 50));
            g.DrawLine(g.Rpen, new Point(100, 420), new Point(570, 420));
            g.DrawLine(g.Rpen, new Point(570, 420), new Point(560, 410));
            g.DrawLine(g.Rpen, new Point(570, 420), new Point(560, 430));

            g.DrawString("月考成绩", g.LargeFont, g.Bbrush, new RectangleF(300, 30, 170, 50));
            g.DrawString("科目", g.LargeFont, g.Bbrush, new RectangleF(530, 450, 100, 40));
            g.DrawString("成绩", g.LargeFont, g.Bbrush, new RectangleF(40, 30, 40, 40));

            for (int i = 0; i < 5; i++)
            {
                g.DrawLine(g.BlackPen, new Point(100, 60 + 72 * i), new Point(570, 60 + 72 * i));
            }
        }

        private void DrawLegend(Platform g)
        {
            int LegendWidth = 250 / (Legend.Count - 1);
            int StringX = 50;
            int LegendX = StringX + 60;
            int k = 0;
            foreach (string legend in Legend)
            {
                switch (k)
                {
                    case 0:
                        g.Brush = Brushes.Blue;
                        break;
                    case 1:
                        g.Brush = Brushes.Red;
                        break;
                    case 2:
                        g.Brush = Brushes.Yellow;
                        break;
                    case 3:
                        g.Brush = Brushes.Green;
                        break;
                }
                g.DrawString(legend, g.LargeFont, Brushes.Blue, StringX, 480);
                Rectangle rect = new Rectangle(LegendX, 480, LegendWidth * 2 / 3, 20);
                g.FillRectangle(g.Brush, rect);

                StringX += 550 / Legend.Count;
                LegendX = StringX + 60;
                k++;
            }
        }



        protected override void DrawCore(float width, Platform g, List<Composition> Compositions)
        {
            DrawAxes(g);
            DrawLegend(g);
            foreach (var datapoint in Compositions[0].DataPoints)
            {
                g.DrawString(datapoint.XValue, g.LargeFont, g.Bbrush, 120, 430);
                g.TranslateTransform(PointFormLarge.X, PointFormLarge.Y);
            }
            g.ResetTransform();

            int YValueMax = 0;
            foreach (var composition in Compositions)
            {
                if (YValueMax <= composition.Max)
                {
                    YValueMax = composition.Max;
                }
            }

            g.YRatioScale = 370 / YValueMax;


            for (int i = 0; i <= 5; i++)
            {
                g.DrawString(Math.Ceiling(360/5/ g.YRatioScale*(5-i)).ToString(), g.LargeFont, g.BlackBrush, new RectangleF(80, 50 + 72 * i, 50, 50));
            }




            void DrawRectangle(float x, float y, float Width, float height, Composition composition)
            {
                Rectangle rect = new Rectangle((int)x, (int)y, (int)width, (int)height);
                g.FillRectangle(composition.BrushColor, rect);
            }
            int j = 1;
            foreach (var composition in Compositions)
            {
                Compositions[0].BrushColor = Brushes.Blue;
                Compositions[1].BrushColor = Brushes.Red;
                Compositions[2].BrushColor = Brushes.Yellow;
                foreach (var datapoint in composition.DataPoints)
                {
                    DrawRectangle(120, 420 - datapoint.YValue * g.YRatioScale, width, datapoint.YValue * g.YRatioScale, composition);
                    g.DrawString(datapoint.YValue.ToString(), g.SmallFont, Brushes.Red, 120, 420 - datapoint.YValue * g.YRatioScale - 15);
                    g.TranslateTransform(PointFormLarge.X, PointFormLarge.Y);
                }
                g.ResetTransform();
                for (int i = 0; i < j; i++)
                {
                    g.TranslateTransform(PointFormSmall.X, PointFormSmall.Y);
                }
                j++;
            }
            g.ResetTransform();
        }
    }
}

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website