diff options
Diffstat (limited to 'src/addons/rmsmartshape/shapes/quad.gd')
-rw-r--r-- | src/addons/rmsmartshape/shapes/quad.gd | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/addons/rmsmartshape/shapes/quad.gd b/src/addons/rmsmartshape/shapes/quad.gd new file mode 100644 index 0000000..54249e7 --- /dev/null +++ b/src/addons/rmsmartshape/shapes/quad.gd @@ -0,0 +1,201 @@ +tool +extends Reference +class_name SS2D_Quad + +enum ORIENTATION { COLINEAR = 0, CCW, CW } +enum CORNER { NONE = 0, OUTER, INNER } + +var pt_a: Vector2 +var pt_b: Vector2 +var pt_c: Vector2 +var pt_d: Vector2 + +var texture: Texture = null +var texture_normal: Texture = null +var color: Color = Color(1.0, 1.0, 1.0, 1.0) + +var flip_texture: bool = false +# Deprecated, should remove control_point_index +var control_point_index: int +var fit_texture = SS2D_Material_Edge.FITMODE.SQUISH_AND_STRETCH + +# Contains value from CORNER enum +var corner: int = 0 + +# EXISTS FOR LEGACY REASONS, THIS PROPERTY IS DEPRECATED +var width_factor: float = 1.0 + + +func _to_string() -> String: + return "[Quad] A:%s B:%s C:%s D:%s | Corner: %s" % [pt_a, pt_b, pt_c, pt_d, corner] + + +func matches_quad(q: SS2D_Quad) -> bool: + if ( + texture == q.texture + and texture_normal == q.texture_normal + and color == q.color + and flip_texture == q.flip_texture + and fit_texture == q.fit_texture + ): + return true + return false + + +func duplicate() -> SS2D_Quad: + var q = __new() + q.pt_a = pt_a + q.pt_b = pt_b + q.pt_c = pt_c + q.pt_d = pt_d + + q.texture = texture + q.texture_normal = texture_normal + q.color = color + + q.flip_texture = flip_texture + q.width_factor = width_factor + q.control_point_index = control_point_index + + q.corner = corner + return q + + +func _init( + a: Vector2 = Vector2.ZERO, + b: Vector2 = Vector2.ZERO, + c: Vector2 = Vector2.ZERO, + d: Vector2 = Vector2.ZERO, + t: Texture = null, + tn: Texture = null, + f: bool = false +): + pt_a = a + pt_b = b + pt_c = c + pt_d = d + texture = t + texture_normal = tn + flip_texture = f + + +func get_rotation() -> float: + return SS2D_NormalRange.get_angle_from_vector(pt_c - pt_a) + + +""" +Given three colinear points p, q, r, the function checks if +point q lies on line segment 'pr' +""" + + +func on_segment(p: Vector2, q: Vector2, r: Vector2) -> bool: + if ( + (q.x <= max(p.x, r.x)) + and (q.x >= min(p.x, r.x)) + and (q.y <= max(p.y, r.y)) + and (q.y >= min(p.y, r.y)) + ): + return true + return false + + +""" +Returns CCW, CW, or colinear +see https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ +""" + + +func get_orientation(a: Vector2, b: Vector2, c: Vector2) -> int: + var val = (float(b.y - a.y) * (c.x - b.x)) - (float(b.x - a.x) * (c.y - b.y)) + if val > 0: + return ORIENTATION.CW + elif val < 0: + return ORIENTATION.CCW + return ORIENTATION.COLINEAR + + +""" +Return true if line segments p1q1 and p2q2 intersect +""" + + +func edges_intersect(p1: Vector2, q1: Vector2, p2: Vector2, q2: Vector2) -> bool: + var o1 = get_orientation(p1, q1, p2) + var o2 = get_orientation(p1, q1, q2) + var o3 = get_orientation(p2, q2, p1) + var o4 = get_orientation(p2, q2, q1) + # General case + if (o1 != o2) and (o3 != o4): + return true + + # Special Cases + # p1 , q1 and p2 are colinear and p2 lies on segment p1q1 + if (o1 == 0) and on_segment(p1, p2, q1): + return true + + # p1 , q1 and q2 are colinear and q2 lies on segment p1q1 + if (o2 == 0) and on_segment(p1, q2, q1): + return true + + # p2 , q2 and p1 are colinear and p1 lies on segment p2q2 + if (o3 == 0) and on_segment(p2, p1, q2): + return true + + # p2 , q2 and q1 are colinear and q1 lies on segment p2q2 + if (o4 == 0) and on_segment(p2, q1, q2): + return true + + return false + + +func self_intersects() -> bool: + return edges_intersect(pt_a, pt_d, pt_b, pt_c) or edges_intersect(pt_a, pt_b, pt_d, pt_c) + + +func render_lines(ci: CanvasItem): + ci.draw_line(pt_a, pt_b, color) + ci.draw_line(pt_b, pt_c, color) + ci.draw_line(pt_c, pt_d, color) + ci.draw_line(pt_d, pt_a, color) + + +func render_points(rad: float, intensity: float, ci: CanvasItem): + ci.draw_circle(pt_a, rad, Color(intensity, 0, 0)) + ci.draw_circle(pt_b, rad, Color(0, 0, intensity)) + ci.draw_circle(pt_c, rad, Color(0, intensity, 0)) + ci.draw_circle(pt_d, rad, Color(intensity, 0, intensity)) + + +# Workaround (class cannot reference itself) +func __new(): + return get_script().new() + + +func get_height_average() -> float: + return (get_height_left() + get_height_right()) / 2.0 + + +func get_height_left() -> float: + return pt_a.distance_to(pt_b) + + +func get_height_right() -> float: + return pt_d.distance_to(pt_c) + + +# Returns the difference in height between the left and right sides +func get_height_difference() -> float: + return get_height_left() - get_height_right() + + +func get_length_average() -> float: + return (get_length_top() + get_length_bottom()) / 2.0 + + +func get_length_top() -> float: + return pt_d.distance_to(pt_a) + + +func get_length_bottom() -> float: + return pt_c.distance_to(pt_b) |