mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-12-03 01:12:55 +00:00
760f70d3f1
so that all files are included by a central one instead of compiling each one separately. This speeds up the compilation process by 25% when doing a complete rebuild in Visual C. - Cleaned up more header dependencies. SVN r1226 (trunk)
763 lines
17 KiB
C++
763 lines
17 KiB
C++
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// This source is available for distribution and/or modification
|
|
// only under the terms of the DOOM Source Code License as
|
|
// published by id Software. All rights reserved.
|
|
//
|
|
// The source is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
|
// for more details.
|
|
//
|
|
// $Log:$
|
|
//
|
|
// DESCRIPTION:
|
|
// Sector utility functions.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "r_data.h"
|
|
#include "p_spec.h"
|
|
#include "c_cvars.h"
|
|
#include "doomstat.h"
|
|
#include "v_palette.h"
|
|
|
|
|
|
// [RH]
|
|
// P_NextSpecialSector()
|
|
//
|
|
// Returns the next special sector attached to this sector
|
|
// with a certain special.
|
|
sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
|
|
{
|
|
sector_t *tsec;
|
|
int i;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line_t *ln = lines[i];
|
|
|
|
if (NULL != (tsec = getNextSector (ln, this)) &&
|
|
tsec != nogood &&
|
|
(tsec->special & 0x00ff) == type)
|
|
{
|
|
return tsec;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// P_FindLowestFloorSurrounding()
|
|
// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindLowestFloorSurrounding (vertex_t **v) const
|
|
{
|
|
int i;
|
|
sector_t *other;
|
|
line_t *check;
|
|
fixed_t floor;
|
|
fixed_t ofloor;
|
|
vertex_t *spot;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
floor = floorplane.ZatPoint (spot);
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v1))
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v2))
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return floor;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_FindHighestFloorSurrounding()
|
|
// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindHighestFloorSurrounding (vertex_t **v) const
|
|
{
|
|
int i;
|
|
line_t *check;
|
|
sector_t *other;
|
|
fixed_t floor;
|
|
fixed_t ofloor;
|
|
vertex_t *spot;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
floor = FIXED_MIN;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
if (ofloor > floor)
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
if (ofloor > floor)
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return floor;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_FindNextHighestFloor()
|
|
//
|
|
// Passed a sector and a floor height, returns the fixed point value
|
|
// of the smallest floor height in a surrounding sector larger than
|
|
// the floor height passed. If no such height exists the floorheight
|
|
// passed is returned.
|
|
//
|
|
// Rewritten by Lee Killough to avoid fixed array and to be faster
|
|
//
|
|
fixed_t sector_t::FindNextHighestFloor (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t ofloor, floor;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
height = floorplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
floor = floorplane.ZatPoint (check->v1);
|
|
if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = ofloor - floor;
|
|
height = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
floor = floorplane.ZatPoint (check->v2);
|
|
if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = ofloor - floor;
|
|
height = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindNextLowestFloor()
|
|
//
|
|
// Passed a sector and a floor height, returns the fixed point value
|
|
// of the largest floor height in a surrounding sector smaller than
|
|
// the floor height passed. If no such height exists the floorheight
|
|
// passed is returned.
|
|
//
|
|
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
|
|
//
|
|
fixed_t sector_t::FindNextLowestFloor (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t ofloor, floor;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
height = floorplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
if (other - sectors == 6)
|
|
other = other;
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
floor = floorplane.ZatPoint (check->v1);
|
|
if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = floor - ofloor;
|
|
height = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
floor = floorplane.ZatPoint (check->v2);
|
|
if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = floor - ofloor;
|
|
height = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// P_FindNextLowestCeiling()
|
|
//
|
|
// Passed a sector and a ceiling height, returns the fixed point value
|
|
// of the largest ceiling height in a surrounding sector smaller than
|
|
// the ceiling height passed. If no such height exists the ceiling height
|
|
// passed is returned.
|
|
//
|
|
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
|
|
//
|
|
fixed_t sector_t::FindNextLowestCeiling (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t oceil, ceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = ceilingplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
ceil = ceilingplane.ZatPoint (check->v1);
|
|
if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = ceil - oceil;
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
ceil = ceilingplane.ZatPoint (check->v2);
|
|
if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = ceil - oceil;
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// P_FindNextHighestCeiling()
|
|
//
|
|
// Passed a sector and a ceiling height, returns the fixed point value
|
|
// of the smallest ceiling height in a surrounding sector larger than
|
|
// the ceiling height passed. If no such height exists the ceiling height
|
|
// passed is returned.
|
|
//
|
|
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
|
|
//
|
|
fixed_t sector_t::FindNextHighestCeiling (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t oceil, ceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = ceilingplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
ceil = ceilingplane.ZatPoint (check->v1);
|
|
if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = oceil - ceil;
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
ceil = ceilingplane.ZatPoint (check->v2);
|
|
if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = oceil - ceil;
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindLowestCeilingSurrounding (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t oceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
if (oceil < height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
if (oceil < height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
|
|
//
|
|
// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindHighestCeilingSurrounding (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t oceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = FIXED_MIN;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
if (oceil > height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
if (oceil > height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// P_FindShortestTextureAround()
|
|
//
|
|
// Passed a sector number, returns the shortest lower texture on a
|
|
// linedef bounding the sector.
|
|
//
|
|
// jff 02/03/98 Add routine to find shortest lower texture
|
|
//
|
|
|
|
static inline void CheckShortestTex (FTextureID texnum, fixed_t &minsize)
|
|
{
|
|
if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX)))
|
|
{
|
|
FTexture *tex = TexMan[texnum];
|
|
if (tex != NULL)
|
|
{
|
|
fixed_t h = tex->GetScaledHeight()<<FRACBITS;
|
|
if (h < minsize)
|
|
{
|
|
minsize = h;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fixed_t sector_t::FindShortestTextureAround () const
|
|
{
|
|
fixed_t minsize = FIXED_MAX;
|
|
|
|
for (int i = 0; i < linecount; i++)
|
|
{
|
|
if (lines[i]->flags & ML_TWOSIDED)
|
|
{
|
|
CheckShortestTex (sides[lines[i]->sidenum[0]].GetTexture(side_t::bottom), minsize);
|
|
CheckShortestTex (sides[lines[i]->sidenum[1]].GetTexture(side_t::bottom), minsize);
|
|
}
|
|
}
|
|
return minsize < FIXED_MAX ? minsize : TexMan[0]->GetHeight() * FRACUNIT;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindShortestUpperAround()
|
|
//
|
|
// Passed a sector number, returns the shortest upper texture on a
|
|
// linedef bounding the sector.
|
|
//
|
|
// Note: If no upper texture exists MAXINT is returned.
|
|
//
|
|
// jff 03/20/98 Add routine to find shortest upper texture
|
|
//
|
|
fixed_t sector_t::FindShortestUpperAround () const
|
|
{
|
|
fixed_t minsize = FIXED_MAX;
|
|
|
|
for (int i = 0; i < linecount; i++)
|
|
{
|
|
if (lines[i]->flags & ML_TWOSIDED)
|
|
{
|
|
CheckShortestTex (sides[lines[i]->sidenum[0]].GetTexture(side_t::top), minsize);
|
|
CheckShortestTex (sides[lines[i]->sidenum[1]].GetTexture(side_t::top), minsize);
|
|
}
|
|
}
|
|
return minsize < FIXED_MAX ? minsize : TexMan[0]->GetHeight() * FRACUNIT;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindModelFloorSector()
|
|
//
|
|
// Passed a floor height and a sector number, return a pointer to a
|
|
// a sector with that floor height across the lowest numbered two sided
|
|
// line surrounding the sector.
|
|
//
|
|
// Note: If no sector at that height bounds the sector passed, return NULL
|
|
//
|
|
// jff 02/03/98 Add routine to find numeric model floor
|
|
// around a sector specified by sector number
|
|
// jff 3/14/98 change first parameter to plain height to allow call
|
|
// from routine not using floormove_t
|
|
//
|
|
sector_t *sector_t::FindModelFloorSector (fixed_t floordestheight) const
|
|
{
|
|
int i;
|
|
sector_t *sec;
|
|
|
|
//jff 5/23/98 don't disturb sec->linecount while searching
|
|
// but allow early exit in old demos
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
sec = getNextSector (lines[i], this);
|
|
if (sec != NULL &&
|
|
(sec->floorplane.ZatPoint (lines[i]->v1) == floordestheight ||
|
|
sec->floorplane.ZatPoint (lines[i]->v2) == floordestheight))
|
|
{
|
|
return sec;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindModelCeilingSector()
|
|
//
|
|
// Passed a ceiling height and a sector number, return a pointer to a
|
|
// a sector with that ceiling height across the lowest numbered two sided
|
|
// line surrounding the sector.
|
|
//
|
|
// Note: If no sector at that height bounds the sector passed, return NULL
|
|
//
|
|
// jff 02/03/98 Add routine to find numeric model ceiling
|
|
// around a sector specified by sector number
|
|
// used only from generalized ceiling types
|
|
// jff 3/14/98 change first parameter to plain height to allow call
|
|
// from routine not using ceiling_t
|
|
//
|
|
sector_t *sector_t::FindModelCeilingSector (fixed_t floordestheight) const
|
|
{
|
|
int i;
|
|
sector_t *sec;
|
|
|
|
//jff 5/23/98 don't disturb sec->linecount while searching
|
|
// but allow early exit in old demos
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
sec = getNextSector (lines[i], this);
|
|
if (sec != NULL &&
|
|
(sec->ceilingplane.ZatPoint (lines[i]->v1) == floordestheight ||
|
|
sec->ceilingplane.ZatPoint (lines[i]->v2) == floordestheight))
|
|
{
|
|
return sec;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Find minimum light from an adjacent sector
|
|
//
|
|
int sector_t::FindMinSurroundingLight (int min) const
|
|
{
|
|
int i;
|
|
line_t* line;
|
|
sector_t* check;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line = lines[i];
|
|
if (NULL != (check = getNextSector (line, this)) &&
|
|
check->lightlevel < min)
|
|
{
|
|
min = check->lightlevel;
|
|
}
|
|
}
|
|
return min;
|
|
}
|
|
|
|
//
|
|
// Find the highest point on the floor of the sector
|
|
//
|
|
fixed_t sector_t::FindHighestFloorPoint (vertex_t **v) const
|
|
{
|
|
int i;
|
|
line_t *line;
|
|
fixed_t height = FIXED_MIN;
|
|
fixed_t probeheight;
|
|
vertex_t *spot = NULL;
|
|
|
|
if ((floorplane.a | floorplane.b) == 0)
|
|
{
|
|
if (v != NULL)
|
|
{
|
|
if (linecount == 0) *v = &vertexes[0];
|
|
else *v = lines[0]->v1;
|
|
}
|
|
return -floorplane.d;
|
|
}
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line = lines[i];
|
|
probeheight = floorplane.ZatPoint (line->v1);
|
|
if (probeheight > height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v1;
|
|
}
|
|
probeheight = floorplane.ZatPoint (line->v2);
|
|
if (probeheight > height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v2;
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// Find the lowest point on the ceiling of the sector
|
|
//
|
|
fixed_t sector_t::FindLowestCeilingPoint (vertex_t **v) const
|
|
{
|
|
int i;
|
|
line_t *line;
|
|
fixed_t height = FIXED_MAX;
|
|
fixed_t probeheight;
|
|
vertex_t *spot = NULL;
|
|
|
|
if ((ceilingplane.a | ceilingplane.b) == 0)
|
|
{
|
|
if (v != NULL)
|
|
{
|
|
if (linecount == 0) *v = &vertexes[0];
|
|
else *v = lines[0]->v1;
|
|
}
|
|
return ceilingplane.d;
|
|
}
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line = lines[i];
|
|
probeheight = ceilingplane.ZatPoint (line->v1);
|
|
if (probeheight < height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v1;
|
|
}
|
|
probeheight = ceilingplane.ZatPoint (line->v2);
|
|
if (probeheight < height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v2;
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
|
|
void sector_t::SetColor(int r, int g, int b, int desat)
|
|
{
|
|
PalEntry color = PalEntry (r,g,b);
|
|
ColorMap = GetSpecialLights (color, ColorMap->Fade, desat);
|
|
}
|
|
|
|
void sector_t::SetFade(int r, int g, int b)
|
|
{
|
|
PalEntry fade = PalEntry (r,g,b);
|
|
ColorMap = GetSpecialLights (ColorMap->Color, fade, ColorMap->Desaturate);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// sector_t :: ClosestPoint
|
|
//
|
|
// Given a point (x,y), returns the point (ox,oy) on the sector's defining
|
|
// lines that is nearest to (x,y).
|
|
//
|
|
//===========================================================================
|
|
|
|
void sector_t::ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy) const
|
|
{
|
|
int i;
|
|
double x = fx, y = fy;
|
|
double bestdist = HUGE_VAL;
|
|
double bestx = 0, besty = 0;
|
|
|
|
for (i = 0; i < linecount; ++i)
|
|
{
|
|
vertex_t *v1 = lines[i]->v1;
|
|
vertex_t *v2 = lines[i]->v2;
|
|
double a = v2->x - v1->x;
|
|
double b = v2->y - v1->y;
|
|
double den = a*a + b*b;
|
|
double ix, iy, dist;
|
|
|
|
if (den == 0)
|
|
{ // Line is actually a point!
|
|
ix = v1->x;
|
|
iy = v1->y;
|
|
}
|
|
else
|
|
{
|
|
double num = (x - v1->x) * a + (y - v1->y) * b;
|
|
double u = num / den;
|
|
if (u <= 0)
|
|
{
|
|
ix = v1->x;
|
|
iy = v1->y;
|
|
}
|
|
else if (u >= 1)
|
|
{
|
|
ix = v2->x;
|
|
iy = v2->y;
|
|
}
|
|
else
|
|
{
|
|
ix = v1->x + u * a;
|
|
iy = v1->y + u * b;
|
|
}
|
|
}
|
|
a = (ix - x);
|
|
b = (iy - y);
|
|
dist = a*a + b*b;
|
|
if (dist < bestdist)
|
|
{
|
|
bestdist = dist;
|
|
bestx = ix;
|
|
besty = iy;
|
|
}
|
|
}
|
|
ox = fixed_t(bestx);
|
|
oy = fixed_t(besty);
|
|
}
|