zoukankan      html  css  js  c++  java
  • C# 开发电子印章制作工具 -- 附下载程序

    前言 本人在业余时间,开发了一款电子印章制作软件。印章制作软件看似简单,其实不然。

    比如对椭圆形印章而言,要求公司名称中的每一个字间隔相等,要求字的方向与椭圆曲线垂直。

    要满足这些条件,需要复杂的计算,并且要有一定的几何学基础。软件界面如下:

    点击下载发票印章生成工具。

    本文主要讲述椭圆形印章制作思路,对于圆形印章 ,软件开发难度并不大。

    椭圆印章要满足以下两个条件:

      1 公司名称字体间隔大小要一样。

      2 字体方向与对应的椭圆曲线是相切的。

    下面分析如何通过程序满足这两点要求。

     1 计算椭圆的弧线长度

       假设公司名称占了椭圆220度边长,如何计算出220度弧线的长度? 肯定有数学公式可以计算。我没有用公式计算。我联想到了“微积分”的概念。可以将这一段弧线切成几千份小的弧线,把小的弧线段长度加起来就是总的长度。小的弧线段长度非常小,可以用两点之间的直线长度代替。

     假设将弧线分成n份,将这n个线段长度加起来就是弧线长度。

           /// <summary>
            /// 将弧线分成splitCount份,计算弧线上的点
            /// </summary>
            /// <param name="startDegree">弧线起始度数</param>
            /// <param name="splitCount">分成多少份</param>
            /// <returns></returns>
            List<PointDouble> GetDrawPoint(double startDegree, int splitCount)
            {
                double a = EllipseWidth / 2;
                double b = EllipseHeight / 2;
    
                List<PointDouble> result = new List<PointDouble>();
    
                Graphics g = Graphics;
                for (int i = 0; i < splitCount; i++)
                {
                    double degree = startDegree + (i * CompanySpanDegree) / splitCount;
                    double k = Math.Tan(ToArc(degree));
                    List<PointDouble> intersections = CalIntersection(a, b, k);
    
                    //Debug.WriteLine(string.Format("degree:{0}", degree));
                    PointDouble ptDraw = new PointDouble();
                    if (degree < 90)
                    {
                        if (intersections[0].X < 0)
                        {
                            ptDraw = intersections[0];
                        }
                        else if (intersections[0].X > 0)
                        {
                            ptDraw = intersections[1];
                        }
                        else
                        {
                        }
                    }
                    else if (degree > 90)
                    {
                        if (intersections[0].X > 0)
                        {
                            ptDraw = intersections[0];
                        }
                        else if (intersections[0].X < 0)
                        {
                            ptDraw = intersections[1];
                        }
                        else
                        {
                        }
                    }
                    else
                    {
                        if (intersections[0].Y < 0)
                        {
                            ptDraw = intersections[0];
                        }
                        else
                        {
                            ptDraw = intersections[1];
                        }
                    }
    
                    result.Add(ptDraw);
                }
    
                return result;
            }

    2 确定每个文字的坐标。

    弧线总长度计算处理后,就可以算出每个文字占用的弧线长度,根据每个文字占用的弧线长度就可以计算出文字的坐标。

            List<PointDouble> CalDrawPoint(float startDegree, int txtCount)
            {
                List<double> listLenPart = new List<double>();
                List<PointDouble> listPoint = GetDrawPoint(startDegree, 10000);
                //计算弧线长度
                double arcLen = CalPointLen(listPoint, listLenPart);
                //每个文字占用的弧线长度
                double txtSpanPer = arcLen / (txtCount - 1);
    
                //计算文字对应的点
                List<PointDouble> result = new List<PointDouble>();
                result.Add(listPoint[0]);
    
                double lenSpanCal = 0;
                for (int i = 0; i < listLenPart.Count; i++)
                {
                    double n = listLenPart[i];
                    lenSpanCal += n;
                    if (lenSpanCal >= txtSpanPer)
                    {
                        result.Add(listPoint[i + 1]);
                        lenSpanCal = 0;
                    }
                }
    
                if (result.Count < txtCount)
                    result.Add(listPoint.Last());
    
                Debug.Assert(result.Count == txtCount);
                return result;
            }

    3 计算文字的旋转角度

     确定了文字的坐标后,就可以计算出该点对应的切线,从而求出切线角度。切线公式如下:

     计算切线坐标源码如下:

           /// <summary>
            /// 计算椭圆切线的角度
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            float CalTangentLineDegree(float x, float y)
            {
                if (y == 0)
                    return 90;
    
                float a = EllipseWidth / 2;
                float b = EllipseHeight / 2;
                float k = -b * b * x / (a * a * y);
                float result = (float)Math.Atan(k);
                result = (float)ToDegree(result);
                return result;
            }

    文字的坐标和旋转角度确定后,后续处理就水到渠成:

     程序界面截图:

     

     

    专注C#、C++。擅长WPF、WinForm、QT等技术。 研究ofd多年,开发了一些列产品。 技术交流QQ群:618168615。
  • 相关阅读:
    This project references NuGet package(s) that are missing on this computer
    Industry Engineer
    winform
    OPC
    groupbox 下的datagridview的列标题字体修改混乱
    vs远程调试
    nuget pack 时不包含依赖包(而不是引用项目的dll,区别于IncludeReferencedProjects)
    Inno Setup入门(二十二)——Inno Setup类参考(8)
    学习GitHub
    python3.4读取excel数据绘图
  • 原文地址:https://www.cnblogs.com/yuanchenhui/p/seal-maker.html
Copyright © 2011-2022 走看看