public static Geometry.Ray_Test_Result TestOBBLine(OBB obb, LineSegment ls, Geometry.Ray_Test_Mode mode)
        {
            var result = new Geometry.Ray_Test_Result();
            var pos2   = obb.Point_W_To_L(ls.end);
            var pos1   = obb.Point_W_To_L(ls.start);
            var dir    = pos2 - pos1;

            if (Math.Abs(dir.X) < 0.01f)
            {
                if (Math.Abs(pos1.X) > obb.HalfAxisWidth.X)
                {
                    result.Did_It_Hit = false;
                    return(result);
                }
            }

            var tleftx  = (-obb.HalfAxisWidth.X - pos1.X) / dir.X;
            var trightx = (obb.HalfAxisWidth.X - pos1.X) / dir.X;
            var tenterx = tleftx < trightx ? tleftx : trightx;
            var texitx  = tleftx < trightx ? trightx : tleftx;


            if (Math.Abs(dir.Y) < 0.01f)
            {
                if (Math.Abs(pos1.Y) > obb.HalfAxisWidth.Y)
                {
                    result.Did_It_Hit = false;
                    return(result);
                }
            }

            var tlefty  = (-obb.HalfAxisWidth.Y - pos1.Y) / dir.Y;
            var trighty = (obb.HalfAxisWidth.Y - pos1.Y) / dir.Y;
            var tentery = tlefty < trighty ? tlefty : trighty;
            var texity  = tlefty < trighty ? trighty : tlefty;

            var tmaxmin = tentery > tenterx ? tentery : tenterx;
            var tminmax = texity < texitx ? texity : texitx;

            result.enter = tmaxmin;
            result.exit  = tminmax;
            switch (mode)
            {
            case Geometry.Ray_Test_Mode.Line: result.Did_It_Hit = (tmaxmin < tminmax);
                break;

            case Geometry.Ray_Test_Mode.Ray: result.Did_It_Hit = (tmaxmin < tminmax) && (tmaxmin >= 0);
                break;

            case Geometry.Ray_Test_Mode.Segment: result.Did_It_Hit = (tmaxmin < tminmax) && (tmaxmin >= 0) && (tmaxmin <= 1);
                break;
            }


            return(result);
        }
        public static Geometry.Ray_Test_Result TestOBBLine(OBB obb, LineSegment ls, Geometry.Ray_Test_Mode mode)
        {
            var result = new Geometry.Ray_Test_Result();
            var pos2 = obb.Point_W_To_L(ls.end);
            var pos1 = obb.Point_W_To_L(ls.start);
            var dir = pos2 - pos1;
            if (Math.Abs(dir.X) < 0.01f)
            {
                if (Math.Abs(pos1.X) > obb.HalfAxisWidth.X)
                {
                    result.Did_It_Hit = false;
                    return result;
                }
            }

            var tleftx = (-obb.HalfAxisWidth.X - pos1.X) / dir.X;
            var trightx = (obb.HalfAxisWidth.X - pos1.X) / dir.X;
            var tenterx = tleftx < trightx ? tleftx : trightx;
            var texitx = tleftx < trightx ? trightx : tleftx;

            if (Math.Abs(dir.Y) < 0.01f)
            {
                if (Math.Abs(pos1.Y) > obb.HalfAxisWidth.Y)
                {
                    result.Did_It_Hit = false;
                    return result;
                }
            }

            var tlefty = (-obb.HalfAxisWidth.Y - pos1.Y) / dir.Y;
            var trighty = (obb.HalfAxisWidth.Y - pos1.Y) / dir.Y;
            var tentery = tlefty < trighty ? tlefty : trighty;
            var texity = tlefty < trighty ? trighty : tlefty;

            var tmaxmin = tentery > tenterx ? tentery : tenterx;
            var tminmax = texity < texitx ? texity : texitx;
            result.enter = tmaxmin;
            result.exit = tminmax;
            switch (mode)
            {
                case Geometry.Ray_Test_Mode.Line: result.Did_It_Hit = (tmaxmin < tminmax);
                    break;
                case Geometry.Ray_Test_Mode.Ray: result.Did_It_Hit = (tmaxmin < tminmax) && (tmaxmin >= 0);
                    break;

                case Geometry.Ray_Test_Mode.Segment: result.Did_It_Hit = (tmaxmin < tminmax) && (tmaxmin >= 0) && (tmaxmin <= 1);
                    break;
            }

            return result;
        }
        /// <summary>
        /// xekinas me deiktes i j
        /// kai kataligeis se final_i, final_j //elegxe to an piaseis esto ena einai ok
        /// exeis kati times tx ty pou deixnoun "se ti pososto os pros monada apo to sinoliko manhattan x kai y antistoixa eisai tora"
        /// diladi xekinane apo miden ftanoun 1 alla kai pali me ta final stamatas
        /// </summary>

        //this method performs a bersenhaam algorithm like traversal of the "neutral" grid using a linesegment.
        //until it hits with an obstacle reporting the ray's/segment's parameter at the point of entering and leaving it
        public static Geometry.Ray_Test_Result Trace_Line(LineSegment ls, Geometry.Ray_Test_Mode mode)
        {
            var direction = ls.end - ls.start;

            if (mode == Geometry.Ray_Test_Mode.Line)
            {
                throw new Exception();
            }

            Grid_Query_Counter.Counter++;
            var grid = GELib.Managers.Spatial_Partitioning_Management.main_spatial_grid.neutral;// grids[(int)Col_Slot.Neutral];

            var cell_size         = World_Info.Collision_Cellsize;
            var cell_coords_start = Spatial.Grid_Func.Grid_Coords(ls.start, cell_size);

            Spatial.Grid_Coord cell_coords_end;
            cell_coords_end = Spatial.Grid_Func.Grid_Coords(ls.end, cell_size);


            var i       = cell_coords_start.col;
            var j       = cell_coords_start.row;
            var final_i = cell_coords_end.col;
            var final_j = cell_coords_end.row;

            var y_manh_dist_inv = direction.Y == 0 ? Single.MaxValue : (float)1 / Math.Abs(direction.Y);
            var x_manh_dist_inv = direction.X == 0 ? Single.MaxValue : (float)1 / Math.Abs(direction.X);

            //an to cell afxanei -1,0,1 kathos proxoras analoga pou koitas
            int di = ((ls.start.X < ls.end.X) ? 1 : ((ls.start.X > ls.end.X) ? -1 : 0));
            int dj = ((ls.start.Y < ls.end.Y) ? 1 : ((ls.start.Y > ls.end.Y) ? -1 : 0));

            //se ti posostioso ton manh_dist xekinises,
            //xekinises oxi h arxiki timi pou einai miden
            //alla ta t deixnoun "to epomeno toixaki"
            //kai mallon me ta midenika sta di pou vazo pio pano ktl h idea einai oti
            //den tha peraseis dyo tixakia mias sintetagmenis seri
            //ex ou kai h anisotita sto for(;;)
            var tx = (ls.start.X > ls.end.X ? ls.start.X - (i * cell_size) : (i + 1) * cell_size - ls.start.X) * x_manh_dist_inv;
            var ty = (ls.start.Y > ls.end.Y ? ls.start.Y - (j * cell_size) : (j + 1) * cell_size - ls.start.Y) * y_manh_dist_inv;

            //ta vimata pou kaneis sthn timi tou tx kathos proxoras
            var dtx = cell_size * x_manh_dist_inv;
            var dty = cell_size * y_manh_dist_inv;

            while (true)
            {
                var aa = grid.getBucket(i, j);
                Geometry.Ray_Test_Result Min = new Geometry.Ray_Test_Result(); Min.enter = Single.MaxValue;
                for (int ib = 0; ib < aa.Count; ib++)
                {
                    var g_obj = aa[ib];
                    if (g_obj.g.Last_Query >= Grid_Query_Counter.Counter || g_obj.col != i || g_obj.row != j)
                    {
                        continue;
                    }
                    g_obj.g.Last_Query = Grid_Query_Counter.Counter;
                    var collidable = g_obj.g.Coll;
                    if (collidable.RTII == RTI.Firing || collidable.RTII == RTI.Just_A_Triangle || collidable.RTII == RTI.Chain_Rectangle)
                    {
                        continue;
                    }

                    var obb       = collidable.OBB;
                    var inner_res = Geometry_Func.TestOBBLine(obb, ls, mode);
                    if (inner_res.Did_It_Hit)
                    {
                        if (inner_res.enter < Min.enter)
                        {
                            Min        = inner_res;
                            last_trace = obb;
                        }
                    }
                }
                if (Min.enter != Single.MaxValue)
                {
                    return(Min);
                }
                if (tx <= ty)
                { // tx smallest, step in x
                    if (i == final_i)
                    {
                        break;
                    }
                    tx += dtx;
                    i  += di;
                }
                else
                { // ty smallest, step in y
                    if (j == final_j)
                    {
                        break;
                    }
                    ty += dty;
                    j  += dj;
                }
            }
            var res = new Geometry.Ray_Test_Result(); res.Did_It_Hit = false;

            return(res);
        }
        /// <summary>
        /// xekinas me deiktes i j
        /// kai kataligeis se final_i, final_j //elegxe to an piaseis esto ena einai ok
        /// exeis kati times tx ty pou deixnoun "se ti pososto os pros monada apo to sinoliko manhattan x kai y antistoixa eisai tora"
        /// diladi xekinane apo miden ftanoun 1 alla kai pali me ta final stamatas
        /// </summary>
        //this method performs a bersenhaam algorithm like traversal of the "neutral" grid using a linesegment.
        //until it hits with an obstacle reporting the ray's/segment's parameter at the point of entering and leaving it
        public static Geometry.Ray_Test_Result Trace_Line(LineSegment ls, Geometry.Ray_Test_Mode mode)
        {
            var direction = ls.end - ls.start;
            if (mode == Geometry.Ray_Test_Mode.Line) throw new Exception();

            Grid_Query_Counter.Counter++;
            var grid = GELib.Managers.Spatial_Partitioning_Management.main_spatial_grid.neutral;// grids[(int)Col_Slot.Neutral];

            var cell_size = World_Info.Collision_Cellsize;
            var cell_coords_start = Spatial.Grid_Func.Grid_Coords(ls.start, cell_size);
            Spatial.Grid_Coord cell_coords_end;
            cell_coords_end = Spatial.Grid_Func.Grid_Coords(ls.end, cell_size);

            var i = cell_coords_start.col;
            var j = cell_coords_start.row;
            var final_i = cell_coords_end.col;
            var final_j = cell_coords_end.row;

            var y_manh_dist_inv = direction.Y == 0 ? Single.MaxValue : (float)1 / Math.Abs(direction.Y);
            var x_manh_dist_inv = direction.X == 0 ? Single.MaxValue : (float)1 / Math.Abs(direction.X);

            //an to cell afxanei -1,0,1 kathos proxoras analoga pou koitas
            int di = ((ls.start.X < ls.end.X) ? 1 : ((ls.start.X > ls.end.X) ? -1 : 0));
            int dj = ((ls.start.Y < ls.end.Y) ? 1 : ((ls.start.Y > ls.end.Y) ? -1 : 0));

            //se ti posostioso ton manh_dist xekinises,
            //xekinises oxi h arxiki timi pou einai miden
            //alla ta t deixnoun "to epomeno toixaki"
            //kai mallon me ta midenika sta di pou vazo pio pano ktl h idea einai oti
            //den tha peraseis dyo tixakia mias sintetagmenis seri
            //ex ou kai h anisotita sto for(;;)
            var tx = (ls.start.X > ls.end.X ? ls.start.X - (i * cell_size) : (i + 1) * cell_size - ls.start.X) * x_manh_dist_inv;
            var ty = (ls.start.Y > ls.end.Y ? ls.start.Y - (j * cell_size) : (j + 1) * cell_size - ls.start.Y) * y_manh_dist_inv;

            //ta vimata pou kaneis sthn timi tou tx kathos proxoras
            var dtx = cell_size * x_manh_dist_inv;
            var dty = cell_size * y_manh_dist_inv;

            while (true)
            {
                var aa = grid.getBucket(i, j);
                Geometry.Ray_Test_Result Min = new Geometry.Ray_Test_Result(); Min.enter = Single.MaxValue;
                for (int ib = 0; ib < aa.Count; ib++)
                {

                    var g_obj = aa[ib];
                    if (g_obj.g.Last_Query >= Grid_Query_Counter.Counter || g_obj.col != i || g_obj.row != j) continue;
                    g_obj.g.Last_Query = Grid_Query_Counter.Counter;
                    var collidable = g_obj.g.Coll;
                    if (collidable.RTII == RTI.Firing || collidable.RTII == RTI.Just_A_Triangle || collidable.RTII == RTI.Chain_Rectangle) continue;

                    var obb = collidable.OBB;
                    var inner_res = Geometry_Func.TestOBBLine(obb, ls, mode);
                    if (inner_res.Did_It_Hit)
                        if (inner_res.enter < Min.enter)
                        {
                            Min = inner_res;
                            last_trace = obb;
                        }

                }
                if (Min.enter != Single.MaxValue) return Min;
                if (tx <= ty)
                { // tx smallest, step in x
                    if (i == final_i) break;
                    tx += dtx;
                    i += di;
                }
                else
                { // ty smallest, step in y
                    if (j == final_j) break;
                    ty += dty;
                    j += dj;
                }
            }
            var res = new Geometry.Ray_Test_Result(); res.Did_It_Hit = false;
            return res;
        }