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); }