using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace OTSIncAReportGraph { #region 基类,抽像类 /// /// 绘制的基本类,下面的画布,多边形,线都要从这里派生 /// public abstract class BaseObject : ICloneable { //自动生成的ID public abstract string ID { get; set; } //画布的坐标 public abstract RectangleF Rect { get; set; } //OTS的坐标 public abstract PointF OTSPointF { get; set; } //画布是否被选择 public abstract bool IsSelect { get; set; } //画布是否被拖动 public abstract bool IsDragging { get; set; } //画布被拖动到的位置 public abstract PointF DraggingPoint { get; set; } //线的颜色 public abstract Color Color { get; set; } //画布的背景色 public abstract Color BackColor { get; set; } //绘制函数 public abstract void OnPaint(PaintEventArgs e); //多边形路径 public abstract GraphicsPath GPath { get; set; } //克隆 public virtual object Clone() { return null; } } #endregion #region 历史操作记录类 ///历史操作记录类,记录颗粒被操作的记录 public class HistoryApolygon { //自增长,操作id,增长在程序中自己写代码控制 private int m_id; //所操作的颗粒的id private string m_apolygonid; //操作类型 private ParticleOperator m_operator; //原先的操作状态类型 private ParticleOperator m_oldoperator; /// /// 操作类ID /// public int ID { get { return m_id; } set { m_id = value; } } /// /// 颗粒类ID /// public string APolygonID { get { return m_apolygonid; } set { m_apolygonid = value; } } /// /// 操作类型 /// public ParticleOperator Operator { get { return m_operator; } set { m_operator = value; } } /// /// 原先的操作类型 /// public ParticleOperator OldOperator { get { return m_oldoperator; } set { m_oldoperator = value; } } } #endregion #region 颗粒分布图,排序图统一使用类 /// /// 颗粒排序,能对颗粒进行分栏的类 /// public class SortParticleDistribution : ICloneable { private List list_dparticle = new List(); private RectangleF m_rectf; private string m_showstr = ""; private float m_size_min = 0; private float m_size_max = 0; public SortParticleDistribution() { } //构造函数 SortParticleDistribution(List inlist_dparticle, SortParticleDistribution in_spd) { m_rectf = in_spd.m_rectf; m_showstr = in_spd.m_showstr; m_size_min = in_spd.m_size_min; m_size_max = in_spd.m_size_max; foreach (DParticle e in inlist_dparticle) { list_dparticle.Add(e.Clone() as DParticle); } } /// /// 克隆方法 /// /// public object Clone() { return new SortParticleDistribution(this.list_dparticle, this); } /// /// 多边形图数组 /// public List List_DParticle { get { return list_dparticle; } set { list_dparticle = value; } } /// /// 整个分类Grid的位置 /// public RectangleF RectF { get { return m_rectf; } set { m_rectf = value; } } /// /// 该分类Grid显示的文字 /// public string ShowStr { get { return m_showstr; } set { m_showstr = value; } } /// /// 该Grid保存多边形范围的最小值 /// public float Size_Min { get { return m_size_min; } set { m_size_min = value; } } /// /// 该Grid保存多边形范围的最大值 /// public float Size_Max { get { return m_size_max; } set { m_size_max = value; } } /// /// 获取多边形Grid内,所有多边形所占有的行数,用于其它计算使用 /// /// public int GetDParticleRowNumber() { int RowsNumber = 0; //首先获取所有多边形的宽度之和 float f_all_dparticle_widthsum = 0; foreach (DParticle dp in this.list_dparticle) { f_all_dparticle_widthsum = f_all_dparticle_widthsum + dp.Rect.Width; } //然后除以自身的宽度+1,就是所有的行数了 float f_rowsnumber = f_all_dparticle_widthsum / this.RectF.Width + 1; RowsNumber = Convert.ToInt32(f_rowsnumber); return RowsNumber; } /// /// 获取多边形分栏,分栏的高度 /// /// public float GetSortGridHeight() { float i_SortGridHeight = 0; int i_RowNumber = GetDParticleRowNumber(); //再获取所有的颗粒中,最长的 float i_heightmax = 0; float i_ls_height = 0; foreach (DParticle dp in this.list_dparticle) { float ls_y = 0;//用来判断y坐标是否有变化,好用来计算长度 foreach (DSegment ds in dp.DSegments) { if (ds.Rect.Y != ls_y) { //i_ls_height++; ls_y = ds.Rect.Y; //如果需要考虑笔宽缩放的话,目前这样写,效果还没有出现问题 i_ls_height = i_ls_height + ds.Rect.Height * ds.PenWidthAndHeight; } if (i_heightmax < i_ls_height) { i_heightmax = i_ls_height; } } i_ls_height = 0; } //用最高的颗粒*行数,来计算整个grid的高度 i_SortGridHeight = i_RowNumber * (i_heightmax + 10) + 20;//因为每行都额外增加了10点的高度 //应该当grid最小大于=50 if (i_SortGridHeight < 50) { i_SortGridHeight = 50; } return i_SortGridHeight; } /// /// 根据传入的2个多边形list,从大到小进行排序,两个多边形list通过guid保持一致 /// 主要用于计算list与old_list能进行相同顺序的排序 /// /// /// public void SortDParticleBySizeFromBigToSmall(List list_dparticle, List old_list_dparticle) { //首先分别将两个多边形list保存起来 List list_dp1 = new List(); List list_dp2 = new List(); foreach (DParticle ls_dp in list_dparticle) { DParticle dp1 = ls_dp.Clone() as DParticle; list_dp1.Add(dp1); } foreach (DParticle ls_dp in old_list_dparticle) { DParticle dp2 = ls_dp.Clone() as DParticle; list_dp2.Add(dp2); } //清除原先的两个多边形list list_dparticle.Clear(); old_list_dparticle.Clear(); //嵌套2次循环 int icount = list_dp1.Count(); for (int i = 0; i < icount; i++) { //找出最大的 float f_max_size = 0; string str_jlguid = ""; DParticle ls_dp = new DParticle(); foreach (DParticle ls_del_dp in list_dp1) { //通过包含的线,获取多边形的尺寸大小 ls_del_dp.FSize = ls_del_dp.GetSizeFormSegmentsAllWidth(); if (f_max_size < ls_del_dp.FSize) { f_max_size = ls_del_dp.FSize; str_jlguid = ls_del_dp.ID; ls_dp = ls_del_dp; } } //然后分别将两个该guid的多边形从list1,2中删除 list_dp1.Remove(ls_dp); //再分别插入到原先的list,和old_list中 ls_dp.Rect = ls_dp.GetRectFromDSegment(); list_dparticle.Add(ls_dp); } //换种方法,按Guid将list2中对应的再添加到old_list中 foreach (DParticle ls_dp in list_dparticle) { foreach (DParticle ls_dp2 in list_dp2) { if (ls_dp2.ID == ls_dp.ID) { ls_dp2.Rect = ls_dp2.GetRectFromDSegment(); old_list_dparticle.Add(ls_dp2); } } } } /// /// 根据传入的2个多边形list,从小到大进行排序,两个多边形list通过guid保持一致 /// 主要用于计算list与old_list能进行相同顺序的排序 /// /// /// public void SortDParticlesBySizeFromSmallToBig(List list_dparticle, List old_list_dparticles) { //首先分别将两个多边形list保存起来 List list_dp1 = new List(); List list_dp2 = new List(); foreach (DParticle ls_dp in list_dparticle) { DParticle dp1 = ls_dp.Clone() as DParticle; list_dp1.Add(dp1); } foreach (DParticle ls_dp in old_list_dparticles) { DParticle dp2 = ls_dp.Clone() as DParticle; list_dp2.Add(dp2); } //清除原先的两个多边形list list_dparticle.Clear(); old_list_dparticles.Clear(); //嵌套2次循环 int icount = list_dparticle.Count(); for (int i = 0; i < icount; i++) { //找出最小的 float f_min_size = 10000000; string str_jlguid = ""; DParticle ls_dp = new DParticle(); foreach (DParticle ls_del_dp in list_dp1) { //通过包含的线,获取多边形的尺寸大小 ls_del_dp.FSize = ls_del_dp.GetSizeFormSegmentsAllWidth(); if (f_min_size > ls_del_dp.FSize) { f_min_size = ls_del_dp.FSize; str_jlguid = ls_del_dp.ID; ls_dp = ls_del_dp; } } //然后分别将两个该guid的多边形从list1,2中删除 list_dp1.Remove(ls_dp); //再分别插入到原先的list,和old_list中 list_dparticle.Add(ls_dp); } //换种方法,按Guid将list2中对应的再添加到old_list中 foreach (DParticle ls_dp in list_dparticle) { foreach (DParticle ls_dp2 in list_dp2) { if (ls_dp2.ID == ls_dp.ID) { old_list_dparticles.Add(ls_dp2); } } } } /// /// 颗粒排序方法2 /// /// public void SortParticle222(float in_f_zoom_record) { float f_ls_x = this.m_rectf.X + 3 * in_f_zoom_record; float f_ls_y = this.m_rectf.Y + 3 * in_f_zoom_record; foreach (DParticle dp in this.list_dparticle) { dp.Rect = dp.GetRectFromDSegment(); if ((f_ls_x + dp.Rect.Width + 6) > this.m_rectf.Width + this.m_rectf.X) { f_ls_x = this.m_rectf.X + 3 * in_f_zoom_record; f_ls_y = f_ls_y + this.GetSortGridHeight() / this.GetDParticleRowNumber() - 5; } float f_cz_x = f_ls_x - dp.Rect.X; float f_cz_y = f_ls_y - dp.Rect.Y; foreach (DSegment ds in dp.DSegments) { ds.Rect = new RectangleF(ds.Rect.X + f_cz_x, ds.Rect.Y + f_cz_y, ds.Rect.Width, ds.Rect.Height); } f_ls_x = f_ls_x + dp.Rect.Width + 3 * in_f_zoom_record; dp.Rect = dp.GetRectFromDSegment(); dp.GPath = dp.GetRegionFromDSegments(); dp.SmallRect = dp.GetSmallRectangleFromRect(); } } /// /// 对已经存入的颗粒信息,按定位好的rect位置,重新给line和各参数,重新进行计算 /// 就是在分栏的Grid中对多边形进行摆放 /// public void SortDParticle(float in_f_zoom_record) { //设置增长的x,y轴值,+3是跳过边框的位置, 可能有个别情况,会在右侧突出占到边框的位置上 float f_ls_x = this.m_rectf.X + 3 * in_f_zoom_record; float f_ls_y = this.m_rectf.Y + 3 * in_f_zoom_record; foreach (DParticle dp in this.list_dparticle) { //这里要对不显示的颗粒进行屏蔽,也就是进行不计算位置,不知道会不会有其它的影响 if (dp.Operator !=ParticleOperator.NODISPLAY) { //首先确定各多边形的矩形位置 dp.Rect = dp.GetRectFromDSegment(); //判断是否已经达到了x的边缘,是的话,那么y轴进行增长,判断x轴+颗粒的宽度+6的相当于边框宽度的差值补值,大于grid宽度时 //在增长前就判断宽度,防止部份多边形突出到分栏外 if ((f_ls_x + dp.Rect.Width + 6) > this.m_rectf.Width + this.m_rectf.X) { //还原x到该分栏Grid的左边框+3的位置,并且将y轴定位到下一高度的y轴位置 f_ls_x = this.m_rectf.X + 3 * in_f_zoom_record; f_ls_y = f_ls_y + this.GetSortGridHeight() / this.GetDParticleRowNumber() - 5;//在获取高度时,已经+10,所以这里再-5,颗粒近一些 } //计算出与定位的Grid的差值,然后重新排序线,用分栏Grid-颗粒的外Rect,取到x,y的差值 float f_cz_x = f_ls_x - dp.Rect.X; float f_cz_y = f_ls_y - dp.Rect.Y; //获取到差值后,再对该多边形下面的所有线进行调整 foreach (DSegment ds in dp.DSegments) { ds.Rect = new RectangleF(ds.Rect.X + f_cz_x, ds.Rect.Y + f_cz_y, ds.Rect.Width, ds.Rect.Height); } //定位好该多边形后,对x轴进行增长,为下一个多边形定位好位置 f_ls_x = f_ls_x + dp.Rect.Width + 3 * in_f_zoom_record; //重新计算sort_ap的 dp.Rect = dp.GetRectFromDSegment(); //通过line获取路径边缘 dp.GPath = dp.GetRegionFromDSegments(); //重新计算小矩形边框 dp.SmallRect = dp.GetSmallRectangleFromRect(); } } } } /// /// 包含DParticle类的field类,目前只用于绘制背景色,按理说应该有更多的作用,比如做多线程分式运算 /// public class DField:BaseObject { string m_id; string m_tagid; string m_fieldid; bool m_IsDragging; Color m_backcolor; List m_list_dparticle; RectangleF m_ots_rect; //按底层设计结构,底层返回的物理坐标位置及大小,OTS坐标大小 RectangleF m_pix_rect; //与底层返回物理坐标及位置大小对应转换成,pixel像素分率下的坐标位置大小 RectangleF m_show_rect;//最后换算到在显示器上显示的坐标位置大小 RectangleF m_current_rect;//当前field在显示器上显示的坐标位置大小 PointF m_dragingpoint;//鼠标拖动的位置 private string m_GBContent; private PointF m_OTSPointF; private bool m_IsSelect; private Color m_color; private GraphicsPath m_GPath; /// /// 构造函数 /// public DField() { m_id = System.Guid.NewGuid().ToString(); } public DField(List in_list_dparticle) { m_list_dparticle = in_list_dparticle; } /// /// ID /// //public string ID //{ // get { return m_id; } // set { m_id = value; } //} public override string ID { get => m_id; set => m_id=value; } /// /// 记录与底层对应的TagID /// public string TagID { get { return m_tagid; } set { m_tagid = value; } } /// /// 是否被拖动标识 /// //public bool IsDragging //{ // get { return m_IsDragging; } // set { m_IsDragging = value; } //} public override bool IsDragging { get => m_IsDragging; set => m_IsDragging=value; } /// /// 被拖动到的位置坐标 /// //public PointF DraggingPoint //{ // get { return m_dragingpoint; } // set { m_dragingpoint = value; } //} public override PointF DraggingPoint { get => m_dragingpoint; set => m_dragingpoint=value; } /// /// 与底层对应的ID,这里叫成FieldID /// public string FieldID { get { return m_fieldid; } set { m_fieldid = value; } } public override Color BackColor { get => m_backcolor; set => m_backcolor=value; } /// /// 包含的Particle列表 /// public List List_DParticle { get { return m_list_dparticle; } set { m_list_dparticle = value; } } /// /// 该Field的OTS坐标及大小 /// public RectangleF OTS_RECT { get { return m_ots_rect; } set { m_ots_rect = value; } } /// /// 该Field物理坐标大小转换出,对应的像素坐标及大小 /// public RectangleF Pix_Rect { get { return m_pix_rect; } set { m_pix_rect = value; } } /// /// 该Field最后在屏幕上显示的坐标及大小 /// public RectangleF Show_Rect { get { return m_show_rect; } set { m_show_rect = value; } } /// /// Field当前在屏幕上显示的坐标及大小 /// public RectangleF Current_Rect { get { return m_current_rect; } set { m_current_rect = value; } } public override RectangleF Rect { get => m_ots_rect; set => m_ots_rect=value; } public override PointF OTSPointF { get => m_OTSPointF; set => m_OTSPointF=value; } public override bool IsSelect { get => m_IsSelect; set => m_IsSelect=value; } public override Color Color { get => m_color; set => m_color=value; } public override GraphicsPath GPath { get => m_GPath; set =>m_GPath=value; } public override void OnPaint(PaintEventArgs e) { throw new NotImplementedException(); } } /// /// Particle对象上操作状态的枚举,显示,不显示,已删除,已选择 /// public enum ParticleOperator { DISPLAY = 0, NODISPLAY = 1, DELETED = 2, SELECTED =3, } /// /// Particle对象上操作xray的枚举状态,显示xray数据,不显示 /// public enum ParticleOperatorShowXray { SELECTANDDISPLAYXRAY = 0, NODISPLAY = 1, } /// /// Segment对象绘制的枚举,以点绘制,还是以线绘制 /// public enum SegmentShowMode { DRAWPOINT = 0, DRAWLINE = 1, } /// /// 颗粒类 /// public class DParticle : BaseObject, ICloneable, IComparable { private string m_id; private RectangleF m_rect; private PointF m_OTSPointF; private RectangleF m_small_rect; private bool m_isselected_smallrect; private bool m_showsmallx; private bool m_isselect; private ParticleOperator m_operator = ParticleOperator.DISPLAY;//显示,不显示,删除,选择,默认应为(不显示) private ParticleOperatorShowXray m_operator_showxray = ParticleOperatorShowXray.NODISPLAY;//选定显示XRAY,不显示XRAY,默认应为(不显示XRAY) private bool m_isdragging; private PointF m_dragingpoint; private Color m_color; private Color m_backcolor; private GraphicsPath m_gpath; private List m_listdsegment = new List(); private bool m_IsMouseMove; private float m_zoom_displaymultiplier = 1; private bool m_zoom_display; private string m_sort_type = "从大到小"; private float m_f_size = 0; private string m_str_lj = "颗粒粒级"; private string m_str_klzl = "颗粒种类"; private string m_str_klfl = "颗粒分类"; private int m_clrfieldid = 0; private int m_clrtagid = 0; private int m_stdtypeid = 0;//表示这个颗粒分析出来后的类型 //TypeId public int TypeId { set; get; } //TypeName public string TypeName { set; get; } //XRayId public int XRayId { set; get; } public int SEMPosX { set; get; } public int SEMPosY { set; get; } //国标内容 private string m_GBContent = ""; public DParticle() { m_id = System.Guid.NewGuid().ToString(); } public DParticle(List in_list_segment, DParticle in_particle) { // m_id = System.Guid.NewGuid().ToString(); m_id = in_particle.m_id; m_zoom_display = in_particle.m_zoom_display; m_zoom_displaymultiplier = in_particle.m_zoom_displaymultiplier; m_clrfieldid = in_particle.m_clrfieldid; m_clrtagid = in_particle.m_clrtagid; m_operator = in_particle.m_operator; m_operator_showxray = in_particle.m_operator_showxray; m_stdtypeid = in_particle.m_stdtypeid; SEMPosX = in_particle.SEMPosX; SEMPosY = in_particle.SEMPosY; foreach (DSegment e in in_list_segment) { m_listdsegment.Add(e.Clone() as DSegment); } } /// /// [目前也不使用该方法了,因为该方法每次排序都有不同的结果]多边形排序,按传入的sort_type的排序类型行排序,但需要两个list做一致性排序 /// /// /// public int CompareTo(DParticle in_particle) { int r_b = 0;//排序返回值 switch (m_sort_type) { case "从大到小": r_b = in_particle.m_f_size.CompareTo(this.m_f_size); break; case "从小到大": //与上面的从大到小正好相反即可 r_b = in_particle.m_f_size.CompareTo(this.m_f_size); if (r_b == 1) r_b = -1; else r_b = 1; break; default: break; } return r_b; } /// /// 克隆方法 /// /// public override object Clone() { return new DParticle(this.m_listdsegment, this); } /// /// ID /// public override string ID { get { return m_id; } set { m_id = value; } } /// /// 颗粒的外边框大小 /// public override RectangleF Rect { get { return m_rect; } set { m_rect = value; } } /// /// OTSPointF /// public override PointF OTSPointF { get { return m_OTSPointF; } set { m_OTSPointF = value; } } /// /// 颗粒里+号位置的外边框大小 /// public RectangleF SmallRect { get { return m_small_rect; } set { m_small_rect = value; } } /// /// 颗粒是否被选择 /// public override bool IsSelect { get { return m_isselect; } set { m_isselect = value; } } /// /// 该颗粒是否被设置成,选中状态 /// public ParticleOperator Operator { get { return m_operator; } set { m_operator = value; } } /// /// 是否对该颗粒选定显示X-Ray能谱图 /// public ParticleOperatorShowXray Operator_ShowXRay { get { return m_operator_showxray; } set { m_operator_showxray = value; } } /// /// 鼠标是否在该矩形上 /// public bool IsMouseMove { get { return m_IsMouseMove; } set { m_IsMouseMove = value; } } /// /// 是否显示x号 /// public bool IsShowSmallX { get { return m_showsmallx; } set { m_showsmallx = value; } } /// /// 颗粒的x-ray的点,是否被选择上了 /// public bool IsSelectedSmallRect { get { return m_isselected_smallrect; } set { m_isselected_smallrect = value; } } /// /// 是否在被拖动 /// public override bool IsDragging { get { return m_isdragging; } set { m_isdragging = value; } } /// /// 被拖动到的位置坐标 /// public override PointF DraggingPoint { get { return m_dragingpoint; } set { m_dragingpoint = value; } } /// /// 线的颜色 /// public override Color Color { get { return m_color; } set { m_color = value; } } /// /// 背景色 /// public override Color BackColor { get { return m_backcolor; } set { m_backcolor = value; } } /// /// 多边形的图形路径边缘 /// public override GraphicsPath GPath { get { return m_gpath; } set { m_gpath = value; } } /// /// 里面包含的多个线的集合 /// public List DSegments { get { return m_listdsegment; } set { m_listdsegment = value; } } /// /// 控制多边形在进行缩放到多少倍时进行显示 /// public float Zoom_DisPlayMultiplier { get { return m_zoom_displaymultiplier; } set { m_zoom_displaymultiplier = value; } } /// /// 临时的变量,控制进行缩放时,是显示+号,还是显示多边形 /// public bool Zoom_DisPlay { get { return m_zoom_display; } set { m_zoom_display = value; } } /// /// 设置排序的类型 /// public string SortType { get { return m_sort_type; } set { m_sort_type = value; } } /// /// 设置该多边形的尺寸大小 /// public float FSize { get { return m_f_size; } set { m_f_size = value; } } /// /// 设置粒级 /// public string ParticleLJ { get { return m_str_lj; } set { m_str_lj = value; } } /// /// 设置种类 /// public string ParticleZL { get { return m_str_klzl; } set { m_str_klzl = value; } } /// /// 设置分类 /// public string ParticleFL { get { return m_str_klfl; } set { m_str_klfl = value; } } /// /// 获取或设置该Particle对应底层的FieldID值 /// public int CLRFieldID { get { return m_clrfieldid; } set { m_clrfieldid = value; } } /// /// 获取或设置该Particle对应底层的ParticleID值 /// public int CLRTagID { get { return m_clrtagid; } set { m_clrtagid = value; } } /// /// 获取或设置STD分析物的ID /// public int STDTypeID { get { return m_stdtypeid; } set { m_stdtypeid = value; } } /// /// 绘制函数 /// /// public override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; //绘制鼠标移动到颗粒上时的边框,需要判断当前鼠标在颗粒上,及颗粒的操作为正常显示 if (true == m_IsMouseMove && m_operator == ParticleOperator.DISPLAY) { //如果有鼠标在该矩形上,那么进行描边 ControlPaint.DrawBorder(g, Rectangle.Round(this.Rect), Color.Lime, 1, ButtonBorderStyle.Solid, Color.Lime, 1, ButtonBorderStyle.Solid, Color.Lime, 1, ButtonBorderStyle.Solid, Color.Lime, 1, ButtonBorderStyle.Solid); } else { //应该是什么都不做就可以了,就刷新掉了 } if (ParticleOperator.SELECTED == m_operator) { //如果説该矩形被选择上了的话,那么也显示边框 ControlPaint.DrawBorder(g, Rectangle.Round(this.Rect), Color.Blue, 1, ButtonBorderStyle.Solid, Color.Blue, 1, ButtonBorderStyle.Solid, Color.Blue, 1, ButtonBorderStyle.Solid, Color.Blue, 1, ButtonBorderStyle.Solid); } if (ParticleOperatorShowXray.SELECTANDDISPLAYXRAY == m_operator_showxray && ParticleOperator.NODISPLAY != m_operator) { //当鼠标在该颗粒上进行点击,则对颗粒状态更改为选定状态,用来显示X-ray能谱表 ControlPaint.DrawBorder(g, Rectangle.Round(this.Rect), Color.DeepSkyBlue, 1, ButtonBorderStyle.Solid, Color.DeepSkyBlue, 1, ButtonBorderStyle.Solid, Color.DeepSkyBlue, 1, ButtonBorderStyle.Solid, Color.DeepSkyBlue, 1, ButtonBorderStyle.Solid); } //只有正常和选择中的颗粒才进行绘制显示 if (m_operator == ParticleOperator.DISPLAY || m_operator == ParticleOperator.SELECTED) { if (m_zoom_display == true) { //调用绘制基本线 foreach (DSegment item in m_listdsegment) { item.OnPaint(e); } } else { g.DrawString("+", new Font("黑体", 6), new SolidBrush(Color.DarkSlateBlue), new PointF(m_small_rect.X, m_small_rect.Y)); } } } /// /// 从Line中获取矩形的边缘闭合路径 /// /// public GraphicsPath GetRegionFromDSegments() { GraphicsPath gpath = new GraphicsPath(); List list_leftpointf = new List(); List list_rightpointf = new List(); //从y循环,这里假设y轴会按lines集合来计算,然后将所有的左x,和右x取出排成两个队列 foreach (DSegment ds in this.m_listdsegment) { list_leftpointf.Add(new PointF(ds.Rect.X, ds.Rect.Y)); list_rightpointf.Add(new PointF(ds.Rect.X + ds.Rect.Width, ds.Rect.Y)); } PointF[] lsp = new PointF[list_leftpointf.Count + list_rightpointf.Count]; //再将两个x,y点依次添加到闭合路径中 for (int i = 0; i < list_leftpointf.Count(); i++) { lsp[i] = list_leftpointf[i]; } //右节点 for (int i = 0; i < list_rightpointf.Count(); i++) { //这边倒着存入 lsp[list_rightpointf.Count() + i] = list_rightpointf[list_rightpointf.Count() - i - 1]; } //防止从低层拿到无数据的外边路径,在我的程序里却需要计算,而防止程序报死,这里做一下特殊处理。 if (lsp.Count() >= 3) { gpath.AddPolygon(lsp); } else { //有时居然有颗粒,有没有segment的时候,防止报错 if (this.DSegments.Count == 0) { lsp = new PointF[3] { new PointF(0, 0), new PointF(0, 0), new PointF(0, 0) }; gpath.AddPolygon(lsp); return gpath; } //有2条数据 if (lsp[1].X != 0 && lsp[1].Y != 0) { lsp = new PointF[3] { new PointF(lsp[0].X, lsp[0].Y), new PointF(lsp[1].X, lsp[1].Y), new PointF(lsp[1].X, lsp[1].Y) }; } //有1条数据 else if (lsp[0].X != 0 && lsp[0].Y != 0) { lsp = new PointF[3] { new PointF(lsp[0].X, lsp[0].Y), new PointF(lsp[0].X, lsp[0].Y), new PointF(lsp[0].X, lsp[0].Y) }; } //剩下的情况 else { lsp = new PointF[3] { new PointF(0, 0), new PointF(0, 0), new PointF(0,0) }; } gpath.AddPolygon(lsp); } return gpath; } /// /// 从已经确定的外边框来计算出里面的+号小框位置 /// /// public RectangleF GetSmallRectangleFromRect() { RectangleF rect = new RectangleF(); //用外边框的坐标,除2获得中心点,然后再分别+,- 4 float x = 0, y = 0; x = m_rect.X + (m_rect.Width / 2); y = m_rect.Y + (m_rect.Height / 2); rect.X = x - 4; rect.Y = y - 4; rect.Width = 8; rect.Height = 4; return rect; } /// /// 根据该多边形所有包含的线长度,计算出,该多边形的面积大小 /// /// public float GetSizeFormSegmentsAllWidth() { float f_size_sum = 0; foreach (DSegment ls_ds in this.m_listdsegment) { f_size_sum = f_size_sum + ls_ds.Rect.Width; } return f_size_sum; } /// /// 从基本线中获取整个矩形的Rectangle /// /// public RectangleF GetRectFromDSegment() { RectangleF rect = new RectangleF(); float x1 = 0, y1 = 0; float i_width = 0, i_height = 0; //先从自身中初始化x,y,和宽,高 if (this.m_listdsegment.Count > 0) { x1 = this.m_listdsegment[0].Rect.X; y1 = this.m_listdsegment[0].Rect.Y; i_width = x1 + this.m_listdsegment[0].Rect.Width; i_height = this.m_listdsegment[0].Rect.Y; } foreach (DSegment ds in this.m_listdsegment) { //分别取出,最小的x,y, if (ds.Rect.X < x1) { x1 = ds.Rect.X; } if (ds.Rect.Y < y1) { y1 = ds.Rect.Y; } //最大的x,y if (ds.Rect.X + ds.Rect.Width > i_width) { i_width = ds.Rect.X + ds.Rect.Width; } if (ds.Rect.Y > i_height) { i_height = ds.Rect.Y; } } //对矩形Rect大小位置进行修补,因为画线是内边框,并且计算出来的位置也是向内占用一像素的, //正常应该是 +2,但实际效果,+3也才勉强够用,因为放大缩小画笔宽度影响的 rect.X = x1 - 2; rect.Y = y1 - 3; rect.Width = i_width - rect.X + 2; rect.Height = i_height - rect.Y + 3; //判断如果太小,就给个最小值吧 if (rect.Width < 8) rect.Width = 8; if (rect.Height < 8) rect.Height = 8; return rect; } } /// /// 基本线类 /// public class DSegment : BaseObject, ICloneable { private string m_id; private RectangleF m_region; private PointF m_OTSPointF; private bool m_isselect; private bool m_isdragging; private PointF m_dragingpoint; private Color m_color; private Color m_backcolor; private GraphicsPath m_gpath; private float m_PenWidthAndHeight = 1; private SegmentShowMode show_mode = SegmentShowMode.DRAWPOINT;//绘线,绘点,默认绘点,意思为默认显示BSE原图像 private List m_list_colors; /// /// 克隆基本线 /// /// public override object Clone() { return MemberwiseClone(); } public DSegment() { m_id = System.Guid.NewGuid().ToString(); } /// /// ID /// public override string ID { get { return m_id; } set { m_id = value; } } /// /// 画面的大小 /// public override RectangleF Rect { get { return m_region; } set { m_region = value; } } /// /// OTSField /// public override PointF OTSPointF { get { return m_OTSPointF; } set { m_OTSPointF = value; } } /// /// 画布是否被选择 /// public override bool IsSelect { get { return m_isselect; } set { m_isselect = value; } } /// /// 是否在被拖动 /// public override bool IsDragging { get { return m_isdragging; } set { m_isdragging = value; } } /// /// 被拖动到的位置坐标 /// public override PointF DraggingPoint { get { return m_dragingpoint; } set { m_dragingpoint = value; } } /// /// 线的颜色 /// public override Color Color { get { return m_color; } set { m_color = value; } } /// /// 背景色 /// public override Color BackColor { get { return m_backcolor; } set { m_backcolor = value; } } /// /// 多边形的图形路径边缘 /// public override GraphicsPath GPath { get { return m_gpath; } set { m_gpath = value; } } /// /// 设置画笔的笔宽度 /// public float PenWidthAndHeight { get { return m_PenWidthAndHeight; } set { m_PenWidthAndHeight = value; } } /// /// 设置显示的方式,可以用,绘线显示查看标准库颜色的,也可以用绘点,查看BSE原图颗粒图色的 /// public SegmentShowMode ShowMode { get { return show_mode; } set { show_mode = value; } } /// /// 保存BSE标准库文件的颗粒点的颜色信息 /// public List List_Colors { get { return m_list_colors; } set { m_list_colors = value; } } /// /// 绘制函数 /// /// public override void OnPaint(PaintEventArgs e) { //两种绘制模式的选择,绘线还是缓点 if (show_mode == SegmentShowMode.DRAWLINE) { //表示显示的是带有标准库的图像 Pen p = new Pen(m_color, m_PenWidthAndHeight + 1f);//这里加1f的宽度后,用线组成多边形不会分散,效果正常,原因不知,但目前没有遇到问题 e.Graphics.DrawLine(p, Rect.X, Rect.Y, Rect.X + Rect.Width, Rect.Y); } else if (show_mode == SegmentShowMode.DRAWPOINT) { //根据color的序列,显示绘制的原像素的图像。 for (int i = 0; i < m_list_colors.Count(); i++) { e.Graphics.FillRectangle(new SolidBrush(m_list_colors[i]), this.Rect.X + (i * m_PenWidthAndHeight) + 1f, this.Rect.Y, m_PenWidthAndHeight, m_PenWidthAndHeight); } } } } #endregion }