364 lines
11 KiB
C#
364 lines
11 KiB
C#
using Io.Github.Kerwinxu.LibShapes.Core.Serialize;
|
||
using Io.Github.Kerwinxu.LibShapes.Core.Shape;
|
||
using Newtonsoft.Json;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Drawing;
|
||
using System.Drawing.Drawing2D;
|
||
using System.Linq;
|
||
using System.Text;
|
||
|
||
|
||
namespace Io.Github.Kerwinxu.LibShapes.Core
|
||
{
|
||
/// <summary>
|
||
/// 图形的集合
|
||
/// </summary>
|
||
public class Shapes
|
||
{
|
||
#region 保存读取相关
|
||
|
||
private static ISerialize serialize = new JsonSerialize();
|
||
|
||
/// <summary>
|
||
/// 读取
|
||
/// </summary>
|
||
/// <param name="filename"></param>
|
||
/// <returns></returns>
|
||
public static Shapes load(string filename)
|
||
{
|
||
if (serialize != null
|
||
&& ! string.IsNullOrEmpty(filename)
|
||
&& System.IO.File.Exists(filename))
|
||
{
|
||
return serialize.DeserializeObject<Shapes>(System.IO.File.ReadAllText(filename));
|
||
}
|
||
else
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入
|
||
/// </summary>
|
||
/// <param name="filename"></param>
|
||
public void save(string filename)
|
||
{
|
||
// 写入文件
|
||
if (serialize != null)
|
||
{
|
||
System.IO.File.WriteAllText(filename, serialize.SerializeObject(this));
|
||
}
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
|
||
#region 一堆属性,这些可以被json保存
|
||
// 图形的集合
|
||
public List<ShapeEle> lstShapes { get; set; }
|
||
/// <summary>
|
||
/// 坐标转换
|
||
/// </summary>
|
||
public PointTransform pointTransform { get; set; }
|
||
|
||
/// <summary>
|
||
/// 纸张的信息
|
||
/// </summary>
|
||
public Paper.Paper Paper { get; set; }
|
||
|
||
/// <summary>
|
||
/// 变量信息
|
||
/// </summary>
|
||
private Dictionary<string,string> _vars;
|
||
|
||
public Dictionary<string,string> Vars
|
||
{
|
||
get { return _vars; }
|
||
set {
|
||
_vars = value;
|
||
// 然后这里直接更新吧。
|
||
if (value != null && lstShapes != null && lstShapes.Count > 0)
|
||
{
|
||
foreach (var item in lstShapes)
|
||
{
|
||
item.setVals(value);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region 构造函数
|
||
|
||
public Shapes()
|
||
{
|
||
lstShapes = new List<ShapeEle>();
|
||
pointTransform = new PointTransform();
|
||
//Paper = new Paper.Paper();
|
||
Vars = new Dictionary<string, string>();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 一堆方法
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="g"></param>
|
||
/// <param name="matrix">偏移和放大</param>
|
||
/// <param name="isShowModelBackground">是否打印模板背景</param>
|
||
public void Draw(Graphics g, Matrix matrix, bool isShowModelBackground=true)
|
||
{
|
||
// 1. 先初始化
|
||
initGraphics(g);
|
||
// 2. 绘制模板背景
|
||
if (isShowModelBackground && this.Paper != null && this.Paper.ModelShape != null)
|
||
{
|
||
// 这个纸张的绘制,x,y都是0,width和height是模板的宽和高,不是纸张的。
|
||
this.Paper.ModelShape.X = 0;
|
||
this.Paper.ModelShape.Y = 0;
|
||
this.Paper.ModelShape.Draw(g, matrix);
|
||
}
|
||
// 3. 显示所有的图形。
|
||
if (lstShapes != null && lstShapes.Count > 0)
|
||
{
|
||
foreach (var item in lstShapes)
|
||
{
|
||
item.Draw(g, matrix); // 绘图每一个
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 这个返回偏移和放大后的矩阵
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public Matrix GetMatrix()
|
||
{
|
||
return pointTransform.GetMatrix();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 这个主要是用来初始化的,高精度的
|
||
/// </summary>
|
||
/// <param name="g"></param>
|
||
private void initGraphics(Graphics g)
|
||
{
|
||
g.SmoothingMode = SmoothingMode.HighQuality; // 高质量
|
||
g.PixelOffsetMode = PixelOffsetMode.HighQuality; // 指定高质量、低速度呈现。
|
||
g.PageUnit = GraphicsUnit.Millimeter; //将毫米设置为度量单位
|
||
}
|
||
|
||
/// <summary>
|
||
/// 鼠标单机选择一个形状
|
||
/// </summary>
|
||
/// <param name="pointF"></param>
|
||
/// <returns></returns>
|
||
public ShapeEle getSelectShape(PointF pointF)
|
||
{
|
||
if (lstShapes != null && lstShapes.Count > 0)
|
||
{
|
||
foreach (var shape in lstShapes)
|
||
{
|
||
if (shape.IsFill)
|
||
{
|
||
if (shape.isVisible(pointTransform.GetMatrix(), pointF))
|
||
{
|
||
return shape;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (shape.isOutlineVisible(pointTransform.GetMatrix(), pointF))
|
||
{
|
||
return shape;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 选择矩形框内的形状
|
||
/// </summary>
|
||
/// <param name="rect"></param>
|
||
/// <returns></returns>
|
||
public List<ShapeEle> getSelectShapes(RectangleF rect)
|
||
{
|
||
var matrix = pointTransform.GetMatrix();
|
||
if (lstShapes!= null && lstShapes.Count > 0)
|
||
{
|
||
return lstShapes.Where(x => x.isBeContains(matrix, rect)).ToList();
|
||
}
|
||
return null;
|
||
|
||
}
|
||
|
||
public int getNextId()
|
||
{
|
||
// 首先取得所有的id
|
||
var ids = getIds(this.lstShapes);
|
||
|
||
if (ids.Count == 0)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
int i = ids.Max() + 1;
|
||
while (ids.Contains(i))
|
||
{
|
||
i++; // 不重复的,
|
||
}
|
||
return i; // 这里简单一点。
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取得所有的id
|
||
/// </summary>
|
||
/// <param name="shapeeles"></param>
|
||
/// <returns></returns>
|
||
private List<int>getIds(List<ShapeEle> shapeeles)
|
||
{
|
||
List<int> ids = shapeeles.Where(x => !(x is ShapeGroup)).Select(x => x.ID).ToList();
|
||
foreach (var item in shapeeles.Where(x => x is ShapeGroup))
|
||
{
|
||
ids.AddRange(getIds(((ShapeGroup)item).shapes));
|
||
}
|
||
return ids;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据某个id取得相应的形状。
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
public ShapeEle getShape(int id)
|
||
{
|
||
return getShape(lstShapes, id);
|
||
}
|
||
|
||
private ShapeEle getShape(List<ShapeEle> shapeeles, int id)
|
||
{
|
||
if (shapeeles!=null)
|
||
{
|
||
foreach (var item in shapeeles)
|
||
{
|
||
if (item.ID == id)
|
||
{
|
||
return item;
|
||
}
|
||
|
||
if (item is ShapeGroup) // 如果是群组
|
||
{
|
||
var tmp = getShape(((ShapeGroup)item).shapes,id);
|
||
if (tmp != null) return tmp;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将这个id的形状替换了。
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <param name="shape"></param>
|
||
public void replaceShape(int id, ShapeEle shape)
|
||
{
|
||
replaceShape(lstShapes, id, shape);
|
||
}
|
||
|
||
private void replaceShape(List<ShapeEle> shapeeles, int id, ShapeEle shape)
|
||
{
|
||
// 遍历所有的形状
|
||
for (int i = 0; i < shapeeles.Count; i++)
|
||
{
|
||
if (shapeeles[i] is ShapeGroup)
|
||
{
|
||
replaceShape(((ShapeGroup)shapeeles[i]).shapes, id, shape);
|
||
}
|
||
|
||
if (shapeeles[i].ID == id)
|
||
{
|
||
// 找到了
|
||
shapeeles.RemoveAt(i);
|
||
shapeeles.Insert(i, shape);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 这个是缩放到指定的大小。
|
||
/// </summary>
|
||
/// <param name="dpix"></param>
|
||
/// <param name="dpiy"></param>
|
||
/// <param name="width">像素宽度</param>
|
||
/// <param name="height">像素高度</param>
|
||
/// <param name="spacing">像素间距</param>
|
||
public void zoomTo(float dpix, float dpiy, float width, float height, float spacing)
|
||
{
|
||
// 然后计算放大
|
||
var width2 = (width - spacing * 2) / dpix * 25.4; // 转成mm
|
||
var height2 = (height - spacing * 2) / dpiy * 25.4; // 转成mm
|
||
// 然后计算所有图形的的宽度和高度
|
||
ShapeGroup group = new ShapeGroup();
|
||
group.shapes = lstShapes.Select(x => x).ToList();// 这里用复制的方式
|
||
// 这里要判断是否有纸张
|
||
if (this.Paper != null && this.Paper.ModelShape != null)
|
||
{
|
||
group.shapes.Add(this.Paper.ModelShape);
|
||
}
|
||
// 如果没有图形,就直接退出
|
||
if (group.shapes.Count == 0) return;
|
||
//
|
||
var rect = group.GetBounds(new Matrix());// 取得不存在放大偏移的情况下,这个的尺寸
|
||
// 这里解方程,思路是,画布的宽度=倍数*(形状总宽度+两边间距的宽度)
|
||
//width/dpix*25.4 = zoom * (rect.Width + spacing*2/dpix*25.4 /zoom)
|
||
// width/dpix*25.4 = zoom * (rect.Width + spacing*2/dpix*25.4
|
||
var scale1 = (width / dpix * 25.4f - spacing * 2 / dpix * 25.4f) / rect.Width;
|
||
var scale2 = (height / dpiy * 25.4f - spacing * 2 / dpiy * 25.4f) / rect.Height;
|
||
// 取得较小值
|
||
this.pointTransform.Zoom = scale1 < scale2 ? scale1 : scale2; // 取得较小值。
|
||
// 然后这里有一个偏移,要算正负两个方向的偏移,要流出两边的spacing,主要留出左边和上边就可以了。
|
||
this.pointTransform.OffsetX = - rect.X + spacing / dpix * 25.4f ;
|
||
this.pointTransform.OffsetY = - rect.Y + spacing / dpix * 25.4f ;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 深度复制一个
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public Shapes DeepClone()
|
||
{
|
||
//这里用json的方式
|
||
JsonSerialize jsonSerialize = new JsonSerialize();
|
||
string json = jsonSerialize.SerializeObject(this);
|
||
// 可能原因是存在自定义对象的集合,所以这里要用复杂的方式去做
|
||
|
||
|
||
|
||
return jsonSerialize.DeserializeObject<Shapes>(json);
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
|
||
}
|
||
}
|