mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-07 02:39:56 +00:00
SWORD25: Converted the math folder files
svn-id: r53197
This commit is contained in:
parent
2f86c7a45c
commit
53a9d2d0a1
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user