三. 向量计算(为SolidWorks写扩展方法)

一. SolidWorks中的向量计算和变换

  • SolidWorks 提供了一个IMathUtility 来提供几何计算和矩阵变换.但在有些情况下不能满足计算需求或者计算起来比较繁琐.
    此处使用 C# 的扩展方法扩展了一部分向量计算, 也重新定义了向量对象以便进行更方便有效的操作.

二. 使用方法

  • 将文章后面的代码配置如下
文件架构
  • 引用自己类的命名空间边可以使用扩展的api

MathUtility 扩展方法:

MathUtility 扩展方法

转换为自定义向量类将可以使用更多的计算方法:

转换为自定义向量类将可以使用更多的计算方法

image.png

三. 配置方法- 自己创建向量类和向量计算方法

2.1 添加一个通用配置类来配置一些计算常量的 IMathUtility的访问

    public class MathUtil
    {
        public static MathUtility swMathUtility { get; set; }

        public const double Epsilon = 2.2204460492503131e-016;

        /// <summary>
        /// 每弧度代表的角度
        /// </summary>
        public const double Rad2Deg = (180.0 / System.Math.PI);
        public const double ZeroTolerance = 1e-08;

        public static double Clamp(double f, double low, double high)
        {
            return (f < low) ? low : (f > high) ? high : f;
        }
    }

2.2 添加一个Vector2 的平面向量类,具体实现如下

public class Vector2
    {
        public double X { get; set; }

        public double Y { get; set; }

        public Vector2(double x,double y)
        {
            X = x;
            Y = y;
        }

        /// <summary>
        /// 角度转换为弧度
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static Vector2 FromAngleRad(double angle)
        {
            return new Vector2(System.Math.Cos(angle), System.Math.Sin(angle));
        }

        /// <summary>
        /// 长度平方值
        /// </summary>
        public double LengthSquared
        {
            get { return X * X + Y * Y; }
        }

        /// <summary>
        /// 长度
        /// </summary>
        public double Length
        {
            get { return (double)System.Math.Sqrt(LengthSquared); }
        }

        /// <summary>
        /// 单位化
        /// </summary>
        /// <param name="epsilon"></param>
        /// <returns></returns>
        public double Normalize(double epsilon = MathUtil.Epsilon)
        {
            double length = Length;
            if (length > epsilon) {
                double invLength = 1.0 / length;
                X *= invLength;
                Y *= invLength;
            } else {
                length = 0;
                X = Y = 0;
            }
            return length;
        }

        public bool IsFinite
        {
            get { double f = X + Y; return double.IsNaN(f) == false && double.IsInfinity(f) == false; }
        }

        /// <summary>
        /// 点乘
        /// </summary>
        /// <param name="v2"></param>
        /// <returns></returns>
        public double Dot(Vector2 v2)
        {
            return X * v2.X + Y * v2.Y;
        }

        /// <summary>
        /// 叉乘
        /// </summary>
        /// <param name="v2"></param>
        /// <returns></returns>
        public double Cross(Vector2 v2)
        {
            return X * v2.Y - Y * v2.X;
        }
        /// <summary>
        /// 求与另外一个向量角度--单位度deg
        /// </summary>
        /// <param name="v2"></param>
        /// <returns></returns>
        public double AngleD(Vector2 v2)
        {
            double fDot = MathUtil.Clamp(Dot(v2), -1, 1);
            return System.Math.Acos(fDot) * MathUtil.Rad2Deg;
        }
        /// <summary>
        /// 两个向量角度--单位度deg
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static double AngleD(Vector2 v1, Vector2 v2)
        {
            return v1.AngleD(v2);
        }
        /// <summary>
        /// 求与另外一个向量角度--单位弧度Rad
        /// </summary>
        /// <param name="v2"></param>
        /// <returns></returns>
        public double AngleR(Vector2 v2)
        {
            double fDot = MathUtil.Clamp(Dot(v2), -1, 1);
            return System.Math.Acos(fDot);
        }
        /// <summary>
        /// 两个向量角度--单位弧度Rad
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static double AngleR(Vector2 v1, Vector2 v2)
        {
            return v1.AngleR(v2);
        }

        /// <summary>
        /// 圆整
        /// </summary>
        /// <param name="nDecimals"></param>
        public void Round(int nDecimals)
        {
            X = System.Math.Round(X, nDecimals);
            Y = System.Math.Round(Y, nDecimals);
        }

        public double DistanceSquared(Vector2 v2)
        {
            double dx = v2.X - X, dy = v2.Y - Y;
            return dx * dx + dy * dy;
        }
        public double Distance(Vector2 v2)
        {
            double dx = v2.X - X, dy = v2.Y - Y;
            return System.Math.Sqrt(dx * dx + dy * dy);
        }

        public void Set(Vector2 o)
        {
            X = o.X; Y = o.Y;
        }
        public void Set(double fX, double fY)
        {
            X= fX; Y = fY;
        }
        public void Add(Vector2 o)
        {
           X+= o.X; Y += o.Y;
        }
        public void Subtract(Vector2 o)
        {
            X -= o.X; Y -= o.Y;
        }
    }

2.3 添加三维向量计算类Vector

  • 具体实现如下
 public class Vector3
    {

        private double x;
        private double y;
        private double z;

        public double X { get => x; set => x = value; }
        public double Y { get => y; set => y = value; }
        public double Z { get => z; set => z = value; }
        public static Vector3 Zero { get; internal set; }
        public static Vector3 UnitZ { get; internal set; }

        public Vector3(double[] arrayData)
        {
            if (arrayData.Length >= 3)
            {
                this.X = arrayData[0];
                this.Y = arrayData[1];
                this.Z = arrayData[2];
            }
        }

        public Vector3(double v1, double v2, double v3)
        {
            this.X = v1;
            this.Y = v2;
            this.Z = v3;
        }

        public Vector2 xy
        {
            get { return new Vector2(x, y); }
            set { x = value.X; y = value.Y; }
        }
        public Vector2 xz
        {
            get { return new Vector2(x, z); }
            set { x = value.X; z = value.Y; }
        }
        public Vector2 yz
        {
            get { return new Vector2(y, z); }
            set { y = value.X; z = value.Y; }
        }

        public double LengthSquared
        {
            get { return x * x + y * y + z * z; }
        }
        public double Length
        {
            get { return System.Math.Sqrt(LengthSquared); }
        }


        public double[] ToDoubles()
        {
            return new double[] { X, Y, Z };
        }

        public MathPoint ToSwMathPoint(MathUtility math = null)
        {
            if (math == null)
            {
                math = MathUtil.swMathUtility;
            }
            if (math == null)
            {
                throw new NullReferenceException("MathUtility未将对象引用到对象的实例");
            }
            return math.CreatePoint(ToDoubles());
        }

        /// <summary>
        /// 求三个坐标的绝对值长度和
        /// </summary>
        public double LengthL1
        {
            get { return System.Math.Abs(x) + System.Math.Abs(y) + System.Math.Abs(z); }
        }

        public double Max
        {
            get { return System.Math.Max(x, Math.Max(y, z)); }
        }
        public double Min
        {
            get { return Math.Min(x, Math.Min(y, z)); }
        }

        public double MaxAbs
        {
            get { return Math.Max(Math.Abs(x), Math.Max(Math.Abs(y), Math.Abs(z))); }
        }
        public double MinAbs
        {
            get { return Math.Min(Math.Abs(x), Math.Min(Math.Abs(y), Math.Abs(z))); }
        }

        public Vector3 Abs
        {
            get { return new Vector3(Math.Abs(x), Math.Abs(y), Math.Abs(z)); }
        }

        public double Normalize(double epsilon = MathUtil.Epsilon)
        {
            double length = Length;
            if (length > epsilon)
            {
                double invLength = 1.0 / length;
                x *= invLength;
                y *= invLength;
                z *= invLength;
            }
            else
            {
                length = 0;
                x = y = z = 0;
            }
            return length;
        }

        public Vector3 Unit(double epsilon = MathUtil.Epsilon)
        {
           
                double length = Length;
                if (length > MathUtil.Epsilon)
                {
                    double invLength = 1.0 / length;
                    return new Vector3(x * invLength, y * invLength, z * invLength);
                }
                else
                    return Vector3.Zero;
            
        }

        public bool IsNormalized
        {
            get { return Math.Abs((x * x + y * y + z * z) - 1) < MathUtil.ZeroTolerance; }
        }

        public bool IsFinite
        {
            get { double f = x + y + z; return double.IsNaN(f) == false && double.IsInfinity(f) == false; }
        }

        public void Round(int nDecimals)
        {
            x = Math.Round(x, nDecimals);
            y = Math.Round(y, nDecimals);
            z = Math.Round(z, nDecimals);
        }

        public double Dot(Vector3 v2)
        {
            return x * v2.x + y * v2.y + z * v2.z;
        }
        public double Dot(ref Vector3 v2)
        {
            return x * v2.x + y * v2.y + z * v2.z;
        }
        public static double Dot(Vector3 v1, Vector3 v2)
        {
            return v1.Dot(ref v2);
        }

        public Vector3 Cross(Vector3 v2)
        {
            return new Vector3(
                y * v2.z - z * v2.y,
                z * v2.x - x * v2.z,
                x * v2.y - y * v2.x);
        }
        public Vector3 Cross(ref Vector3 v2)
        {
            return new Vector3(
                y * v2.z - z * v2.y,
                z * v2.x - x * v2.z,
                x * v2.y - y * v2.x);
        }

        public static Vector3 Cross(Vector3 v1, Vector3 v2)
        {
            return v1.Cross(ref v2);
        }

        /// <summary>
        /// 叉乘后单位化
        /// </summary>
        /// <param name="v2"></param>
        /// <returns></returns>
        public Vector3 UnitCross(ref Vector3 v2)
        {
            Vector3 n = new Vector3(
                y * v2.z - z * v2.y,
                z * v2.x - x * v2.z,
                x * v2.y - y * v2.x);
            n.Normalize();
            return n;
        }

        /// <summary>
        /// 叉乘后单位化
        /// </summary>
        /// <param name="v2"></param>
        /// <returns></returns>
        public Vector3 UnitCross(Vector3 v2)
        {
            return UnitCross(ref v2);
        }

        public double AngleD(Vector3 v2)
        {
            double fDot = MathUtil.Clamp(Dot(v2), -1, 1);
            return Math.Acos(fDot) * MathUtil.Rad2Deg;
        }
        public static double AngleD(Vector3 v1, Vector3 v2)
        {
            return v1.AngleD(v2);
        }
        public double AngleR(Vector3 v2)
        {
            double fDot = MathUtil.Clamp(Dot(v2), -1, 1);
            return Math.Acos(fDot);
        }
        public static double AngleR(Vector3 v1, Vector3 v2)
        {
            return v1.AngleR(v2);
        }

        public double DistanceSquared(Vector3 v2)
        {
            double dx = v2.x - x, dy = v2.y - y, dz = v2.z - z;
            return dx * dx + dy * dy + dz * dz;
        }
        public double DistanceSquared(ref Vector3 v2)
        {
            double dx = v2.x - x, dy = v2.y - y, dz = v2.z - z;
            return dx * dx + dy * dy + dz * dz;
        }

        public double Distance(Vector3 v2)
        {
            double dx = v2.x - x, dy = v2.y - y, dz = v2.z - z;
            return Math.Sqrt(dx * dx + dy * dy + dz * dz);
        }
        public double Distance(ref Vector3 v2)
        {
            double dx = v2.x - x, dy = v2.y - y, dz = v2.z - z;
            return Math.Sqrt(dx * dx + dy * dy + dz * dz);
        }

        public void Set(Vector3 o)
        {
            x = o.x; y = o.y; z = o.z;
        }
        public void Set(double fX, double fY, double fZ)
        {
            x = fX; y = fY; z = fZ;
        }

        public Vector3 Add(Vector3 vector3)
        {
            return new Vector3(x + vector3.x, y + vector3.y, z + vector3.z);
        }

        public Vector3 Scale(double length)
        {
            return new Vector3(x * length, y * length, z * length);
        }
    }

四. 配置SolidWorks 计算类的扩展方法

4.1 扩展 MathUtility

public static class MathUtilityExtension
    {
        public static MathPoint PointEx(this MathUtility math, double[] value)
        {
            return math.CreatePoint(value);
        }

        public static MathVector ZAxis(this MathUtility math)
        {
            return math.CreateVector(new double[] { 0, 0, 1 });
        }

        public static MathVector XAxis(this MathUtility math)
        {
            return math.CreateVector(new double[] { 1, 0, 0 });
        }

        public static MathVector YAxis(this MathUtility math)
        {
            return math.CreateVector(new double[] { 0, 1, 0 });
        }
    }

4.2 扩展 MathPoint

  • 具体实现如下
public static class MathPointExtension
    {
        /// <summary>
        /// 转换到Vector3
        /// </summary>
        /// <param name="mathPoint"></param>
        /// <returns></returns>
        public static Vector3 ToVector3(this MathPoint mathPoint)
        {
            return new Vector3((double[])mathPoint.ArrayData);
        }

        /// <summary>
        /// 计算在某轴上的投影
        /// </summary>
        /// <param name="point"></param>
        /// <param name="origin"></param>
        /// <param name="axis"></param>
        /// <returns></returns>
        public static MathPoint Project(this IMathPoint point, IMathPoint origin, IMathVector axis)
        {
            var a = (IMathVector)point.Subtract(origin);
            var t = a.Project(axis);
            var v = (MathVector)axis.Scale(t);
            return (MathPoint)origin.AddVector(v);
        }

        public static MathVector SubtractTs(this IMathPoint a, IMathPoint b)
        {
            return (MathVector)a.Subtract(b);
        }

        public static MathVector SubtractTs(this IMathVector a, IMathVector b)
        {
            return (MathVector)a.Subtract(b);
        }

        /// <summary>
        /// 此点在 XY Plane 中的角度
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static double Angle2D(this IMathPoint p)
        {
            var pData = p.ArrayData.CastArray<double>();
            var angle = System.Math.Atan2(pData[1], pData[0]);
            return angle < 0.0 ? angle + 2 * System.Math.PI : angle;
        }
    }

4.3 扩展 MathVector

 public static class MathVectorExtension
    {

        /// <summary>
        /// a X b => 投影到 b
        /// gives the multiplier for b which would be the projection of a on b
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static double Project(this IMathVector a, IMathVector b)
        {
            return a.Dot(b) / (b.Dot(b));
        }


        public static Vector3 ToVector3(this MathVector mathvector)
        {
            return new Vector3((double[])mathvector.ArrayData);
        }

        public static double LengthOfProjectionXY(this double[] vector)
        {
            return System.Math.Sqrt(vector.Take(2).Sum(c => System.Math.Pow(c, 2)));
        }

        /// <summary>
        /// 两个向量之间的角度
        /// </summary>
        /// <param name="v0"></param>
        /// <param name="v1"></param>
        /// <returns></returns>
        public static double AngleBetweenVectors(this IMathVector v0, IMathVector v1)
        {
            if (((double[])v0.ArrayData).Length == ((double[])v1.ArrayData).Length)
            {
                var sign = System.Math.Sign(((IMathVector)(v0.Cross(v1))).ArrayData.CastArray<double>()[2]);
                var ret = System.Math.Acos(v0.Dot(v1) / (v0.GetLength() * v1.GetLength()));
                return sign * ret;
            }
            throw new Exception("Vectors must have the same dimension!");
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • 主要内容 自然语言输入编码 前馈网络 卷积网络 循环网络(recurrent networks ) 递归网络(re...
    JackHorse阅读 4,000评论 0 2
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,754评论 0 5
  • 更新:【面试题含答案】http://bbs.9ria.com/thread-288394-1-1.html 高频问...
    好怕怕阅读 4,618评论 3 52
  • 咱们大部分中国人不习惯晒恩爱,可是我喜欢。很多人觉得晒幸福,会损耗幸福本身。其实并不。――力的作用是互相的,爱也是...
    千漫千寻阅读 1,273评论 23 39
  • 散文诗一首 蛤蟆湾里的健身操 蛤蟆湾,是人们对活动场所的别称 人们晚饭后都来这儿,进行健身活动。 在里面有做操的、...
    潇洒丽人阅读 262评论 0 0