private static float MaxErrorLocation(ArcOfSphere arc, float begin, float end) { Vector2 L1 = SpaceConverter.SphereToUV(arc.Evaluate(begin)); Vector2 L2 = SpaceConverter.SphereToUV(arc.Evaluate(end)); // 2) use binary / bisection search to find the point of maximal error while (end - begin > delta) { float midpoint = (begin + end) / 2; float error_left = Point_Line_Distance(L1, L2, SpaceConverter.SphereToUV(arc.Evaluate(midpoint - delta))); float error_right = Point_Line_Distance(L1, L2, SpaceConverter.SphereToUV(arc.Evaluate(midpoint + delta))); if (error_left < error_right) //error begin should be replaced since it has less error { begin = midpoint; } else //error end should be replaced since it has less error { end = midpoint; } } return((begin + end) / 2); // return location of max error }
private static void UpdateSigns(ArcOfSphere arc, ref int[,] data, float location, float delta) { //assert data's size is [2, 3] for (int dimension = 0; dimension < 3; ++dimension) { data[0, dimension] = System.Math.Sign(arc.Evaluate(location)[dimension]); } for (int dimension = 0; dimension < 3; ++dimension) { data[1, dimension] = System.Math.Sign(arc.Evaluate(location + delta)[dimension] - arc.Evaluate(location)[dimension]) * System.Math.Sign(delta); } }
public void GroundedUpdate(CharacterMotor self) { if (self.input.sqrMagnitude > 1) { self.input.Normalize(); } Vector3 input3D = new Vector3(self.input.x, self.input.y, 0f); //FIXME: JANK if (input3D.sqrMagnitude > 1) { input3D.Normalize(); } Quaternion rotation = Quaternion.LookRotation(self.current_position, self.arc.EvaluateNormal(self.angle, self.radius)); float left_product = Vector3.Dot(rotation * input3D, self.left); float right_product = Vector3.Dot(rotation * input3D, self.right); float product = -Mathf.Abs(left_product); if (right_product > left_product) { product = +Mathf.Abs(right_product); } if (right_product < 0 && left_product < 0) { product = 0; } self.angle += product / self.height / 64; //FIXME: slight math error here-ish self.current_position = ArcOfSphere.Evaluate(self.ground.data, self.radius); self.transform.rotation = Quaternion.LookRotation(self.current_position, self.arc.EvaluateNormal(self.angle, self.radius)); }
public static void AddLine(ArcOfSphere edge, float begin, float end) { Vector2 begin_UV = SpaceConverter.SphereToUV(edge.Evaluate(begin)); Vector2 end_UV = SpaceConverter.SphereToUV(edge.Evaluate(end)); if (Vector2.Distance(begin_UV, end_UV) > threshold) { Vector2 delta_begin_UV = SpaceConverter.SphereToUV(edge.Evaluate(begin + 64 * delta)); Vector2 delta_end_UV = SpaceConverter.SphereToUV(edge.Evaluate(end - 64 * delta)); Vector2 control_point = Intersection(begin_UV, delta_begin_UV, delta_end_UV, end_UV); DebugUtility.Log("AddLine:", begin_UV, end_UV); lines.Add(new QuadraticBezier(edge, begin_UV, control_point, end_UV, begin, end)); } }
public bool Traverse(ArcOfSphere path, Vector3 desiredPos) //I don't like these parameters, they can be fixed //I don't like that this is public, it should be private and exposed via a generic move option if possible { optional <float> interpolation_factor = path.CartesianToRadial(desiredPos); if (interpolation_factor.exists) { ground = new GroundInfo(); ground.data.angle = interpolation_factor.data; ground.data.arc = path; ground.data.block = path.GetComponentInParent <Block>(); ground.data.height = path.LengthRadius(radius); ground.data.begin = path.Begin(radius); ground.data.end = path.End(radius); current_position = ArcOfSphere.Evaluate(ground.data, radius); } else { Debug.Log("Critical Failure: Traverse's interpolation factor doesn't exist!"); } return(interpolation_factor.exists); }
private static void Subdivide(ArcOfSphere arc, float begin, float end) { float midpoint = MaxErrorLocation(arc, begin, end); Vector2 L1 = SpaceConverter.SphereToUV(arc.Evaluate(begin)); Vector2 L2 = SpaceConverter.SphereToUV(arc.Evaluate(end)); Vector2 P = SpaceConverter.SphereToUV(arc.Evaluate(midpoint)); if (Point_Line_Distance(L1, L2, P) > threshold) // if the max error is greater than a threshold, recursively add the left and right halves into the list of lines { Subdivide(arc, begin, midpoint); Subdivide(arc, midpoint, end); } else { AddLine(arc, begin, end); } }
public override void Initialize(ArcOfSphere left, ArcOfSphere right) { #if UNITY_EDITOR this.Save(); #endif Vector3 path_center = right.Evaluate(right.Begin()); //Debug.DrawRay(path_center, Vector3.up, Color.yellow); path_normal = right.Evaluate(right.Begin()); arc_left = left.EvaluateNormal(left.End()); arc_right = right.EvaluateNormal(right.Begin()); Initialize(path_center); this.Relink(left, right); }
public static Edge LinkRight(ArcOfSphere left, Vector3 position) { Vector3 right = left.Evaluate(left.End()); Edge obj = Edge.StartEdge(left.transform.parent.transform, right, position); obj.Relink(left, left.next); return(obj); }
public void Move(Vector2 input) { if (between_levels) //FEATURE: enable movement (grounded and aerial) in between_levels { connection.data.Move(Input.GetAxis("Vertical"), this); } else if (grounded) //FIXME: this entire block if it is JANK //spelling -_-' { if (input.sqrMagnitude > 1) { input.Normalize(); } Transform camera_transform = GameObject.Find("MainCamera").transform; //FIXME: JANK Vector3 input3D = new Vector3(input.x, input.y, 0f); //FIXME: JANK if (input3D.sqrMagnitude > 1) { input3D.Normalize(); } float left_product = Vector3.Dot(camera_transform.rotation * input3D, left); float right_product = Vector3.Dot(camera_transform.rotation * input3D, right); float product = -Mathf.Abs(left_product); if (right_product > left_product) { product = +Mathf.Abs(right_product); } if (right_product < 0 && left_product < 0) { product = 0; } angle += product / height / 64; //FIXME: slight math error here-ish current_position = ArcOfSphere.Evaluate(ground.data, radius); transform.rotation = Quaternion.LookRotation(current_position, arc.EvaluateNormal(angle, radius)); } else { SphereUtility.Accelerate(ref phi, ref theta, ref vertical_velocity, ref horizontal_velocity, 0.03f, -input.x / 10, Time.fixedDeltaTime); current_position = SphereUtility.SphereToCartesian(new Vector2(phi, theta)); transform.rotation = Quaternion.LookRotation(current_position, North); } }
protected static Vector3 MaxGradient(ArcOfSphere arc, Vector3 desired) { Vector3 max_gradient = Vector3.zero; float max_product = Mathf.NegativeInfinity; /** if we don't calculate per quadrant, calculations for an arc with angle 2*PI become ambiguous because left == right */ float quadrants = Mathf.Ceil(arc.End() / (Mathf.PI / 2f)); //maximum of 4, always integral, float for casting "left" and "right" for (float quadrant = 0; quadrant < quadrants; ++quadrant) { float left = arc.End() * (quadrant / quadrants); //get beginning of quadrant i.e. 0.00,0.25,0.50,0.75 float right = arc.End() * ((quadrant + 1) / quadrants); //get end of quadrant i.e. 0.25,0.50,0.75,1.00 float left_product = Vector3.Dot(arc.Evaluate(left), desired); //find the correlation factor between left and the desired direction float right_product = Vector3.Dot(arc.Evaluate(right), desired); /** this is basically a binary search * * 1) take the left and right vectors and compute their dot products with the desired direction. * 2) take the lesser dot product and ignore that half of the remaining arc */ for (int iteration = 0; iteration < 8 * sizeof(float); ++iteration) //because we are dealing with floats, more precision could help (or hurt?) { float midpoint = (left + right) / 2; if (left_product < right_product) //is the right vector closer to the desired direction? { left = midpoint; //throw out the left half if the right vector is closer left_product = Vector3.Dot(arc.Evaluate(left), desired); } else { right = midpoint; //throw out the right half if the left vector is closer right_product = Vector3.Dot(arc.Evaluate(right), desired); } } /** figure out if this quadrant contains a larger gradient */ if (max_product < right_product) { max_gradient = arc.Evaluate(right); max_product = right_product; } if (max_product < left_product) { max_gradient = arc.Evaluate(left); max_product = left_product; } } return(max_gradient); }