/// <summary> /// 创建圆形mesh /// </summary> /// <param name="center"></param> /// <param name="radius"></param> /// <returns></returns> private static Mesh CreateCircleMesh(Vector3 center, float radius) { Mesh mesh = new Mesh(); float angle = Mathf.Deg2Rad * 1.0f; Double2 dir = Double2.right * radius; Vector3[] vertices = new Vector3[361]; vertices[360] = center; for (int i = 0; i < 360; i++) { Double2 newPos = Double2.Rotate(dir, i * angle); vertices[i] = center + new Vector3((float)newPos.x, 0, (float)newPos.y); } int[] triangles = new int[360 * 3]; for (int i = 0; i < 360; i++) { int index = i * 3; triangles[index] = 360; triangles[index + 1] = i; triangles[index + 2] = (i + 1) > 359 ? 0: (i + 1); } Vector2[] uvs = new Vector2[361]; for (int i = 0; i < 361; i++) { Vector3 diff = (vertices[i] - center) / radius * 0.5f; uvs[i] = new Vector2(diff.x + 0.5f, diff.z + 0.5f); } mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = uvs; return(mesh); }
/// <summary> /// Retrieve an elipse in its center-radius form using parameters from the SVG specification /// </summary> /// <param name="cur">Current point</param> /// <param name="radii">The ellipse radius</param> /// <param name="xRotation">The rotation of the ellipse in relation to the x-axis</param> /// <param name="largeArc">Wheter the large arc should be selected or not</param> /// <param name="sweep">Sweep direction (false for clockwise, true for counterclockwise)</param> /// <param name="target">The target point</param> /// <returns></returns> public static Curve EllipticArc(Double2 cur, Double2 radii, double xRotation, bool largeArc, bool sweep, Double2 target) { // The algorithm used here is presented on this link: https://svgwg.org/svg2-draft/implnote.html var xpun = (cur - target) / 2; var xpr = xpun.Rotate(-xRotation); // Guarantee that the radii are positive radii.X = Math.Abs(radii.X); radii.Y = Math.Abs(radii.Y); // Guarantee that the radius are large enough var rr = radii.X * radii.X * xpr.Y * xpr.Y + radii.Y * radii.Y * xpr.X * xpr.X; var r2 = radii.X * radii.X * radii.Y * radii.Y; double skr; if (rr > r2) { radii *= Math.Sqrt(rr / r2); skr = 0; } else { skr = Math.Sqrt((r2 - rr) / rr); } var cpr = new Double2(skr * radii.X * xpr.Y / radii.Y, -skr * radii.Y * xpr.X / radii.X); if (largeArc == sweep) { cpr = -cpr; } // Calculate the center var cpun = cpr.Rotate(xRotation) + (target + cur) / 2; // Calculate the angle var t1 = Math.Atan2(radii.X * (xpr.Y - cpr.Y), radii.Y * (xpr.X - cpr.X)); var t2 = Math.Atan2(radii.X * (-xpr.Y - cpr.Y), radii.Y * (-xpr.X - cpr.X)); var dt = t2 - t1; if (!sweep && dt > 0) { dt -= TwoPi; } else if (sweep && dt < 0) { dt += TwoPi; } return(EllipticArcInternal(cpun, radii, Double2.FromAngle(xRotation), t1, dt)); }
/// <summary> /// 优化路线 /// </summary> /// <param name="lineStart">线段起点</param> /// <param name="lineEnd">线段终点</param> /// <param name="near">与动态挡格相交 near点</param> /// <param name="far">与动态挡格相交 far点</param> /// <param name="listMidPoint">2个交点之间的路线</param> /// <returns></returns> public static List <Double2> OptimizationLine(Double2 lineStart, Double2 lineEnd, Double2 near, Double2 far, bool isCounterclockwiseDir, List <Double2> listMidPoint) { if (listMidPoint == null || listMidPoint.Count == 0) { return(listMidPoint); } /* #if UNITY_EDITOR * List<Float2> l = new List<Float2>(); * l.Add(near); * l.AddRange(listMidPoint); * l.Add(far); * SkillObb.instance.TargetPoly = l.ToArray(); #endif */ List <Double2> listOptimizationLine = listMidPoint; // 先顺序来一次优化 Double2 outdir = (lineEnd - lineStart).normalized; if (isCounterclockwiseDir == false) { outdir = Double2.Rotate(outdir, MathUtil.kPI - MathUtil.kEpsilon); } else { outdir = Double2.Rotate(outdir, -MathUtil.kPI + MathUtil.kEpsilon); } listOptimizationLine = SearchOutPoint(lineStart, far, outdir.normalized, listOptimizationLine); // 再倒序来一次优化 listOptimizationLine.Reverse(); outdir = (lineStart - lineEnd).normalized; if (isCounterclockwiseDir == true) { outdir = Double2.Rotate(outdir, MathUtil.kPI - MathUtil.kEpsilon); } else { outdir = Double2.Rotate(outdir, -MathUtil.kPI + MathUtil.kEpsilon); } listOptimizationLine = SearchOutPoint(lineEnd, near, outdir.normalized, listOptimizationLine); listOptimizationLine.Reverse(); // return(listOptimizationLine); }
private static List <Double2> OptimizationStepLine(Double2 lineStart, Double2 lineEnd, Double2 near, Double2 far, bool isCounterclockwiseDir, List <Double2> listMidPoint) { if (listMidPoint == null || listMidPoint.Count == 0) { return(listMidPoint); } List <Double2> listOptimizationLine = listMidPoint; // 先顺序来一次优化 Double2 outdir = (lineEnd - lineStart).normalized; if (isCounterclockwiseDir == false) { outdir = Double2.Rotate(outdir, MathUtil.kPI - MathUtil.kEpsilon); } else { outdir = Double2.Rotate(outdir, -MathUtil.kPI + MathUtil.kEpsilon); } listOptimizationLine = SearchOutPoint(lineStart, far, outdir.normalized, listOptimizationLine); // 再倒序来一次优化 outdir = (lineStart - lineEnd).normalized; if (isCounterclockwiseDir == true) { outdir = Double2.Rotate(outdir, MathUtil.kPI - MathUtil.kEpsilon); } else { outdir = Double2.Rotate(outdir, -MathUtil.kPI + MathUtil.kEpsilon); } listOptimizationLine.Reverse(); listOptimizationLine = SearchOutPoint(lineEnd, near, outdir.normalized, listOptimizationLine); listOptimizationLine.Reverse(); // return(listOptimizationLine); }
/// <summary> /// 最短射线包围盒路径 /// </summary> /// <param name="line">线段</param> /// <param name="offset">偏移值</param> /// <param name="rbi">包围盒信息</param> /// <returns>true,表示线段与aabb有相交,并返回最短包围路径</returns> public override RBIResultType RayboundingNearestPath(LineSegment2D line, double offset, ref RayboundingInfo rbi) { if (rbi == null) { rbi = new RayboundingInfo(); } Double2 diff = this.circleCenter - line.startPoint; if (diff == Double2.zero) { return(RBIResultType.Fail); } // Double2 projectoint = line.ProjectPoint(this.circleCenter); diff = this.circleCenter - projectoint; // 跟直线相交奥 double dis = diff.sqrMagnitude - this.radius * this.radius; if (dis >= 0) { return(RBIResultType.Fail); } dis = -dis; // 在同侧不行。 Double2 diff1 = line.startPoint - projectoint; Double2 diff2 = line.endPoint - projectoint; if (Double2.Dot(diff1, diff2) >= 0) { return(RBIResultType.Fail); } // if (diff1.sqrMagnitude < dis || diff2.sqrMagnitude < dis) { return(RBIResultType.Fail); } dis = System.Math.Sqrt(dis) + offset; Double2 p1 = projectoint - line.normalizedDir * dis; Double2 p2 = projectoint + line.normalizedDir * dis; double bigRadius = this.radius + offset; double angle = SignedAngleInCircle(p1 - this.circleCenter, p2 - this.circleCenter, bigRadius); int count = (int)(System.Math.Abs(angle / 0.25f)); double diffangle = angle / count; List <Double2> listpath = new List <Double2>(); Double2 startVector = (p1 - this.circleCenter).normalized * bigRadius; for (int i = 1; i <= count - 1; i++) { Double2 rorateVector = Double2.Rotate(startVector, -diffangle * i); listpath.Add(rorateVector + this.circleCenter); } rbi.listpath = listpath; if (rbi.listpath != null && rbi.listpath.Count > 0) { rbi.CalcHelpData(line, offset, p1, p2); return(RBIResultType.Succ); } return(RBIResultType.Fail); }