/// <summary>Finds the lowest distance of point P to a line segment defined by points A and B</summary> public static float distance_from_point_to_segment(crds2 a, crds2 b, crds2 p) { float l2 = a.dist_squared(b); if (l2 < 0.000001f) return a.dist(p); // case : a == b float t = crds2.dot(p-a, b-a) / l2; if (t < 0f) return a.dist(p); if (t > 1f) return b.dist(p); crds2 proj = a.lerp(b, t); return proj.dist(p); }
public static bool are_points_clockwise(crds2[] polygon) { var sum = 0f; for (int i = 0; i < polygon.Length-1; i++) { sum += (polygon[i+1].x - polygon[i ].x) * (polygon[i + 1].y + polygon[i].y); } return sum > 0; }
public void render(crds2 screen_coords, float alpha_multiplier = 1f, float scale_multiplier = 1f, float temperature = 0f) { foreach (var layer in _layers) { var spr = Graphics.add_sprite(layer.texture, screen_coords.x, screen_coords.y); spr.set_scale(layer.scale * scale_multiplier); spr.set_colors(layer.color, layer.alpha * alpha_multiplier); spr.blit.sequence.x = (uint)layer.sequence_x; spr.blit.sequence.y = (uint)layer.sequence_y; } }
/// <summary>same as segment-segment int. but points only define the line, don't limit it</summary> public static bool line_line_intersection(crds2 A, crds2 B, crds2 C, crds2 D, out crds2 intersection_point) { intersection_point = crds2.zero; var z = (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y); if (z.approximately(0f)) return false; var U1 = ((D.x - C.x) * (A.y - C.y) - (D.y - C.y) * (A.x - C.x)) / z; var U2 = ((B.x - A.x) * (A.y - C.y) - (B.y - A.y) * (A.x - C.x)) / z; intersection_point = A.lerp(B, U1); return true; }
public static crds2 centroid_of_polygon(crds2[] polygon) { var n = polygon.Length; float sum = 0f; for (int i = 0; i < n; i++) { var j = i + 1; if (j == n) j = 0; sum += polygon[i].x * polygon[j].y - polygon[j].x * polygon[i].y; } var surf = sum / 2; crds2 coordz = crds2.zero; for (int i = 0; i < n; i++) { var j = i + 1; if (j == n) j = 0; coordz.x += (polygon[i].x + polygon[j].x) * (polygon[i].x * polygon[j].y - polygon[j].x * polygon[i].y); coordz.y += (polygon[i].y + polygon[j].y) * (polygon[i].x * polygon[j].y - polygon[j].x * polygon[i].y); } coordz.x /= 6 * surf; coordz.y /= 6 * surf; return coordz; }
public static void encompass(crds2 hi_extr, crds2 lo_extr, float zoom_factor = 1f) { var c = (hi_extr + lo_extr) * 0.5f; var dhor = XMath.abs((hi_extr - lo_extr).x); var dver = XMath.abs((hi_extr - lo_extr).y); if (dhor < 1f) dhor = 1f; if (dver < 1f) dver = 1f; var aspect = dhor / dver; var screen_aspect = (float)Graphics.screen_w / Graphics.screen_h; var desired_zoom = 1f; if (aspect > screen_aspect) // width rules desired_zoom = (float)Graphics.screen_w / dhor; else // height rules desired_zoom = (float)Graphics.screen_h / dver; _target = new crds4(c.x, c.y, 0f, desired_zoom * zoom_factor); current = _target; delta = default(crds4); raise_restrictions(); }
/// <summary>Returns the point of projection of point P on a segment defined by A and B, expressed as a float interpolation value between A and B</returns> public static float projection_of_point_on_segment(crds2 a, crds2 b, crds2 p) { return crds2.dot(p - a, b - a) / a.dist_squared(b); }
// this also works perfectly if you change crds2 into crds3 public static crds2 bezier_at(crds2 A, crds2 M, crds2 B, float t) { var q = 1f - t; return ((A * q + M * t) * q + (M * q + B * t) * t); }
public bool contains(crds2 point, float tolerance = 0f) { if ( point.x > lo.x - tolerance && point.x < hi.x + tolerance && point.y > lo.y - tolerance && point.y < hi.y + tolerance) return true; return false; }
public rect(float x0, float y0, float w, float h) { lo = new crds2(x0, y0); hi = new crds2(x0 + w, y0 + h); }
/// <summary>Returns a boolean stating whether there is ANY overlap between two triangles</summary> /// <param name="first_triangle">an array of exactly THREE 2d vertices defining the FIRST triangle</param> /// <param name="second_triangle">an array of exactly THREE 2d vertices defining the SECOND triangle</param> public static bool triangle_triangle_intersection(crds2[] first_triangle, crds2[] second_triangle) { if (first_triangle.Length != 3 || second_triangle.Length != 3) throw new Exception("triangle triangle intersection error - not a triangle!"); // if any vertex of triangle A is in triangle B, or any vertex of triangle B is in triangle A, return true for (int i = 0; i < 3; i++) if (point_in_triangle(first_triangle[0], first_triangle[1], first_triangle[2], second_triangle[i])) return true; for (int i = 0; i < 3; i++) if (point_in_triangle(second_triangle[0], second_triangle[1], second_triangle[2], first_triangle[i])) return true; // no luck yet huh? ok, if any two segments intersect overlap crds2 p; for (int a = 0; a < 3; a++) for (int b = 0; b < 3; b++) { var a2 = a + 1; if (a2 == 3) a2 = 0; var b2 = b + 1; if (b2 == 3) b2 = 0; if (segment_segment_intersection(first_triangle[a], first_triangle[a2], second_triangle[b], second_triangle[b2], out p)) return true; } // nope? Huh. Guess there is no intersection. Huh. return false; }
public static void set_extremes(crds2 upper_left, crds2 lower_right, float min_zoom, float max_zoom) { restrictions_low.x = upper_left.x; restrictions_low.y = upper_left.y; restrictions_high.x = lower_right.x; restrictions_high.y = lower_right.y; restrictions_low.w = min_zoom * ZOOM_FACTOR; restrictions_high.w = max_zoom * ZOOM_FACTOR; set_target(upper_left.lerp(lower_right, 0.5f)); }
public static void set_target(crds2 coords) { _target.x = coords.x; _target.y = coords.y; }
public static crds3 unproject(crds2 screen_coords) { var x = (screen_coords.x - Graphics.scrW2) / zoom + current.x; var y = (screen_coords.y - Graphics.scrH2) / (zoom * cos_phi) + current.y; //var A = (Graphics.scrH2 - screen_coords.y) / zoom; //var B = current.z * inv_cos_phi; //var y = (A + B) * inv_cos_phi + current.y; return new crds3(x, y, 0); }
public static Sprite add_shape(crds2[] coords, uint color = 0xffffffffu) { Sprite spr = current_layer.new_sprite; spr.coords.set(0f, 0f); spr.kind = Sprite.draw_mode.poly; spr.blit.color = color; spr.points = coords; last_sprite = spr; return spr; }
static public Sprite[] add_capsule(Texture t, float x0, float y0, float x1, float y1, float w) // capsule extends the line outwards from the points { var center = current_layer.new_sprite; var left = current_layer.new_sprite; var right = current_layer.new_sprite; var array = new Sprite[] { left, center, right }; var c = new crds2((x0 + x1) / 2, (y0 + y1) / 2); var d = (float)Math.Sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1)); if (d <= 0.5f) d = 0.5f; var h = w / t.size.y; var aspect = (float)t.size.x / t.size.y; var invaspect = 1f / aspect; var v = invaspect / 2; var rot_angle = XMath.get_angle(x1 - x0, y1 - y0); var d1 = crds2.deflect(c, new crds2(x0, y0), w / 4f); var d2 = crds2.deflect(c, new crds2(x1, y1), w / 4f); var scalex = d / t.size.x; center.coords.set(c.x, c.y); center.set_scale(scalex, h); center.blit.set_special_margins(v, 0f, 1f - v * 2, 1f, true); left.coords.set(d1.x, d1.y); left.blit.set_special_margins(0f, 0f, v, 1f, true); left.set_scale(h, h); right.coords.set(d2.x, d2.y); right.blit.set_special_margins(1f - v, 0f, v, 1f, true); right.set_scale(h, h); foreach (var spr in array) { spr.blit.t = t; spr.blit.rotation = rot_angle; spr.kind = Sprite.draw_mode.spr; } //left.set_colors(0xff0000, 0.5f); //center.set_colors(0x00ff00, 0.5f); //right.set_colors(0x0000ff, 0.5f); last_sprite = right; return array; }
private static void render_text_advanced(Sprite spr) { Texture t = spr.txt.font_id.tex; BitmapFont f = spr.txt.font_id; #region SFML sprite state set sfml_spr.Image = t.image; sfml_spr.BlendMode = (SFML.Graphics.BlendMode)spr.blit.mode; sfml_spr.Color = familiarize_color(spr.blit.color); sfml_spr.Rotation = 0.0f; sfml_spr.Origin = new Vector2f(0f, 0f);// new Vector2f(spr.blit.scale.x, spr.blit.scale.y); sfml_spr.Scale = new Vector2f(spr.blit.scale.x, spr.blit.scale.y); #endregion float x_offset = 0.0f, y_offset = 0.0f; for (int c = 1, n = spr.txt.txt.Length; c < n; c++) { char a = spr.txt.txt[c]; if (a == '|') // new line { y_offset += (f.v_spacing) * spr.blit.scale.y; x_offset = 0; } else if (a == '#') // DIRECTIVE { char d = spr.txt.txt[c + 1]; if (d == 'C') // directive is COLOR { uint color = 0; var param = find_directive_param(spr.txt.txt, c, out c); if (param == "0") color = spr.blit.color; else if (param == "R") color = 0xff0000; else if (param == "G") color = 0x00ff00; else if (param == "B") color = 0x0000ff; else if (param == "Y") color = 0xffff00; else if (param == "P") color = 0xff00ff; else if (param == "O") color = 0xff8000; sfml_spr.Color = familiarize_color(0xff000000 | color); } else if (d == 'K') // Krest { var param = find_directive_param(spr.txt.txt, c, out c); Crest crest = Crest.find(param); var crest_correction = new crds2(8f, 3f); if (crest != null) crest.render(crest_correction + new crds2(spr.coords.x + x_offset, spr.coords.y + y_offset), (1f / 255f) * sfml_spr.Color.A); x_offset += 24f; } } else // letter! { uint sx = f.char_data[a].seq_x; uint sy = f.char_data[a].seq_y; sfml_spr.Origin = new Vector2f(0f, 0f); sfml_spr.Position = new Vector2f(spr.coords.x + x_offset, spr.coords.y + y_offset); sfml_spr.SubRect = new SFML.Graphics.IntRect( (int)(t.size.x * sx), (int)(t.size.y * sy), (int)(t.size.x),// * (sx + 1)), (int)(t.size.y));// * (sy + 1))); render_target.Draw(sfml_spr, spr.effect.shader.sfml_shader_object); x_offset += (f.char_data[a].width + f.h_spacing) * spr.blit.scale.x; } } }
public static void move_center(crds2 coords) { _target.x += coords.x; _target.y += coords.y; }
/// <summary>returns whether a point p lies to the LEFT side of a line defined by points line_a and line_b</summary> /// <returns>true if the point is "left" of the line as defined by direction from line_a to line_b</returns> public static bool is_left(crds2 line_a, crds2 line_b, crds2 p) { return ((line_b.x - line_a.x) * (p.y - line_a.y) - (line_b.y - line_a.y) * (p.x - line_a.x)) > 0; }
public static crds2 random_point_in_triangle(crds2 A, crds2 B, crds2 C) { var a = Random.range(0f, 1f); var b = Random.range(0f, 1f); if (a + b > 1f) { a = 1f - a; b = 1f - b; } var c = 1f - a - b; return A * a + B * b + C * c; }
//static public bool random_point_in_polygon(crds2[] poly) //{ //} /// <summary>concept nabbed from http://www.blackpawn.com/texts/pointinpoly/default.html </summary> /// <returns>true if point p is in triangle (A, B, C)</returns> public static bool point_in_triangle(crds2 A, crds2 B, crds2 C, crds2 p) { // Compute vectors var v0 = C - A; var v1 = B - A; var v2 = p - A; // Compute dot products var dot00 = crds2.dot(v0, v0); var dot01 = crds2.dot(v0, v1); var dot02 = crds2.dot(v0, v2); var dot11 = crds2.dot(v1, v1); var dot12 = crds2.dot(v1, v2); // Compute barycentric coordinates var invDenom = 1 / (dot00 * dot11 - dot01 * dot01); var u = (dot11 * dot02 - dot01 * dot12) * invDenom; var v = (dot00 * dot12 - dot01 * dot02) * invDenom; // Check if point is in triangle return (u > 0f) && (v > 0f) && (u + v < 1f); }
/// <summary> Returns the point of intersection of two segments, where first segment is defined by A and B, and 2nd segment by C and D. </summary> /// <param name="A">Point A</param><param name="B">Point B</param><param name="C">Point C</param><param name="D">Point D</param><param name="intersection_point">Intersection point, if any</param> /// <returns>True if there is an intersection, and if so, fills intersection_point with the exact location</returns> public static bool segment_segment_intersection(crds2 A, crds2 B, crds2 C, crds2 D, out crds2 intersection_point) { intersection_point = crds2.zero; var z = (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y); if (z.approximately(0f)) return false; var U1 = ((D.x - C.x) * (A.y - C.y) - (D.y - C.y) * (A.x - C.x)) / z; var U2 = ((B.x - A.x) * (A.y - C.y) - (B.y - A.y) * (A.x - C.x)) / z; if ((U1 >= 0f && U1 <= 1f) && (U2 >= 0f && U2 <= 1f)) { intersection_point = A.lerp(B, U1); return true; } return false; }
public static float surface_of_polygon(crds2[] polygon) { var n = polygon.Length; float sum = 0f; for (int i = 0; i < n; i++) { var j = i + 1; if (j == n) j = 0; sum += polygon[i].x * polygon[j].y - polygon[j].x * polygon[i].y; } return XMath.abs(sum * 0.5f); // SUM is now the full SURFACE of the polygon }
public static crds3 project(crds2 world_coords) { var c = world_coords; var me = current + delta * Session.interpolation; return new crds3( Graphics.scrW2 + (c.x - me.x) * zoom, Graphics.scrH2 + ((c.y - me.y) * cos_phi) * zoom, zoom); }