SWORD25: Converted the math folder files

svn-id: r53197
This commit is contained in:
Paul Gilbert 2010-08-01 08:31:50 +00:00 committed by Eugene Sandulenko
parent 2f86c7a45c
commit 53a9d2d0a1
17 changed files with 1018 additions and 1432 deletions

View File

@ -40,23 +40,21 @@
#include "sword25/kernel/inputpersistenceblock.h"
using namespace std;
namespace Sword25 {
// -----------------------------------------------------------------------------
// Construction / Destruction
// Constructor / Destructor
// -----------------------------------------------------------------------------
BS_InputPersistenceBlock::BS_InputPersistenceBlock(const void * Data, unsigned int DataLength) :
m_Data(static_cast<const unsigned char *>(Data), static_cast<const unsigned char *>(Data) + DataLength),
m_ErrorState(NONE)
{
m_Data(static_cast<const unsigned char *>(Data), DataLength),
m_ErrorState(NONE) {
m_Iter = m_Data.begin();
}
// -----------------------------------------------------------------------------
BS_InputPersistenceBlock::~BS_InputPersistenceBlock()
{
BS_InputPersistenceBlock::~BS_InputPersistenceBlock() {
if (m_Iter != m_Data.end()) BS_LOG_WARNINGLN("Persistence block was not read to the end.");
}
@ -64,80 +62,69 @@ BS_InputPersistenceBlock::~BS_InputPersistenceBlock()
// Reading
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(signed int & Value)
{
if (CheckMarker(SINT_MARKER))
{
void BS_InputPersistenceBlock::Read(int16 &Value) {
signed int v;
Read(v);
Value = static_cast<int16>(v);
}
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(signed int &Value) {
if (CheckMarker(SINT_MARKER)) {
RawRead(&Value, sizeof(signed int));
Value = ConvertEndianessFromStorageToSystem(Value);
}
else
{
} else {
Value = 0;
}
}
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(unsigned int & Value)
{
if (CheckMarker(UINT_MARKER))
{
void BS_InputPersistenceBlock::Read(unsigned int &Value) {
if (CheckMarker(UINT_MARKER)) {
RawRead(&Value, sizeof(unsigned int));
Value = ConvertEndianessFromStorageToSystem(Value);
}
else
{
} else {
Value = 0;
}
}
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(float & Value)
{
if (CheckMarker(FLOAT_MARKER))
{
void BS_InputPersistenceBlock::Read(float &Value) {
if (CheckMarker(FLOAT_MARKER)) {
RawRead(&Value, sizeof(float));
Value = ConvertEndianessFromStorageToSystem(Value);
}
else
{
} else {
Value = 0.0f;
}
}
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(bool & Value)
{
if (CheckMarker(BOOL_MARKER))
{
void BS_InputPersistenceBlock::Read(bool &Value) {
if (CheckMarker(BOOL_MARKER)) {
unsigned int UIntBool;
RawRead(&UIntBool, sizeof(float));
UIntBool = ConvertEndianessFromStorageToSystem(UIntBool);
Value = UIntBool == 0 ? false : true;
}
else
{
} else {
Value = 0.0f;
}
}
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(std::string & Value)
{
void BS_InputPersistenceBlock::Read(Common::String &Value) {
Value = "";
if (CheckMarker(STRING_MARKER))
{
if (CheckMarker(STRING_MARKER)) {
unsigned int Size;
Read(Size);
if (CheckBlockSize(Size))
{
Value = std::string(reinterpret_cast<const char *>(&*m_Iter), Size);
if (CheckBlockSize(Size)) {
Value = Common::String(reinterpret_cast<const char *>(&*m_Iter), Size);
m_Iter += Size;
}
}
@ -145,16 +132,13 @@ void BS_InputPersistenceBlock::Read(std::string & Value)
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::Read(vector<unsigned char> & Value)
{
if (CheckMarker(BLOCK_MARKER))
{
void BS_InputPersistenceBlock::Read(Common::Array<unsigned char> &Value) {
if (CheckMarker(BLOCK_MARKER)) {
unsigned int Size;
Read(Size);
if (CheckBlockSize(Size))
{
Value = vector<unsigned char>(m_Iter, m_Iter + Size);
if (CheckBlockSize(Size)) {
Value = Common::Array<unsigned char>(m_Iter, Size);
m_Iter += Size;
}
}
@ -162,10 +146,8 @@ void BS_InputPersistenceBlock::Read(vector<unsigned char> & Value)
// -----------------------------------------------------------------------------
void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size)
{
if (CheckBlockSize(Size))
{
void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size) {
if (CheckBlockSize(Size)) {
memcpy(DestPtr, &*m_Iter, Size);
m_Iter += Size;
}
@ -173,14 +155,10 @@ void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size)
// -----------------------------------------------------------------------------
bool BS_InputPersistenceBlock::CheckBlockSize(int Size)
{
if (m_Data.end() - m_Iter >= Size)
{
bool BS_InputPersistenceBlock::CheckBlockSize(int Size) {
if (m_Data.end() - m_Iter >= Size) {
return true;
}
else
{
} else {
m_ErrorState = END_OF_DATA;
BS_LOG_ERRORLN("Unexpected end of persistence block.");
return false;
@ -189,18 +167,16 @@ bool BS_InputPersistenceBlock::CheckBlockSize(int Size)
// -----------------------------------------------------------------------------
bool BS_InputPersistenceBlock::CheckMarker(unsigned char Marker)
{
bool BS_InputPersistenceBlock::CheckMarker(unsigned char Marker) {
if (!IsGood() || !CheckBlockSize(1)) return false;
if (*m_Iter++ == Marker)
{
if (*m_Iter++ == Marker) {
return true;
}
else
{
} else {
m_ErrorState = OUT_OF_SYNC;
BS_LOG_ERRORLN("Wrong type marker found in persistence block.");
return false;
}
}
} // End of namespace Sword25

View File

@ -62,12 +62,13 @@ public:
BS_InputPersistenceBlock(const void *Data, unsigned int DataLength);
virtual ~BS_InputPersistenceBlock();
void Read(int16 &Value);
void Read(signed int &Value);
void Read(unsigned int &Value);
void Read(float &Value);
void Read(bool &Value);
void Read(std::string &Value);
void Read(std::vector<unsigned char> &Value);
void Read(Common::String &Value);
void Read(Common::Array<unsigned char> &Value);
bool IsGood() const { return m_ErrorState == NONE; }
ErrorState GetErrorState() const { return m_ErrorState; }

View File

@ -339,6 +339,18 @@ public:
BS_Service* (*CreateMethod)(BS_Kernel *);
};
template<class T>
void ReverseArray(Common::Array<T> Arr) {
if (Arr.size() < 2)
return;
for (uint i = 0; i < (Arr.size() / 2 - 1); ++i) {
T temp = Arr[i];
Arr[i] = Arr[Arr.size() - i - 1];
Arr[Arr.size() - i - 1] = temp;
}
}
} // End of namespace Sword25
#endif

View File

@ -36,11 +36,7 @@
// Includes
// -----------------------------------------------------------------------------
#include "sword25/kernel/memlog_off.h"
#include <memory>
#include <vector>
#include "sword25/kernel/memlog_on.h"
#include "common/array.h"
#include "sword25/gfx/graphicengine.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/kernel.h"
@ -55,21 +51,20 @@
// -----------------------------------------------------------------------------
using namespace std;
namespace Sword25 {
// -----------------------------------------------------------------------------
// Constants
// -----------------------------------------------------------------------------
// Die Strings werden als #defines definiert um Stringkomposition zur Compilezeit zu ermöglichen.
// These strings are defined as #defines to enable compile-time string composition
#define REGION_CLASS_NAME "Geo.Region"
#define WALKREGION_CLASS_NAME "Geo.WalkRegion"
// -----------------------------------------------------------------------------
// Wie luaL_checkudata, nur ohne dass kein Fehler erzeugt wird.
static void * my_checkudata (lua_State *L, int ud, const char *tname)
{
// How luaL_checkudata, only without that no error is generated.
static void *my_checkudata(::lua_State *L, int ud, const char *tname) {
int top = lua_gettop(L);
void * p = lua_touserdata(L, ud);
@ -79,8 +74,8 @@ static void * my_checkudata (lua_State *L, int ud, const char *tname)
{
// lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
BS_LuaBindhelper::GetMetatable(L, tname);
if (lua_rawequal(L, -1, -2)) /* does it have the correct mt? */
{
/* does it have the correct mt? */
if (lua_rawequal(L, -1, -2)) {
lua_settop(L, top);
return p;
}
@ -93,50 +88,43 @@ static void * my_checkudata (lua_State *L, int ud, const char *tname)
// -----------------------------------------------------------------------------
static void NewUintUserData(lua_State * L, unsigned int Value)
{
static void NewUintUserData(::lua_State *L, unsigned int Value) {
void * UserData = lua_newuserdata(L, sizeof(Value));
memcpy(UserData, &Value, sizeof(Value));
}
// -----------------------------------------------------------------------------
static bool IsValidPolygonDefinition(lua_State * L)
{
static bool IsValidPolygonDefinition(::lua_State *L) {
#ifdef DEBUG
int __startStackDepth = lua_gettop(L);
#endif
// Sicherstellen, dass wir wirklich eine Tabelle betrachten
if (!lua_istable(L, -1))
{
// Ensure that we actually consider a table
if (!lua_istable(L, -1)) {
luaL_error(L, "Invalid polygon definition. Unexpected type, \"table\" needed.");
return false;
}
int TableSize = luaL_getn(L, -1);
// Sicherstellen, dass mindestens 3 Vertecies existieren.
if (TableSize < 6)
{
// Make sure that there are at least three Vertecies
if (TableSize < 6) {
luaL_error(L, "Invalid polygon definition. At least three vertecies needed.");
return false;
}
// Sicherstellen, dass die Anzahl der Tabellenelemente durch zwei teilbar ist.
// Da je zwei Elemente ein Vertex definieren, ist eine ungerade Anzahl an Elementen nicht zulässig.
if ((TableSize % 2) != 0)
{
// Make sure that the number of table elements is divisible by two.
// Since any two elements is a vertex, an odd number of elements is not allowed
if ((TableSize % 2) != 0) {
luaL_error(L, "Invalid polygon definition. Even number of table elements needed.");
return false;
}
// Sicherstellen, dass alle Elemente der Tabelle vom Typ Number sind.
for (int i = 1; i <= TableSize; i += 1)
{
// Ensure that all elements in the table are of type Number
for (int i = 1; i <= TableSize; i += 1) {
lua_rawgeti(L, -1, i);
if (!lua_isnumber(L, -1))
{
if (!lua_isnumber(L, -1)) {
luaL_error(L, "Invalid polygon definition. All table elements have to be numbers.");
return false;
}
@ -152,32 +140,31 @@ static bool IsValidPolygonDefinition(lua_State * L)
// -----------------------------------------------------------------------------
static void TablePolygonToPolygon(lua_State * L, BS_Polygon & Polygon)
{
static void TablePolygonToPolygon(::lua_State *L, BS_Polygon &Polygon) {
#ifdef DEBUG
int __startStackDepth = lua_gettop(L);
#endif
// Sicherstellen, dass eine gültige Polygon-Definition auf dem Stack liegt.
// Es ist nicht notwendig den Rückgabewert abzufangen, da alle Fehler über luaL_error ausgegeben werden und somit die Ausführung des
// Skriptes beenden.
// Ensure that a valid polygon definition is on the stack.
// It is not necessary to catch the return value, since all errors are reported on luaL_error
// End script.
IsValidPolygonDefinition(L);
int VertexCount = luaL_getn(L, -1) / 2;
// Speicher für Vertecies reservieren
vector<BS_Vertex> Vertecies;
// Memory is reserved for Vertecies
Common::Array<BS_Vertex> Vertecies;
Vertecies.reserve(VertexCount);
// Vertecies erstellen
// Create Vertecies
for (int i = 0; i < VertexCount; i++)
{
// X-Wert
// X Value
lua_rawgeti(L, -1, (i * 2) + 1);
int X = static_cast<int>(lua_tonumber(L, -1));
lua_pop(L, 1);
// Y-Wert
// Y Value
lua_rawgeti(L, -1, (i * 2) + 2);
int Y = static_cast<int>(lua_tonumber(L, -1));
lua_pop(L, 1);
@ -185,72 +172,63 @@ static void TablePolygonToPolygon(lua_State * L, BS_Polygon & Polygon)
// Vertex
Vertecies.push_back(BS_Vertex(X, Y));
}
BS_ASSERT(Vertecies.size() == VertexCount);
BS_ASSERT((int)Vertecies.size() == VertexCount);
#ifdef DEBUG
BS_ASSERT(__startStackDepth == lua_gettop(L));
#endif
// Polygon erstellen
// Create polygon
Polygon.Init(VertexCount, &Vertecies[0]);
}
// -----------------------------------------------------------------------------
static unsigned int TableRegionToRegion(lua_State * L, const char * ClassName)
{
static unsigned int TableRegionToRegion(::lua_State *L, const char *ClassName) {
#ifdef DEBUG
int __startStackDepth = lua_gettop(L);
#endif
// Man kann eine Region in Lua auf zwei Arten definieren:
// 1. Eine Tabelle, die ein Polygon definiert (Polygon = Tabelle mit Zahlen, wobei je zwei aufeinander folgende Zahlen ein Vertex definieren)
// Das eine Polygon definiert die Region vollständig (=> keine Löcher möglich)
// 2. Eine Tabelle, die mehrere Polygondefinitionen (wiederum Tabellen (siehe 1.)) enthält.
// Dann definiert das erste Polygon den Umriss der Region und die folgenden Löcher im ersten Polygon.
// You can define a region in Lua in two ways:
// 1. A table that defines a polygon (polgon = table with numbers, which define
// two consecutive numbers per vertex)
// 2. A table containing more polygon definitions
// Then the first polygon is the contour of the region, and the following are holes
// defined in the first polygon.
// Es darf nur ein Parameter übergeben werden und dieser muss eine Tabelle sein.
if (lua_gettop(L) != 1 || !lua_istable(L, -1))
{
// It may be passed only one parameter, and this must be a table
if (lua_gettop(L) != 1 || !lua_istable(L, -1)) {
luaL_error(L, "First and only parameter has to be of type \"table\".");
return 0;
}
unsigned int RegionHandle;
if (ClassName == REGION_CLASS_NAME)
{
if (ClassName == REGION_CLASS_NAME) {
RegionHandle = BS_Region::Create(BS_Region::RT_REGION);
}
else if (ClassName == WALKREGION_CLASS_NAME)
{
} else if (ClassName == WALKREGION_CLASS_NAME) {
RegionHandle = BS_WalkRegion::Create(BS_Region::RT_WALKREGION);
}
else
{
} else {
BS_ASSERT(false);
}
BS_ASSERT(RegionHandle);
// Wenn das erste Element des Parameters eine Zahl ist, wird der 1. Fall angenommen.
// Wenn das erste Element des Parameters eine Tabelle ist, wird der 2. Fall angenommen.
// Wenn das erste Element des Parameters einen anderen Typ hat, liegt ein Fehler vor.
// If the first element of the parameter is a number, then case 1 is accepted
// If the first element of the parameter is a table, then case 2 is accepted
// If the first element of the parameter has a different type, there is an error
lua_rawgeti(L, -1, 1);
int FirstElementType = lua_type(L, -1);
lua_pop(L, 1);
switch(FirstElementType)
{
case LUA_TNUMBER:
{
switch(FirstElementType) {
case LUA_TNUMBER: {
BS_Polygon Polygon;
TablePolygonToPolygon(L, Polygon);
BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)->Init(Polygon);
}
break;
case LUA_TTABLE:
{
case LUA_TTABLE: {
lua_rawgeti(L, -1, 1);
BS_Polygon Polygon;
TablePolygonToPolygon(L, Polygon);
@ -259,19 +237,17 @@ static unsigned int TableRegionToRegion(lua_State * L, const char * ClassName)
int PolygonCount = luaL_getn(L, -1);
if (PolygonCount == 1)
BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)->Init(Polygon);
else
{
vector<BS_Polygon> Holes;
else {
Common::Array<BS_Polygon> Holes;
Holes.reserve(PolygonCount - 1);
for (int i = 2; i <= PolygonCount; i++)
{
for (int i = 2; i <= PolygonCount; i++) {
lua_rawgeti(L, -1, i);
Holes.resize(Holes.size() + 1);
TablePolygonToPolygon(L, Holes.back());
lua_pop(L, 1);
}
BS_ASSERT(Holes.size() == PolygonCount - 1);
BS_ASSERT((int)Holes.size() == PolygonCount - 1);
BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle)->Init(Polygon, &Holes);
}
@ -292,10 +268,10 @@ static unsigned int TableRegionToRegion(lua_State * L, const char * ClassName)
// -----------------------------------------------------------------------------
static void NewUserdataRegion(lua_State * L, const char * ClassName)
static void NewUserdataRegion(::lua_State *L, const char *ClassName)
{
// Region aufgrund des Lua-Codes erstellen.
// Fehler treten nicht auf, sondern werden von der Funktion über luaL_error abgefangen.
// Region due to the Lua code to create
// Any errors that occur will be intercepted to the luaL_error
unsigned int RegionHandle = TableRegionToRegion(L, ClassName);
BS_ASSERT(RegionHandle);
@ -308,26 +284,23 @@ static void NewUserdataRegion(lua_State * L, const char * ClassName)
// -----------------------------------------------------------------------------
static int NewRegion(lua_State * L)
{
static int NewRegion(::lua_State *L) {
NewUserdataRegion(L, REGION_CLASS_NAME);
return 1;
}
// -----------------------------------------------------------------------------
static int NewWalkRegion(lua_State * L)
{
static int NewWalkRegion(::lua_State *L) {
NewUserdataRegion(L, WALKREGION_CLASS_NAME);
return 1;
}
// -----------------------------------------------------------------------------
static const char * GEO_LIBRARY_NAME = "Geo";
static const char *GEO_LIBRARY_NAME = "Geo";
static const luaL_reg GEO_FUNCTIONS[] =
{
static const luaL_reg GEO_FUNCTIONS[] = {
"NewRegion", NewRegion,
"NewWalkRegion", NewWalkRegion,
0, 0,
@ -335,28 +308,23 @@ static const luaL_reg GEO_FUNCTIONS[] =
// -----------------------------------------------------------------------------
static BS_Region * CheckRegion(lua_State * L)
{
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Geo.Region oder Geo.WalkRegion
unsigned int * RegionHandlePtr;
static BS_Region * CheckRegion(::lua_State *L) {
// The first parameter must be of type 'userdata', and the Metatable class Geo.Region or Geo.WalkRegion
unsigned int *RegionHandlePtr;
if ((RegionHandlePtr = reinterpret_cast<unsigned int *>(my_checkudata(L, 1, REGION_CLASS_NAME))) != 0 ||
(RegionHandlePtr = reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0)
{
(RegionHandlePtr = reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) {
return BS_RegionRegistry::GetInstance().ResolveHandle(*RegionHandlePtr);
}
else
{
} else {
luaL_argcheck(L, 0, 1, "'" REGION_CLASS_NAME "' expected");
}
// Compiler ruhigstellen. Ausführung kommt nie an diesem Punkt an.
// Compilation fix. Execution never reaches this point
return 0;
}
// -----------------------------------------------------------------------------
static int R_IsValid(lua_State * L)
{
static int R_IsValid(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -366,8 +334,7 @@ static int R_IsValid(lua_State * L)
// -----------------------------------------------------------------------------
static int R_GetX(lua_State * L)
{
static int R_GetX(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -377,8 +344,7 @@ static int R_GetX(lua_State * L)
// -----------------------------------------------------------------------------
static int R_GetY(lua_State * L)
{
static int R_GetY(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -388,8 +354,7 @@ static int R_GetY(lua_State * L)
// -----------------------------------------------------------------------------
static int R_GetPos(lua_State * L)
{
static int R_GetPos(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -399,8 +364,7 @@ static int R_GetPos(lua_State * L)
// -----------------------------------------------------------------------------
static int R_IsPointInRegion(lua_State * L)
{
static int R_IsPointInRegion(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -412,8 +376,7 @@ static int R_IsPointInRegion(lua_State * L)
// -----------------------------------------------------------------------------
static int R_SetPos(lua_State * L)
{
static int R_SetPos(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -426,8 +389,7 @@ static int R_SetPos(lua_State * L)
// -----------------------------------------------------------------------------
static int R_SetX(lua_State * L)
{
static int R_SetX(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -438,8 +400,7 @@ static int R_SetX(lua_State * L)
// -----------------------------------------------------------------------------
static int R_SetY(lua_State * L)
{
static int R_SetY(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
@ -450,9 +411,8 @@ static int R_SetY(lua_State * L)
// -----------------------------------------------------------------------------
static void DrawPolygon(const BS_Polygon & Polygon, unsigned int Color, const BS_Vertex & Offset)
{
BS_GraphicEngine * pGE = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
static void DrawPolygon(const BS_Polygon &Polygon, unsigned int Color, const BS_Vertex &Offset) {
BS_GraphicEngine *pGE = static_cast<BS_GraphicEngine *>(BS_Kernel::GetInstance()->GetService("gfx"));
BS_ASSERT(pGE);
for (int i = 0; i < Polygon.VertexCount - 1; i++)
@ -463,8 +423,7 @@ static void DrawPolygon(const BS_Polygon & Polygon, unsigned int Color, const BS
// -----------------------------------------------------------------------------
static void DrawRegion(const BS_Region & Region, unsigned int Color, const BS_Vertex & Offset)
{
static void DrawRegion(const BS_Region &Region, unsigned int Color, const BS_Vertex &Offset) {
DrawPolygon(Region.GetContour(), Color, Offset);
for (int i = 0; i < Region.GetHoleCount(); i++)
DrawPolygon(Region.GetHole(i), Color, Offset);
@ -472,15 +431,12 @@ static void DrawRegion(const BS_Region & Region, unsigned int Color, const BS_Ve
// -----------------------------------------------------------------------------
static int R_Draw(lua_State * L)
{
static int R_Draw(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
switch (lua_gettop(L))
{
case 3:
{
switch (lua_gettop(L)) {
case 3: {
BS_Vertex Offset;
BS_Vertex::LuaVertexToVertex(L, 3, Offset);
DrawRegion(*pR, BS_GraphicEngine::LuaColorToARGBColor(L, 2), Offset);
@ -500,8 +456,7 @@ static int R_Draw(lua_State * L)
// -----------------------------------------------------------------------------
static int R_GetCentroid(lua_State * L)
{
static int R_GetCentroid(::lua_State *L) {
BS_Region * RPtr = CheckRegion(L);
BS_ASSERT(RPtr);
@ -512,8 +467,7 @@ static int R_GetCentroid(lua_State * L)
// -----------------------------------------------------------------------------
static int R_Delete(lua_State * L)
{
static int R_Delete(::lua_State *L) {
BS_Region * pR = CheckRegion(L);
BS_ASSERT(pR);
delete pR;
@ -522,8 +476,7 @@ static int R_Delete(lua_State * L)
// -----------------------------------------------------------------------------
static const luaL_reg REGION_METHODS[] =
{
static const luaL_reg REGION_METHODS[] = {
"SetPos", R_SetPos,
"SetX", R_SetX,
"SetY", R_SetY,
@ -539,28 +492,23 @@ static const luaL_reg REGION_METHODS[] =
// -----------------------------------------------------------------------------
static BS_WalkRegion * CheckWalkRegion(lua_State * L)
{
// Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Geo.WalkRegion
static BS_WalkRegion *CheckWalkRegion(::lua_State *L) {
// The first parameter must be of type 'userdate', and the Metatable class Geo.WalkRegion
unsigned int RegionHandle;
if ((RegionHandle = *reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0)
{
if ((RegionHandle = *reinterpret_cast<unsigned int *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) {
return reinterpret_cast<BS_WalkRegion *>(BS_RegionRegistry::GetInstance().ResolveHandle(RegionHandle));
}
else
{
} else {
luaL_argcheck(L, 0, 1, "'" WALKREGION_CLASS_NAME "' expected");
}
// Compiler ruhigstellen. Ausführung kommt nie an diesem Punkt an.
// Compilation fix. Execution never reaches this point
return 0;
}
// -----------------------------------------------------------------------------
static int WR_GetPath(lua_State * L)
{
BS_WalkRegion * pWR = CheckWalkRegion(L);
static int WR_GetPath(::lua_State *L) {
BS_WalkRegion *pWR = CheckWalkRegion(L);
BS_ASSERT(pWR);
BS_Vertex Start;
@ -568,18 +516,15 @@ static int WR_GetPath(lua_State * L)
BS_Vertex End;
BS_Vertex::LuaVertexToVertex(L, 3, End);
BS_Path Path;
if (pWR->QueryPath(Start, End, Path))
{
if (pWR->QueryPath(Start, End, Path)) {
lua_newtable(L);
BS_Path::const_iterator it = Path.begin();
for (; it != Path.end(); it++)
{
for (; it != Path.end(); it++) {
lua_pushnumber(L, (it - Path.begin()) + 1);
BS_Vertex::VertexToLuaVertex(L, *it);
lua_settable(L, -3);
}
}
else
} else
lua_pushnil(L);
return 1;
@ -587,21 +532,19 @@ static int WR_GetPath(lua_State * L)
// -----------------------------------------------------------------------------
static const luaL_reg WALKREGION_METHODS[] =
{
static const luaL_reg WALKREGION_METHODS[] = {
"GetPath", WR_GetPath,
0, 0,
};
// -----------------------------------------------------------------------------
bool BS_Geometry::_RegisterScriptBindings()
{
bool BS_Geometry::_RegisterScriptBindings() {
BS_Kernel * pKernel = BS_Kernel::GetInstance();
BS_ASSERT(pKernel);
BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script"));
BS_ASSERT(pScript);
lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject());
::lua_State *L = static_cast< ::lua_State *>(pScript->GetScriptObject());
BS_ASSERT(L);
if (!BS_LuaBindhelper::AddMethodsToClass(L, REGION_CLASS_NAME, REGION_METHODS)) return false;
@ -615,3 +558,5 @@ bool BS_Geometry::_RegisterScriptBindings()
return true;
}
} // End of namespace Sword25

View File

@ -35,11 +35,11 @@
/*
BS_Line
-------
Diese Klasse enthält nur statische Methoden, die mit Geradensegmenten zu tun haben.
Es gibt keine wirkliche Geradensegment-Klasse, da diese Klasse vor allem zu
Berechnungen mit Polygonen herangezogen wird und es dabei wichtig ist, Start- und
Endpunkte der Linien dynamisch wählen zu können. Dieses würde sich verbieten, wenn
ein Polygon aus einer Menge von festen Geradensegmenten gebildet wäre.
This class contains only static methods, which have to do with straight line
segments. There is no real straight line segment class. Calculations will be
used with polygons, and it is important the process of starting and selecting
endpoints of lines is dynamic. This would prhobit a polygon from a set
being formed by fixed line segments
Autor: Malte Thiesen
*/
@ -55,77 +55,69 @@
// -----------------------------------------------------------------------------
class BS_Line
{
namespace Sword25 {
class BS_Line {
public:
/**
@brief Bestimmt ob sich ein Punkt links von einer Linie befindet.
@param a der Startpunkt der Linie
@param b der Endpunkt der Linie
@param c der Testpunkt
@return Gibt true zurück, wenn sich der Punkt links von der Linie befindet.<br>
Falls sich der Punkt rechts von der Linie oder auf der Linie befindet wird false zurückgegeben.<br>
@remark Ein Punkt liegt links von einer Linie, wenn er vom Startpunkt aus betrachtet links neben der Linie liegt.
*/
static bool IsVertexLeft(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
* Determines whether a piont is left of a line
* @param a The start point of a line
* @param b The end point of a line
* @param c The test point
* @return Returns true if the point is to the left of the line.
* If the point is to the right of the line or on the line, false is returned.
*/
static bool IsVertexLeft(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
return _TriangleArea2(a, b, c) > 0;
}
static bool IsVertexLeftOn(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
static bool IsVertexLeftOn(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
return _TriangleArea2(a, b, c) >= 0;
}
/**
@brief Bestimmt ob sich ein Punkt rechts von einer Linie befindet.
@param a der Startpunkt der Linie
@param b der Endpunkt der Linie
@param c der Testpunkt
@return Gibt true zurück, wenn sich der Punkt recht von der Linie befindet.<br>
Falls sich der Punkt links von der Linie oder auf der Linie befindet wird false zurückgegeben.<br>
@remark Ein Punkt liegt rechts von einer Linie, wenn er vom Startpunkt aus betrachtet rechts neben der Linie liegt.
*/
static bool IsVertexRight(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
* Determines whether a piont is right of a line
* @param a The start point of a line
* @param b The end point of a line
* @param c The test point
* @return Returns true if the point is to the right of the line.
* If the point is to the right of the line or on the line, false is returned.
*/
static bool IsVertexRight(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
return _TriangleArea2(a, b, c) < 0;
}
static bool IsVertexRightOn(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
static bool IsVertexRightOn(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
return _TriangleArea2(a, b, c) <= 0;
}
/**
@brief Bestimmt ob sich ein Punkt auf einer Linie befindet.
@param a der Startpunkt der Linie
@param b der Endpunkt der Linie
@param c der Testpunkt
@return Gibt true zurück, wenn sich der Punkt auf der Linie befindet.
*/
static bool IsVertexOn(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
* Determines whether a piont is on a line
* @param a The start point of a line
* @param b The end point of a line
* @param c The test point
* @return Returns true if the point is on the line, false otherwise.
*/
static bool IsVertexOn(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
return _TriangleArea2(a, b, c) == 0;
}
enum VERTEX_CLASSIFICATION
{
enum VERTEX_CLASSIFICATION {
LEFT,
RIGHT,
ON
};
/**
@brief Bestimmt wo sich ein Punkt relativ zu einer Linie befindet.
@param a der Startpunkt der Linie
@param b der Endpunkt der Linie
@param c der Testpunkt
@return Gibt LEFT zurück, wenn sich der Punkt links von der Line befindet.<br>
Gibt RIGHT zurück, wenn sich der Punkt links von der Line befindet.<br>
Gibt ON zurück, wenn sich der Punkt auf der Linie befindet.
*/
static VERTEX_CLASSIFICATION ClassifyVertexToLine(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
* Determines where a point is relative to a line.
* @param a The start point of a line
* @param b The end point of a line
* @param c The test point
* @return LEFT is returned if the point is to the left of the line.
* RIGHT is returned if the point is to the right of the line.
* ON is returned if the point is on the line.
*/
static VERTEX_CLASSIFICATION ClassifyVertexToLine(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
int Area = _TriangleArea2(a, b, c);
if (Area > 0) return LEFT;
if (Area < 0) return RIGHT;
@ -133,15 +125,14 @@ public:
}
/**
@brief Bestimmt ob sich zwei Linien schneiden.
@param a der Startpunkt der ersten Linie
@param b der Endpunkt der ersten Linie
@param c der Startpunkt der zweiten Linie
@param d der Endpunkt der zweiten Linie
@remark In den Fällen in denen eine Linie die andere nur berührt, wird false zurückgegeben (improper intersection).
*/
static bool DoesIntersectProperly(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c, const BS_Vertex & d)
{
* Determines whether two lines intersect
* @param a The start point of the first line
* @param b The end point of the first line
* @param c The start point of the second line
* @param d The end point of the second line
* @remark In cases where a line only touches the other, false is returned (improper intersection)
*/
static bool DoesIntersectProperly(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c, const BS_Vertex &d) {
VERTEX_CLASSIFICATION Class1 = ClassifyVertexToLine(a, b, c);
VERTEX_CLASSIFICATION Class2 = ClassifyVertexToLine(a, b, d);
VERTEX_CLASSIFICATION Class3 = ClassifyVertexToLine(c, d, a);
@ -153,26 +144,22 @@ public:
}
/**
@brief Bestimmt ob sich ein Punkt auf einem Liniensegment befindet
@param a der Startpunkt der Liniensegmentes
@param b der Endpunkt der Liniensegmentes
@param c der Testpunkt
*/
static bool IsOnLine(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
// Die Punkte müssen alle Kollinear sein, sonst liegt der Testpunkt nicht auf dem Liniensegment
* Determines whether a point is on a line segment
* @param a The start point of a line
* @param b The end point of a line
* @param c The test point
*/
static bool IsOnLine(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
// The items must all be Collinear, otherwise don't bothering testing the point
if (_TriangleArea2(a, b, c) != 0) return false;
// Falls das Liniensegment nicht vertikal ist prüfe auf der X-Achse, ansonsten auf der Y-Achse
if (a.X != b.X)
{
// If the line segment is not vertical, check on the x-axis, otherwise the y-axis
if (a.X != b.X) {
return ((a.X <= c.X) &&
(c.X <= b.X)) ||
((a.X >= c.X) &&
(c.X >= b.X));
}
else
{
} else {
return ((a.Y <= c.Y) &&
(c.Y <= b.Y)) ||
((a.Y >= c.Y) &&
@ -180,21 +167,17 @@ public:
}
}
static bool IsOnLineStrict(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
// Die Punkte müssen alle Kollinear sein, sonst liegt der Testpunkt nicht auf dem Liniensegment
static bool IsOnLineStrict(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
// The items must all be Collinear, otherwise don't bothering testing the point
if (_TriangleArea2(a, b, c) != 0) return false;
// Falls das Liniensegment nicht vertikal ist prüfe auf der X-Achse, ansonsten auf der Y-Achse
if (a.X != b.X)
{
// If the line segment is not vertical, check on the x-axis, otherwise the y-axis
if (a.X != b.X) {
return ((a.X < c.X) &&
(c.X < b.X)) ||
((a.X > c.X) &&
(c.X > b.X));
}
else
{
} else {
return ((a.Y < c.Y) &&
(c.Y < b.Y)) ||
((a.Y > c.Y) &&
@ -203,19 +186,19 @@ public:
}
private:
/**
@brief Gibt die doppelte Größe des durch a, b und c definierten Dreiecks zurück.
Das Ergebnis ist positiv wenn die Punkte entgegen dem Uhrzeigersinn angeordnet sind und negativ wenn sie mit dem
Uhrzeigersinn angeordnet sind.
*/
static int _TriangleArea2(const BS_Vertex & a, const BS_Vertex & b, const BS_Vertex & c)
{
* Return double the size of the triangle defined by the three passed points.
*
* The result is positive if the points are arrange counterclockwise,
* and negative if they are arranged counter-clockwise.
*/
static int _TriangleArea2(const BS_Vertex &a, const BS_Vertex &b, const BS_Vertex &c) {
return a.X * b.Y - a.Y * b.X +
a.Y * c.X - a.X * c.Y +
b.X * c.Y - c.X * b.Y;
}
};
} // End of namespace Sword25
#endif

View File

@ -32,11 +32,6 @@
*
*/
#include "sword25/kernel/memlog_off.h"
#include <utility>
#include <vector>
#include "sword25/kernel/memlog_on.h"
#include <math.h>
#include "sword25/kernel/outputpersistenceblock.h"
@ -45,58 +40,52 @@
#include "sword25/math/polygon.h"
#include "sword25/math/line.h"
namespace Sword25 {
#define max(a,b) (((a) > (b)) ? (a) : (b))
// Konstruktion / Destruktion
// Constructor / Destructor
// --------------------------
BS_Polygon::BS_Polygon() : VertexCount(0), Vertecies(NULL)
{
BS_Polygon::BS_Polygon() : VertexCount(0), Vertecies(NULL) {
}
BS_Polygon::BS_Polygon(int VertexCount, const BS_Vertex* Vertecies) : VertexCount(0), Vertecies(NULL)
{
BS_Polygon::BS_Polygon(int VertexCount, const BS_Vertex *Vertecies) : VertexCount(0), Vertecies(NULL) {
Init(VertexCount, Vertecies);
}
BS_Polygon::BS_Polygon(const BS_Polygon& Other) : VertexCount(0), Vertecies(NULL)
{
BS_Polygon::BS_Polygon(const BS_Polygon &Other) : VertexCount(0), Vertecies(NULL) {
Init(Other.VertexCount, Other.Vertecies);
}
BS_Polygon::BS_Polygon(BS_InputPersistenceBlock & Reader) : VertexCount(0), Vertecies(NULL)
{
BS_Polygon::BS_Polygon(BS_InputPersistenceBlock &Reader) : VertexCount(0), Vertecies(NULL) {
Unpersist(Reader);
}
BS_Polygon::~BS_Polygon()
{
BS_Polygon::~BS_Polygon() {
delete[] Vertecies;
}
// Initialisierung
// Initialisation
// ---------------
bool BS_Polygon::Init(int VertexCount, const BS_Vertex* Vertecies)
{
// Alten Objektzustand merken um ihn wieder herstellen zu können, falls beim Initialisieren mit den neuen Daten ein Fehler auftreten
// sollte.
bool BS_Polygon::Init(int VertexCount, const BS_Vertex *Vertecies) {
// Rember the old obstate to restore it if an error occurs whilst initialising it with the new data
int OldVertexCount = this->VertexCount;
BS_Vertex* OldVertecies = this->Vertecies;
BS_Vertex *OldVertecies = this->Vertecies;
this->VertexCount = VertexCount;
this->Vertecies = new BS_Vertex[VertexCount + 1];
memcpy(this->Vertecies, Vertecies, sizeof(BS_Vertex) * VertexCount);
// TODO:
// Doppelte und überflüssige Vertecies entfernen (überflüssig = 3 Verts kollinear)
// Duplicate and remove redundant vertecies (Superflous = 3 co-linear verts)
// _WeedRepeatedVertecies();
// Das erste Vertex wird am Ende des Vertex-Arrays wiederholt, dieses vereinfacht einige Algorithmen, die alle Edges durchgehen und
// sich so die Überlaufkontrolle sparen können.
// The first vertex is repeated at the end of the vertex array; this simplifies
// some algorithms, running through the edges and thus can save the overflow control.
this->Vertecies[VertexCount] = this->Vertecies[0];
// Falls das Polygon selbstüberschneidend ist, wird der alte Objektzustand wieder hergestellt und ein Fehler signalisiert.
if (CheckForSelfIntersection())
{
// If the polygon is self-intersecting, the object state is restore, and an error signalled
if (CheckForSelfIntersection()) {
delete[] this->Vertecies;
this->Vertecies = OldVertecies;
this->VertexCount = OldVertexCount;
@ -105,10 +94,10 @@ bool BS_Polygon::Init(int VertexCount, const BS_Vertex* Vertecies)
return false;
}
// Alte Vertexliste freigeben
// Release old vertex list
delete[] OldVertecies;
// Eigenschaften des Polygons berechnen.
// Calculate properties of the polygon
m_IsCW = ComputeIsCW();
m_IsConvex = ComputeIsConvex();
m_Centroid = ComputeCentroid();
@ -116,52 +105,44 @@ bool BS_Polygon::Init(int VertexCount, const BS_Vertex* Vertecies)
return true;
}
// Überprüfung der Reihenfolge der Vertecies
// -----------------------------------------
// Review the order of the Vertecies
// ---------------------------------
bool BS_Polygon::IsCW() const
{
bool BS_Polygon::IsCW() const {
return m_IsCW;
}
bool BS_Polygon::IsCCW() const
{
bool BS_Polygon::IsCCW() const {
return !IsCW();
}
bool BS_Polygon::ComputeIsCW() const
{
if (VertexCount)
{
// Vertex finden, dass am weitesten rechts unten liegt.
bool BS_Polygon::ComputeIsCW() const {
if (VertexCount) {
// Find the vertex on extreme bottom right
int V2Index = FindLRVertexIndex();
// Vertex vorher und nachher finden.
// Find the vertex before and after it
int V1Index = (V2Index + (VertexCount - 1)) % VertexCount;
int V3Index = (V2Index + 1) % VertexCount;
// Kreuzprodukt bilden.
// Wenn das Kreuzprodukt des am weitesten unten links liegenden Vertex positiv ist, sind die Vertecies im Uhrzeigersinn angeordnet
// ansonsten entgegen des Uhrzeigersinns.
// Cross product form
// If the cross product of the vertex lying fartherest bottom left is positive,
// the vertecies arrranged in a clockwise order. Otherwise counter-clockwise
if (CrossProduct(Vertecies[V1Index], Vertecies[V2Index], Vertecies[V3Index]) >= 0) return true;
}
return false;
}
int BS_Polygon::FindLRVertexIndex() const
{
if (VertexCount)
{
int BS_Polygon::FindLRVertexIndex() const {
if (VertexCount) {
int CurIndex = 0;
int MaxX = Vertecies[0].X;
int MaxY = Vertecies[0].Y;
for (int i = 1; i < VertexCount; i++)
{
for (int i = 1; i < VertexCount; i++) {
if (Vertecies[i].Y > MaxY ||
(Vertecies[i].Y == MaxY && Vertecies[i].X > MaxX))
{
(Vertecies[i].Y == MaxY && Vertecies[i].X > MaxX)) {
MaxX = Vertecies[i].X;
MaxY = Vertecies[i].Y;
CurIndex = i;
@ -174,109 +155,101 @@ int BS_Polygon::FindLRVertexIndex() const
return -1;
}
// Testen auf Konvex/Konkav
// Testing for Convex / Concave
// ------------------------
bool BS_Polygon::IsConvex() const
{
bool BS_Polygon::IsConvex() const {
return m_IsConvex;
}
bool BS_Polygon::IsConcave() const
{
bool BS_Polygon::IsConcave() const {
return !IsConvex();
}
bool BS_Polygon::ComputeIsConvex() const
{
// Polygone mit 3 oder weniger Vertecies können nur Konvex sein.
bool BS_Polygon::ComputeIsConvex() const {
// Polygons with three or less Vertecies can only be convex
if (VertexCount <= 3) return true;
// Alle Winkel im Polygon berechnen, wenn das Polygon Konvex ist, müssen alle Winkel das selbe Vorzeichen haben.
// All angles in the polygon computed will have the same direction sign if the polygon is convex
int Flag = 0;
for (int i = 0; i < VertexCount; i++)
{
// Die Indizies der beiden nächsten Vertecies nach i bestimmen.
for (int i = 0; i < VertexCount; i++) {
// Determine the next two vertecies to check
int j = (i + 1) % VertexCount;
int k = (i + 2) % VertexCount;
// Kreuzprodukt der drei Vertecies berechnen.
// Calculate the cross product of the three vertecies
int Cross = CrossProduct(Vertecies[i], Vertecies[j], Vertecies[k]);
// Die unteren beiden Bits von Flag haben folgende Bedeutung:
// 0 : negativer Winkel ist aufgetreten
// 1 : positiver Winkel ist aufgetreten
// The lower two bits of the flag represent the following:
// 0: negative angle occurred
// 1: positive angle occurred
// Vorzeichen des aktuellen Winkels in Flag vermerken.
// The sign of the current angle is recorded in Flag
if (Cross < 0)
Flag |= 1;
else if (Cross > 0)
Flag |= 2;
// Falls Flag 3 ist, sind sowohl positive als auch negative Winkel vorhanden -> Polygon ist Konkav.
// If flag is 3, there are both positive and negative angles; so the polygon is concave
if (Flag == 3) return false;
}
// Polygon ist Konvex.
// Polygon is convex
return true;
}
// Sicherstellen einer bestimmen Vertexordnung
// -------------------------------------------
// Make a determine vertex order
// -----------------------------
void BS_Polygon::EnsureCWOrder()
{
void BS_Polygon::EnsureCWOrder() {
if (!IsCW())
ReverseVertexOrder();
}
void BS_Polygon::EnsureCCWOrder()
{
void BS_Polygon::EnsureCCWOrder() {
if (!IsCCW())
ReverseVertexOrder();
}
// Umkehren der Reihenfolge der Vertecies
// --------------------------------------
// Reverse the order of vertecies
// ------------------------------
void BS_Polygon::ReverseVertexOrder()
{
// Vertecies paarweise vertauschen, bis die Liste komplett umgekehrt wurde.
for (int i = 0; i < VertexCount / 2; i++)
std::swap(Vertecies[i], Vertecies[VertexCount - i - 1]);
void BS_Polygon::ReverseVertexOrder() {
// Vertecies are exchanged in pairs, until the list has been completely reversed
for (int i = 0; i < VertexCount / 2; i++) {
BS_Vertex tempVertex = Vertecies[i];
Vertecies[i] = Vertecies[VertexCount - i - 1];
Vertecies[VertexCount - i - 1] = tempVertex;
}
// Vertexordnung neu berechnen.
m_IsCW = ComputeIsCW();
}
// Kreuzprodukt
// ------------
// Cross Product
// -------------
int BS_Polygon::CrossProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const
{
int BS_Polygon::CrossProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const {
return (V2.X - V1.X) * (V3.Y - V2.Y) -
(V2.Y - V1.Y) * (V3.X - V2.X);
}
// Skalarproduct
// -------------
// Scalar Product
// --------------
int BS_Polygon::DotProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const
{
int BS_Polygon::DotProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const {
return (V1.X - V2.X) * (V3.X - V2.X) +
(V1.Y - V2.Y) * (V3.X - V2.Y);
}
// Überprüfen auf Selbstüberschneidung
// -----------------------------------
// Check for self-intersections
// ----------------------------
bool BS_Polygon::CheckForSelfIntersection() const
{
// TODO: Fertigstellen
bool BS_Polygon::CheckForSelfIntersection() const {
// TODO: Finish this
/*
float AngleSum = 0.0f;
for (int i = 0; i < VertexCount; i++)
{
for (int i = 0; i < VertexCount; i++) {
int j = (i + 1) % VertexCount;
int k = (i + 2) % VertexCount;
@ -289,8 +262,7 @@ bool BS_Polygon::CheckForSelfIntersection() const
(Vertecies[k].Y - Vertecies[j].Y) * (Vertecies[k].Y - Vertecies[j].Y));
float Norm = Length1 * Length2;
if (Norm > 0.0f)
{
if (Norm > 0.0f) {
Dot /= Norm;
AngleSum += acos(Dot);
}
@ -300,46 +272,43 @@ bool BS_Polygon::CheckForSelfIntersection() const
return false;
}
// Verschieben
// -----------
// Move
// ----
void BS_Polygon::operator+=(const BS_Vertex& Delta)
{
// Alle Vetecies verschieben
void BS_Polygon::operator+=(const BS_Vertex &Delta) {
// Move all vertecies
for (int i = 0; i < VertexCount; i++)
Vertecies[i] += Delta;
// Den Schwerpunkt verschieben.
// Shift the focus
m_Centroid += Delta;
}
// Sichtlinie
// ----------
// Line of Sight
// -------------
bool BS_Polygon::IsLineInterior(const BS_Vertex & a, const BS_Vertex & b) const
{
// Beide Punkte müssen im Polygon sein
bool BS_Polygon::IsLineInterior(const BS_Vertex &a, const BS_Vertex &b) const {
// Both points have to be in the polygon
if (!IsPointInPolygon(a, true) || !IsPointInPolygon(b, true)) return false;
// Falls die Punkte identisch sind, ist die Linie trivialerweise innerhalb des Polygons
// If the points are identical, the line is trivially within the polygon
if (a == b) return true;
// Testen, ob die Linie ein Liniensegment strikt schneidet (proper intersection)
for (int i = 0; i < VertexCount; i++)
{
// Test whether the line intersects a line segment strictly (proper intersection)
for (int i = 0; i < VertexCount; i++) {
int j = (i + 1) % VertexCount;
const BS_Vertex & VS = Vertecies[i];
const BS_Vertex & VE = Vertecies[j];
const BS_Vertex &VS = Vertecies[i];
const BS_Vertex &VE = Vertecies[j];
// Falls die Linie ein Liniensegment strikt schneidet (proper intersection) ist die Linie nicht innerhalb des Polygons
// If the line intersects a line segment strictly (proper cross section) the line is not in the polygon
if (BS_Line::DoesIntersectProperly(a, b, VS, VE)) return false;
// Falls einer der beiden Linienpunkte auf der Kante liegt und der andere rechts der Kante liegt, befindet sich die Linie nicht
// vollständig innerhalb des Polygons.
// If one of the two line items is on the edge and the other is to the right of the edge,
// then the line is not completely within the polygon
if (BS_Line::IsOnLineStrict(VS, VE, a) && BS_Line::IsVertexRight(VS, VE, b)) return false;
if (BS_Line::IsOnLineStrict(VS, VE, b) && BS_Line::IsVertexRight(VS, VE, a)) return false;
// Falls einer der beiden Linienpunkte auf einem Vertex liegt muss die Linie in das Polygon hinein verlaufen
// If one of the two line items is on a vertex, the line traces into the polygon
if ((a == VS) && !IsLineInCone(i, b, true)) return false;
if ((b == VS) && !IsLineInCone(i, a, true)) return false;
}
@ -347,37 +316,34 @@ bool BS_Polygon::IsLineInterior(const BS_Vertex & a, const BS_Vertex & b) const
return true;
}
bool BS_Polygon::IsLineExterior(const BS_Vertex & a, const BS_Vertex & b) const
{
// Keiner der beiden Punkte darf strikt im Polygon sein (auf der Kante ist erlaubt)
bool BS_Polygon::IsLineExterior(const BS_Vertex &a, const BS_Vertex &b) const {
// Neither of the two points must be strictly in the polygon (on the edge is allowed)
if (IsPointInPolygon(a, false) || IsPointInPolygon(b, false)) return false;
// Falls die Punkte identisch sind, ist die Linie trivialerweise ausserhalb des Polygons
// If the points are identical, the line is trivially outside of the polygon
if (a == b) return true;
// Testen, ob die Linie ein Liniensegment strikt schneidet (proper intersection)
for (int i = 0; i < VertexCount; i++)
{
// Test whether the line intersects a line segment strictly (proper intersection)
for (int i = 0; i < VertexCount; i++) {
int j = (i + 1) % VertexCount;
const BS_Vertex & VS = Vertecies[i];
const BS_Vertex & VE = Vertecies[j];
const BS_Vertex &VS = Vertecies[i];
const BS_Vertex &VE = Vertecies[j];
// Falls die Linie ein Liniensegment strikt schneidet (proper intersection) ist die Linie teilweise innerhalb des Polygons
// If the line intersects a line segment strictly (proper intersection), then
// the line is partially inside the polygon
if (BS_Line::DoesIntersectProperly(a, b, VS, VE)) return false;
// Falls einer der beiden Linienpunkte auf der Kante liegt und der andere rechts der Kante liegt, befindet sich die Linie nicht vollständig
// ausserhalb des Polygons.
// If one of the two line items is on the edge and the other is to the right of the edge,
// the line is not completely outside the polygon
if (BS_Line::IsOnLineStrict(VS, VE, a) && BS_Line::IsVertexLeft(VS, VE, b)) return false;
if (BS_Line::IsOnLineStrict(VS, VE, b) && BS_Line::IsVertexLeft(VS, VE, a)) return false;
// Falls einer der beiden Linienpunkte auf einem Vertex liegt, darf die Linie nicht in das Polygon hinein verlaufen
// If one of the lwo line items is on a vertex, the line must not run into the polygon
if ((a == VS) && IsLineInCone(i, b, false)) return false;
if ((b == VS) && IsLineInCone(i, a, false)) return false;
// Falls das Vertex mit Start- und Zielpunkt kollinear ist, dürfen die beiden Liniensegmente (a, VS) und (b, VS) nicht in das Polygon hinein
// verlaufen
if (BS_Line::IsOnLine(a, b, VS))
{
// If the vertex with start and end point is collinear, (a VS) and (b, VS) is not in the polygon
if (BS_Line::IsOnLine(a, b, VS)) {
if (IsLineInCone(i, a, false)) return false;
if (IsLineInCone(i, b, false)) return false;
}
@ -386,23 +352,19 @@ bool BS_Polygon::IsLineExterior(const BS_Vertex & a, const BS_Vertex & b) const
return true;
}
bool BS_Polygon::IsLineInCone(int StartVertexIndex, const BS_Vertex & EndVertex, bool IncludeEdges) const
{
const BS_Vertex & StartVertex = Vertecies[StartVertexIndex];
const BS_Vertex & NextVertex = Vertecies[(StartVertexIndex + 1) % VertexCount];
const BS_Vertex & PrevVertex = Vertecies[(StartVertexIndex + VertexCount - 1) % VertexCount];
bool BS_Polygon::IsLineInCone(int StartVertexIndex, const BS_Vertex &EndVertex, bool IncludeEdges) const {
const BS_Vertex &StartVertex = Vertecies[StartVertexIndex];
const BS_Vertex &NextVertex = Vertecies[(StartVertexIndex + 1) % VertexCount];
const BS_Vertex &PrevVertex = Vertecies[(StartVertexIndex + VertexCount - 1) % VertexCount];
if (BS_Line::IsVertexLeftOn(PrevVertex, StartVertex, NextVertex))
{
if (BS_Line::IsVertexLeftOn(PrevVertex, StartVertex, NextVertex)) {
if (IncludeEdges)
return BS_Line::IsVertexLeftOn(EndVertex, StartVertex, NextVertex) &&
BS_Line::IsVertexLeftOn(StartVertex, EndVertex, PrevVertex);
else
return BS_Line::IsVertexLeft(EndVertex, StartVertex, NextVertex) &&
BS_Line::IsVertexLeft(StartVertex, EndVertex, PrevVertex);
}
else
{
} else {
if (IncludeEdges)
return !(BS_Line::IsVertexLeft(EndVertex, StartVertex, PrevVertex) &&
BS_Line::IsVertexLeft(StartVertex, EndVertex, NextVertex));
@ -412,56 +374,49 @@ bool BS_Polygon::IsLineInCone(int StartVertexIndex, const BS_Vertex & EndVertex,
}
}
// Punkt-Polygon Tests
// Point-Polygon Tests
// -------------------
bool BS_Polygon::IsPointInPolygon(int X, int Y, bool BorderBelongsToPolygon) const
{
bool BS_Polygon::IsPointInPolygon(int X, int Y, bool BorderBelongsToPolygon) const {
return IsPointInPolygon(BS_Vertex(X, Y), BorderBelongsToPolygon);
}
bool BS_Polygon::IsPointInPolygon(const BS_Vertex & Point, bool EdgesBelongToPolygon) const
{
int Rcross = 0; // Anzahl der rechtsseitigen Überschneidungen
int Lcross = 0; // Anzahl der linksseitigen Überschneidungen
bool BS_Polygon::IsPointInPolygon(const BS_Vertex &Point, bool EdgesBelongToPolygon) const {
int Rcross = 0; // Number of right-side overlaps
int Lcross = 0; // Number of left-side overlaps
// Jede Kante wird überprüft ob sie den vom Punkt ausgehenden Strahl schneidet
for (int i = 0; i < VertexCount; i++)
{
const BS_Vertex & EdgeStart = Vertecies[i];
const BS_Vertex & EdgeEnd = Vertecies[(i + 1) % VertexCount];
// Each edge is checked whether it cuts the outgoing stream from the point
for (int i = 0; i < VertexCount; i++) {
const BS_Vertex &EdgeStart = Vertecies[i];
const BS_Vertex &EdgeEnd = Vertecies[(i + 1) % VertexCount];
// Ist der Punkt ein Vertex? Dann liegt er auf einer Kante des Polygons
// A vertex is a point? Then it lies on one edge of the polygon
if (Point == EdgeStart) return EdgesBelongToPolygon;
if ((EdgeStart.Y > Point.Y) != (EdgeEnd.Y > Point.Y))
{
if ((EdgeStart.Y > Point.Y) != (EdgeEnd.Y > Point.Y)) {
int Term1 = (EdgeStart.X - Point.X) * (EdgeEnd.Y - Point.Y) - (EdgeEnd.X - Point.X) * (EdgeStart.Y - Point.Y);
int Term2 = (EdgeEnd.Y - Point.Y) - (EdgeStart.Y - EdgeEnd.Y);
if ((Term1 > 0) == (Term2 >= 0)) Rcross++;
}
if ((EdgeStart.Y < Point.Y) != (EdgeEnd.Y < Point.Y))
{
if ((EdgeStart.Y < Point.Y) != (EdgeEnd.Y < Point.Y)) {
int Term1 = (EdgeStart.X - Point.X) * (EdgeEnd.Y - Point.Y) - (EdgeEnd.X - Point.X) * (EdgeStart.Y - Point.Y);
int Term2 = (EdgeEnd.Y - Point.Y) - (EdgeStart.Y - EdgeEnd.Y);
if ((Term1 < 0) == (Term2 <= 0)) Lcross++;
}
}
// Der Punkt befindet sich auf einer Kante, wenn die Anzahl der linken und rechten Überschneidungen nicht die gleiche Geradzahligkeit haben
// The point is on an adge, if the number of left and right intersections have the same even numbers
if ((Rcross % 2 ) != (Lcross % 2 )) return EdgesBelongToPolygon;
// Der Punkt befindet sich genau dann strikt innerhalb des Polygons, wenn die Anzahl der Überschneidungen ungerade ist
// The point is strictly inside the polygon if and only if the number of overlaps is odd
if ((Rcross % 2) == 1) return true;
else return false;
}
bool BS_Polygon::Persist(BS_OutputPersistenceBlock & Writer)
{
bool BS_Polygon::Persist(BS_OutputPersistenceBlock &Writer) {
Writer.Write(VertexCount);
for (int i = 0; i < VertexCount; ++i)
{
for (int i = 0; i < VertexCount; ++i) {
Writer.Write(Vertecies[i].X);
Writer.Write(Vertecies[i].Y);
}
@ -469,16 +424,16 @@ bool BS_Polygon::Persist(BS_OutputPersistenceBlock & Writer)
return true;
}
bool BS_Polygon::Unpersist(BS_InputPersistenceBlock & Reader)
{
bool BS_Polygon::Unpersist(BS_InputPersistenceBlock &Reader) {
int StoredVertexCount;
Reader.Read(StoredVertexCount);
std::vector<BS_Vertex> StoredVertecies(StoredVertexCount);
for (int i = 0; i < StoredVertexCount; ++i)
{
Reader.Read(StoredVertecies[i].X);
Reader.Read(StoredVertecies[i].Y);
Common::Array<BS_Vertex> StoredVertecies;
for (int i = 0; i < StoredVertexCount; ++i) {
int x, y;
Reader.Read(x);
Reader.Read(y);
StoredVertecies.push_back(BS_Vertex(x, y));
}
Init(StoredVertexCount, &StoredVertecies[0]);
@ -486,30 +441,26 @@ bool BS_Polygon::Unpersist(BS_InputPersistenceBlock & Reader)
return Reader.IsGood();
}
// Schwerpunkt
// -----------
// Main Focus
// ----------
BS_Vertex BS_Polygon::GetCentroid() const
{
BS_Vertex BS_Polygon::GetCentroid() const {
return m_Centroid;
}
BS_Vertex BS_Polygon::ComputeCentroid() const
{
// Flächeninhalt des Polygons berechnen.
BS_Vertex BS_Polygon::ComputeCentroid() const {
// Area of the polygon is calculated
int DoubleArea = 0;
for (int i = 0; i < VertexCount; ++i)
{
for (int i = 0; i < VertexCount; ++i) {
DoubleArea += Vertecies[i].X * Vertecies[i + 1].Y - Vertecies[i + 1].X * Vertecies[i].Y;
}
// Division durch 0 beim nächsten Schritt vermeiden.
// Avoid division by zero in the next step
if (DoubleArea == 0) return BS_Vertex();
// Schwerpunkt berechnen.
// Calculate centroid
BS_Vertex Centroid;
for (int i = 0; i < VertexCount; ++i)
{
for (int i = 0; i < VertexCount; ++i) {
int Area = Vertecies[i].X * Vertecies[i + 1].Y - Vertecies[i + 1].X * Vertecies[i].Y;
Centroid.X += (Vertecies[i].X + Vertecies[i + 1].X) * Area;
Centroid.Y += (Vertecies[i].Y + Vertecies[i + 1].Y) * Area;
@ -519,3 +470,5 @@ BS_Vertex BS_Polygon::ComputeCentroid() const
return Centroid;
}
} // End of namespace Sword25

View File

@ -40,6 +40,8 @@
#include "sword25/kernel/persistable.h"
#include "sword25/math/vertex.h"
namespace Sword25 {
// -----------------------------------------------------------------------------
// Forward Declarations
// -----------------------------------------------------------------------------
@ -49,158 +51,151 @@ class BS_Vertex;
/**
@brief Eine Polygonklasse.
*/
class BS_Polygon : public BS_Persistable
{
class BS_Polygon : public BS_Persistable {
public:
/**
@brief Erzeugt ein Objekt vom Typ #BS_Polygon, das 0 Vertecies enthält.
Mit der Methode Init() können dem Polygon später Vertecies hinzugefügt werden.
*/
* Creates an object of type #BS_Polygon, containing 0 Vertecies.
*
* With the method Init(), Vertices can be added in later
*/
BS_Polygon();
/**
@brief Copy-Constructor
*/
BS_Polygon(const BS_Polygon& Other);
* Copy constructor
*/
BS_Polygon(const BS_Polygon &Other);
/**
@brief Erstellt ein Polygon anhand persistierter Daten.
*/
BS_Polygon(BS_InputPersistenceBlock & Reader);
* Creates a polygon using persisted data
*/
BS_Polygon(BS_InputPersistenceBlock &Reader);
/**
@brief Erzeugt ein Objekt vom Typ #BS_Polygon und ordnet ihm Vertecies zu.
@param VertexCount die Anzahl der Vertecies im Vertex Array.
@param Vertecies ein Array, das Objekte vom Typ BS_Vertex enthält, die die Vertecies des Polygons darstellen.
@remark Die Vertecies müssen ein nicht selbstüberschneidendes Polygon definieren.
Falls das Polygon selbstüberschneidend sein sollte wird ein leeres BS_Polygon Objekt erzeugt.
*/
BS_Polygon(int VertexCount, const BS_Vertex* Vertecies);
* Creaes an object of type #BS_Polygon, and assigns Vertices to it
* @param VertexCount The number of vertices being passed
* @param Vertecies An array of BS_Vertex objects representing the vertices in the polygon.
* @remark The Vertecies that define a polygon must not have any self-intersections.
* If the polygon does have self-intersections, then an empty polygon object is created.
*/
BS_Polygon(int VertexCount, const BS_Vertex *Vertecies);
/**
@brief Löscht das BS_Polygon Objekt.
*/
* Deletes the BS_Polygon object
*/
virtual ~BS_Polygon();
/**
@brief Initialisiert das BS_Polygon mit einer Liste von Vertecies.
* Initialises the BS_Polygon with a list of Vertecies.
*
* The Vertices need to define a polygon must not have self-intersections.
* If a polygon already has verticies, this will re-initialise it with the new list.
*
* @param VertexCount The number of vertices being passed
* @param Vertecies An array of BS_Vertex objects representing the vertices in the polygon.
* @return Returns false if the Vertecies have self-intersections. In this case,
* the object is not initialised.
*/
bool Init(int VertexCount, const BS_Vertex *Vertecies);
Die Vertecies müssen ein nicht selbstüberschneidendes Polygon definieren.
Es kann auch einem Polygon, welches bereits Vertecies enthält, mit einer neue Vertexliste initialisiert werden, dabei gehen die
alten Vertecies verloren.
@param VertexCount die Anzahl der Vertecies im Vertecies Array.
@param Vertecies ein Array, das Objekte vom Typ BS_Vertex enthält, die die Vertecies des Polygons darstellen.
@return Gibt false zurück, falls die Vertecies ein selbstüberschneidendes Polygon definiert haben.
In diesem Fall wird das Objekt nicht initialisiert.
*/
bool Init(int VertexCount, const BS_Vertex* Vertecies);
//@{
/** @name Sondierende Methoden */
//
// ** Exploratory methods **
//
/**
@brief Überprüft, ob die Vertecies des Polygons im Uhrzeigersinn angeordnet sind.
@return Gibt true zurück, wenn die Vertecies des Polygons im Uhrzeigersinn angeordnet sind oder Koplanar sind.<br>
Gibt false zurück, wenn die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind.
@remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat.
*/
* Checks whether the Vertecies of the polygon are arranged in a clockwise direction.
* @return Returns true if the Vertecies of the polygon are arranged clockwise or co-planar.
* Returns false if the Vertecies of the polygon are arrange counter-clockwise.
* @remark This method only returns a meaningful result if the polygon has at least three Vertecies.
*/
bool IsCW() const;
/**
@brief Überprüft, ob die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind.
@return Gibt true zurück, wenn die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind.<br>
Gibt false zurück, wenn die Vertecies des Polygons im Uhrzeigersinn angeordnet sind oder Koplanar sind.
@remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat.
*/
* Checks whether the Vertices of the polygon are arranged in a counter-clockwise direction.
* @return Returns true if the Vertecies of the polygon are arranged counter-clockwise.
* Returns false if the Vertecies of the polygon are arranged clockwise or co-planar.
* @remark This method only returns a meaningful result if the polygon has at least three Vertecies.
*/
bool IsCCW() const;
/**
@brief Überprüft, ob das Polygon konvex ist.
@return Gibt true zurück, wenn das Polygon konvex ist.<br>
Gibt false zurück, wenn das Polygon konkav ist.
@remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat.
*/
* Checks whether the polygon is convex.
* @return Returns true if the polygon is convex. Returns false if the polygon is concave.
* @remark This method only returns a meaningful result if the polygon has at least three Vertecies.
*/
bool IsConvex() const;
/**
@brief Überprüft, ob das Polygon konkav ist.
@return Gibt true zurück, wenn das Polygon konkav ist.<br>
Gibt false zurück, wenn das Polygon konvex ist.
@remark Diese Methode gibt nur ein sinnvolles Ergebnis zurück, wenn das Polygon mindestens 3 Vertecies hat.
*/
* Checks whether the polygon is concave.
* @return Returns true if the polygon is concave. Returns false if the polygon is convex.
* @remark This method only returns a meaningful result if the polygon has at least three Vertecies.
*/
bool IsConcave() const;
/**
@brief Überprüft, ob sich ein Punkt innerhalb des Polygons befindet.
@param Vertex ein Vertex, mit den Koordinaten des zu testenden Punktes.
@param BorderBelongsToPolygon gibt an, ob der Rand des Polygons als Teil des Polygons betrachtet werden soll.<br>
Der Standardwert ist true.
@return Gibt true zurück, wenn sich der Punkt innerhalb des Polygons befindet.<br>
Gibt false zurück, wenn sich der Punkt außerhalb des Polygons befindet.
*/
bool IsPointInPolygon(const BS_Vertex& Vertex, bool BorderBelongsToPolygon = true) const;
* Checks whether a point is inside the polygon
* @param Vertex A Vertex with the co-ordinates of the point to be tested.
* @param BorderBelongsToPolygon Specifies whether the edge of the polygon should be considered
* @return Returns true if the point is inside the polygon, false if it is outside.
*/
bool IsPointInPolygon(const BS_Vertex &Vertex, bool BorderBelongsToPolygon = true) const;
/**
@brief Überprüft, ob sich ein Punkt innerhalb des Polygons befindet.
@param X die Position des Punktes auf der X-Achse.
@param Y die Position des Punktes auf der Y-Achse.
@param BorderBelongsToPolygon gibt an, ob der Rand des Polygons als Teil des Polygons betrachtet werden soll.<br>
Der Standardwert ist true.
@return Gibt true zurück, wenn sich der Punkt innerhalb des Polygons befindet.<br>
Gibt false zurück, wenn sich der Punkt außerhalb des Polygons befindet.
*/
* Checks whether a point is inside the polygon
* @param X The X position of the point
* @param Y The Y position of the point
* @param BorderBelongsToPolygon Specifies whether the edge of the polygon should be considered
* @return Returns true if the point is inside the polygon, false if it is outside.
*/
bool IsPointInPolygon(int X, int Y, bool BorderBelongsToPolygon = true) const;
/**
@brief Gibt den Schwerpunkt des Polygons zurück.
*/
* Returns the focus/centroid of the polygon
*/
BS_Vertex GetCentroid() const;
// Rand gehört zum Polygon
// Polygon muss CW sein
bool IsLineInterior(const BS_Vertex & a, const BS_Vertex & b) const;
// Rand gehört nicht zum Polygon
// Polygon muss CW sein
bool IsLineExterior(const BS_Vertex & a, const BS_Vertex & b) const;
// Edge belongs to the polygon
// Polygon must be CW
bool IsLineInterior(const BS_Vertex &a, const BS_Vertex &b) const;
// Edge does not belong to the polygon
// Polygon must be CW
bool IsLineExterior(const BS_Vertex &a, const BS_Vertex &b) const;
//@}
//@{
/** @name Manipulierende Methoden */
//
// Manipulation methods
//
/**
@brief Stellt sicher, dass die Vertecies des Polygons im Uhrzeigersinn angeordnet sind.
*/
* Ensures that the Vertecies of the polygon are arranged in a clockwise direction
*/
void EnsureCWOrder();
/**
@brief Stellt sicher, dass die Vertecies des Polygons entgegen dem Uhrzeigersinn angeordnet sind.
*/
* Ensures that the Vertecies of the polygon are arranged in a counter-clockwise direction
*/
void EnsureCCWOrder();
/**
@brief Kehrt die Reihenfolge der Vertecies um.
*/
* Reverses the Vertecies order.
*/
void ReverseVertexOrder();
/**
@brief Verschiebt das Polygon.
@param Delta das Vertex um das das Polygon verschoben werden soll.
*/
void operator+=(const BS_Vertex& Delta);
* Moves the polygon.
* @param Delta The vertex around the polygon to be moved.
*/
void operator+=(const BS_Vertex &Delta);
//@}
//
//------------------
//
/// Gibt die Anzahl an Vertecies im Vertecies-Array an.
/// Specifies the number of Vertecies in the Vertecies array.
int VertexCount;
/// Enthält die Vertecies des Polygons.
BS_Vertex* Vertecies;
/// COntains the Vertecies of the polygon
BS_Vertex *Vertecies;
virtual bool Persist(BS_OutputPersistenceBlock & Writer);
virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
virtual bool Persist(BS_OutputPersistenceBlock &Writer);
virtual bool Unpersist(BS_InputPersistenceBlock &Reader);
private:
bool m_IsCW;
@ -208,60 +203,64 @@ private:
BS_Vertex m_Centroid;
/**
@brief Berechnet den Schwerpunkt des Polygons.
*/
* Computes the centroid of the polygon.
*/
BS_Vertex ComputeCentroid() const;
/**
@brief Bestimmt wie die Vertecies des Polygon angeordnet sind.
@return Gibt true zurück, wenn die Vertecies im Uhrzeigersinn angeordnet sind, ansonsten false.
*/
* Determines how the Vertecies of the polygon are arranged.
* @return Returns true if the Vertecies are arranged in a clockwise
* direction, otherwise false.
*/
bool ComputeIsCW() const;
/**
@brief Bestimmt ob das Polygon Konvex oder Konkav ist.
@return Gibt true zurück, wenn das Polygon Konvex ist, ansonsten false.
*/
* Determines whether the polygon is convex or concave.
* @return Returns true if the polygon is convex, otherwise false.
*/
bool ComputeIsConvex() const;
/**
@brief Berechnet das Kreuzprodukt dreier Vertecies.
@param V1 das erste Vertex
@param V2 des zweite Vertex
@param V3 das dritte Vertex
@return Gibt das Kreuzprodukt der drei Vertecies zurück.
@todo Diese Methode sollte an geeigneter Stelle in die BS_Vertex Klasse integriert werden.
*/
int CrossProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const;
* Calculates the cross product of three Vertecies
* @param V1 The first Vertex
* @param V2 The second Vertex
* @param V3 The third Vertex
* @return Returns the cross-product of the three vertecies
* @todo This method would be better as a method of the BS_Vertex class
*/
int CrossProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const;
/**
@brief Berechnet des Skalarprodukt der beiden von drei Vertecies aufgespannten Vektoren.
Die Vektoren werden von V2 -> V1 und V2 -> V3 aufgespannt.
@param V1 das erste Vertex
@param V2 des zweite Vertex
@param V3 das dritte Vertex
@return Gibt das Skalarprodukt der drei Vertecies zurück.
@todo Diese Methode sollte an geeigneter Stelle in die BS_Vertex Klasse integriert werden.
*/
int DotProduct(const BS_Vertex& V1, const BS_Vertex& V2, const BS_Vertex& V3) const;
* Computes the scalar product of two vectors spanning three vertecies
*
* The vectors are spanned by V2->V1 and V2->V3
*
* @param V1 The first Vertex
* @param V2 The second Vertex
* @param V3 The third Vertex
* @return Returns the dot product of the three Vertecies.
* @todo This method would be better as a method of the BS_Vertex class
*/
int DotProduct(const BS_Vertex &V1, const BS_Vertex &V2, const BS_Vertex &V3) const;
/**
@brief Überprüft ob das Polygon selbstüberschneidend ist.
@return Gibt true zurück, wenn das Polygon selbstüberschneidend ist.<br>
Gibt false zurück, wenn das Polygon nicht selbstüberschneidend ist.
*/
* Checks whether the polygon is self-intersecting
* @return Returns true if the polygon is self-intersecting.
* Returns false if the polygon is not self-intersecting.
*/
bool CheckForSelfIntersection() const;
/**
@brief Findet das Vertex des Polygons das am weitesten rechts unten liegt und gibt dessen Index im Vertex-Array zurück.
@return Gibt den Index des Vertex zurück das am weiteesten rechts unten liegt.<br>
Gibt -1 zurück, wenn die Vertexliste leer ist.
*/
* Find the vertex of the polygon that is located below the right-most point,
* and returns it's index in the vertex array.
* @return Returns the index of the vertex at the bottom-right of the polygon.
* Returns -1 if the vertex list is empty.
*/
int FindLRVertexIndex() const;
bool IsLineInCone(int StartVertexIndex, const BS_Vertex & EndVertex, bool IncludeEdges) const;
bool IsLineInCone(int StartVertexIndex, const BS_Vertex &EndVertex, bool IncludeEdges) const;
};
} // End of namespace Sword25
#endif

View File

@ -36,278 +36,57 @@
#define SWORD25_RECT_H
// Includes
#include "common/rect.h"
#include "sword25/kernel/common.h"
#include "sword25/math/vertex.h"
// Klassendefinition
namespace Sword25 {
// Class definitions
/**
@brief Diese Klasse beschreibt ein Rechteck und einige nützliche Operationen auf Rechtecken.
* Rect class. Currently this encapsultes the ScummVM Rect class. Eventually all usage of this
* class should be replaced with Common::Rect directly.
*/
class BS_Rect
{
class BS_Rect: public Common::Rect {
public:
/// Das linke Extrem des Rechteckes.
int left;
/// Das obere Extrem des Rechteckes.
int top;
/// Das rechte Extrem des Rechteckes + 1.
int right;
/// Das untere Extrem des Rechteckes + 1.
int bottom;
BS_Rect() : Common::Rect() {}
BS_Rect(int16 w, int16 h) : Common::Rect(w, h) {}
BS_Rect(int16 x1, int16 y1, int16 x2, int16 y2) : Common::Rect(x1, y1, x2, y2) {}
/**
@brief Konstruktor, der alle Werte des Rechteckes mit 0 initialisiert.
*/
BS_Rect()
{
left = 0;
top = 0;
right = 0;
bottom = 0;
}
/**
@brief Konstruktor, der das Rechteck mit den übergebenen Werten initialisiert.
@param left das linke Extrem des Rechteckes
@param top das obere Extrem des Rechteckes
@param right das rechte Extrem des Rechteckes + 1
@param bottom des untere Extrem des Rechteckes + 1
*/
BS_Rect(int left_, int top_, int right_, int bottom_)
{
this->left = left_;
this->top = top_;
this->right = right_;
this->bottom = bottom_;
}
/**
@brief Verschiebt das Rechteck.
@param DeltaX der Wert um den das Rechteck auf der X-Achse verschoben werden soll.
@param DeltaY der Wert um den das Rechteck auf der Y-Achse verschoben werden soll.
*/
void Move(int DeltaX, int DeltaY)
{
left += DeltaX;
right += DeltaX;
top += DeltaY;
bottom += DeltaY;
}
/**
@brief Testet ob sich zwei Rechtecke schneiden.
@return Gibt true zurück, wenn sich die Rechtecke schneiden.
*/
bool DoesIntersect(const BS_Rect& Rect) const
{
int Dist;
// Intersektion auf der X-Achse
Dist = left - Rect.left;
if (Dist < 0)
{
Dist = abs(Dist);
// Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht
if (Dist >= GetWidth())
return false;
}
else
{
// Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht
if (Dist >= Rect.right - Rect.left)
return false;
}
// Intersektion auf der Y-Achse
Dist = top - Rect.top;
if (Dist < 0)
{
Dist = abs(Dist);
// Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht
if (Dist >= GetHeight())
return false;
}
else
{
// Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht
if (Dist >= Rect.bottom - Rect.top)
return false;
}
return true;
void Move(int DeltaX, int DeltaY) { translate(DeltaX, DeltaY); }
bool DoesIntersect(const BS_Rect &Rect) const { return intersects(Rect); }
bool Intersect(const BS_Rect &Rect, BS_Rect &Result) const {
Result = Rect;
Result.clip(*this);
}
/**
@brief Bildet den Durchschnitt zweier Rechtecke
@param Rect das Rechteck, dass mit dem Objekt geschnitter werden soll.
@param Result das Rechteck, dass das Ergebnisrechteck enthalten soll.
@return Gibt false zurück, falls Result undefiniert ist.<br>
Dies ist der Fall, wenn sich die Rechtecke nicht schneiden.
*/
bool Intersect(const BS_Rect& Rect, BS_Rect& Result) const
{
int Dist;
// Intersektion auf der X-Achse
Dist = left - Rect.left;
if (Dist < 0)
{
Dist = abs(Dist);
// Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht
if (Dist >= GetWidth())
{
Result = BS_Rect(0, 0, 0, 0);
return false;
}
// Die Abmessungen des Rect auf der X-Achse berechnen
Result.left = Rect.left;
}
else
{
// Schneiden sich die Rechtecke nicht auf der X-Achse, so schneiden sie sich gar nicht
if (Dist >= Rect.right - Rect.left)
{
Result = BS_Rect(0, 0, 0, 0);
return false;
}
// Die Abmessungen des Rect auf der X-Achse berechnen
Result.left = left;
}
Result.right = right < Rect.right ? right : Rect.right;
// Intersektion auf der Y-Achse
Dist = top - Rect.top;
if (Dist < 0)
{
Dist = abs(Dist);
// Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht
if (Dist >= GetHeight())
{
Result = BS_Rect(0, 0, 0, 0);
return false;
}
// Die Abmessungen des Rect auf der Y-Achse berechnen
Result.top = Rect.top;
}
else
{
// Schneiden sich die Rechtecke nicht auf der Y-Achse, so schneiden sie sich gar nicht
if (Dist >= Rect.bottom - Rect.top)
{
Result = BS_Rect(0, 0, 0, 0);
return false;
}
// Die Abmessungen des Rect auf der Y-Achse berechnen
Result.top = top;
}
Result.bottom = bottom < Rect.bottom ? bottom : Rect.bottom;
return true;
}
/**
@brief Bildet die Bounding-Box zweier Rechtecke.
@param Rect das Rechteck, dass mit dem Objekt verbunden werden soll.
@remark Das Ergebnis ist nicht ein Join in eigentlichen Sinne, sondern vielmehr die Bounding-Box um die Beiden
Rechtecke.
*/
void Join(const BS_Rect& Rect, BS_Rect& Result) const
{
Result.left = left < Rect.left ? left : Rect.left;
Result.top = top < Rect.top ? top : Rect.top;
Result.right = right > Rect.right ? right : Rect.right;
Result.bottom = bottom > Rect.bottom ? bottom : Rect.bottom;
return;
}
/**
@brief Gibt die Breite des Rechteckes zurück.
@return Die Breite des Rechteckes.
*/
int GetWidth() const
{
return right - left;
}
/**
@brief Gibt die Höhe des Rechteckes zurück.
@return Die Höhe des Rechteckes.
*/
int GetHeight() const
{
return bottom - top;
}
/** @brief Gibt den Flächeninhalt des Rechteckes zurück.
@return Der Flächeninhalt des Rechteckes.
*/
int GetArea() const
{
return GetWidth() * GetHeight();
}
/**
@brief Vergleichsoperator zum Überprüfen der Gleichheit zweier BS_Rect Objekte.
@return Gibt true zurück, wenn die Objekte die gleichen Werte haben, ansonsten false.
*/
bool operator== (const BS_Rect& rhs)
{
return (left == rhs.left) &&
(top == rhs.top) &&
(right == rhs.right) &&
(bottom == rhs.bottom);
}
/**
@brief Vergleichsoperator zum Überprüfen der Ungleichheit zweier BS_Rect Objekte.
@return Gibt true zurück, wenn die Objekte ungleiche Werte haben, ansonsten false.
*/
bool operator!= (const BS_Rect& rhs)
{
return !(*this == rhs);
}
/**
@brief Überprüft, ob das Objekt einen gültigen Zustand hat.
@return Gibt false zurück, wenn das Objekt einen ungültigen Zustand hat.
*/
bool IsValid() const
{
if (left < right && top < bottom) return true;
return false;
}
/**
@brief Testet, ob sich ein Vertex innerhalb des Rechteckes befindet.
@param Vertex das Vertex, dass mit dem Rechteckes getestet werden soll
@return Gibt true zurück, wenn sich das Vertex innerhalb des Rechteckes befindet.<br>
Gibt false zurück, wenn sich das Vertex außerhalb des Rechteckes befindet.
*/
bool IsPointInRect(const BS_Vertex& Vertex) const
{
if (Vertex.X >= left && Vertex.X < right &&
Vertex.Y >= top && Vertex.Y < bottom)
return true;
return false;
}
/**
@brief Testet, ob sich ein Punkt innerhalb des Rechteckes befindet.
@param X die Position des Punktes auf der X-Achse.
@param Y die Position des Punktes auf der Y-Achse.
@return Gibt true zurück, wenn sich der Punkt innerhalb des Rechteckes befindet.<br>
Gibt false zurück, wenn sich der Punkt außerhalb des Rechteckes befindet.
*/
bool IsPointInRect(int X, int Y) const
{
return IsPointInRect(BS_Vertex(X, Y));
}
/**
@brief Testet, ob ein andere Rechteck komplett in den Rechteck enthalten ist.
@param OtherRect das zu testende Rechteck
@brief Gibt true zurück, wenn sich das andere Rechteck komplett im Rechteck enthalten ist, ansonsten false.
*/
bool ContainsRect(const BS_Rect & OtherRect) const
{
return IsPointInRect(OtherRect.left, OtherRect.top) &&
IsPointInRect(OtherRect.right - 1, OtherRect.bottom - 1);
void Join(const BS_Rect &Rect, BS_Rect &Result) const {
Result = Rect;
Result.extend(*this);
}
int GetWidth() const { return width(); }
int GetHeight() const { return height(); }
int GetArea() const { return width() * height(); }
bool operator==(const BS_Rect &rhs) const { return equals(rhs); }
bool operator!= (const BS_Rect &rhs) const { return !equals(rhs); }
bool IsValid() const { return isValidRect(); }
bool IsPointInRect(const BS_Vertex &Vertex) const { return contains(Vertex.X, Vertex.Y); }
bool IsPointInRect(int X, int Y) const { return contains(X, Y); }
bool ContainsRect(const BS_Rect &OtherRect) const { return contains(OtherRect); }
};
} // End of namespace Sword25
#endif

View File

@ -41,29 +41,27 @@
#define BS_LOG_PREFIX "REGION"
// Konstruktion/Destruktion
namespace Sword25 {
// Constructor / Destructor
// ------------------------
BS_Region::BS_Region() : m_Valid(false), m_Type(RT_REGION)
{
BS_Region::BS_Region() : m_Valid(false), m_Type(RT_REGION) {
BS_RegionRegistry::GetInstance().RegisterObject(this);
}
// -----------------------------------------------------------------------------
BS_Region::BS_Region(BS_InputPersistenceBlock & Reader, unsigned int Handle) : m_Valid(false), m_Type(RT_REGION)
{
BS_Region::BS_Region(BS_InputPersistenceBlock &Reader, unsigned int Handle) : m_Valid(false), m_Type(RT_REGION) {
BS_RegionRegistry::GetInstance().RegisterObject(this, Handle);
Unpersist(Reader);
}
// -----------------------------------------------------------------------------
unsigned int BS_Region::Create(REGION_TYPE Type)
{
unsigned int BS_Region::Create(REGION_TYPE Type) {
BS_Region * RegionPtr;
switch (Type)
{
switch (Type) {
case RT_REGION:
RegionPtr = new BS_Region();
break;
@ -81,24 +79,18 @@ unsigned int BS_Region::Create(REGION_TYPE Type)
// -----------------------------------------------------------------------------
unsigned int BS_Region::Create(BS_InputPersistenceBlock & Reader, unsigned int Handle)
{
// Typ einlesen.
unsigned int BS_Region::Create(BS_InputPersistenceBlock & Reader, unsigned int Handle) {
// Read type
unsigned int Type;
Reader.Read(Type);
// Je nach Typ ein neues BS_Region oder BS_WalkRegion Objekt erstellen.
// Depending on the type, create a new BS_Region or BS_WalkRegion object
BS_Region * RegionPtr;
if (Type == RT_REGION)
{
if (Type == RT_REGION) {
RegionPtr = new BS_Region(Reader, Handle);
}
else if (Type == RT_WALKREGION)
{
} else if (Type == RT_WALKREGION) {
RegionPtr = new BS_WalkRegion(Reader, Handle);
}
else
{
} else {
BS_ASSERT(false);
}
@ -107,37 +99,33 @@ unsigned int BS_Region::Create(BS_InputPersistenceBlock & Reader, unsigned int H
// -----------------------------------------------------------------------------
BS_Region::~BS_Region()
{
BS_Region::~BS_Region() {
BS_RegionRegistry::GetInstance().DeregisterObject(this);
}
// -----------------------------------------------------------------------------
bool BS_Region::Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* pHoles)
{
// Objektzustand zurücksetzen.
bool BS_Region::Init(const BS_Polygon& Contour, const Common::Array<BS_Polygon> *pHoles) {
// Reset object state
m_Valid = false;
m_Position = BS_Vertex(0, 0);
m_Polygons.clear();
// Genügend Platz für Kontur und Löcher im Polygon-Vektor reservieren
// Reserve sufficient space for countour and holes in the polygon list
if (pHoles)
m_Polygons.reserve(1 + pHoles->size());
else
m_Polygons.reserve(1);
// Kontur an die erste Position im Polygon-Vektor kopieren
// The first polygon will be the contour
m_Polygons.push_back(BS_Polygon());
m_Polygons[0].Init(Contour.VertexCount, Contour.Vertecies);
// Sicherstellen, dass die Vertecies der Contour im Uhrzeigersinn angeordnet sind.
// Make sure that the Vertecies in the Contour are arranged in a clockwise direction
m_Polygons[0].EnsureCWOrder();
// Übergebene Lochpolygone an die folgenden Positionen im Polygon-Vektor kopieren
if (pHoles)
{
for (unsigned int i = 0; i< pHoles->size(); ++i)
{
// Place the hole polygons in the following positions
if (pHoles) {
for (unsigned int i = 0; i< pHoles->size(); ++i) {
m_Polygons.push_back(BS_Polygon());
m_Polygons[i + 1].Init((*pHoles)[i].VertexCount, (*pHoles)[i].Vertecies);
m_Polygons[i + 1].EnsureCWOrder();
@ -145,7 +133,7 @@ bool BS_Region::Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* p
}
// Bounding-Box initialisieren.
// Initialise bounding box
UpdateBoundingBox();
m_Valid = true;
@ -154,17 +142,14 @@ bool BS_Region::Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* p
// -----------------------------------------------------------------------------
void BS_Region::UpdateBoundingBox()
{
if (m_Polygons[0].VertexCount)
{
void BS_Region::UpdateBoundingBox() {
if (m_Polygons[0].VertexCount) {
int MinX = m_Polygons[0].Vertecies[0].X;
int MaxX = m_Polygons[0].Vertecies[0].X;
int MinY = m_Polygons[0].Vertecies[0].Y;
int MaxY = m_Polygons[0].Vertecies[0].Y;
for (int i = 1; i < m_Polygons[0].VertexCount; i++)
{
for (int i = 1; i < m_Polygons[0].VertexCount; i++) {
if (m_Polygons[0].Vertecies[i].X < MinX) MinX = m_Polygons[0].Vertecies[i].X;
else if (m_Polygons[0].Vertecies[i].X > MaxX) MaxX = m_Polygons[0].Vertecies[i].X;
if (m_Polygons[0].Vertecies[i].Y < MinY) MinY = m_Polygons[0].Vertecies[i].Y;
@ -175,55 +160,47 @@ void BS_Region::UpdateBoundingBox()
}
}
// Positionsänderungen
// -------------------
// Position Changes
// ----------------
void BS_Region::SetPos(int X, int Y)
{
// Unterschied zwischen alter und neuer Position berechnen.
void BS_Region::SetPos(int X, int Y) {
// Calculate the difference between the old and new position
BS_Vertex Delta(X - m_Position.X, Y - m_Position.Y);
// Neue Position im internen Zustand merken.
// Save the new position
m_Position = BS_Vertex(X, Y);
// Alle Vertecies verschieben.
for (unsigned int i = 0; i < m_Polygons.size(); ++i)
{
// Move all the vertecies
for (unsigned int i = 0; i < m_Polygons.size(); ++i) {
m_Polygons[i] += Delta;
}
// Bounding-Box aktualisieren
// Update the bounding box
UpdateBoundingBox();
}
// -----------------------------------------------------------------------------
void BS_Region::SetPosX(int X)
{
void BS_Region::SetPosX(int X) {
SetPos(X, m_Position.Y);
}
// -----------------------------------------------------------------------------
void BS_Region::SetPosY(int Y)
{
void BS_Region::SetPosY(int Y) {
SetPos(m_Position.X, Y);
}
// Punkt-Region Tests
// Point-Region Tests
// ------------------
bool BS_Region::IsPointInRegion(int X, int Y) const
{
// Testen, ob der Punkt in der Bounding-Box ist.
if (m_BoundingBox.IsPointInRect(X, Y))
{
// Testen, ob der Punkt in der Contour ist.
if (m_Polygons[0].IsPointInPolygon(X, Y, true))
{
// Testen, ob der Punkt in einem Loch ist.
for (unsigned int i = 1; i < m_Polygons.size(); i++)
{
bool BS_Region::IsPointInRegion(int X, int Y) const {
// Test whether the point is in the bounding box
if (m_BoundingBox.IsPointInRect(X, Y)) {
// Test whether the point is in the contour
if (m_Polygons[0].IsPointInPolygon(X, Y, true)) {
// Test whether the point is in a hole
for (unsigned int i = 1; i < m_Polygons.size(); i++) {
if (m_Polygons[i].IsPointInPolygon(X,Y, false))
return false;
}
@ -237,22 +214,19 @@ bool BS_Region::IsPointInRegion(int X, int Y) const
// -----------------------------------------------------------------------------
bool BS_Region::IsPointInRegion(const BS_Vertex& Vertex) const
{
bool BS_Region::IsPointInRegion(const BS_Vertex &Vertex) const {
return IsPointInRegion(Vertex.X, Vertex.Y);
}
// -----------------------------------------------------------------------------
BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex& Point) const
{
// Feststellen, ob sich der Punkt innerhalb eines Loches befindet, falls dies der Fall ist wird der dichteste Punkt am Rand des Loches gesucht
BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex &Point) const {
// Determine whether the point is inside a hole. If that is the case, the closest
// point on the edge of the hole is determined
int PolygonIdx = 0;
{
for (unsigned int i = 1; i < m_Polygons.size(); ++i)
{
if (m_Polygons[i].IsPointInPolygon(Point))
{
for (unsigned int i = 1; i < m_Polygons.size(); ++i) {
if (m_Polygons[i].IsPointInPolygon(Point)) {
PolygonIdx = i;
break;
}
@ -263,30 +237,27 @@ BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex& Point) const
BS_ASSERT(Polygon.VertexCount > 1);
// Für jede Linie des Polygons wird der Punkt berechnet, der dem übergebenen am nächsten ist.
// Der Punkt dieser Menge mit dem gerigsten Abstand zum übergebenen Punkt ist das Ergebnis.
// For each line of the polygon, calculate the point that is cloest to the given point
// The point of this set with the smallest distance to the given point is the result.
BS_Vertex ClosestVertex = FindClosestPointOnLine(Polygon.Vertecies[0], Polygon.Vertecies[1], Point);
int ClosestVertexDistance2 = ClosestVertex.Distance(Point);
for (int i = 1; i < Polygon.VertexCount; ++i)
{
for (int i = 1; i < Polygon.VertexCount; ++i) {
int j = (i + 1) % Polygon.VertexCount;
BS_Vertex CurVertex = FindClosestPointOnLine(Polygon.Vertecies[i], Polygon.Vertecies[j], Point);
if (CurVertex.Distance(Point) < ClosestVertexDistance2)
{
if (CurVertex.Distance(Point) < ClosestVertexDistance2) {
ClosestVertex = CurVertex;
ClosestVertexDistance2 = CurVertex.Distance(Point);
}
}
// Feststellen, ob der konstruierte Punkt wirklich von der Methode IsPointInRegion als innerhalb der Region liegend erkannt wird.
// Dies muss nicht so sein, da aufgrund von Rundungsfehlern am Rand der Polygone Ungenauigkeiten auftreten.
// Determine whether the point is really within the region. This must not be so, as a result of rounding
// errors can occur at the edge of polygons
if (IsPointInRegion(ClosestVertex))
return ClosestVertex;
else
{
// Es wird versucht einen Punkt innerhalb der Region zu konstruieren indem 8 Punkte getestet werden, die in unmittelbarer Umgebung des
// berechneten Punktes liegen
else {
// Try to construct a point within the region - 8 points are tested in the immediate vacinity
// of the point
if (IsPointInRegion(ClosestVertex + BS_Vertex(-2, -2)))
return ClosestVertex + BS_Vertex(-2, -2);
else if (IsPointInRegion(ClosestVertex + BS_Vertex(0, -2)))
@ -304,30 +275,27 @@ BS_Vertex BS_Region::FindClosestRegionPoint(const BS_Vertex& Point) const
else if (IsPointInRegion(ClosestVertex + BS_Vertex(2, 2)))
return ClosestVertex + BS_Vertex(2, 2);
// Falls auch auf diese Weise kein Punkt gefunden werden konnte, der innerhalb der Region liegt wird das Vertex genommen, welches am
// nächst an dem Punkt liegt.
// If no point could be found that way that lies within the region, find the next point
ClosestVertex = Polygon.Vertecies[0];
int ShortestVertexDistance2 = Polygon.Vertecies[0].Distance2(Point);
{
for (int i = 1; i < Polygon.VertexCount; i++)
{
for (int i = 1; i < Polygon.VertexCount; i++) {
int CurDistance2 = Polygon.Vertecies[i].Distance2(Point);
if (CurDistance2 < ShortestVertexDistance2)
{
if (CurDistance2 < ShortestVertexDistance2) {
ClosestVertex = Polygon.Vertecies[i];
ShortestVertexDistance2 = CurDistance2;
}
}
}
BS_LOG_WARNINGLN("Clostest vertex forced because edgepoint was outside region.");
return ClosestVertex;
BS_LOG_WARNINGLN("Clostest vertex forced because edgepoint was outside region.");
return ClosestVertex;
}
}
// -----------------------------------------------------------------------------
BS_Vertex BS_Region::FindClosestPointOnLine(const BS_Vertex & LineStart, const BS_Vertex & LineEnd, const BS_Vertex Point) const
{
BS_Vertex BS_Region::FindClosestPointOnLine(const BS_Vertex &LineStart, const BS_Vertex &LineEnd, const BS_Vertex Point) const {
float Vector1X = static_cast<float>(Point.X - LineStart.X);
float Vector1Y = static_cast<float>(Point.Y - LineStart.Y);
float Vector2X = static_cast<float>(LineEnd.X - LineStart.X);
@ -347,15 +315,14 @@ BS_Vertex BS_Region::FindClosestPointOnLine(const BS_Vertex & LineStart, const B
}
// -----------------------------------------------------------------------------
// Sichtlinie
// Line of Sight
// -----------------------------------------------------------------------------
bool BS_Region::IsLineOfSight(const BS_Vertex & a, const BS_Vertex & b) const
{
bool BS_Region::IsLineOfSight(const BS_Vertex &a, const BS_Vertex &b) const {
BS_ASSERT(m_Polygons.size());
// Die Linie muss innerhalb des Kontur-Polygons und ausserhalb aller Loch-Polygone sein
std::vector<BS_Polygon>::const_iterator iter = m_Polygons.begin();
// The line must be within the contour polygon, and outside of any hole polygons
Common::Array<BS_Polygon>::const_iterator iter = m_Polygons.begin();
if (!(*iter).IsLineInterior(a, b)) return false;
for (iter++; iter != m_Polygons.end(); iter++)
if (!(*iter).IsLineExterior(a, b)) return false;
@ -364,11 +331,10 @@ bool BS_Region::IsLineOfSight(const BS_Vertex & a, const BS_Vertex & b) const
}
// -----------------------------------------------------------------------------
// Persistenz
// Persistence
// -----------------------------------------------------------------------------
bool BS_Region::Persist(BS_OutputPersistenceBlock & Writer)
{
bool BS_Region::Persist(BS_OutputPersistenceBlock &Writer) {
bool Result = true;
Writer.Write(static_cast<unsigned int>(m_Type));
@ -377,9 +343,8 @@ bool BS_Region::Persist(BS_OutputPersistenceBlock & Writer)
Writer.Write(m_Position.Y);
Writer.Write(m_Polygons.size());
std::vector<BS_Polygon>::iterator It = m_Polygons.begin();
while (It != m_Polygons.end())
{
Common::Array<BS_Polygon>::iterator It = m_Polygons.begin();
while (It != m_Polygons.end()) {
Result &= It->Persist(Writer);
++It;
}
@ -394,8 +359,7 @@ bool BS_Region::Persist(BS_OutputPersistenceBlock & Writer)
// -----------------------------------------------------------------------------
bool BS_Region::Unpersist(BS_InputPersistenceBlock & Reader)
{
bool BS_Region::Unpersist(BS_InputPersistenceBlock &Reader) {
Reader.Read(m_Valid);
Reader.Read(m_Position.X);
Reader.Read(m_Position.Y);
@ -403,8 +367,7 @@ bool BS_Region::Unpersist(BS_InputPersistenceBlock & Reader)
m_Polygons.clear();
unsigned int PolygonCount;
Reader.Read(PolygonCount);
for (unsigned int i = 0; i < PolygonCount; ++i)
{
for (unsigned int i = 0; i < PolygonCount; ++i) {
m_Polygons.push_back(BS_Polygon(Reader));
}
@ -418,10 +381,11 @@ bool BS_Region::Unpersist(BS_InputPersistenceBlock & Reader)
// -----------------------------------------------------------------------------
BS_Vertex BS_Region::GetCentroid() const
{
BS_Vertex BS_Region::GetCentroid() const {
if (m_Polygons.size() > 0)
return m_Polygons[0].GetCentroid();
return
BS_Vertex();
}
} // End of namespace Sword25

View File

@ -35,192 +35,188 @@
#ifndef SWORD25_REGION_H
#define SWORD25_REGION_H
#include "sword25/kernel/memlog_off.h"
#include <vector>
#include "sword25/kernel/memlog_on.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistable.h"
#include "sword25/math/vertex.h"
#include "sword25/math/polygon.h"
#include "sword25/math/rect.h"
/**
@brief Diese Klasse ist die Basisklasse aller Regionen.
namespace Sword25 {
Mit der Methode IsValid() lässt sich abfragen, ob sich das Objekt in einem gültigen Zustand befindet.<br>
Sollte dies nicht der Fall sein, ist die Methode Init() die einzige Methode die aufgerufen werden darf.
Diese Klasse garantiert, dass die Vertecies der die Umriss- und die Lochpolygone im Uhrzeigersinn angeordnet sind, so dass auf den Polygonen
arbeitende Algorithmen nur für diese Anordnung implementiert werden müssen.
*/
class BS_Region : public BS_Persistable
{
/**
* This class is the base class of all regions.
*
* The IsValid() method can be queried to see whether the object is in a valid state.
* If this is not the case, the method Init() is the only method that may be invoked.
* This class guarantees that the Vertecies outline of the hole, and the polygons are
* arranged in a clockwise direction, so that the polygon working algorithms will
* work properly.
*/
class BS_Region : public BS_Persistable {
protected:
/**
@brief Erzeugt ein uninitialisiertes #BS_Region Objekt.
Nach dem Erzeugen ist das Objekt noch ungültig (IsValid() gibt false zurück), allerdings kann das Objekt nachträglich über
einen Aufruf von Init() in einen gültigen Zustand versetzt werden.
*/
* Creates a new BS_Region object
*
* After creation the object is invaild (IsValid() return false), but a call can
* be made later on to Init() to set up the region into a valid state.
*/
BS_Region();
BS_Region(BS_InputPersistenceBlock & Reader, unsigned int Handle);
BS_Region(BS_InputPersistenceBlock &Reader, unsigned int Handle);
public:
enum REGION_TYPE
{
enum REGION_TYPE {
RT_REGION,
RT_WALKREGION
};
static unsigned int Create(REGION_TYPE Type);
static unsigned int Create(BS_InputPersistenceBlock & Reader, unsigned int Handle = 0);
static unsigned int Create(BS_InputPersistenceBlock &Reader, unsigned int Handle = 0);
virtual ~BS_Region();
/**
@brief Initialisiert ein BS_Region Objekt.
@param Contour ein Polygon das den Umriss der Region angibt.
@param pHoles ein Pointer auf einen Vector von Polygonen, die Löcher in der Region angeben.<br>
Falls die Region keine Löcher hat, muss NULL übergeben werden.<br>
Der Standardwert ist NULL.
@return Gibt true zurück, wenn die Initialisierung erfolgreich war.<br>
Gibt false zurück, wenn die Intialisierung fehlgeschlagen ist.
@remark Falls die Region bereits initialisiert war, wird der alte Zustand gelöscht.
*/
virtual bool Init(const BS_Polygon& Contour, const std::vector<BS_Polygon>* pHoles = NULL);
//@{
/** @name Sondierende Methoden */
* Initialises a BS_Region object
* @param Contour A polygon indicating the outline of the region
* @param pHoles A pointer to an array of polygons representing the hole state in the region.
* If the region has no holes, it must be passed as NULL. The default value is NULL.
* @return Returns true if the initialisation was successful, otherwise false.
* @remark If the region was already initialised, the old state will be deleted.
*/
virtual bool Init(const BS_Polygon &Contour, const Common::Array<BS_Polygon> *pHoles = NULL);
//
// Exploratory Methods
//
/**
@brief Gibt an, ob das Objekt in einem gültigen Zustand ist.
@return Gibt true zurück, wenn sich das Objekt in einem gültigen Zustand befindet.
Gibt false zurück, wenn sich das Objekt in einem ungültigen Zustand befindet.
@remark Ungültige Objekte können durch einen Aufruf von Init() in einen gültigen Zustand versetzt werden.
*/
* Specifies whether the object is in a valid state
* @return Returns true if the object is in a valid state, otherwise false.
* @remark Invalid objects can be made valid by calling Init with a valid state.
*/
bool IsValid() const { return m_Valid; }
/**
@brief Gibt die Position der Region zurück.
*/
const BS_Vertex& GetPosition() const { return m_Position; }
* Returns the position of the region
*/
const BS_Vertex &GetPosition() const { return m_Position; }
/**
@brief Gibt die Position des Region auf der X-Achse zurück.
*/
* Returns the X position of the region
*/
int GetPosX() const { return m_Position.X; }
/**
@brief Gibt die Position des Region auf der Y-Achse zurück.
*/
* Returns the Y position of the region
*/
int GetPosY() const { return m_Position.Y; }
/**
@brief Gibt an, ob sich ein Punkt innerhalb der Region befindet.
@param Vertex ein Vertex, mit den Koordinaten des zu testenden Punktes.
@return Gibt true zurück, wenn sich der Punkt innerhalb der Region befindet.<br>
Gibt false zurück, wenn sich der Punkt außerhalb der Region befindet.
*/
bool IsPointInRegion(const BS_Vertex& Vertex) const;
* Indicates whether a point is inside the region
* @param Vertex A verex with the co-ordinates of the test point
* @return Returns true if the point is within the region, otherwise false.
*/
bool IsPointInRegion(const BS_Vertex &Vertex) const;
/**
@brief Gibt an, ob sich ein Punkt innerhalb der Region befindet.
@param X die Position des Punktes auf der X-Achse.
@param Y die Position des Punktes auf der Y-Achse.
@return Gibt true zurück, wenn sich der Punkt innerhalb der Region befindet.<br>
Gibt false zurück, wenn sich der Punkt außerhalb der Region befindet.
*/
* Indicates whether a point is inside the region
* @param X The X position
* @param Y The Y position
* @return Returns true if the point is within the region, otherwise false.
*/
bool IsPointInRegion(int X, int Y) const;
/**
@brief Gibt das Umrisspolygon der Region zurück.
*/
const BS_Polygon& GetContour() const { return m_Polygons[0]; }
* Returns the countour of the region
*/
const BS_Polygon &GetContour() const { return m_Polygons[0]; }
/**
@brief Gibt die Anzahl der Lochpolygone in der Region zurück.
*/
* Returns the number of polygons in the hole region
*/
int GetHoleCount() const { return static_cast<int>(m_Polygons.size() - 1); }
/**
@brief Gibt ein bestimmtes Lochpolygon in der Region zurück.
@param i die Nummer des zurückzugebenen Loches.<br>
Dieser Wert muss zwischen 0 und GetHoleCount() - 1 liegen.
@return Gibt das gewünschte Lochpolygon zurück.
*/
inline const BS_Polygon& GetHole(unsigned int i) const;
* Returns a specific hole polygon in the region
* @param i The number of the hole to return.
* The index must be between 0 and GetHoleCount() - 1.
* @return Returns the desired hole polygon
*/
inline const BS_Polygon &GetHole(unsigned int i) const;
/**
@brief Findet für einen Punkt ausserhalb der Region den nächsten Punkt, der sich innerhalb der Region befindet.
@param Point der Punkt, der sich ausserhalb der Region befindet
@return Gibt den Punkt innerhalb der Region zurück, der den geringsten Abstand zum übergebenen Punkt hat.
@remark Diese Methode arbeitet nicht immer Pixelgenau. Man sollte sich also nicht darauf verlassen, dass es wirklich keine Punkt innerhalb der
Region gibt, der dichter am übergebenen Punkt liegt.
*/
BS_Vertex FindClosestRegionPoint(const BS_Vertex& Point) const;
* For a point outside the region, finds the closest point inside the region
* @param Point The point that is outside the region
* @return Returns the point within the region which is closest
* @remark This method does not always work with pixel accuracy.
* One should not therefore rely on the fact that there is really no point in
* the region which is closer to the given point.
*/
BS_Vertex FindClosestRegionPoint(const BS_Vertex &Point) const;
/**
@brief Gibt den Schwerpunkt des Umrisspolygons zurück.
*/
* Returns the centroid for the region
*/
BS_Vertex GetCentroid() const;
bool IsLineOfSight(const BS_Vertex & a, const BS_Vertex & b) const;
bool IsLineOfSight(const BS_Vertex &a, const BS_Vertex &b) const;
//@}
//@{
/** @name Manipulierende Methoden */
//
// Manipulation Methods
//
/**
@brief Setzt die Position der Region.
@param X die neue Position der Region auf der X-Achse.
@param Y die neue Position der Region auf der Y-Achse.
*/
* Sets the position of the region
* @param X The new X psoition of the region
* @param Y The new Y psoition of the region
*/
virtual void SetPos(int X, int Y);
/**
@brief Setzt die Position der Region auf der X-Achse.
@param X die neue Position der Region auf der X-Achse.
*/
* Sets the X position of the region
* @param X The new X position of the region
*/
void SetPosX(int X);
/**
@brief Setzt die Position der Region auf der Y-Achse.
@param Y die neue Position der Region auf der Y-Achse.
*/
* Sets the Y position of the region
* @param Y The new Y position of the region
*/
void SetPosY(int Y);
//@}
//
// Manipulation Methods
//
virtual bool Persist(BS_OutputPersistenceBlock & Writer);
virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
virtual bool Persist(BS_OutputPersistenceBlock &Writer);
virtual bool Unpersist(BS_InputPersistenceBlock &Reader);
protected:
/// Diese Variable gibt den Typ des Objektes an.
/// This specifies the type of object
REGION_TYPE m_Type;
/// Diese Variable gibt an, ob der aktuelle Objektzustand gültig ist.
/// This variable indicates whether the current object state is valid
bool m_Valid;
/// Dieses Vertex gibt die Position der Region an.
/// This vertex is the position of the region
BS_Vertex m_Position;
/// Dieser Vector enthält alle Polygone die die Region definieren. Das erste Element des Vectors ist die Kontur, alle weiteren sind die Löcher.
std::vector<BS_Polygon> m_Polygons;
/// Die Bounding-Box der Region.
/// This array contains all the polygons that define the region. The first element of
// the array is the contour, all others are the holes
Common::Array<BS_Polygon> m_Polygons;
/// The bounding box for the region
BS_Rect m_BoundingBox;
/**
@brief Aktualisiert die Bounding-Box der Region.
*/
* Updates the bounding box of the region.
*/
void UpdateBoundingBox();
/**
@brief Findet den Punkt auf einer Linie, der einem anderen Punkt am nächsten ist.
@param LineStart der Startpunkt der Linie
@param LineEnd der Endpunkt der Linie
@param Point der Punkt, zu dem der nächste Punkt auf der Linie konstruiert werden soll.
@return Gibt den Punkt auf der Linie zurück, der dem übergebenen Punkt am nächsten ist.
*/
BS_Vertex FindClosestPointOnLine(const BS_Vertex & LineStart, const BS_Vertex & LineEnd, const BS_Vertex Point) const;
* Find the point on a line which is closest to another point
* @param LineStart The start of the line
* @param LineEnd The end of the line
* @param Point The point to be compared against
* @return Returns the point on the line which is cloest to the passed point.
*/
BS_Vertex FindClosestPointOnLine(const BS_Vertex &LineStart, const BS_Vertex &LineEnd, const BS_Vertex Point) const;
};
@ -228,10 +224,11 @@ protected:
// Inlines
// -----------------------------------------------------------------------------
inline const BS_Polygon& BS_Region::GetHole(unsigned int i) const
{
inline const BS_Polygon &BS_Region::GetHole(unsigned int i) const {
BS_ASSERT(i < m_Polygons.size() - 1);
return m_Polygons[i + 1];
}
} // End of namespace Sword25
#endif

View File

@ -47,46 +47,44 @@
#include "sword25/math/regionregistry.h"
#include "sword25/math/region.h"
namespace Sword25 {
// -----------------------------------------------------------------------------
// Implementation
// -----------------------------------------------------------------------------
std::auto_ptr<BS_RegionRegistry> BS_RegionRegistry::m_InstancePtr;
Common::SharedPtr<BS_RegionRegistry> BS_RegionRegistry::m_InstancePtr;
// -----------------------------------------------------------------------------
void BS_RegionRegistry::LogErrorLn(const char * Message) const
{
void BS_RegionRegistry::LogErrorLn(const char *Message) const {
BS_LOG_ERRORLN(Message);
}
// -----------------------------------------------------------------------------
void BS_RegionRegistry::LogWarningLn(const char * Message) const
{
void BS_RegionRegistry::LogWarningLn(const char *Message) const {
BS_LOG_WARNINGLN(Message);
}
// -----------------------------------------------------------------------------
bool BS_RegionRegistry::Persist(BS_OutputPersistenceBlock & Writer)
{
bool BS_RegionRegistry::Persist(BS_OutputPersistenceBlock &Writer) {
bool Result = true;
// Das nächste zu vergebene Handle schreiben.
// Write out the next handle
Writer.Write(m_NextHandle);
// Anzahl an BS_Regions schreiben.
// Number of regions to write
Writer.Write(m_Handle2PtrMap.size());
// Alle BS_Regions persistieren.
// Persist all the BS_Regions
HANDLE2PTR_MAP::const_iterator Iter = m_Handle2PtrMap.begin();
while (Iter != m_Handle2PtrMap.end())
{
// Handle persistieren.
while (Iter != m_Handle2PtrMap.end()) {
// Handle persistence
Writer.Write(Iter->first);
// Objekt persistieren.
// Persist object
Result &= Iter->second->Persist(Writer);
++Iter;
@ -97,30 +95,30 @@ bool BS_RegionRegistry::Persist(BS_OutputPersistenceBlock & Writer)
// -----------------------------------------------------------------------------
bool BS_RegionRegistry::Unpersist(BS_InputPersistenceBlock & Reader)
{
bool BS_RegionRegistry::Unpersist(BS_InputPersistenceBlock &Reader) {
bool Result = true;
// Das nächste zu vergebene Handle wieder herstellen.
// Read in the next handle
Reader.Read(m_NextHandle);
// Alle vorhandenen BS_Regions zerstören.
// Destroy all existing BS_Regions
while (!m_Handle2PtrMap.empty()) delete m_Handle2PtrMap.begin()->second;
// Anzahl an BS_Regions einlesen.
// Read in the number of BS_Regions
unsigned int RegionCount;
Reader.Read(RegionCount);
// Alle gespeicherten BS_Regions wieder herstellen.
for (unsigned int i = 0; i < RegionCount; ++i)
{
// Handle lesen.
// Restore all the BS_Regions objects
for (unsigned int i = 0; i < RegionCount; ++i) {
// Handle read
unsigned int Handle;
Reader.Read(Handle);
// BS_Region wieder herstellen.
// BS_Region restore
Result &= BS_Region::Create(Reader, Handle) != 0;
}
return Reader.IsGood() && Result;
}
} // End of namespace Sword25

View File

@ -39,41 +39,40 @@
// Includes
// -----------------------------------------------------------------------------
#include "common/ptr.h"
#include "sword25/kernel/common.h"
#include "sword25/kernel/persistable.h"
#include "sword25/kernel/objectregistry.h"
#include "sword25/kernel/memlog_off.h"
#include <memory>
#include "sword25/kernel/memlog_on.h"
namespace Sword25 {
// -----------------------------------------------------------------------------
// Forward Deklarationen
// Forward Declarations
// -----------------------------------------------------------------------------
class BS_Region;
// -----------------------------------------------------------------------------
// Klassendeklaration
// Class definitions
// -----------------------------------------------------------------------------
class BS_RegionRegistry : public BS_ObjectRegistry<BS_Region>, public BS_Persistable
{
class BS_RegionRegistry : public BS_ObjectRegistry<BS_Region>, public BS_Persistable {
public:
static BS_RegionRegistry & GetInstance()
{
if (!m_InstancePtr.get()) m_InstancePtr.reset(new BS_RegionRegistry);
static BS_RegionRegistry & GetInstance() {
if (!m_InstancePtr.get()) m_InstancePtr = Common::SharedPtr<BS_RegionRegistry>(new BS_RegionRegistry());
return *m_InstancePtr.get();
}
virtual bool Persist(BS_OutputPersistenceBlock & Writer);
virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
virtual bool Persist(BS_OutputPersistenceBlock &Writer);
virtual bool Unpersist(BS_InputPersistenceBlock &Reader);
private:
virtual void LogErrorLn(const char * Message) const;
virtual void LogWarningLn(const char * Message) const;
virtual void LogErrorLn(const char *Message) const;
virtual void LogWarningLn(const char *Message) const;
static std::auto_ptr<BS_RegionRegistry> m_InstancePtr;
static Common::SharedPtr<BS_RegionRegistry> m_InstancePtr;
};
} // End of namespace Sword25
#endif

View File

@ -34,31 +34,36 @@
#include "sword25/math/vertex.h"
namespace {
extern "C"
{
#include "sword25/util/lua/lua.h"
#include "sword25/util/lua/lauxlib.h"
}
}
// -----------------------------------------------------------------------------
BS_Vertex & BS_Vertex::LuaVertexToVertex(lua_State * L, int StackIndex, BS_Vertex & Vertex)
{
namespace Sword25 {
BS_Vertex &BS_Vertex::LuaVertexToVertex(lua_State *L, int StackIndex, BS_Vertex &Vertex) {
#ifdef DEBUG
int __startStackDepth = lua_gettop(L);
#endif
// Sicherstellen, dass wir wirklich eine Tabelle betrachten
// Ensure that we actually consider a table
luaL_checktype(L, StackIndex, LUA_TTABLE);
// X Komponente auslesen
// Read X Component
lua_pushstring(L, "X");
lua_gettable(L, StackIndex);
if (!lua_isnumber(L, -1)) luaL_argcheck(L, 0, StackIndex, "the X component has to be a number");
Vertex.X = static_cast<int>(lua_tonumber(L, -1));
lua_pop(L, 1);
// Y Komponente auslesen
// Read Y Component
lua_pushstring(L, "Y");
lua_gettable(L, StackIndex);
if (!lua_isnumber(L, -1)) luaL_argcheck(L, 0, StackIndex, "the Y component has to be a number");
@ -74,18 +79,19 @@ BS_Vertex & BS_Vertex::LuaVertexToVertex(lua_State * L, int StackIndex, BS_Verte
// -----------------------------------------------------------------------------
void BS_Vertex::VertexToLuaVertex(lua_State * L, const BS_Vertex & Vertex)
{
// Neue Tabelle erstellen
void BS_Vertex::VertexToLuaVertex(lua_State * L, const BS_Vertex &Vertex) {
// Create New Table
lua_newtable(L);
// X-Wert in die Tabelle schreiben
// X value is written to table
lua_pushstring(L, "X");
lua_pushnumber(L, Vertex.X);
lua_settable(L, -3);
// Y-Wert in die Tabelle schreiben
// Y value is written to table
lua_pushstring(L, "Y");
lua_pushnumber(L, Vertex.Y);
lua_settable(L, -3);
}
} // End of namespace Sword25

View File

@ -46,14 +46,19 @@
#include <math.h>
#include "sword25/kernel/common.h"
// Forward-Declarations
namespace {
// Forward declarations
struct lua_State;
}
namespace Sword25 {
/**
@brief Ein 2D-Vertex.
*/
class BS_Vertex
{
* Defines a 2-D Vertex
*/
class BS_Vertex {
public:
BS_Vertex() : X(0), Y(0) {};
BS_Vertex(int X_, int Y_) { this->X = X_; this->Y = Y_; }
@ -62,91 +67,87 @@ public:
int Y;
/**
@brief Vergleicht zwei Vertecies.
*/
* Compares two Vertecies.
*/
inline bool operator==(const BS_Vertex& rhs) const { if (X == rhs.X && Y == rhs.Y) return true; return false; }
/**
@brief Vergleicht zwei Vertecies.
*/
* Compares two Vertecies.
*/
inline bool operator!=(const BS_Vertex& rhs) const { if (X != rhs.X || Y != rhs.Y) return true; return false; }
/**
@brief Addiert ein Vertex zum Vertex.
*/
* Adds a vertex to vertex
*/
inline void operator+=(const BS_Vertex& Delta) { X += Delta.X; Y += Delta.Y; }
/**
@brief Subtrahiert ein Vertex vom Vertex.
*/
* Subtracts a vertex from a vertex
*/
inline void operator-=(const BS_Vertex& Delta) { X -= Delta.X; Y -= Delta.Y; }
/**
@brief Addiert zwei Vertecies
*/
* Adds two vertecies
*/
inline BS_Vertex operator+(const BS_Vertex& Delta) const { return BS_Vertex(X + Delta.X, Y + Delta.Y); }
/**
@brief Subtrahiert zwei Vertecies
*/
* Subtracts two vertecies
*/
inline BS_Vertex operator-(const BS_Vertex& Delta) const { return BS_Vertex(X - Delta.X, Y - Delta.Y); }
/**
@brief Berechnet das Quadrat des Abstandes zweier Vertecies.
@param Vertex das Vertex zu dem der Abstand berechnet werden soll.
@return Gibt das Quadrat des Abstandes zwischen diesem Objekt und Vertex zurück.
@remark Falls nur Abstände verglichen werden sollen, sollte diese Methode benutzt werden, da sie schneller ist, als Distance().
*/
inline int Distance2(const BS_Vertex& Vertex) const
{
* Calculates the square of the distance between two Vertecies.
* @param Vertex The vertex for which the distance is to be calculated
* @return Returns the square of the distance between itself and the passed vertex
* @remark If only distances should be compared, this method should be used because
* it is faster than Distance()
*/
inline int Distance2(const BS_Vertex& Vertex) const {
return (X - Vertex.X) * (X - Vertex.X) + (Y - Vertex.Y) * (Y - Vertex.Y);
}
/**
@brief Berechnet den Abstand zweier Vertecies.
@param Vertex das Vertex zu dem der Abstand berechnet werden soll.
@return Gibt den Abstand zwischen diesem Objekt und Vertex zurück.
@remark Falls nur Abstände verglichen werden sollen, sollte diese Methode Distance2(), die das Quadrat des Abstandes berechnet.
Sie ist schneller.
*/
inline int Distance(const BS_Vertex& Vertex) const
{
* Calculates the square of the distance between two Vertecies.
* @param Vertex The vertex for which the distance is to be calculated
* @return Returns the square of the distance between itself and the passed vertex
* @remark If only distances should be compared, Distance2() should be used, since it is faster.
*/
inline int Distance(const BS_Vertex& Vertex) const {
return (int)(sqrtf(static_cast<float>(Distance2(Vertex))) + 0.5);
}
/**
@brief Berechnet das Kreuzprodukt dieses Vertex mit einem weiteren Vertex. Hierbei werden die Vertecies als Vektoren aufgefasst.
@param Vertex das zweite Vertex
@return Gibt das Kreuzprodukt von diesem Vertex und dem Parameter Vertex zurück.
*/
inline int ComputeCrossProduct(const BS_Vertex& Vertex) const
{
* Calculates the cross product of the vertex with another vertex. Here the Vertecies will be
* interpreted as vectors.
* @param Vertex The second vertex
* @return Returns the cross product of this vertex and the passed vertex.
*/
inline int ComputeCrossProduct(const BS_Vertex& Vertex) const {
return X * Vertex.Y - Vertex.X * Y;
}
/**
@brief Berechnet das Skalarprodukt dieses Vertex mit einem weiteren Vertex. Hierbei werden die Vertecies als Vektoren aufgefasst.
@param Vertex das zweite Vertex
@return Gibt das Skalarprodukt von diesem Vertex und dem Parameter Vertex zurück.
*/
* Returns the dot product of this vertex with another vertex. Here the Vertecies are interpreted as vectors.
* @param Vertex The second vertex
* @return Returns the dot product of this vertex and the passed vertex.
*/
inline int ComputeDotProduct(const BS_Vertex& Vertex) const
{
return X * Vertex.X + Y * Vertex.Y;
}
/**
@brief Berechnet den Winkel zwischen diesem Vertex und einem weiteren Vertex. Hierbei werden die Vertecies als Vektoren aufgefasst.
@param Vertex das zweite Vertex
@return Gibt den Winkel zwischen diesem Vertex und dem Parameter Vertex im Bogenmaß zurück.
*/
inline float ComputeAngle(const BS_Vertex& Vertex) const
{
* Calculates the angle between this vertex and another vertex. Here the Vertecies are interpreted as vectors.
* @param Vertex The second vertex
* @return Returns the angle between this vertex and the passed vertex in radians.
*/
inline float ComputeAngle(const BS_Vertex& Vertex) const {
return atan2f(static_cast<float>(ComputeCrossProduct(Vertex)), static_cast<float>(ComputeDotProduct(Vertex)));
}
/**
@brief Berechnet die Länge des Vektors
*/
inline float ComputeLength() const
{
* Calculates the length of the vector
*/
inline float ComputeLength() const {
return sqrtf(static_cast<float>(X * X + Y * Y));
}
@ -154,4 +155,6 @@ public:
static void VertexToLuaVertex(lua_State * L, const BS_Vertex & Vertex);
};
} // End of namespace Sword25
#endif

View File

@ -32,8 +32,7 @@
*
*/
#include <list>
#include <algorithm>
#include "sword25/kernel/kernel.h"
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/kernel/outputpersistenceblock.h"
#include "sword25/math/walkregion.h"
@ -41,65 +40,62 @@
#define BS_LOG_PREFIX "WALKREGION"
namespace Sword25 {
// -----------------------------------------------------------------------------
// Konstanten
// Constants
// -----------------------------------------------------------------------------
static const int infinity = INT_MAX;
// -----------------------------------------------------------------------------
// Konstruktion / Destruktion
// Constructor / Destructor
// -----------------------------------------------------------------------------
BS_WalkRegion::BS_WalkRegion()
{
BS_WalkRegion::BS_WalkRegion() {
m_Type = RT_WALKREGION;
}
// -----------------------------------------------------------------------------
BS_WalkRegion::BS_WalkRegion(BS_InputPersistenceBlock &Reader, unsigned int Handle) :
BS_Region(Reader, Handle)
{
BS_Region(Reader, Handle) {
m_Type = RT_WALKREGION;
Unpersist(Reader);
}
// -----------------------------------------------------------------------------
BS_WalkRegion::~BS_WalkRegion()
{
BS_WalkRegion::~BS_WalkRegion() {
}
// -----------------------------------------------------------------------------
bool BS_WalkRegion::Init(const BS_Polygon & Contour, const std::vector<BS_Polygon> * pHoles)
{
// Standard-Initialisierungen der Region vornehmen.
bool BS_WalkRegion::Init(const BS_Polygon &Contour, const Common::Array<BS_Polygon> *pHoles) {
// Default initialisation of the region
if (!BS_Region::Init(Contour, pHoles)) return false;
// Datenstrukturen fürs Pathfinding vorbereiten
// Prepare structures for pathfinding
InitNodeVector();
ComputeVisibilityMatrix();
// Erfolg signalisieren.
// Signal success
return true;
}
// -----------------------------------------------------------------------------
bool BS_WalkRegion::QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path & Path)
{
bool BS_WalkRegion::QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path &Path) {
BS_ASSERT(Path.empty());
// Falls Start und Ziel identisch sind, muss trivialerweise kein Pfad gefunden werden.
// If the start and finish are identical, no path can be found trivially
if (StartPoint == EndPoint) return true;
// Sicherstellen, dass Start und Ziel gültig sind und neuen Start- und Zielpunkt finden, falls sie ausserhalb des Polygons liegen.
// Ensure that the start and finish are valid and find new start points if either
// are outside the polygon
if (!CheckAndPrepareStartAndEnd(StartPoint, EndPoint)) return false;
// Wenn zwischen Start- und Endpunkt eine Sichtlinie besteht, muss kein Pathfindung durchgeführt werden und als Ergebnis wird die
// direkte Verbindungslinie zwischen Start- und Endpunkt zurückgegeben.
// If between the start and point a line of sight exists, then it can be returned.
if (IsLineOfSight(StartPoint, EndPoint))
{
Path.push_back(StartPoint);
@ -112,9 +108,8 @@ bool BS_WalkRegion::QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path
// -----------------------------------------------------------------------------
struct DijkstraNode
{
typedef std::vector<DijkstraNode> Container;
struct DijkstraNode {
typedef Common::Array<DijkstraNode> Container;
typedef Container::iterator Iter;
typedef Container::const_iterator ConstIter;
@ -124,30 +119,27 @@ struct DijkstraNode
bool Chosen;
};
static void InitDijkstraNodes(DijkstraNode::Container & DijkstraNodes, const BS_Region & Region, const BS_Vertex & Start, const std::vector<BS_Vertex> & Nodes)
{
// Ausreichend Platz im Vector reservieren
static void InitDijkstraNodes(DijkstraNode::Container &DijkstraNodes, const BS_Region &Region,
const BS_Vertex &Start, const Common::Array<BS_Vertex> &Nodes) {
// Allocate sufficient space in the array
DijkstraNodes.resize(Nodes.size());
// Alle Randknoten initialisieren, die vom Startknoten sichtbar sind
// Initialise all the nodes which are visible from the starting node
DijkstraNode::Iter DijkstraIter = DijkstraNodes.begin();
for (std::vector<BS_Vertex>::const_iterator NodesIter = Nodes.begin(); NodesIter != Nodes.end(); NodesIter++, DijkstraIter++)
{
for (Common::Array<BS_Vertex>::const_iterator NodesIter = Nodes.begin();
NodesIter != Nodes.end(); NodesIter++, DijkstraIter++) {
(*DijkstraIter).ParentIter = DijkstraNodes.end();
if (Region.IsLineOfSight(*NodesIter, Start)) (*DijkstraIter).Cost = (*NodesIter).Distance(Start);
}
BS_ASSERT(DijkstraIter == DijkstraNodes.end());
}
static DijkstraNode::Iter ChooseClosestNode(DijkstraNode::Container & Nodes)
{
static DijkstraNode::Iter ChooseClosestNode(DijkstraNode::Container & Nodes) {
DijkstraNode::Iter ClosestNodeInter = Nodes.end();
int MinCost = infinity;
for (DijkstraNode::Iter iter = Nodes.begin(); iter != Nodes.end(); iter++)
{
if (!(*iter).Chosen && (*iter).Cost < MinCost)
{
for (DijkstraNode::Iter iter = Nodes.begin(); iter != Nodes.end(); iter++) {
if (!(*iter).Chosen && (*iter).Cost < MinCost) {
MinCost = (*iter).Cost;
ClosestNodeInter = iter;
}
@ -156,22 +148,19 @@ static DijkstraNode::Iter ChooseClosestNode(DijkstraNode::Container & Nodes)
return ClosestNodeInter;
}
static void RelaxNodes(DijkstraNode::Container & Nodes,
const std::vector< std::vector<int> > & VisibilityMatrix,
const DijkstraNode::ConstIter & CurNodeIter)
{
// Alle Nachfolger vom aktuellen Knoten, die noch nicht gewählt wurden, werden in die Randknotenliste eingefügt und die Kosten werden
// aktualisiert, wenn ein kürzerer Pfad zu ihnen gefunden wurde.
static void RelaxNodes(DijkstraNode::Container &Nodes,
const Common::Array< Common::Array<int> > &VisibilityMatrix,
const DijkstraNode::ConstIter &CurNodeIter) {
// All the successors of the current node that have not been chosen will be
// inserted into the boundary node list, and the cost will be updated if
// a shorter path has been found to them.
int CurNodeIndex = CurNodeIter - Nodes.begin();
for (unsigned int i = 0; i < Nodes.size(); i++)
{
for (unsigned int i = 0; i < Nodes.size(); i++) {
int Cost = VisibilityMatrix[CurNodeIndex][i];
if (!Nodes[i].Chosen && Cost != infinity)
{
if (!Nodes[i].Chosen && Cost != infinity) {
int TotalCost = (*CurNodeIter).Cost + Cost;
if (TotalCost < Nodes[i].Cost)
{
if (TotalCost < Nodes[i].Cost) {
Nodes[i].ParentIter = CurNodeIter;
Nodes[i].Cost = TotalCost;
}
@ -179,90 +168,82 @@ static void RelaxNodes(DijkstraNode::Container & Nodes,
}
}
static void RelaxEndPoint(const BS_Vertex & CurNodePos,
const DijkstraNode::ConstIter & CurNodeIter,
const BS_Vertex & EndPointPos,
DijkstraNode & EndPoint,
const BS_Region & Region)
{
if (Region.IsLineOfSight(CurNodePos, EndPointPos))
{
static void RelaxEndPoint(const BS_Vertex &CurNodePos,
const DijkstraNode::ConstIter &CurNodeIter,
const BS_Vertex &EndPointPos,
DijkstraNode &EndPoint,
const BS_Region &Region) {
if (Region.IsLineOfSight(CurNodePos, EndPointPos)) {
int TotalCost = (*CurNodeIter).Cost + CurNodePos.Distance(EndPointPos);
if (TotalCost < EndPoint.Cost)
{
if (TotalCost < EndPoint.Cost) {
EndPoint.ParentIter = CurNodeIter;
EndPoint.Cost = TotalCost;
}
}
}
bool BS_WalkRegion::FindPath(const BS_Vertex & Start, const BS_Vertex & End, BS_Path & Path) const
{
// Dies ist eine Implementation des Dijkstra-Algorithmus
bool BS_WalkRegion::FindPath(const BS_Vertex &Start, const BS_Vertex &End, BS_Path &Path) const {
// This is an implementation of Dijkstra's algorithm
// Randknotenliste initialisieren
// Initialise edge node list
DijkstraNode::Container DijkstraNodes;
InitDijkstraNodes(DijkstraNodes, *this, Start, m_Nodes);
// Der Endpunkt wird gesondert behandelt, da er im Sichtbarkeitsgraphen nicht vorhanden ist
// The end point is treated separately, since it does not exist in the visibility graph
DijkstraNode EndPoint;
// Da in jedem Durchgang ein Knoten aus der Knotenliste gewählt wird, und danach nie wieder gewählt werden kann, ist die maximale Anzahl der
// Schleifendurchläufe durch die Anzahl der Knoten begrenzt.
for (unsigned int i = 0; i < m_Nodes.size(); i++)
{
// Bestimme nächstgelegenen Knoten in der Randknotenliste
// Since a node is selected each round from the node list, and can never be selected again
// after that, the maximum number of loop iterations is limited by the number of nodes
for (unsigned int i = 0; i < m_Nodes.size(); i++) {
// Determine the nearest edge node in the node list
DijkstraNode::Iter NodeInter = ChooseClosestNode(DijkstraNodes);
(*NodeInter).Chosen = true;
// Falls kein freier Knoten mehr in der Randknotenliste vorhanden ist, gibt es keinen Weg vom Start- zum Endknoten.
// Dieser Fall sollte nie auftreten, da die Anzahl der Schleifendurchgänge begrenzt ist, aber sicher ist sicher.
// If no free nodes are absent from the edge node list, there is no path from start
// to end node. This case should never occur, since the number of loop passes is
// limited, but etter safe than sorry
if (NodeInter == DijkstraNodes.end()) return false;
// Wenn der Zielpunkt noch näher liegt als der nächte Punkt, ist die Suche beendet
if (EndPoint.Cost <= (*NodeInter).Cost)
{
// Ergebnispfad extrahieren
// Den Endpunkt in den Ergebnispfad einfügen
// If the destination point is closer than the point cost, scan can stop
if (EndPoint.Cost <= (*NodeInter).Cost) {
// Insert the end point in the list
Path.push_back(End);
// Die Wegknoten in umgekehrter Reihenfolge ablaufen und in den Ergebnispfad einfügen
// The list is done in reverse order and inserted into the path
DijkstraNode::ConstIter CurNode = EndPoint.ParentIter;
while (CurNode != DijkstraNodes.end())
{
while (CurNode != DijkstraNodes.end()) {
BS_ASSERT((*CurNode).Chosen);
Path.push_back(m_Nodes[CurNode - DijkstraNodes.begin()]);
CurNode = (*CurNode).ParentIter;
}
// Den Startpunkt in den Ergebnispfad einfügen
// The starting point is inserted into the path
Path.push_back(Start);
// Die Knoten des Pfades müssen ungedreht werden, da sie in umgekehrter Reihenfolge extrahiert wurden.
// Diesen Schritt könnte man sich sparen, wenn man den Pfad vom Ende zum Anfang sucht.
std::reverse(Path.begin(), Path.end());
// The nodes of the path must be untwisted, as they were extracted in reverse order.
// This step could be saved if the path from end to the beginning was desired
ReverseArray<BS_Vertex>(Path);
return true;
}
// Relaxation-Schritt für die Knoten des Graphen und für den Endknoten durchführen
// Relaxation step for nodes of the graph, and perform the end nodes
RelaxNodes(DijkstraNodes, m_VisibilityMatrix, NodeInter);
RelaxEndPoint(m_Nodes[NodeInter - DijkstraNodes.begin()], NodeInter, End, EndPoint, *this);
}
// Falls die Schleife komplett durchlaufen wurde, wurden alle Knoten gewählt und es wurde trotzdem kein Pfad gefunden. Es existiert also keiner.
// If the loop has been completely run through, all the nodes have been chosen, and still
// no path was found. There is therefore no path available
return false;
}
// -----------------------------------------------------------------------------
void BS_WalkRegion::InitNodeVector()
{
// Knoten-Vector leeren.
void BS_WalkRegion::InitNodeVector() {
// Empty the Node list
m_Nodes.clear();
// Anzahl der Knoten bestimmen.
// Determine the number of nodes
int NodeCount = 0;
{
for (unsigned int i = 0; i < m_Polygons.size(); i++)
@ -280,26 +261,27 @@ void BS_WalkRegion::InitNodeVector()
// -----------------------------------------------------------------------------
void BS_WalkRegion::ComputeVisibilityMatrix()
{
// Sichtbarkeitsmatrix initialisieren
m_VisibilityMatrix = std::vector< std::vector <int> >(m_Nodes.size(), std::vector<int>(m_Nodes.size(), infinity));
void BS_WalkRegion::ComputeVisibilityMatrix() {
// Initialise visibility matrix
m_VisibilityMatrix = Common::Array< Common::Array <int> >();
for (uint idx = 0; idx < m_Nodes.size(); ++idx) {
Common::Array<int> arr;
for (uint idx2 = 0; idx2 < m_Nodes.size(); ++idx2)
arr.push_back(infinity);
// Sichtbarkeiten zwischen Vertecies berechnen und in die Sichbarkeitsmatrix eintragen.
for (unsigned int j = 0; j < m_Nodes.size(); ++j)
{
for (unsigned int i = j; i < m_Nodes.size(); ++i)
{
if (IsLineOfSight(m_Nodes[i], m_Nodes[j]))
{
// Wenn eine Sichtlinie besteht wird die Entfernung der Knoten eingetragen
m_VisibilityMatrix.push_back(arr);
}
// Calculate visibility been vertecies
for (unsigned int j = 0; j < m_Nodes.size(); ++j) {
for (unsigned int i = j; i < m_Nodes.size(); ++i) {
if (IsLineOfSight(m_Nodes[i], m_Nodes[j])) {
// There is a line of sight, so save the distance between the two
int Distance = m_Nodes[i].Distance(m_Nodes[j]);
m_VisibilityMatrix[i][j] = Distance;
m_VisibilityMatrix[j][i] = Distance;
}
else
{
// Wenn keine Sichtlinie besteht wird die Entfernung "unendlich" eingetragen
} else {
// There is no line of sight, so save infinity as the distance
m_VisibilityMatrix[i][j] = infinity;
m_VisibilityMatrix[j][i] = infinity;
}
@ -309,15 +291,12 @@ void BS_WalkRegion::ComputeVisibilityMatrix()
// -----------------------------------------------------------------------------
bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & End) const
{
if (!IsPointInRegion(Start))
{
bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex &Start, BS_Vertex &End) const {
if (!IsPointInRegion(Start)) {
BS_Vertex NewStart = FindClosestRegionPoint(Start);
// Sicherstellen, dass der ermittelte Punkt wirklich innerhalb der Region liegt und Notfalls abbrechen.
if (!IsPointInRegion(NewStart))
{
// Check to make sure the point is really in the region. If not, stop with an error
if (!IsPointInRegion(NewStart)) {
BS_LOG_ERRORLN("Constructed startpoint ((%d,%d) from (%d,%d)) is not inside the region.",
NewStart.X, NewStart.Y,
Start.X, Start.Y);
@ -327,14 +306,13 @@ bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & En
Start = NewStart;
}
// Falls der Zielpunkt außerhalb der Region liegt, wird der nächste Punkt innerhalb der Region bestimmt und als Endpunkt benutzt.
if (!IsPointInRegion(End))
{
// If the destination is outside the region, a point is determined that is within the region,
// and that is used as an endpoint instead
if (!IsPointInRegion(End)) {
BS_Vertex NewEnd = FindClosestRegionPoint(End);
// Sicherstellen, dass der ermittelte Punkt wirklich innerhalb der Region liegt und Notfalls abbrechen.
if (!IsPointInRegion(NewEnd))
{
// Make sure that the determined point is really within the region
if (!IsPointInRegion(NewEnd)) {
BS_LOG_ERRORLN("Constructed endpoint ((%d,%d) from (%d,%d)) is not inside the region.",
NewEnd.X, NewEnd.Y,
End.X, End.Y);
@ -344,52 +322,47 @@ bool BS_WalkRegion::CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & En
End = NewEnd;
}
// Erfolg signalisieren
// Signal success
return true;
}
// -----------------------------------------------------------------------------
void BS_WalkRegion::SetPos(int X, int Y)
{
// Unterschied zwischen alter und neuer Position berechnen.
void BS_WalkRegion::SetPos(int X, int Y) {
// Calculate the difference between old and new position
BS_Vertex Delta(X - m_Position.X, Y - m_Position.Y);
// Alle Nodes verschieben.
// Move all the nodes
for (unsigned int i = 0; i < m_Nodes.size(); i++) m_Nodes[i] += Delta;
// Region verschieben
// Move regions
BS_Region::SetPos(X, Y);
}
// -----------------------------------------------------------------------------
bool BS_WalkRegion::Persist(BS_OutputPersistenceBlock & Writer)
{
bool BS_WalkRegion::Persist(BS_OutputPersistenceBlock &Writer) {
bool Result = true;
// Elternobjekt persistieren.
// Persist the parent region
Result &= BS_Region::Persist(Writer);
// Knoten persistieren.
// Persist the nodes
Writer.Write(m_Nodes.size());
std::vector<BS_Vertex>::const_iterator It = m_Nodes.begin();
while (It != m_Nodes.end())
{
Common::Array<BS_Vertex>::const_iterator It = m_Nodes.begin();
while (It != m_Nodes.end()) {
Writer.Write(It->X);
Writer.Write(It->Y);
++It;
}
// Sichtbarkeitsmatrix persistieren.
// Persist the visibility matrix
Writer.Write(m_VisibilityMatrix.size());
std::vector< std::vector<int> >::const_iterator RowIter = m_VisibilityMatrix.begin();
while (RowIter != m_VisibilityMatrix.end())
{
Common::Array< Common::Array<int> >::const_iterator RowIter = m_VisibilityMatrix.begin();
while (RowIter != m_VisibilityMatrix.end()) {
Writer.Write(RowIter->size());
std::vector<int>::const_iterator ColIter = RowIter->begin();
while (ColIter != RowIter->end())
{
Common::Array<int>::const_iterator ColIter = RowIter->begin();
while (ColIter != RowIter->end()) {
Writer.Write(*ColIter);
++ColIter;
}
@ -402,40 +375,36 @@ bool BS_WalkRegion::Persist(BS_OutputPersistenceBlock & Writer)
// -----------------------------------------------------------------------------
bool BS_WalkRegion::Unpersist(BS_InputPersistenceBlock & Reader)
{
bool BS_WalkRegion::Unpersist(BS_InputPersistenceBlock &Reader) {
bool Result = true;
// Das Elternobjekt wurde schon über den Konstruktor von BS_Region geladen, daher müssen an dieser Stelle nur noch die zusätzlichen Daten von
// BS_WalkRegion geladen werden.
// The parent object was already loaded in the constructor of BS_Region, so at
// this point only the additional data from BS_WalkRegion needs to be loaded
// Knoten laden.
// Node load
unsigned int NodeCount;
Reader.Read(NodeCount);
m_Nodes.clear();
m_Nodes.resize(NodeCount);
std::vector<BS_Vertex>::iterator It = m_Nodes.begin();
while (It != m_Nodes.end())
{
Common::Array<BS_Vertex>::iterator It = m_Nodes.begin();
while (It != m_Nodes.end()) {
Reader.Read(It->X);
Reader.Read(It->Y);
++It;
}
// Sichtbarkeitsmatrix laden.
// Visibility matrix load
unsigned int RowCount;
Reader.Read(RowCount);
m_VisibilityMatrix.clear();
m_VisibilityMatrix.resize(RowCount);
std::vector< std::vector<int> >::iterator RowIter = m_VisibilityMatrix.begin();
while (RowIter != m_VisibilityMatrix.end())
{
Common::Array< Common::Array<int> >::iterator RowIter = m_VisibilityMatrix.begin();
while (RowIter != m_VisibilityMatrix.end()) {
unsigned int ColCount;
Reader.Read(ColCount);
RowIter->resize(ColCount);
std::vector<int>::iterator ColIter = RowIter->begin();
while (ColIter != RowIter->end())
{
Common::Array<int>::iterator ColIter = RowIter->begin();
while (ColIter != RowIter->end()) {
Reader.Read(*ColIter);
++ColIter;
}
@ -445,3 +414,5 @@ bool BS_WalkRegion::Unpersist(BS_InputPersistenceBlock & Reader)
return Result && Reader.IsGood();
}
} // End of namespace Sword25

View File

@ -35,83 +35,83 @@
#ifndef SWORD25_WALKREGION_H
#define SWORD25_WALKREGION_H
#include "sword25/kernel/memlog_off.h"
#include <vector>
#include "sword25/kernel/memlog_on.h"
#include "common/array.h"
#include "sword25/kernel/common.h"
#include "sword25/math/region.h"
// -----------------------------------------------------------------------------
// Typdefinitionen
// -----------------------------------------------------------------------------
typedef std::vector<BS_Vertex> BS_Path;
namespace Sword25 {
// -----------------------------------------------------------------------------
// Klassendefinition
// Type definitions
// -----------------------------------------------------------------------------
typedef Common::Array<BS_Vertex> BS_Path;
// -----------------------------------------------------------------------------
// Class definitions
// -----------------------------------------------------------------------------
/**
@brief Diese Klasse stellt die Region dar, in der sich der Hauptcharakter bewegen kann.
*/
class BS_WalkRegion : public BS_Region
{
* This class represents the region in which the main character can move
*/
class BS_WalkRegion : public BS_Region {
friend class BS_Region;
protected:
BS_WalkRegion();
BS_WalkRegion(BS_InputPersistenceBlock & Reader, unsigned int Handle);
BS_WalkRegion(BS_InputPersistenceBlock &Reader, unsigned int Handle);
public:
virtual ~BS_WalkRegion();
virtual bool Init(const BS_Polygon & Contour, const std::vector<BS_Polygon> * pHoles = 0);
virtual bool Init(const BS_Polygon &Contour, const Common::Array<BS_Polygon> *pHoles = 0);
/**
@brief Ermittelt den kürzesten Weg zwischen zwei Punkten in der Region.
Diese Methode verlangt, dass der Startpunkt innerhalb der Region liegt. Der Endpunkt darf außerhalb der Region liegen. In diesem
Fall wählt die Methode als Endpunkt den Punkt innerhalb der Region, der am dichtesten am Endpunkt liegt.
@param X1 X-Koordinate des Startpunktes
@param Y1 Y-Koordinate des Startpunktes
@param X2 X-Koordinate des Zielpunktes
@param Y2 Y-Koordinate des Zielpunktes
@param Path ein leerer BS_Path, der den Ergebnispfad aufnehmen soll
@return Gibt false zurück, fall die Eingaben ungültig waren, ansonsten wird true zurückgegeben.
* Get the shortest path between two points in the region
*
* This method requires that the starting point lies within the region. The end point
* may lie outside the region. Int his case, the end is chosen as the cloest point to it
* that lies within the region.
*
* @param X1 X Co-ordinate of the start point
* @param Y1 Y Co-ordinate of the start point
* @param X2 X Co-ordinate of the end point
* @param Y2 Y Co-ordinate of the end point
* @param Path An empty BS_Path that will be set to the resulting path
* @return Returns false if the result is invalid, otherwise returns true.
*/
bool QueryPath(int X1, int Y1, int X2, int Y2, BS_Path & Path) { return QueryPath(BS_Vertex(X1, Y1), BS_Vertex(X2, Y2), Path); }
bool QueryPath(int X1, int Y1, int X2, int Y2, BS_Path &Path) {
return QueryPath(BS_Vertex(X1, Y1), BS_Vertex(X2, Y2), Path);
}
/**
@brief Ermittelt den kürzesten Weg zwischen zwei Punkten in der Region.
Diese Methode verlangt, dass der Startpunkt innerhalb der Region liegt. Der Endpunkt darf außerhalb der Region liegen. In diesem
Fall wählt die Methode als Endpunkt den Punkt innerhalb der Region, der am dichtesten am Endpunkt liegt.
@param StartPoint der Startpunkt
@param EndPoint der Endpunkt
@param Path ein leerer BS_Path, der den Ergebnispfad aufnehmen soll
@return Gibt false zurück, fall die Eingaben ungültig waren, ansonsten wird true zurückgegeben.
* Get the shortest path between two points in the region.
*
* @param StartPoint The start point
* @param EndPoint The end point
* @param Path An empty BS_Path that will be set to the resulting path
* @return Returns false if the result is invalid, otherwise returns true.
*/
bool QueryPath(BS_Vertex StartPoint, BS_Vertex EndPoint, BS_Path & Path);
virtual void SetPos(int X, int Y);
const std::vector<BS_Vertex> & GetNodes() const { return m_Nodes; }
const std::vector< std::vector<int> > & GetVisibilityMatrix() const { return m_VisibilityMatrix; }
const Common::Array<BS_Vertex> &GetNodes() const { return m_Nodes; }
const Common::Array< Common::Array<int> > &GetVisibilityMatrix() const { return m_VisibilityMatrix; }
virtual bool Persist(BS_OutputPersistenceBlock & Writer);
virtual bool Unpersist(BS_InputPersistenceBlock & Reader);
virtual bool Persist(BS_OutputPersistenceBlock &Writer);
virtual bool Unpersist(BS_InputPersistenceBlock &Reader);
private:
std::vector<BS_Vertex> m_Nodes;
std::vector< std::vector<int> > m_VisibilityMatrix;
Common::Array<BS_Vertex> m_Nodes;
Common::Array< Common::Array<int> > m_VisibilityMatrix;
void InitNodeVector();
void ComputeVisibilityMatrix();
bool CheckAndPrepareStartAndEnd(BS_Vertex & Start, BS_Vertex & End) const;
bool FindPath(const BS_Vertex & Start, const BS_Vertex & End, BS_Path & Path) const;
bool CheckAndPrepareStartAndEnd(BS_Vertex &Start, BS_Vertex &End) const;
bool FindPath(const BS_Vertex &Start, const BS_Vertex &End, BS_Path &Path) const;
};
} // End of namespace Sword25
#endif

View File

@ -540,7 +540,7 @@ bool BS_LuaScriptEngine::Unpersist(BS_InputPersistenceBlock &Reader) {
ClearGlobalTable(m_State, ClearExceptionsSecondPass);
// Persisted Lua data
vector<unsigned char> chunkData;
Common::Array<unsigned char> chunkData;
Reader.Read(chunkData);
// Chunk-Reader initialisation. It is used with pluto_unpersist to restore read data