/// <summary> /// Wrap a position equation around a cylinder. /// </summary> /// <param name="radius">Radius of the cylinder</param> /// <param name="ang0">Starting angle offset (radians) on the cylinder. 0 = z-axis</param> /// <param name="maxWrap">Maximum angle value (radians) of the wrap. After this, the function will continue along the tangent. Starting offset not included. Absolute value tested.</param> /// <param name="axisOff">Offset angle (radians) of the axis of the cylinder from the y-axis</param> /// <param name="position">Position equation</param> /// <returns></returns> public static tv3 CylinderWrap(efloat radius, efloat ang0, efloat maxWrap, efloat axisOff, ev2 position) => EEx.Resolve(radius, ang0, axisOff, position, (r, a0, axis, _v2) => { var cs = new TExV2(); var xyd = new TExV2(); var v2 = new TExV2(_v2); var v3 = new TExV3(); var a = ExUtils.VFloat(); var aRem = ExUtils.VFloat(); var aMax = ExUtils.VFloat(); var a_cs = new TExV2(); var a0_cs = new TExV2(); return(Ex.Block(new[] { v3, cs, xyd, a, aRem, aMax, a_cs, a0_cs }, aMax.Is(maxWrap), cs.Is(CosSin(axis)), xyd.Is(ConvertBasis(v2, cs)), a.Is(xyd.x.Div(r)), aRem.Is(E0), Ex.IfThen(Abs(a).GT(aMax), Ex.Block( Ex.IfThen(a.LT0(), MulAssign(aMax, EN1)), aRem.Is(a.Sub(aMax)), a.Is(aMax) )), a0_cs.Is(CosSin(a0)), a_cs.Is(CosSin(a.Add(a0))), xyd.x.Is(r.Mul(a_cs.y.Sub(a0_cs.y).Add(aRem.Mul(a_cs.x)))), v3.Is(TP3(DeconvertBasis(xyd, cs))), v3.z.Is(r.Mul(a_cs.x.Sub(a0_cs.x).Sub(aRem.Mul(a_cs.y)))), v3 )); });
public static void TestV2Utils() { var exv2 = new TExV2(); var exb = new TExV2(); var r = VFloat(); var rot = Ex.Lambda <Func <Vector2, float, Vector2> >(Rotate(r, exv2), exv2, r).Compile(); var norm = Ex.Lambda <Func <Vector2, Vector2> >(Norm(exv2), exv2).Compile(); var conv = Ex.Lambda <Func <Vector2, Vector2, Vector2> >(ConvertBasis(exv2, exb), exv2, exb).Compile(); var deconv = Ex.Lambda <Func <Vector2, Vector2, Vector2> >(DeconvertBasis(exv2, exb), exv2, exb).Compile(); for (float x = -3; x < 3; x += 0.5f) { for (float y = -3; y < 3; y += 0.5f) { var v2 = new Vector2(x, y); for (float ang = -300; ang < 400; ang += 24) { var dir = M.CosSinDeg(ang); VecEq(rot(new Vector2(x, y), ang), M.RotateVectorDeg(x, y, ang)); VecEq(M.ConvertBasis(v2, dir), conv(v2, dir)); VecEq(M.DeconvertBasis(v2, dir), deconv(v2, dir)); VecEq(deconv(conv(v2, dir), dir), v2); } VecEq(norm(new Vector2(x, y)), (new Vector2(x, y)).normalized); } } }
/// <summary> /// Note: requires that normalVec and planeVec are perpendicular. /// </summary> public static tv3 RotateInPlane(tfloat rot, tv3 normalVec, ev3 planeVec) => EEx.Resolve(planeVec, p => { var cs = new TExV2(); var cross = new TExV3(); return(Ex.Block(new ParameterExpression[] { cs, cross }, cs.Is(CosSinDeg(rot)), cross.Is(CrossProduct(normalVec, p)), cs.x.Mul(p).Add(cs.y.Mul(v3Mag(p).Div(v3Mag(cross)).Mul(cross))) )); });
public static ExTP LNearestEnemy() => b => { var loc = new TExV2(); return(Ex.Block(new ParameterExpression[] { loc }, Ex.IfThen(Ex.Not(Enemy.findNearest.Of(b.loc, loc)), loc.Is(Ex.Constant(new Vector2(0f, 50f))) ), loc )); };
/// <summary> /// Home towards a target location at a fixed speed. /// </summary> /// <remarks> /// Use with StopSampling to home for only a few seconds. /// <para>This is primarily for use with non-rotational velocity. /// Rotational use creates: contracting spirals (0,90), circle around player [90], expanding spiral (90,180).</para> /// </remarks> /// <param name="speed">Speed</param> /// <param name="location">Target location</param> /// <returns></returns> public static ExTP VHome(ExBPY speed, ExTP location) { TExV2 l = new TExV2(); return(bpi => Ex.Block(new ParameterExpression[] { l }, Ex.Assign(l, location(bpi).Sub(bpi.loc)), l.Mul(Ex.Divide(speed(bpi), Sqrt(Ex.Add(SqrMag(l), EPS)))) )); }
public static tv3 FromSphere(tfloat radius, ev2 sphere) => radius.Mul(EEx.ResolveV2(sphere, s => { var cst = new TExV2(); var csp = new TExV2(); return(Ex.Block(new ParameterExpression[] { cst, csp }, cst.Is(CosSinDeg(s.x)), csp.Is(CosSinDeg(s.y)), V3(cst.x.Mul(csp.y), cst.y.Mul(csp.y), csp.x) )); }));
public static ExCoordF CartesianRot(ExTP erv) => (c, s, bpi, nrv, fxy) => { var v2 = new TExV2(); return(Ex.Block(new ParameterExpression[] { v2 }, Ex.Assign(v2, erv(bpi)), fxy(Ex.Subtract(Ex.Multiply(c, v2.x), Ex.Multiply(s, v2.y)), Ex.Add(Ex.Multiply(s, v2.x), Ex.Multiply(c, v2.y))), Expression.Empty() )); };
/// <summary> /// Multiply the x-component of a parametric equation by a function of input. /// </summary> /// <param name="f">Function of input</param> /// <param name="tp">Parametric equation</param> /// <returns></returns> public static ExTP MultiplyX(ExBPY f, ExTP tp) { var v = TExV2.Variable(); var by = ExUtils.VFloat(); return(bpi => Ex.Block( new[] { v, by }, Ex.Assign(v, tp(bpi)), MulAssign(v.x, f(bpi)), v )); }
/// <summary> /// Add a function of input to the y-component of a parametric equation. /// </summary> /// <param name="f">Function of input</param> /// <param name="tp">Parametric equation</param> /// <returns></returns> public static ExTP AddY(ExBPY f, ExTP tp) { var v = TExV2.Variable(); var by = ExUtils.VFloat(); return(bpi => Ex.Block( new[] { v, by }, Ex.Assign(v, tp(bpi)), ExUtils.AddAssign(v.y, f(bpi)), v )); }
public static ExCoordF Polar2(ExTP radThetaDeg) { var rt = new TExV2(); var lookup = new TExV2(); return((c, s, bpi, nrv, fxy) => Ex.Block(new ParameterExpression[] { rt, lookup }, Ex.Assign(rt, radThetaDeg(bpi)), Ex.Assign(lookup, ExM.CosSinDeg(rt.y)), fxy(Ex.Subtract(Ex.Multiply(c, lookup.x), Ex.Multiply(s, lookup.y)).Mul(rt.x), Ex.Add(Ex.Multiply(s, lookup.x), Ex.Multiply(c, lookup.y)).Mul(rt.x)), Expression.Empty() )); }
public static ExCoordF Polar(ExBPY r, ExBPY theta) { var vr = ExUtils.VFloat(); var lookup = new TExV2(); return((c, s, bpi, nrv, fxy) => Ex.Block(new[] { vr, lookup }, Ex.Assign(lookup, ExM.CosSinDeg(theta(bpi))), Ex.Assign(vr, r(bpi)), fxy(Ex.Subtract(Ex.Multiply(c, lookup.x), Ex.Multiply(s, lookup.y)).Mul(vr), Ex.Add(Ex.Multiply(s, lookup.x), Ex.Multiply(c, lookup.y)).Mul(vr)), Expression.Empty() )); }
/// <summary> /// Multiply a unit vector at a given angle from the target function by the magnitude, /// and add it to the target function. /// </summary> /// <param name="angle">Angle offset (degrees)</param> /// <param name="magnitude">Magnitude of offset vector</param> /// <param name="tp">Target function</param> /// <returns></returns> public static ExTP AddAtAngle(ExBPY angle, ExBPY magnitude, ExTP tp) { TExV2 v2 = TExV2.Variable(); TExV2 v2norm = TExV2.Variable(); var mag = ExUtils.VFloat(); return(bpi => Ex.Block(new[] { v2, v2norm, mag }, Ex.Assign(v2, tp(bpi)), Ex.Assign(v2norm, Rotate(angle(bpi), Norm(v2))), Ex.Assign(mag, magnitude(bpi)), Ex.Assign(v2norm.x, v2.x.Add(v2norm.x.Mul(mag))), Ex.Assign(v2norm.y, v2.y.Add(v2norm.y.Mul(mag))), v2norm )); }
public static void TestCylinder() { var xz = TP3(bpi => XZrY(ExC(3f), ExC(2f), bpi.t, 5f)); var yz = TP3(bpi => YZrX(ExC(3f), ExC(2f), bpi.t, 5f)); var xy = TP3(bpi => XYrZ(ExC(3f), ExC(2f), bpi.t, 5f)); var b = new ParametricInfo() { t = 1f }; var c = 2f * Mathf.Cos(b.t * M.TAU / 3f); var s = 2f * Mathf.Sin(b.t * M.TAU / 3f); VecEq(new Vector3(c, 5f, s), xz(b)); VecEq(new Vector3(5f, c, s), yz(b)); VecEq(new Vector3(c, s, 5f), xy(b)); var f1 = VFloat(); var f2 = VFloat(); var f3 = VFloat(); var f4 = VFloat(); var v21 = new TExV2(); var cyl = Ex.Lambda <Func <float, float, float, float, Vector2, Vector3> >(CylinderWrap(f1, f2, f3, f4, v21), f1, f2, f3, f4, v21).Compile(); VecEq(cyl(2f, M.HPI, M.PI, 0f, new Vector2(1f, 0f)), new Vector3(Mathf.Cos(1f / 2f) * 2f - 2f, 0f, -2f * Mathf.Sin(1f / 2f))); VecEq(cyl(2f, M.HPI, M.PI, 0f, new Vector2(1f + 2 * M.PI, 0f)), new Vector3(-4f, 0f, 1f)); for (float r = 1; r < 3; r += 0.8f) { for (float ang0 = -1; ang0 < 2; ang0 += 0.8f) { for (float maxWrap = 0.5f; maxWrap < 5f; maxWrap += 1.1f) { for (float axis = -2; axis < 5; axis += 0.9f) { for (float x = -3; x < 10; x += 1.3f) { for (float y = -2; y < 3; y += 0.5f) { var v2 = new Vector2(x, y); VecEq(cyl(r, ang0, maxWrap, axis, v2), M.CylinderWrap(r, ang0, maxWrap, axis, v2), $"Cyl({r},{ang0},{maxWrap},{axis},<{x},{y}>)"); } } } } } } }
public static ExTP LSaveNearestEnemy() => b => { var key = b.Ctx.NameWithSuffix("_LSaveNearestEnemyKey"); var eid_in = ExUtils.V <int?>(); var eid = ExUtils.V <int>(); var loc = new TExV2(); return(Ex.Block(new[] { eid_in, eid, loc }, eid_in.Is(Ex.Condition(FiringCtx.Contains <int>(b, key), FiringCtx.GetValue <int>(b, key).As <int?>(), Ex.Constant(null).As <int?>()) ), Ex.IfThenElse(Enemy.findNearestSave.Of(b.loc, eid_in, eid, loc), FiringCtx.SetValue <int>(b, key, eid), loc.Is(Ex.Constant(new Vector2(0f, 50f))) ), loc )); };
/// <summary> /// Derive a V2RV2 from two vectors and a float. /// </summary> /// <param name="nrot">Nonrotational x,y</param> /// <param name="rot">Rotational x,y</param> /// <param name="angle">Rotational angle (degrees)</param> /// <returns></returns> public static trv2 V2V2F(ev2 nrot, ev2 rot, tfloat angle) => EEx.Resolve(nrot, rot, (_nr, _r) => { var nr = new TExV2(_nr); var r = new TExV2(_r); return(VRV2(nr.x, nr.y, r.x, r.y, angle)); });
/// <summary> /// Derive a V2RV2 from a nonrotational vector and a rotational vector3. /// </summary> /// <param name="nrot">Nonrotational component</param> /// <param name="rot">Rotational component (x,y,angle)</param> /// <returns></returns> public static trv2 V2V3(ev2 nrot, ev3 rot) => EEx.Resolve(nrot, rot, (_nr, _r) => { var nr = new TExV2(_nr); var r = new TExV3(_r); return(VRV2(nr.x, nr.y, r.x, r.y, r.z)); });
/// <summary> /// Return the angle in radians whose tangent is v2.y/v2.x. /// </summary> public static tfloat ATanR(ev2 f) => EEx.Resolve(f, v2 => { var tv2 = new TExV2(v2); return(_AtanYX.Of(tv2.y, tv2.x)); });
/// <summary> /// Rotate a V2 by a vector containing cosine and sine values counterclockwise. /// </summary> public static tv2 RotateV2(ev2 cossin, efloat xv, efloat yv) => EEx.Resolve(cossin, (cs) => { var _cs = new TExV2(cs); return(RotateCS2(_cs.x, _cs.y, xv, yv)); });
/// <summary> /// Rotate a V2 by a vector containing cosine and sine values counterclockwise. /// </summary> public static tv2 RotateV(ev2 cossin, ev2 v2) => EEx.Resolve(cossin, v2, (cs, vec) => { var _cs = new TExV2(cs); var tv2 = new TExV2(vec); return(RotateCS2(_cs.x, _cs.y, tv2.x, tv2.y)); });
/// <summary> /// Rotate a V2 by a calculated cosine and sine value counterclockwise. /// </summary> public static tv2 RotateCS(tfloat cos, tfloat sin, ev2 v2) => EEx.Resolve(v2, vec => { var tv2 = new TExV2(vec); return(RotateCS2(cos, sin, tv2.x, tv2.y)); });