|||
测井质量检查是需要面临的基础问题,在拿到数据进行质控的第一步,保证后续处理的准确性意义重大。常规的是二维交会图查看,利用中子-密度-声波三条曲线两两交会查看三张图,如下图所示:
某一天在Geolog上面发现有三维的交会图,用起来看着非常直观,虽然细节上不如二维交会图,但是在总体观察效果上的确有优点,于是想着自己山寨一个看看效果。最初想到的OCC控件,瞬间对于C++的指针郁闷上来了,打包也麻烦;随后考虑国内的类似的AnyCAD,只有初步的试用版,而且还是不太好用,网上看到有不少Bug;继续浏览发现了2017年横空出世的LightingChart,是真的强大,试用发现操作接口比较函数式,比较好理解。相对比专业的3D绘图不是那么全面,但是够用。尤其是渲染速度非常快速,响应比AnyCAD要快很多。最终试验效果图如下图所示:
网上和说明书有的不细说,在此记录下几个有用的参数设置,具体如下:
三维视图对象:View3D v = _chart.View3D;
绘图操作类似OpenGL的定义,有个开始和结束更新,在中间添加各种操作即可。
在 3D 空间中心创建 3D 模型。维度量级定义了三维空间中模型箱的大小。用该维度箱可以定义墙和轴的大小。用 Dimensions属性可设置每个维度的量级。
//v.Dimensions.X = 50; v.Dimensions.Y = 70; //v.Dimensions.Z = 100;
这个参数是确定在控件上看到的图形整体大小,类似二维绘图的图纸大小。
具体的坐标参数区间通过每个坐标轴来进行设置,简单明了。
v.XAxisPrimary3D.Title.Text = "中子"; v.XAxisPrimary3D.Maximum = 50; v.XAxisPrimary3D.Minimum = -8; v.YAxisPrimary3D.Title.Text = "密度"; v.YAxisPrimary3D.Maximum = 3.0; v.YAxisPrimary3D.Minimum = 1.9; v.ZAxisPrimary3D.Title.Text = "声波"; v.ZAxisPrimary3D.Maximum = 140; v.ZAxisPrimary3D.Minimum = 40;
点和线都是同一个数据集,跟ZedGraph控件一样,将点和线的可见属性进行设置即可完成显示的转换。LightingChart的数据是通过不同的数据集进行组合管理的,如PointLineSeries3D、SurfaceGridSeries3D、SurfaceMeshSeries3D等数据集合,添加对应的数据类型进去即可。在此添加数据点集如下:
PointLineSeries3D seriesIndividualPointColors = new PointLineSeries3D(v, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary); seriesIndividualPointColors.Title.Text = "Individual point colors"; seriesIndividualPointColors.IndividualPointColors = true; seriesIndividualPointColors.MouseInteraction = true; seriesIndividualPointColors.PointsVisible = true; seriesIndividualPointColors.PointStyle.Shape3D = PointShape3D.Sphere; seriesIndividualPointColors.PointStyle.Size3D.SetValues(1.5f, 1.5f, 1.5f); seriesIndividualPointColors.LineVisible = false; SeriesPoint3D[] points2 = new SeriesPoint3D[pointCount]; for (int i = 0; i < pointCount; i++) { Cyq_PlatePoint pp = get_point_by_id(list_ID_PlatePoint_Diagram[i]); points2[i].X = pp.CNCF; points2[i].Y = pp.RHOB; points2[i].Z = pp.DT; } seriesIndividualPointColors.Points = points2; v.PointLineSeries3D.Add(seriesIndividualPointColors);
数据点颜色设置需要手动进行,具体颜色通过两种方式可以实现计算:取值区间和调色板。
(1)利用取值区间颜色设定数据点颜色
int green = Convert.ToInt32((limit_gr_max - pp.GR) / (limit_gr_max - limit_gr_min) * 255.0); points2[i].Color = Color.FromArgb(0, green, 0);
(2)利用调色板颜色设定数据点颜色
ValueRangePalette palette = new ValueRangePalette(); palette.Steps.Clear(); palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(255, Color.DarkGray), 100)); palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(255, Color.Yellow), 50)); palette.Steps.Add(new PaletteStep(palette, Color.FromArgb(255, Color.Red), 0)); palette.Steps[0].MaxValue = limit_gr_min + (limit_gr_max - limit_gr_min) * 0.7; palette.Steps[1].MaxValue = limit_gr_min + (limit_gr_max - limit_gr_min) * 0.3; palette.Steps[2].MaxValue = limit_gr_min + (limit_gr_max - limit_gr_min) * 0; Color c; palette.GetColorByValue(pp.GR, out c); points2[i].Color = c;
三维数据点集PointLineSeries3D的ShapType属性可以修改为Shape2D,设置的数据点坐标同样是三维的,但是显示出来的数据点就是二维的,不再有光源和明暗关系变化等情况,这里用来投射成三面墙的二维映射交互图,实例代码如下:
PointLineSeries3D seriesIndividualPointColors_DEN_DT = new PointLineSeries3D(v, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary); seriesIndividualPointColors_DEN_DT.PointStyle.ShapeType = ShapeType.Shape2D; seriesIndividualPointColors_DEN_DT.PointStyle.Shape2D.Shape = Shape.Circle; seriesIndividualPointColors_DEN_DT.PointStyle.Shape2D.Width = 3.0f; seriesIndividualPointColors_DEN_DT.PointStyle.Shape2D.Height = 3.0f; SeriesPoint3D[] points_DEN_DT = new SeriesPoint3D[pointCount]; for (int i = 0; i < pointCount; i++) { Cyq_PlatePoint pp = get_point_by_id(list_ID_PlatePoint_Diagram[i]); points_DEN_DT[i].X = xmin; points_DEN_DT[i].Y = pp.RHOB; points_DEN_DT[i].Z = pp.DT; points_DEN_DT[i].Color = Color.DarkOrchid; } seriesIndividualPointColors_DEN_DT.Points = points_DEN_DT;v.PointLineSeries3D.Add(seriesIndividualPointColors_DEN_DT);
绘图效果如下:
线条绘制常规三维绘制一样,只是需要固定一个维度的坐标值。
文本标注需要设置一个坐标系统为屏幕坐标即可,这样就不会随着旋转变化,固定了屏幕x、y坐标。程序中显示数据点个数就是二维文本,代码如下:
Annotation3D description = new Annotation3D(v, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary); description.TargetCoordinateSystem = AnnotationTargetCoordinates.AxisValues; description.LocationCoordinateSystem = CoordinateSystem.ScreenCoordinates; description.LocationRelativeOffset.SetValues(0, 0); description.Visible = true; description.MouseInteraction = false; description.Style = AnnotationStyle.Rectangle; description.Shadow.Visible = false; description.TargetAxisValues.SetValues(19, 2.9, zmax); description.Text = string.Format("数据点:{0} 个", pointCount); description.BorderVisible = false; description.TextStyle.Color = Color.White; description.Fill.Color = Color.Empty; description.Fill.GradientColor = Color.Empty; _chart.View3D.Annotations.Add(description);
简单实现数据点的追踪,直接拷贝示例程序中的代码如下:
在创建绘图的时候,加入鼠标移动事件响应函数:
_chart.MouseMove += new MouseEventHandler(_chart_MouseMove);
编写响应函数代码:
void _chart_MouseMove(object sender, MouseEventArgs e) { //Disable rendering, strongly recommended before updating chart properties _chart.BeginUpdate(); //Get 3D view View3D view3D = _chart.View3D; //Reset highlighted point colors foreach (PointLineSeries3D pointLineSeries3D in _chart.View3D.PointLineSeries3D) { if (pointLineSeries3D.Tag != null) { //Restore color int pointIndex = (int)pointLineSeries3D.Tag; pointLineSeries3D.Points[pointIndex].Color = pointLineSeries3D.Title.Color; } } //Annotation for value tracking Annotation3D targetValueLabel = view3D.Annotations[0]; targetValueLabel.Visible = false; //hide it //Get object under mouse if any object obj = _chart.GetActiveMouseOverObject(); //check if object is valid if (obj != null) { //if object is PointLineSeries3D if (obj is PointLineSeries3D) { PointLineSeries3D pointLineSeries = obj as PointLineSeries3D; //Get last data index at mouse coordinates int pointIndex = pointLineSeries.LastMouseHitTestIndex; //Change the color of point in current position pointLineSeries.Points[pointIndex].Color = ChartTools.CalcGradient(pointLineSeries.Title.Color, Color.White, 50); pointLineSeries.Tag = pointIndex; //Store info of point index that is highlighted SeriesPoint3D point = pointLineSeries.Points[pointIndex]; int id_point = list_ID_PlatePoint_Diagram[pointIndex]; Cyq_PlatePoint pp = get_point_by_id(id_point); targetValueLabel.TargetAxisValues.SetValues(point.X, point.Y, point.Z); targetValueLabel.Text = "深度= " + pp.DepthStart.ToString("F4") + "\n中子=" + point.X.ToString("0.00") + " ; 密度=" + point.Y.ToString("0.00") + " ; 声波=" + point.Z.ToString("0.00"); targetValueLabel.Fill.Color = ChartTools.CalcGradient(pointLineSeries.Title.Color, Color.White, 90); targetValueLabel.Fill.GradientColor = ChartTools.CalcGradient(pointLineSeries.Title.Color, Color.White, 50); targetValueLabel.Visible = true; } } //Allow chart rendering _chart.EndUpdate(); }
实现效果如下图所示:
控件还有其他更多图形保存输出、打印等功能,以后慢慢探索。
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-11-22 17:54
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社