Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

How to fill color a self-intersecting polygon ?

Discussion in 'Scripting' started by nav5, Feb 27, 2020.

  1. nav5

    nav5

    Joined:
    Nov 28, 2017
    Posts:
    5
    i want to fill the self-intersecting polygon (which user draws) - with a color
    i know how to fill a non self-intersecting polygon
    but i dont know how to do with the other
    Thanks
     
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    can you please tell me precisely what a polygon is, in your context. is it a 2D application, or a 3D one. is it just an element of N chained points, or a triangulation. do you consider self-intersecting when its edges cross at some point? how do you "fill" the polygon with some color already? what exact technique you're using. etc.
     
  3. nav5

    nav5

    Joined:
    Nov 28, 2017
    Posts:
    5
    Hi , thanks for the reply
    -it's a polygon in 2D
    - it's a shape in 2d which user draw freely
    -i consider self intersecting polygon is when 2 edges cross each other in middle of edges
    yes, i filled the non-self intersecting polygon already,using this :
    https://www.assetstore.unity3d.com/en/#!/content/100641
    but it does not work with self intersecting polygon
     
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    ok, this has to be some sort of a triangulation.
    it is not trivial to change the existing behavior of this script.
    you either have to find another solution, or you have to get knee deep into solving it yourself.

    if you want to do it, you can detect whether two edges collide with each other, calculate the point of their intersection, and reconnect the two resulting polygons. this requires a better understanding of how that drawing program works in the first place.

    the alternative would be to simply reject the self-intersecting polygon, and inform the user that a polygon is not allowed.

    in either case you need some math to intersect two segments, here's a function that does this in 2D

    Code (csharp):
    1. static public bool CalcLinesIntersection(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, out Vector2 intersect) {
    2.   intersect = new Vector2(float.NaN, float.NaN);
    3.  
    4.   float dxa = a2.x - a1.x;
    5.   float dxb = b2.x - b1.x;
    6.  
    7.   // parallel/antiparallel lines: no intersection
    8.   if((a2 - a1).IsCollinearTo(b2 - b1)) return false;
    9.  
    10.   if(dxa.IsCloseToZero()) { // a is vertical
    11.     float kb = (b2.y - b1.y) / dxb;
    12.     float nb = b1.y - kb * b1.x;
    13.     intersect = new Vector2(a1.x, kb * a1.x + nb);
    14.  
    15.   } else if(dxb.IsCloseToZero()) { // b is vertical
    16.     float ka = (a2.y - a1.y) / dxa;
    17.     float na = a1.y - ka * a1.x;
    18.     intersect = new Vector2(b1.x, ka * b1.x + na);
    19.  
    20.   } else {
    21.     float ka = (a2.y - a1.y) / dxa;
    22.     float kb = (b2.y - b1.y) / dxb;
    23.     float na = a1.y - ka * a1.x;
    24.     float nb = b1.y - kb * b1.x;
    25.     float d = 1f / (kb - ka);
    26.     intersect = new Vector2(na - nb, kb * na - ka * nb) * d;
    27.  
    28.   }
    29.  
    30.   return true;
    31. }
    32.  
    33. static public bool IsCollinearTo(this Vector2 lhs, Vector2 rhs)
    34.    => (lhs.x * rhs.y - lhs.y * rhs.x).IsCloseToZero(); // "perp-dot"
    35.  
    36. static public bool IsCloseToZero(this float value)
    37.    => Mathf.Approximately(value, 0f);
    However this will find intersection between two lines that run indefinitely, instead of doing it between two bound segments, so you need to be able to tell whether the calculated point truly belongs to any of the edge segments, or if it lives somewhere outside of it.

    For this you can use Mathf.InverseLerp
    Code (csharp):
    1. static public bool IsWithinSegment(this Vector2 point, Vector2 start, Vector2 end) {
    2.   var dx = Mathf.Abs(end.x - start.x);
    3.   var dy = Mathf.Abs(end.y - start.y);
    4.   var t = (dx > dy)? Mathf.InverseLerp(start.x, end.x, point.x)
    5.                    : Mathf.InverseLerp(start.y, end.y, point.y);
    6.   return t >= 0f && t <= 1f;
    7. }
    usage (the argument declared as out will pop out as your secondary result)
    Code (csharp):
    1. if(CalcLinesIntersection(edge1.start, edge1.end, edge2.start, edge2.end, out var intersection)) {
    2.   if(intersection.IsWithinSegment(edge1.start, edge1.end)) {
    3.     // do something with intersection
    4.   } else {
    5.     // lines do intersect, but segments don't
    6.   }
    7. } else {
    8.   // lines do not intersect
    9. }
    put all of these in a custom static class of your choosing (in its own file).
    Code (csharp):
    1. static public class MyClass {
    2.  ...
    3. }
    methods that have a keyword this in their argument signature are supposed to be used as extensions.
    please find all about extension methods in the MS documentation to understand their functionality. (you can already tell how I used IsWithinSegment in this example.)
     
    Last edited: Mar 2, 2020
    nav5 likes this.
  5. nav5

    nav5

    Joined:
    Nov 28, 2017
    Posts:
    5
    Thank you very much for the help, i wil ltry it