Blame mono/Contours/Geometry.cs

Ivan Mahonin 80bc9b
/*
Ivan Mahonin 80bc9b
    ......... 2015 Ivan Mahonin
Ivan Mahonin 80bc9b
Ivan Mahonin 80bc9b
    This program is free software: you can redistribute it and/or modify
Ivan Mahonin 80bc9b
    it under the terms of the GNU General Public License as published by
Ivan Mahonin 80bc9b
    the Free Software Foundation, either version 3 of the License, or
Ivan Mahonin 80bc9b
    (at your option) any later version.
Ivan Mahonin 80bc9b
Ivan Mahonin 80bc9b
    This program is distributed in the hope that it will be useful,
Ivan Mahonin 80bc9b
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Ivan Mahonin 80bc9b
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ivan Mahonin 80bc9b
    GNU General Public License for more details.
Ivan Mahonin 80bc9b
Ivan Mahonin 80bc9b
    You should have received a copy of the GNU General Public License
Ivan Mahonin 80bc9b
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
Ivan Mahonin 80bc9b
*/
Ivan Mahonin 80bc9b
Ivan Mahonin f6cc12
using System;
Ivan Mahonin f6cc12
using System.Drawing;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
namespace Contours {
Ivan Mahonin f6cc12
    public static class Geometry {
Ivan Mahonin f6cc12
        public enum IntersectionType {
Ivan Mahonin f6cc12
            None,
Ivan Mahonin f6cc12
            Cross,
Ivan Mahonin f6cc12
            Identical,
Ivan Mahonin f6cc12
            Inverted,
Ivan Mahonin f6cc12
            Touch_a0,
Ivan Mahonin f6cc12
            Touch_a1,
Ivan Mahonin f6cc12
            Touch_b0,
Ivan Mahonin f6cc12
            Touch_b1,
Ivan Mahonin f6cc12
            Touch_a0_b0,
Ivan Mahonin f6cc12
            Touch_a0_b1,
Ivan Mahonin f6cc12
            Touch_a1_b0,
Ivan Mahonin f6cc12
            Touch_a1_b1,
Ivan Mahonin f6cc12
            Along_a0_b0_a1_b1,
Ivan Mahonin f6cc12
            Along_a0_b0_b1_a1,
Ivan Mahonin f6cc12
            Along_a0_b1_a1_b0,
Ivan Mahonin f6cc12
            Along_a0_b1_b0_a1,
Ivan Mahonin f6cc12
            Along_b0_a0_a1_b1,
Ivan Mahonin f6cc12
            Along_b0_a0_b1_a1,
Ivan Mahonin f6cc12
            Along_b1_a0_a1_b0,
Ivan Mahonin f6cc12
            Along_b1_a0_b0_a1
Ivan Mahonin f6cc12
        }
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
        // Compare to points place at line base0-base1
Ivan Mahonin f6cc12
        public static int comparePointsAtLine(Point a0, Point a1, Point base0, Point base1) {
Ivan Mahonin f6cc12
            if (base0.X < base1.X && a0.X < a1.X) return -1;
Ivan Mahonin f6cc12
            if (base0.X < base1.X && a1.X < a0.X) return  1;
Ivan Mahonin f6cc12
            if (base1.X < base0.X && a0.X < a1.X) return  1;
Ivan Mahonin f6cc12
            if (base1.X < base0.X && a1.X < a0.X) return -1;
Ivan Mahonin f6cc12
            if (base0.Y < base1.Y && a0.Y < a1.Y) return -1;
Ivan Mahonin f6cc12
            if (base0.Y < base1.Y && a1.Y < a0.Y) return  1;
Ivan Mahonin f6cc12
            if (base1.Y < base0.Y && a0.Y < a1.Y) return  1;
Ivan Mahonin f6cc12
            if (base1.Y < base0.Y && a1.Y < a0.Y) return -1;
Ivan Mahonin f6cc12
            return 0;
Ivan Mahonin f6cc12
        }
Ivan Mahonin f6cc12
Ivan Mahonin b0fc65
        public static bool isPointAtLine(Point p, Point p0, Point p1) {
Ivan Mahonin b0fc65
            if (p == p0 || p == p1)
Ivan Mahonin b0fc65
                return true;
Ivan Mahonin b0fc65
            if (p0 == p1)
Ivan Mahonin b0fc65
                return false;
Ivan Mahonin b0fc65
            if ((long)(p.Y-p0.Y)*(long)(p1.X-p0.X) != (long)(p.X-p0.X)*(long)(p1.Y-p0.Y))
Ivan Mahonin b0fc65
                return false;
Ivan Mahonin b0fc65
            if (p1.X > p0.X)
Ivan Mahonin b0fc65
                return p.X >= p0.X && p.X <= p1.X;
Ivan Mahonin b0fc65
            if (p1.X < p0.X)
Ivan Mahonin b0fc65
                return p.X >= p1.X && p.X <= p0.X;
Ivan Mahonin b0fc65
            if (p1.Y > p0.Y)
Ivan Mahonin b0fc65
                return p.Y >= p0.Y && p.Y <= p1.Y;
Ivan Mahonin b0fc65
            //if (p1.Y < p0.Y)
Ivan Mahonin b0fc65
                return p.Y >= p1.Y && p.Y <= p0.Y;
Ivan Mahonin b0fc65
        }
Ivan Mahonin b0fc65
Ivan Mahonin f6cc12
        public static IntersectionType findIntersection(Point a0, Point a1, Point b0, Point b1, out Point c) {
Ivan Mahonin f6cc12
            c = new Point(0, 0);
Ivan Mahonin f6cc12
            Point da = new Point(a1.X - a0.X, a1.Y - a0.Y);
Ivan Mahonin f6cc12
            Point db = new Point(b1.X - b0.X, b1.Y - b0.Y);
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            if (a0.X == b0.X && a0.Y == b0.Y && a1.X == b1.X && a1.Y == b1.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Identical;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            if (a0.X == b1.X && a0.Y == b1.Y && a1.X == b0.X && a1.Y == b0.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Inverted;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            long divider = (long)da.X*(long)db.Y - (long)db.X*(long)da.Y;
Ivan Mahonin f6cc12
            if (divider == 0) {
Ivan Mahonin f6cc12
                if ((long)da.X*(long)(b0.Y - a0.Y) != (long)da.Y*(long)(b0.X - a0.X))
Ivan Mahonin f6cc12
                    return IntersectionType.None;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
                int a0b0 = comparePointsAtLine(a0, b0, a0, a1);
Ivan Mahonin f6cc12
                int a0b1 = comparePointsAtLine(a0, b1, a0, a1);
Ivan Mahonin f6cc12
                int a1b0 = comparePointsAtLine(a1, b0, a0, a1);
Ivan Mahonin f6cc12
                int a1b1 = comparePointsAtLine(a1, b1, a0, a1);
Ivan Mahonin f6cc12
                int b0b1 = comparePointsAtLine(b0, b1, a0, a1);
Ivan Mahonin f6cc12
                int b0a0 = -a0b0;
Ivan Mahonin f6cc12
                int b0a1 = -a1b0;
Ivan Mahonin f6cc12
                int b1a0 = -a0b1;
Ivan Mahonin f6cc12
                int b1a1 = -a1b1;
Ivan Mahonin f6cc12
                int b1b0 = -b0b1;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
                // a0a1b0b1
Ivan Mahonin 04c11c
                if (a1b0 == 0 && b0b1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Touch_a1_b0;
Ivan Mahonin f6cc12
                // a0a1b1b0
Ivan Mahonin 04c11c
                if (a1b1 == 0 && b1b0 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Touch_a1_b1;
Ivan Mahonin f6cc12
                // b0b1a0a1
Ivan Mahonin 04c11c
                if (b0b1 <= 0 && b1a0 == 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Touch_a0_b1;
Ivan Mahonin f6cc12
                // b1b0a0a1
Ivan Mahonin 04c11c
                if (b1b0 <= 0 && b0a0 == 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Touch_a0_b0;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
                if (a0b0 <= 0 && b0a1 <= 0 && a1b1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_a0_b0_a1_b1;
Ivan Mahonin f6cc12
                if (a0b0 <= 0 && b0b1 <= 0 && b1a1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_a0_b0_b1_a1;
Ivan Mahonin f6cc12
                if (a0b1 <= 0 && b1a1 <= 0 && a1b0 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_a0_b1_a1_b0;
Ivan Mahonin f6cc12
                if (a0b1 <= 0 && b1b0 <= 0 && b0a1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_a0_b1_b0_a1;
Ivan Mahonin f6cc12
                if (b0a0 <= 0 && /*  a0a1  */ a1b1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_b0_a0_a1_b1;
Ivan Mahonin f6cc12
                if (b0a0 <= 0 && a0b1 <= 0 && b1a1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_b0_a0_b1_a1;
Ivan Mahonin f6cc12
                if (b1a0 <= 0 && /*  a0a1  */ a1b0 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_b1_a0_a1_b0;
Ivan Mahonin f6cc12
                if (b1a0 <= 0 && a0b0 <= 0 && b0a1 <= 0)
Ivan Mahonin f6cc12
                    return IntersectionType.Along_b1_a0_b0_a1;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
                return IntersectionType.None;
Ivan Mahonin f6cc12
            }
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            if (a0.X == b0.X && a0.Y == b0.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_a0_b0;
Ivan Mahonin f6cc12
            if (a0.X == b1.X && a0.Y == b1.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_a0_b1;
Ivan Mahonin f6cc12
            if (a1.X == b0.X && a1.Y == b0.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_a1_b0;
Ivan Mahonin f6cc12
            if (a1.X == b1.X && a1.Y == b1.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_a1_b1;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            long numeratorX = (long)da.X*((long)b1.Y*(long)b0.X - (long)b0.Y*(long)b1.X)
Ivan Mahonin f6cc12
                            - (long)db.X*((long)a1.Y*(long)a0.X - (long)a0.Y*(long)a1.X);
Ivan Mahonin f6cc12
            long numeratorY = (long)db.Y*((long)a1.X*(long)a0.Y - (long)a0.X*(long)a1.Y)
Ivan Mahonin f6cc12
                            - (long)da.Y*((long)b1.X*(long)b0.Y - (long)b0.X*(long)b1.Y);
Ivan Mahonin f6cc12
            Point p = new Point((int)(numeratorX/divider), (int)(numeratorY/divider));
Ivan Mahonin 04c11c
            if ( comparePointsAtLine(p, a0, a0, a1) < 0
Ivan Mahonin 04c11c
              || comparePointsAtLine(p, a1, a0, a1) > 0
Ivan Mahonin 04c11c
              || comparePointsAtLine(p, b0, b0, b1) < 0
Ivan Mahonin 04c11c
              || comparePointsAtLine(p, b1, b0, b1) > 0 )
Ivan Mahonin f6cc12
                return IntersectionType.None;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            if (p.X == a0.X && p.Y == a0.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_a0;
Ivan Mahonin f6cc12
            if (p.X == a1.X && p.Y == a1.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_a1;
Ivan Mahonin f6cc12
            if (p.X == b0.X && p.Y == b0.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_b0;
Ivan Mahonin f6cc12
            if (p.X == b1.X && p.Y == b1.Y)
Ivan Mahonin f6cc12
                return IntersectionType.Touch_b1;
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
            c = p;
Ivan Mahonin f6cc12
            return IntersectionType.Cross;
Ivan Mahonin f6cc12
        }
Ivan Mahonin f6cc12
        
Ivan Mahonin f6cc12
        public static bool isCCW(Point a, Point b, Point c) {
Ivan Mahonin f6cc12
            long d = (long)a.X*(long)c.Y - (long)a.Y*(long)c.X;
Ivan Mahonin f6cc12
            // angle AC < 180 deg
Ivan Mahonin f6cc12
            if (d > 0)
Ivan Mahonin f6cc12
                return (long)a.X*(long)b.Y >= (long)a.Y*(long)b.X
Ivan Mahonin f6cc12
                    && (long)c.X*(long)b.Y <= (long)c.Y*(long)b.X;
Ivan Mahonin f6cc12
            // angle AC > 180 deg
Ivan Mahonin f6cc12
            if (d < 0)
Ivan Mahonin f6cc12
                return (long)a.X*(long)b.Y >= (long)a.Y*(long)b.X
Ivan Mahonin f6cc12
                    || (long)c.X*(long)b.Y <= (long)c.Y*(long)b.X;
Ivan Mahonin f6cc12
            // angle AC == 180 deg
Ivan Mahonin f6cc12
            if ((a.X >= 0) != (c.X >= 0) || (a.Y >= 0) != (c.Y >= 0))
Ivan Mahonin f6cc12
                return (long)a.X*(long)b.Y >= (long)a.Y*(long)b.X;
Ivan Mahonin f6cc12
            // angle AC == 0 deg
Ivan Mahonin f6cc12
            return true;
Ivan Mahonin f6cc12
        }
Ivan Mahonin f6cc12
Ivan Mahonin f6cc12
        public static bool isCCW(Point center, Point a, Point b, Point c) {
Ivan Mahonin f6cc12
            return isCCW(
Ivan Mahonin f6cc12
                new Point(a.X - center.X, a.Y - center.Y),
Ivan Mahonin f6cc12
                new Point(b.X - center.X, b.Y - center.Y),
Ivan Mahonin f6cc12
                new Point(c.X - center.X, c.Y - center.Y) );
Ivan Mahonin f6cc12
        }
Ivan Mahonin f6cc12
        
Ivan Mahonin f6cc12
        public static void makeLongestLine(Point p0, ref Point p1) {
Ivan Mahonin 4717b8
            int MaxValue = int.MaxValue >> 1;
Ivan Mahonin f6cc12
            Point direction = new Point(p1.X - p0.X, p1.Y - p0.Y);
Ivan Mahonin f6cc12
            int amplifierX =
Ivan Mahonin f6cc12
                direction.X > 0 ? (MaxValue - p0.X)/direction.X + 1
Ivan Mahonin f6cc12
              : direction.X < 0 ? (MaxValue + p0.X)/(-direction.X) + 1
Ivan Mahonin f6cc12
              : int.MaxValue;
Ivan Mahonin f6cc12
            int amplifierY =
Ivan Mahonin f6cc12
                direction.Y > 0 ? (MaxValue - p0.Y)/direction.Y + 1
Ivan Mahonin f6cc12
              : direction.Y < 0 ? (MaxValue + p0.Y)/(-direction.Y) + 1
Ivan Mahonin f6cc12
              : int.MaxValue;
Ivan Mahonin f6cc12
            int amplifier = Math.Min(amplifierX, amplifierY);
Ivan Mahonin f6cc12
            p1 = new Point(
Ivan Mahonin f6cc12
                    p0.X + direction.X*amplifier,
Ivan Mahonin f6cc12
                    p0.Y + direction.Y*amplifier );
Ivan Mahonin f6cc12
        }
Ivan Mahonin f6cc12
                
Ivan Mahonin f6cc12
    }
Ivan Mahonin f6cc12
}
Ivan Mahonin f6cc12