public void Add() { var p2 = new Vec2d(1, 2); Assert.AreEqual(new Vec2d(2, 4), p2.Added(new Vec2d(1, 2))); p2.Add(new Vec2d(1, 2)); Assert.AreEqual(new Vec2d(2, 4), p2); }
public static WavefrontFormat DrawLine(this WavefrontFormat wf, string color, Vec2d point, Vec2d v, double ext = 1000) { wf.UseMaterial(color); Vec2d p0 = point.Sub(v.Mul(ext)); Vec2d p1 = point.Add(v.Mul(ext)); wf.AddLines(new Vec2d[] { p0, p1 }, false); return(wf); }
/// <summary> /// Obtiene el centro de la circunferencia que pasa por los 2 puntos, con el radio indicado. /// Dependiendo del criterio (leftRule), se interpreta el signo del radio: /// Si leftRule entonces el radio se multiplica por la normal a la izquierda (leftNormal) para obtener el centro de la /// circunferencia. /// Si rightRule (!leftRule) entonces el radio se multiplica por la normal a la derecha (rightNormal) para obtener el /// centro de la circunferencia. /// Clip utiliza un criterio rightRule. /// <p /> /// Criterio rightRule: /// <c><![CDATA[ /// _ _ /// _ / \c /// _/ O pf O /// _/ / / \ /// / _/ radio - _/ | /// / /| radio + <-- /| | /// | / --> / / /// / / / _/ /// |/ / _/ /// O pi O__/ /// \ _/ /// ]]></c> /// <![CDATA[ /// p1 a/2 pm a/2 p2 /// x---------+-------->x /// \ | / /// \ | / /// \ | / /// \ |b / /// \ | / r /// \ | / /// \ | / /// \ | / /// \|/ /// pc /// ]]> /// Teniendo como dato p1, p2 y r, tenemos que obtener el centro del circulo que pasa por /// p1 y p2, con radio r. /// Con el vector 1-2 obtenemos la distancia a. /// b es calculado mediante la fórmula b = raizcua(r * r + a/2 * a/2). /// Creamos un vector perpendicular al 1-2 a una distacion a/2 desde p1 y obtenemos /// el punto central de la circunferencia. /// Con este dato y conociendo el radio ya simplemente calculamos la esquina del rectangulo. /// Si el radio es positivo, avanza en sentido contrario a las agujas del reloj. /// Si el radio es negativo, avanza en sentido de las agujas del reloj. /// <![CDATA[ /// + p2 /// /|\ /// | /// /____ | ____\ /// \ \___ | ___/ / /// \__ | __/ /// \_ | _/ /// radio - \ | / radio + /// (giro \ | / (giro horario) /// antihorario) \|/ /// | /// + p1 /// ]]> /// </summary> /// <exception cref="CalculoImposibleException"> /// Indica que no se puede calcular el /// centro. /// </exception> public static Vec2d EvaluateCenter(Vec2d pt0, Vec2d pt1, double radius, bool leftRule) { // Vector direccion normalizado y longitud. Vec2d dir = pt1.Sub(pt0); double a = dir.Length; if (a.EpsilonEquals(0)) { throw new Exception("CalculoImposible: Puntos coincidentes."); } dir = dir.Div(a); // Punto medio. Vec2d pm = vecMath.Interpolate(pt0, pt1, 0.5); // Se tratan radios erroneos que no permitan generar un circunferencia. double v = radius * radius - a * a / 4; if (v.EpsilonEquals(0)) { return(pm); } if (v < 0) { throw new Exception("CalculoImposible: Radio erroneo."); } double b = SysMath.Sign(radius) * SysMath.Sqrt(v); Vec2d normal; if (leftRule) { // Vector normal a la izquierda. normal = vecMath.PerpLeft(dir); } else { // Vector normal a la derecha. normal = vecMath.PerpRight(dir); } Vec2d vectorm1 = normal.Mul(b); return(pm.Add(vectorm1)); }
public void ValueType_Vec2d() { var p1 = new Vec2d(1, 0); var p2 = new Vec2d(0, 1); Assert.IsFalse(p1.IsEqual(p2, 0.99, 0.1)); Assert.IsTrue(p1.IsEqual(p2, 1.01, 0.1)); Assert.IsTrue(p1.IsEqual(p2, 0.99, Math.PI / 2)); Assert.IsTrue(p1.IsNormal(p2, 0.1)); Assert.IsFalse(p1.IsOpposite(p2, 0.1)); Assert.IsTrue(p1.IsOpposite(p2, Math.PI / 2)); Assert.IsFalse(p1.IsParallel(p2, 0.1)); Assert.IsTrue(p1.IsParallel(p2, Math.PI / 2)); p1 = new Vec2d(1, 2); p2 = new Vec2d(4, 5); Assert.AreEqual(5, p1.SquareMagnitude()); Assert.AreEqual(Math.Sqrt(5), p1.Magnitude()); p2 = p1; p2.Add(new Vec2d(1, 2)); Assert.AreEqual(new Vec2d(2, 4), p2); Assert.AreEqual(new Vec2d(2, 4), p1.Added(new Vec2d(1, 2))); p2 = new Vec2d(1, 2); p2.Subtract(new Vec2d(3, 2)); Assert.AreEqual(new Vec2d(-2, 0), p2); Assert.AreEqual(new Vec2d(-2, 0), p1.Subtracted(new Vec2d(3, 2))); p2 = new Vec2d(1, 2); Assert.AreEqual(-4, p1.Crossed(new Vec2d(3, 2))); Assert.AreEqual(Math.Sqrt(16), p1.CrossMagnitude(new Vec2d(3, 2))); Assert.AreEqual(16, p1.CrossSquareMagnitude(new Vec2d(3, 2))); p2 = new Vec2d(1, 2); p2.Divide(2); Assert.AreEqual(new Vec2d(0.5, 1), p2); Assert.AreEqual(new Vec2d(0.5, 1), p1.Divided(2)); Assert.AreEqual(5, p1.Dot(new Vec2d(1, 2))); p2 = new Vec2d(1, 2); p2.Multiply(2); Assert.AreEqual(new Vec2d(2, 4), p2); Assert.AreEqual(new Vec2d(2, 4), p1.Multiplied(2)); p2 = new Vec2d(1, 2); p2.Scale(2); Assert.AreEqual(new Vec2d(2, 4), p2); Assert.AreEqual(new Vec2d(2, 4), p1.Scaled(2)); p2 = new Vec2d(1, 23); Assert.AreEqual("0.0434372242763069,0.99905615835506", p2.Normalized().ToString()); p2.Normalize(); Assert.AreEqual("0.0434372242763069,0.99905615835506", p2.ToString()); p2 = new Vec2d(1, 2); p2.Reverse(); Assert.AreEqual(new Vec2d(-1, -2), p2); Assert.AreEqual(new Vec2d(-1, -2), p1.Reversed()); p2.SetLinearForm(new Vec2d(1, 2), new Vec2d(4, 5)); Assert.AreEqual(new Vec2d(5, 7), p2); p2.SetLinearForm(2, new Vec2d(1, 2), new Vec2d(4, 5)); Assert.AreEqual(new Vec2d(6, 9), p2); p2.SetLinearForm(2, new Vec2d(1, 2), 3, new Vec2d(4, 5)); Assert.AreEqual(new Vec2d(14, 19), p2); p2.SetLinearForm(2, new Vec2d(1, 2), 3, new Vec2d(4, 5), new Vec2d(7, 8)); Assert.AreEqual(new Vec2d(21, 27), p2); p2 = new Vec2d(2, 1); Assert.AreEqual(new Vec2d(1, 0), p2.Mirrored(new Vec2d(1, 0))); p2.Mirror(new Vec2d(1, 0)); Assert.AreEqual(new Vec2d(1, 0), p2); var m2 = new Ax2d(new Pnt2d(-1, 2), new Dir2d(-1, 0)); p2 = new Vec2d(2, 1); Assert.AreEqual(new Vec2d(2, -1), p2.Mirrored(m2)); p2.Mirror(m2); Assert.AreEqual(new Vec2d(2, -1), p2); p2 = new Vec2d(2, 1); Assert.AreEqual("-1,2", p2.Rotated(Math.PI / 2).ToString()); p2.Rotate(Math.PI / 2); Assert.AreEqual("-1,2", p2.ToString()); //TestContext.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", gp2.x, gp2.y, gp2.z)); Trsf2d t1 = new Trsf2d(); t1.SetRotation(new Pnt2d(1, 2), Math.PI / 2); p2 = new Vec2d(2, 1); Assert.AreEqual("-1,2", p2.Transformed(t1).ToString()); p2.Transform(t1); Assert.AreEqual("-1,2", p2.ToString()); }
/// <summary> /// Prueba el constructor ClothoidArc2d(double,Vec2d,Vec2d,double,double). /// </summary> private static void TestClotho(double a, bool invertY, bool negX, double tg0, double tg1, Vec2d p0, Vec2d dir, string fileName = null, bool toWavefront = false) { //double a = 5; //bool invertY = true; //double tg0 = -4 * SysMath.PI / 10; //double tg1 = -SysMath.PI / 10; // Si se indica negX, se invierten las tangentes. int sign = 1; if (negX) { sign = -1; } double l0 = sign * ClothoUtils.FindTangent(invertY, a, tg0); double l1 = sign * ClothoUtils.FindTangent(invertY, a, tg1); double r0 = ClothoUtils.ClothoRadious(l0, invertY, a); double r1 = ClothoUtils.ClothoRadious(l1, invertY, a); Vec2d pp0 = ClothoUtils.Clotho(l0, invertY, a); Vec2d pp1 = ClothoUtils.Clotho(l1, invertY, a); //Vec2d p0 = new Vec2d(5, 5); Vec2d p1 = p0.Add(dir.Mul(pp1.Sub(pp0).Length)); ClothoidArc2 arc = new ClothoidArc2(l0, p0, p1, r0, r1); Assert.IsTrue(arc.Point0.EpsilonEquals(p0, ERROR)); Assert.IsTrue(arc.Point1.EpsilonEquals(p1, ERROR)); Assert.IsTrue(arc.GetRadius(arc.TMin).EpsilonEquals(r0, ERROR)); Assert.IsTrue(arc.GetRadius(arc.TMax).EpsilonEquals(r1, ERROR)); // <- Assert.IsTrue(arc.InvertY == invertY); Assert.IsTrue(arc.A.EpsilonEquals(a, ERROR)); // Salida por fichero de la prueba. if ((fileName != null) && toWavefront) { double figSize = 0.5; string mtl = Path.ChangeExtension(fileName, "mtl"); using (MaterialFormat mf = new MaterialFormat(mtl)) { mf.DefaultColors(); } using (WavefrontFormat wf = new WavefrontFormat(fileName)) { wf.LoadMaterialLib(Path.GetFileName(mtl)); wf.DrawLine("Yellow", Vec2d.Zero, new Vec2d(1, 0), 50); wf.DrawLine("Yellow", Vec2d.Zero, new Vec2d(0, 1), 50); wf.DrawFigure("Blue", WaveFigure.X, ClothoUtils.Clotho(l0, invertY, a), figSize); wf.DrawFigure("Olive", WaveFigure.X, ClothoUtils.Clotho(l1, invertY, a), figSize); wf.DrawClotho(invertY, a, "Red"); wf.DrawClotho("Magenta", arc); wf.DrawFigure("Blue", WaveFigure.X, p0, figSize); wf.DrawFigure("Olive", WaveFigure.X, p1, figSize); } } }
public static WavefrontFormat DrawFigure(this WavefrontFormat wf, string color, WaveFigure figure, Vec2d point, double size) { wf.UseMaterial(color); switch (figure) { case WaveFigure.Circle: { wf.AddLines(MathUtils.For(0, 2 * SysMath.PI, 20).Select(t => point.Add(vecMath.NewRotate(t).Mul(size))), true); break; } case WaveFigure.Rectangle: { wf.AddLines(new Vec2d[] { point.Add(new Vec2d(size, size)), point.Add(new Vec2d(-size, size)), point.Add(new Vec2d(-size, -size)), point.Add(new Vec2d(size, -size)), }, true); break; } case WaveFigure.Diamond: { wf.AddLines(new Vec2d[] { point.Add(new Vec2d(0, size)), point.Add(new Vec2d(-size, 0)), point.Add(new Vec2d(0, -size)), point.Add(new Vec2d(size, 0)), }, true); break; } case WaveFigure.Plus: { wf.AddLines(new Vec2d[] { point.Add(new Vec2d(0, size)), point.Add(new Vec2d(0, -size)), }, false); wf.AddLines(new Vec2d[] { point.Add(new Vec2d(size, 0)), point.Add(new Vec2d(-size, 0)), }, false); break; } case WaveFigure.X: { wf.AddLines(new Vec2d[] { point.Add(new Vec2d(size, size)), point.Add(new Vec2d(-size, -size)), }, false); wf.AddLines(new Vec2d[] { point.Add(new Vec2d(-size, size)), point.Add(new Vec2d(size, -size)), }, false); break; } default: { throw new Exception(); } } return(wf); }