Пример #1
0
        //绘制MARK点
        internal static void Draw(Graphics g, 
                                  Channels chnls, 
                                  ChannelMark[] mrks,
                                  AixsVisibleArea ava, 
                                  ChannelPictureArea cpa, 
                                  Font mrkFont)
        { 
            int k = 0;
            
            //扫描mrks中所有的点
            for (int i = 0; i < mrks.Length; i++) 
            {
                //第i个MARK点,可见,则绘制它
                //并且根据不同的MarkType,绘制动作会有差异
                if (mrks[i].showText) {
                    if (mrks[i].markType == MarkType.mrkNormal)
                        DrawMark(k, (i + 1), g, chnls, mrks[i], ava, cpa, mrkFont);

                    else if (mrks[i].markType == MarkType.mrkPeak)
                        DrawPeak(k, (i + 1), g, chnls, mrks[i], ava, cpa, mrkFont);

                    else
                        continue;

                    //else if (mrks[i].markType == MarkType.mrkValley)
                    //    ;

                    //递增可见MARK点的个数
                    k++;

                } else
                    continue;
            }  
        }
Пример #2
0
        //使用channel中的所有数据
        //依X坐标,从小到大,绘制成图形曲线       
        internal static void Draw(Channel chnl, 
                                  Graphics g, 
                                  AixsVisibleArea ava, 
                                  ChannelPictureArea cpa,
                                  Boolean sampling)
        {   
            PointF[] p;

            PointF[] src;

            ChannelNode chNode;

            ChannelCurveStyle ccStyle = chnl.ccStyle;            

            //当前段数据与上一段数据的衔接点
            //当(i > 0), 将被更新(页面坐标)
            PointF preTail = new PointF(float.MinValue, float.MinValue);          

            //建立画笔
            Pen pn = new Pen(ccStyle.lineColor);
            pn.Width = ccStyle.lineWidth;

            //上一次有效数据段在chnl中的索引
            int k = -1;

            //重置channel Nodes
            chnl.ClearNodes();
           
            //一次将channel中,以i为索引的一段数据
            //依X坐标,从小到大,绘制成图形曲线            
            for (int i = 0; i <= chnl.MaxIndex; i++)
            {
                src = chnl.DataOf(i);
                if (src == null)
                    continue;

                //假设src按X递增顺序形式
                if (src[0].X > src[src.Length - 1].X)
                    continue;

                //不启动X轴滚动,则从src中采样数据(世界坐标)
                if (sampling)
                    p = DataSampling.SamplingFrom(src, ava.xBegin, ava.xEnd, cpa.N0);
                
                //启用X轴滚动时,不采样,从src(世界坐标)复制数据
                else  { 
                    p = new PointF[src.Length];
                    for (int j = 0; j < src.Length; j++)
                        p[j] = src[j];
                }

                if (p == null)
                    continue;
                
                //查找p中,具有最大、最小Y值的点
                //并且设置当前数据段的最小,最大值(世界坐标)
                chNode = MinMaxOf(p);                
                chnl.SetHeadNode(2, i, chNode.head);
                chnl.SetTailNode(2, i, chNode.tail);
                
                //对p做世界变换,页面坐标
                //并且设置当前数据段绘图数据的头部点、尾部点(页面坐标)
                DrawingChannel.WorldTransform(p, chnl.UnitOffset, ava, cpa);                 
                chnl.SetHeadNode(0, i, p[0]);
                chnl.SetTailNode(0, i, p[p.Length - 1]);
                
                //计算当前数据段,与其前一数据段的连接点              
                //索引(i - 1)无效时,TailNodeOf返回 p(-1, -1)
                preTail = chnl.TailNodeOf(0, k);

                //绘制当前段与前一段的连接线
                if ((preTail.X > float.MinValue) && (preTail != p[0]))
                    g.DrawLine(pn, preTail, p[0]);

                //绘制当前数据段曲线
                if (p.Length >= 2)                  
                    g.DrawLines(pn, p);
                else
                    g.DrawLine(pn, p[0], p[0]);

                //绘制曲线图标
                if (ccStyle.showIcon)
                    DrawingCurveIcon.Draw(p, g, ccStyle);
                
                //记录前一次有效数据段在chnl中的索引
                k = i;
            }
        }
Пример #3
0
        //将p进行世界变换,   
        //va坐标轴当前可见区域
        //cpa绘制曲线区域
        internal static void WorldTransform(PointF[] p, float yUnitOffset, AixsVisibleArea ava, ChannelPictureArea cpa)
        {
            int yValue;
            double dx, dy;

            yValue = cpa.rec.Y + cpa.rec.Height;

            dx = ava.xEnd - ava.xBegin;

            dy = ava.yEnd - ava.yBegin;

            for (int i = 0; i < p.Length; i++) 
            {   
                //使用yUnitOffset修正p在Y方向上的值
                p[i].Y = p[i].Y + yUnitOffset;

                //执行世界变换计算
                p[i].X = (float)(cpa.rec.X + (p[i].X - ava.xBegin) * cpa.rec.Width / dx);

                p[i].Y = (float)(yValue - (p[i].Y - ava.yBegin) * cpa.rec.Height / dy);
            }
        }
Пример #4
0
        //在mrk.sequence[]中指定的那些channel中,搜索MARK点
        //把找到的点,合并成一个文本,作为该MARK点文本
        //绘制MARK点文本和MARK图形
        private static void DrawMark( int mrkCount,
                                      int mrkOrder,
                                      Graphics g, 
                                      Channels chnls, 
                                      ChannelMark mrk,
                                      AixsVisibleArea ava, 
                                      ChannelPictureArea cpa, 
                                      Font mrkFont)
        {
            int i, j;         
            SizeF szf;
            Channel chnl;
            
            string label = "";
            bool bExists = false;
            PointF srcPoint = new PointF(float.MinValue, float.MinValue);

            //用于绘制MARK线时,定位坐标
            PointF gphPoint = srcPoint;

            //计算MARK点的世界坐标,即mrk.value,由外部传入      
           
            MarkInfo[] mi = new MarkInfo[mrk.sequence.Length];
            //在指定的channel中构造MARK文本
            for (i = 0; i < mrk.sequence.Length; i++) 
            {
                mi[i].iChannel = -1;
                mi[i].iOrder = mrkOrder;

                j = mrk.sequence[i];

                chnl = chnls.ChannelOf(j);
                if (chnl == null)
                    continue;

                srcPoint = Search2(chnl, ava, cpa, mrk.searchType, mrk.value);
              
                if (srcPoint.X > float.MinValue) 
                {
                    if (!bExists) {
                        bExists = true;
                        gphPoint = srcPoint;
                    }
                }

                mi[i].fPoint = srcPoint;
                mi[i].iChannel = (j + 1);
            }
            
            //若找到MARK点
            if ((mrk.showMarkShape) && (gphPoint.X > float.MinValue))
            {
                //使用找的MARK,绘制其文本
                if (GenMarkText != null)
                {
                    label = GenMarkText(mi);
                    szf = g.MeasureString(label, mrkFont);
                    g.DrawString(label,
                                 mrkFont,
                                 new LinearGradientBrush(new RectangleF(0, 0, szf.Width, szf.Height), mrk.markColor, mrk.markColor, 0.0),
                                 new Point(cpa.rec.X, (int)(cpa.rec.Y + mrkCount * szf.Height + MARKMARGIN)));

                }

                //使用找的MARK,构造形状
                Point[] p;
                RectangleF recf;

                //使用找到点的X坐标值来计算MARK点页面坐标在X轴方向的值,不使用mrk.value
                float x = (int)(cpa.rec.X + 
                                (gphPoint.X - ava.xBegin) * cpa.rec.Width / (ava.xEnd - ava.xBegin));              

                if (mrk.markShape == MarkShape.markPloygon) {
                    p = new Point[7];
                    recf = MakeMarkPolygon(p, (int)x, cpa);

                } else {
                    p = new Point[3];
                    int y = (int)(cpa.rec.Y + cpa.rec.Height -
                                  (gphPoint.Y - ava.yBegin) * cpa.rec.Height / (ava.yEnd - ava.yBegin));

                    recf = MakeMarkTriangle(p, new Point((int)x, y), cpa);
                }

                //绘制MARK形状
                g.DrawPolygon(new Pen(mrk.markColor), p);

                //绘制MARK形状内的文本
                szf = g.MeasureString(mrkOrder.ToString(), mrkFont);
                g.DrawString(mrkOrder.ToString(),
                             mrkFont,
                             new LinearGradientBrush(recf, mrk.markColor, mrk.markColor, 0.0),
                             new PointF(recf.X + (recf.Width - szf.Width) / 2, recf.Y + (recf.Height - szf.Height) / 2)
                             );
            }
        }
Пример #5
0
        //在chnl的源数据中,搜索MARK点
        private static PointF Search2(Channel chnl,
                                     AixsVisibleArea ava,
                                     ChannelPictureArea cpa,
                                     MarkSearchType schType,
                                     float value)
        {
            int i, k;
            float Vcurr, Vmin;
            PointF pMin = new PointF(float.MinValue, float.MinValue);

            //获取chnl拥有的第一段数据和最后一段数据
            PointF[] src1 = chnl.DataOf(0);
            PointF[] src2 = chnl.DataOf(chnl.MaxIndex);

            //chnl中包含的源数据为空
            if ((src1 == null) || (src2 == null))
                return pMin;

            //若value在chnl数据之外
            if ((value < src1[0].X) || (value > src2[src2.Length - 1].X))
                return pMin;

            //若value在坐标轴之外
            if ((value < ava.xBegin) || (value > ava.xEnd))
                return pMin;

            //查找与value最接近的段          
            PointF[] src;
            k = -1;
            Vmin = float.MaxValue;
            for (i = 0; i <= chnl.MaxIndex; i++)
            {
                src = chnl.DataOf(i);
                if (src == null)
                    continue;

                Vcurr = Math.Min(Math.Abs(value - src[0].X),
                                 Math.Abs(src[src.Length - 1].X - value));

                if (Vcurr < Vmin) {
                    k = i;
                    Vmin = Vcurr;
                }
            }

            //找不到源数据所在的数据段
            if (k < 0)
                return pMin;

            //若MarkSearchType.schValue,则在chnl.DataOf(k)中搜索
            //否则将对chnl.DataOf(k)进行采样,再在采样返回的点集中进行搜索
            src = chnl.DataOf(k);

            if (schType == MarkSearchType.schPoint)
                src = DataSampling.SamplingFrom(src, ava.xBegin, ava.xEnd, cpa.N0);         

            if (src == null)
                return pMin;
            
            //在src中,查找一个点,其X坐标与value相差最小
            k = -1;
            Vmin = float.MaxValue;
            for (i = 0; i < src.Length; i++)
            {
                Vcurr = Math.Abs(src[i].X - value);

                if (Vcurr < Vmin) {
                    Vmin = Vcurr;
                    k = i;
                }
            }

            //使用yUnitOffset修正src的Y方向的值
            src[k].Y = src[k].Y + chnl.UnitOffset;
            return src[k];
        }
Пример #6
0
        //以三角形图形,显示MARK点
        private static RectangleF MakeMarkTriangle(Point[] p, Point m, ChannelPictureArea cpa)
        {
            p[0] = m;

            p[1].X = p[0].X - 8;
            p[1].Y = p[0].Y - 14;

            if (p[1].X <= cpa.rec.X) {
                p[1].X = p[0].X;
                p[1].Y = p[0].Y - 16;

                p[2].X = p[0].X + 14;
                p[2].Y = p[0].Y - 8;

                return new RectangleF(p[0].X, p[0].Y - 14, 10, 11);

            } else if ((p[1].X + 15) >= (cpa.rec.X + cpa.rec.Width)) {
                p[1].X = p[0].X - 14;
                p[1].Y = p[0].Y - 8;

                p[2].X = p[0].X;
                p[2].Y = p[0].Y - 16;

                return new RectangleF(p[0].X - 10, p[0].Y - 14, 10, 11);

            } else {
                p[1].X = p[0].X - 8;
                p[1].Y = p[0].Y - 14;

                p[2].X = p[0].X + 8;
                p[2].Y = p[0].Y - 14;

                return new RectangleF(p[0].X - 5, p[0].Y - 14, 10, 11);
            }
        }
Пример #7
0
        //以竖直线和多边形构成的图形,显示MARK点
        private static RectangleF MakeMarkPolygon(Point[] p, int x, ChannelPictureArea cpa)
        {
            bool b = false;

            p[0].X = x;
            p[0].Y = cpa.rec.Y;

            p[1].X = p[0].X;
            p[1].Y = p[0].Y + cpa.rec.Height - 22;

            p[2].X = p[1].X - 8;
            p[2].Y = p[1].Y + 6;

            if (p[2].X <= cpa.rec.X) {
                p[2].X = p[1].X;
                p[2].Y = p[1].Y + 6;

                p[3].X = p[2].X;
                p[3].Y = p[2].Y + 16;

                p[4].X = p[3].X + 16;
                p[4].Y = p[3].Y;

            } else if ((p[2].X + 16) >= (cpa.rec.X + cpa.rec.Width)) {
                p[2].X = p[1].X;
                p[2].Y = p[1].Y + 6;

                p[3].X = p[2].X;
                p[3].Y = p[2].Y + 16;

                p[4].X = p[3].X - 16;
                p[4].Y = p[3].Y;

                b = true;

            } else {
                p[3].X = p[2].X;
                p[3].Y = p[2].Y + 16;

                p[4].X = p[3].X + 16;
                p[4].Y = p[3].Y;
            }

            p[5].X = p[4].X;
            p[5].Y = p[4].Y - 16;

            p[6].X = p[1].X;
            p[6].Y = p[1].Y;

            if (b)
                return new RectangleF(p[5].X, p[5].Y, 16, 16);
            else
                return new RectangleF(p[2].X, p[2].Y, 16, 16);
        }
Пример #8
0
        //在mrk.sequence[]中指定的那些channel中,搜索Y值最大的点
        //绘制PEAK点文本和PEAK图形
        private static void DrawPeak( int mrkCount,
                                      int mrkOrder,
                                      Graphics g, 
                                      Channels chnls, 
                                      ChannelMark mrk,
                                      AixsVisibleArea ava, 
                                      ChannelPictureArea cpa, 
                                      Font mrkFont)
        {
            SizeF szf;
            Channel chnl;           
            string label = "";
            PointF p2 = new PointF(float.MinValue, float.MinValue);
            PointF srcPoint = p2;
            
            //在mrk.sequence指定的channel搜索PEAK点
            int k = -1;
            for (int i = 0; i < mrk.sequence.Length; i++) 
            {
                chnl = chnls.ChannelOf(mrk.sequence[i]);
                if (chnl != null) {
                    p2 = SearchPeak(chnl);

                    if (p2.Y > srcPoint.Y) {
                        k = i;
                        srcPoint = p2;
                    }
                }
            }
            
            //找到PEAK点
            if ((mrk.showMarkShape) && (srcPoint.X > float.MinValue)) 
            {
                //对srcPoint的X坐标执行世界变换
                int x = (int)(cpa.rec.X + (srcPoint.X - ava.xBegin) * cpa.rec.Width / (ava.xEnd - ava.xBegin));

                MarkInfo[] mi = new MarkInfo[1];
                mi[0].fPoint = srcPoint;
                mi[0].iChannel = (k + 1);
                mi[0].iOrder = mrkOrder;

                //构造并绘制PEAK文本
                if (GenPeakText != null) {                   
                    label = GenPeakText(mi);
                    szf   = g.MeasureString(label, mrkFont);
                    g.DrawString(label,
                                 mrkFont,
                                 new LinearGradientBrush(new RectangleF(0, 0, szf.Width, szf.Height), mrk.markColor, mrk.markColor, 0.0),
                                 new Point(cpa.rec.X, (int)(cpa.rec.Y + mrkCount * szf.Height + MARKMARGIN)));
                }

                Point[] p;
                RectangleF recf;
              
                p = new Point[7];
                recf = MakeMarkPolygon(p, x, cpa);

                //绘制PEAK形状
                g.DrawPolygon(new Pen(mrk.markColor), p);

                //绘制PEAK形状内的文本
                szf = g.MeasureString(mrkOrder.ToString(), mrkFont);

                g.DrawString(mrkOrder.ToString(),
                             mrkFont,
                             new LinearGradientBrush(recf, mrk.markColor, mrk.markColor, 0.0),
                             new PointF(recf.X + (recf.Width - szf.Width) / 2, recf.Y + (recf.Height - szf.Height) / 2)
                             );
            }
        }
Пример #9
0
        //语句依据次序执行,建立控件
        internal PlotEx(XY2dPlotEx plot)
        {
            //保存控件的winform对象
            this.plot = plot;

            //默认,启用采样,仅绘制坐标轴可见范围内的数据
            Sampling = true;

            //设置控件内边距,默认10像素
            innerMargin = 10;

            GridBackColor = Color.SkyBlue;

            AixsLineColor = Color.Black;

            //构造控件的标题对象
            tt = new plotTitle();

            //构造控件的X轴对象
            xa = new XAixs();

            //构造控件的Y轴对象
            ya = new YAixs();

            //构造控件的当前可见区域对象
            aixvblArea = new AixsVisibleArea(xa.start, xa.stop, ya.start, ya.stop);

            //构造控件的绘图区域对象
            chnlPicArea = new ChannelPictureArea();

            //构造控件的边框控制对象
            pltBorder = new PlotBorder();

            //使用上述部件,绘制控件
            RedrawInNewBitmap();

            //构造数据对象,用于绘制曲线
            chnls = new Channels();
            
            //构造支持的MARK对象
            marks = new ChannelMark[MARKCAPCITY];
            for (int i = 0; i < marks.Length; i++)
                marks[i] = new ChannelMark(chnls.Length);
        }