zoomedit: C++ized Polygon

This commit is contained in:
neoraider 2007-09-16 19:06:02 +00:00
parent 01e98d51fe
commit 5ea7f0464e
14 changed files with 378 additions and 341 deletions

72
Line.cpp Normal file
View file

@ -0,0 +1,72 @@
#include "Line.h"
#include <math.h>
int lineIntersection(const LINE *la, const LINE *lb, Vertex *v) {
double xa1 = la->v1.getX(), ya1 = la->v1.getY();
double xa2 = la->v2.getX(), ya2 = la->v2.getY();
double xb1 = lb->v1.getX(), yb1 = lb->v1.getY();
double xb2 = lb->v2.getX(), yb2 = lb->v2.getY();
double temp;
int switched = 0;
Vertex v2;
if(!v) v = &v2;
if(xa1 == xa2 && ya1 == ya2) return INTERSECTION_ERROR;
if(xb1 == xb2 && yb1 == yb2) return INTERSECTION_ERROR;
if(xa1 == xa2 || xb1 == xb2) {
temp = xa1; xa1 = ya1; ya1 = temp;
temp = xa2; xa2 = ya2; ya2 = temp;
temp = xb1; xb1 = yb1; yb1 = temp;
temp = xb2; xb2 = yb2; yb2 = temp;
switched = 1;
}
if(xa1 == xa2 && xb1 == xb2)
return (xa1 == xb1) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
if(xa1 == xa2) {
v->setX(xa1);
v->setY(yb1);
}
else if(xb1 == xb2) {
v->setX(xb1);
v->setY(ya1);
}
else {
double ma = (ya2-ya1)/(xa2-xa1);
double mb = (yb2-yb1)/(xb2-xb1);
double ba = ya1 - ma*xa1;
double bb = yb1 - mb*xb1;
if(ma == mb) return (ba == bb) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
v->setX((bb-ba)/(ma-mb));
v->setY(ma*v->getX() + ba);
}
if(switched) {
temp = v->getX(); v->setX(v->getY()); v->setY(temp);
//switch back everything for segment tests
temp = xa1; xa1 = ya1; ya1 = temp;
temp = xa2; xa2 = ya2; ya2 = temp;
temp = xb1; xb1 = yb1; yb1 = temp;
temp = xb2; xb2 = yb2; yb2 = temp;
}
if(v->getX() < fmin(xa1,xa2) || v->getX() > fmax(xa1, xa2) || v->getY() < fmin(ya1,ya2) || v->getY() > fmax(ya1, ya2)) {
if(v->getX() < fmin(xb1,xb2) || v->getX() > fmax(xb1, xb2) || v->getY() < fmin(yb1,yb2) || v->getY() > fmax(yb1, yb2))
return INTERSECTION_LINE_LINE;
else
return INTERSECTION_LINE_SEGMENT;
}
else if(v->getX() < fmin(xb1,xb2) || v->getX() > fmax(xb1, xb2) || v->getY() < fmin(yb1,yb2) || v->getY() > fmax(yb1, yb2))
return INTERSECTION_SEGMENT_LINE;
else
return INTERSECTION_SEGMENT_SEGMENT;
}

23
Line.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef LINE_H_
#define LINE_H_
#include "Vertex.h"
#define INTERSECTION_ERROR -1
#define INTERSECTION_NONE 0
#define INTERSECTION_IDENTICAL 1
#define INTERSECTION_LINE 2
#define INTERSECTION_LINE_LINE 2
#define INTERSECTION_LINE_SEGMENT 3
#define INTERSECTION_SEGMENT_LINE 6
#define INTERSECTION_SEGMENT_SEGMENT 7
typedef struct _LINE {
Vertex v1, v2;
} LINE;
int lineIntersection(const LINE *la, const LINE *lb, Vertex *v);
#endif /*LINE_H_*/

View file

@ -1,4 +1,4 @@
bin_PROGRAMS = zoomedit
zoomedit_SOURCES = zoomedit.cpp window.cpp ui.cpp draw.cpp level.cpp geometry.cpp edit.cpp Vertex.cpp
zoomedit_SOURCES = zoomedit.cpp window.cpp ui.cpp draw.cpp level.cpp geometry.cpp edit.cpp Vertex.cpp Line.cpp Polygon.cpp
zoomedit_CPPFLAGS = @GTK_CFLAGS@
zoomedit_LDADD = @GTK_LIBS@

View file

@ -52,7 +52,8 @@ am_zoomedit_OBJECTS = zoomedit-zoomedit.$(OBJEXT) \
zoomedit-window.$(OBJEXT) zoomedit-ui.$(OBJEXT) \
zoomedit-draw.$(OBJEXT) zoomedit-level.$(OBJEXT) \
zoomedit-geometry.$(OBJEXT) zoomedit-edit.$(OBJEXT) \
zoomedit-Vertex.$(OBJEXT)
zoomedit-Vertex.$(OBJEXT) zoomedit-Line.$(OBJEXT) \
zoomedit-Polygon.$(OBJEXT)
zoomedit_OBJECTS = $(am_zoomedit_OBJECTS)
zoomedit_DEPENDENCIES =
DEFAULT_INCLUDES = -I.@am__isrc@
@ -170,7 +171,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
zoomedit_SOURCES = zoomedit.cpp window.cpp ui.cpp draw.cpp level.cpp geometry.cpp edit.cpp Vertex.cpp
zoomedit_SOURCES = zoomedit.cpp window.cpp ui.cpp draw.cpp level.cpp geometry.cpp edit.cpp Vertex.cpp Line.cpp Polygon.cpp
zoomedit_CPPFLAGS = @GTK_CFLAGS@
zoomedit_LDADD = @GTK_LIBS@
all: config.h
@ -261,6 +262,8 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-Line.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-Polygon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-Vertex.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-draw.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-edit.Po@am__quote@
@ -396,6 +399,34 @@ zoomedit-Vertex.obj: Vertex.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o zoomedit-Vertex.obj `if test -f 'Vertex.cpp'; then $(CYGPATH_W) 'Vertex.cpp'; else $(CYGPATH_W) '$(srcdir)/Vertex.cpp'; fi`
zoomedit-Line.o: Line.cpp
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT zoomedit-Line.o -MD -MP -MF $(DEPDIR)/zoomedit-Line.Tpo -c -o zoomedit-Line.o `test -f 'Line.cpp' || echo '$(srcdir)/'`Line.cpp
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/zoomedit-Line.Tpo $(DEPDIR)/zoomedit-Line.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Line.cpp' object='zoomedit-Line.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o zoomedit-Line.o `test -f 'Line.cpp' || echo '$(srcdir)/'`Line.cpp
zoomedit-Line.obj: Line.cpp
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT zoomedit-Line.obj -MD -MP -MF $(DEPDIR)/zoomedit-Line.Tpo -c -o zoomedit-Line.obj `if test -f 'Line.cpp'; then $(CYGPATH_W) 'Line.cpp'; else $(CYGPATH_W) '$(srcdir)/Line.cpp'; fi`
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/zoomedit-Line.Tpo $(DEPDIR)/zoomedit-Line.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Line.cpp' object='zoomedit-Line.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o zoomedit-Line.obj `if test -f 'Line.cpp'; then $(CYGPATH_W) 'Line.cpp'; else $(CYGPATH_W) '$(srcdir)/Line.cpp'; fi`
zoomedit-Polygon.o: Polygon.cpp
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT zoomedit-Polygon.o -MD -MP -MF $(DEPDIR)/zoomedit-Polygon.Tpo -c -o zoomedit-Polygon.o `test -f 'Polygon.cpp' || echo '$(srcdir)/'`Polygon.cpp
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/zoomedit-Polygon.Tpo $(DEPDIR)/zoomedit-Polygon.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Polygon.cpp' object='zoomedit-Polygon.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o zoomedit-Polygon.o `test -f 'Polygon.cpp' || echo '$(srcdir)/'`Polygon.cpp
zoomedit-Polygon.obj: Polygon.cpp
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT zoomedit-Polygon.obj -MD -MP -MF $(DEPDIR)/zoomedit-Polygon.Tpo -c -o zoomedit-Polygon.obj `if test -f 'Polygon.cpp'; then $(CYGPATH_W) 'Polygon.cpp'; else $(CYGPATH_W) '$(srcdir)/Polygon.cpp'; fi`
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/zoomedit-Polygon.Tpo $(DEPDIR)/zoomedit-Polygon.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Polygon.cpp' object='zoomedit-Polygon.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(zoomedit_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o zoomedit-Polygon.obj `if test -f 'Polygon.cpp'; then $(CYGPATH_W) 'Polygon.cpp'; else $(CYGPATH_W) '$(srcdir)/Polygon.cpp'; fi`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \

118
Polygon.cpp Normal file
View file

@ -0,0 +1,118 @@
#include "Polygon.h"
#include <math.h>
double Polygon::area() const {
double d = 0.0;
for(const_iterator it = begin(); it != end(); it++) {
const_iterator it2 = it+1;
if(it2 == end()) it2 = begin();
d += (it2->getX()+it->getX())*(it2->getY()-it->getY());
}
return fabs(d/2);
}
double Polygon::perimeter() const {
double d = 0.0;
for(const_iterator it = begin(); it != end(); it++) {
const_iterator it2 = it+1;
if(it2 == end()) it2 = begin();
d += it->distance(*it2);
}
return d;
}
int Polygon::quadrant(const Vertex &v) const {
if(v.getX() > 0 && v.getY() >= 0) return 1;
if(v.getX() >= 0 && v.getY() < 0) return 2;
if(v.getX() < 0 && v.getY() <= 0) return 3;
if(v.getX() <= 0 && v.getY() > 0) return 4;
return 0;
}
bool Polygon::contains(const Vertex &v) const {
int d = 0;
int q, ql, q2;
LINE d1 = {Vertex(-1, -1), Vertex(1, 1)};
LINE d2 = {Vertex(-1, 1), Vertex(1, -1)};
LINE l;
Vertex v2;
if(empty()) return false;
v2 = back() - v;
q = quadrant(v2);
if(q == 0) return true;
for(const_iterator it = begin(); it != end(); it++) {
ql = q;
v2 = *it - v;
q = quadrant(v2);
if(q == 0) return true;
switch(q-ql) {
case 0:
break;
case 1:
case -3:
d++;
break;
case 3:
case -1:
d--;
break;
default:
l.v1 = ((it == begin()) ? back() : *(it-1)) - v;
l.v2 = v2;
if(q == 1 || q == 3) {
if(!(lineIntersection(&l, &d2, &v2) & INTERSECTION_LINE)) return false;
q2 = quadrant(v2);
if(q2 == 0) return true;
if((q == 1 && q2 == 2) || (q == 3 && q2 == 4)) d -= 2;
else d += 2;
}
else {
if(!(lineIntersection(&l, &d1, &v2) & INTERSECTION_LINE)) return false;
q2 = quadrant(v2);
if(q2 == 0) return true;
if((q == 2 && q2 == 3) || (q == 4 && q2 == 1)) d -= 2;
else d += 2;
}
}
}
return (d != 0);
}
bool Polygon::intersects(const LINE *l) const {
LINE line;
for(Polygon::const_iterator it = begin(); it != end(); it++) {
Polygon::const_iterator it2 = it+1;
if(it2 == end()) it2 = begin();
line.v1 = *it;
line.v2 = *it2;
if(lineIntersection(l, &line, NULL) == INTERSECTION_SEGMENT_SEGMENT)
return true;
}
return false;
}

19
Polygon.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef POLYGON_H_
#define POLYGON_H_
#include "Vertex.h"
#include "Line.h"
#include <vector>
class Polygon : public std::vector<Vertex> {
private:
int quadrant(const Vertex &v) const;
public:
double area() const;
double perimeter() const;
bool contains(const Vertex &v) const;
bool intersects(const LINE *l) const;
};
#endif /*POLYGON_H_*/

View file

@ -68,31 +68,27 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
}
}
static void polygon2path(cairo_t *cr, const POLYGON *polygon, const RECTANGLE *rect, gboolean close) {
int i;
POLYGON polygon2 = {0, NULL};
static void polygon2path(cairo_t *cr, const Polygon *polygon, const RECTANGLE *rect, gboolean close) {
Polygon polygon2;
// no vertices
if(polygon->nVertices == 0) return;
if(polygon->empty()) return;
if(rect)
simplifyPolygon(polygon, rect, &polygon2);
else
polygon2 = *polygon;
if(polygon2.nVertices == 0) return;
if(polygon2.empty()) return;
cairo_new_sub_path(cr);
for(i = 0; i < polygon2.nVertices; i++) {
cairo_line_to(cr, polygon2.vertices[i].getX(), polygon2.vertices[i].getY());
for(Polygon::iterator it = polygon2.begin(); it != polygon2.end(); it++) {
cairo_line_to(cr, it->getX(), it->getY());
}
if(close)
cairo_close_path(cr);
if(rect && polygon2.vertices)
free(polygon2.vertices);
}
gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
@ -201,7 +197,7 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_fill_preserve(cr);
if(getActiveRoom()->polygon.nVertices && getHoveredVertex()) {
if(!getActiveRoom()->polygon.empty() && getHoveredVertex()) {
vertexOk = isVertexOk(getHoveredVertex());
if(vertexOk)
@ -214,11 +210,10 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr);
if(getActiveRoom()->polygon.nVertices && getHoveredVertex() && !vertexOk) {
if(!getActiveRoom()->polygon.empty() && getHoveredVertex() && !vertexOk) {
cairo_set_source_rgba(cr, 1.0, 0.3, 0.3, 0.7);
i = getActiveRoom()->polygon.nVertices - 1;
cairo_move_to(cr, getActiveRoom()->polygon.vertices[i].getX(), getActiveRoom()->polygon.vertices[i].getY());
cairo_move_to(cr, getActiveRoom()->polygon.back().getX(), getActiveRoom()->polygon.back().getY());
cairo_line_to(cr, getHoveredVertex()->getX(), getHoveredVertex()->getY());
cairo_stroke(cr);
@ -253,13 +248,14 @@ void viewToImage(Vertex *v) {
double getImageWidth() {
const LEVEL *level = getLevel();
double min = 0.0, max = 0.0;
int i, j;
int i;
if(level) {
for(i = 0; i < level->nRooms; i++) {
for(j = 0; j < level->rooms[i].polygon.nVertices; j++) {
min = MIN(min, level->rooms[i].polygon.vertices[j].getX());
max = MAX(max, level->rooms[i].polygon.vertices[j].getX());
for(Polygon::iterator it = level->rooms[i].polygon.begin(); it != level->rooms[i].polygon.end(); it++) {
min = MIN(min, it->getX());
max = MAX(max, it->getX());
}
}
}
@ -270,13 +266,13 @@ double getImageWidth() {
double getImageHeight() {
const LEVEL *level = getLevel();
double min = 0.0, max = 0.0;
int i, j;
int i;
if(level) {
for(i = 0; i < level->nRooms; i++) {
for(j = 0; j < level->rooms[i].polygon.nVertices; j++) {
min = MIN(min, level->rooms[i].polygon.vertices[j].getY());
max = MAX(max, level->rooms[i].polygon.vertices[j].getY());
for(Polygon::iterator it = level->rooms[i].polygon.begin(); it != level->rooms[i].polygon.end(); it++) {
min = MIN(min, it->getY());
max = MAX(max, it->getY());
}
}
}

101
edit.cpp
View file

@ -1,7 +1,6 @@
#include "edit.h"
#include "level.h"
#include "geometry.h"
#include <stdlib.h>
static int editMode = EDIT_MODE_VIEW;
@ -48,9 +47,9 @@ void setHoveredVertex(Vertex *v) {
hoveredRoom = NULL;
for(i = 0; i < l->nRooms; i++) {
if(vertexInPolygon(v, &l->rooms[i].polygon)) {
//hoveredRoom = &l->rooms[i];
//break;
if(l->rooms[i].polygon.contains(*v)) {
hoveredRoom = &l->rooms[i];
break;
}
}
}
@ -62,8 +61,7 @@ void setHoveredVertex(Vertex *v) {
void startAddMode() {
activeRoom = (ROOM*)calloc(1, sizeof(ROOM));
activeRoom->polygon.nVertices = 0;
activeRoom->polygon.vertices = NULL;
activeRoom->polygon = Polygon();
activeRoom->name = (char*)calloc(1, sizeof(unsigned char));
editMode = EDIT_MODE_ADD;
@ -77,48 +75,48 @@ ROOM *getHoveredRoom() {
return hoveredRoom;
}
static int isLineOk(LINE *l) {
static bool isLineOk(LINE *l) {
LEVEL *lvl = getLevel();
LINE l2;
int i;
if(activeRoom) {
for(i = 0; i+2 < activeRoom->polygon.nVertices; i++) {
l2.v1 = activeRoom->polygon.vertices[i];
l2.v2 = activeRoom->polygon.vertices[i+1];
for(int i = 0; i+2 < activeRoom->polygon.size(); i++) {
l2.v1 = activeRoom->polygon[i];
l2.v2 = activeRoom->polygon[i+1];
if(lineIntersection(l, &l2, NULL) == INTERSECTION_SEGMENT_SEGMENT) return 0;
if(lineIntersection(l, &l2, NULL) == INTERSECTION_SEGMENT_SEGMENT) return false;
}
if(activeRoom->polygon.nVertices > 1) {
l2.v1 = activeRoom->polygon.vertices[activeRoom->polygon.nVertices-2];
l2.v2 = activeRoom->polygon.vertices[activeRoom->polygon.nVertices-1];
if(vertexOnLine(&l->v2, &l2)) return 0;
if(activeRoom->polygon.size() > 1) {
l2.v1 = activeRoom->polygon[activeRoom->polygon.size()-2];
l2.v2 = activeRoom->polygon.back();
if(vertexOnLine(&l->v2, &l2)) return false;
}
}
for(i = 0; i < lvl->nRooms; i++) {
if(linePolygonIntersection(l, &lvl->rooms[i].polygon))
return 0;
for(int i = 0; i < lvl->nRooms; i++) {
if(lvl->rooms[i].polygon.intersects(l))
return false;
}
return 1;
return true;
}
int isVertexOk(Vertex *v) {
bool isVertexOk(Vertex *v) {
LEVEL *lvl = getLevel();
LINE l;
int i;
for(i = 0; i < lvl->nRooms; i++) {
if(vertexInPolygon(v, &lvl->rooms[i].polygon)) return 0;
if(lvl->rooms[i].polygon.contains(*v)) return false;
}
if(!(getActiveRoom() && getActiveRoom()->polygon.nVertices))
return 1;
if(!(getActiveRoom() && !getActiveRoom()->polygon.empty()))
return true;
l.v1 = getActiveRoom()->polygon.vertices[getActiveRoom()->polygon.nVertices-1];
l.v1 = getActiveRoom()->polygon.back();
l.v2 = *v;
return isLineOk(&l);
@ -126,45 +124,52 @@ int isVertexOk(Vertex *v) {
int isPolygonOk(POLYGON *polygon) {
bool isPolygonOk(Polygon *polygon) {
LEVEL *lvl = getLevel();
LINE l, l2;
int i, j;
if(!polygon->nVertices) return 0;
if(polygon->empty()) return false;
for(i = 0; i < lvl->nRooms; i++) {
if(!lvl->rooms[i].polygon.nVertices) continue;
for(int i = 0; i < lvl->nRooms; i++) {
if(lvl->rooms[i].polygon.empty()) continue;
if(vertexInPolygon(&polygon->vertices[0], &lvl->rooms[i].polygon))
return 0;
if(lvl->rooms[i].polygon.contains(polygon->front()));
return false;
if(vertexInPolygon(&lvl->rooms[i].polygon.vertices[0], polygon))
return 0;
if(polygon->contains(lvl->rooms[i].polygon.front()));
return false;
}
if(polygon->nVertices == 1)
return 1;
if(polygon->size() == 1)
return true;
for(i = 0; i < polygon->nVertices; i++) {
l.v1 = polygon->vertices[i];
l.v2 = polygon->vertices[(i+1)%polygon->nVertices];
for(Polygon::const_iterator it = polygon->begin(); it != polygon->end(); it++) {
Polygon::const_iterator it2 = it+1;
if(it2 == polygon->end()) it2 = polygon->begin();
for(j = 0; j < lvl->nRooms; j++) {
if(linePolygonIntersection(&l, &lvl->rooms[j].polygon))
return 0;
l.v1 = *it;
l.v2 = *it2;
for(int i = 0; i < lvl->nRooms; i++) {
if(lvl->rooms[i].polygon.intersects(&l))
return false;
}
for(j = i+2; j < polygon->nVertices; j++) {
if(i == 0 && j == polygon->nVertices-1) continue;
if(it2 != polygon->begin()) {
for(Polygon::const_iterator it3 = it2+1; it3 != polygon->end(); it3++) {
Polygon::const_iterator it4 = it3+1;
if(it4 == polygon->end()) it4 = polygon->begin();
l2.v1 = polygon->vertices[j];
l2.v2 = polygon->vertices[(j+1)%polygon->nVertices];
if(it == polygon->begin() && it4 == polygon->begin()) continue;
l2.v1 = *it3;
l2.v2 = *it4;
if(lineIntersection(&l, &l2, NULL) == INTERSECTION_SEGMENT_SEGMENT)
return 0;
return false;
}
}
}
return 1;
return true;
}

4
edit.h
View file

@ -21,7 +21,7 @@ ROOM *getHoveredRoom();
Vertex *getHoveredVertex();
void setHoveredVertex(Vertex *v);
int isVertexOk(Vertex *v);
int isPolygonOk(POLYGON *polygon);
bool isVertexOk(Vertex *v);
bool isPolygonOk(Polygon *polygon);
#endif /*EDIT_H_*/

View file

@ -4,39 +4,6 @@
#include <gtk/gtk.h>
void addVertex(VERTEX_LIST *list, const Vertex *v) {
list->nVertices++;
list->vertices = (Vertex*)realloc(list->vertices, list->nVertices*sizeof(Vertex));
list->vertices[list->nVertices-1] = *v;
}
void insertVertex(VERTEX_LIST *list, const Vertex *v, unsigned int n) {
int i;
if(n > list->nVertices)
n = list->nVertices;
list->nVertices++;
list->vertices = (Vertex*)realloc(list->vertices, list->nVertices*sizeof(Vertex));
for(i = list->nVertices-1; i > n; i--)
list->vertices[i] = list->vertices[i-1];
list->vertices[n] = *v;
}
void deleteVertex(VERTEX_LIST *list, unsigned int n) {
int i;
list->nVertices--;
for(i = n; i < list->nVertices; i++)
list->vertices[i] = list->vertices[i+1];
list->vertices = (Vertex*)realloc(list->vertices, list->nVertices*sizeof(Vertex));
}
int vertexOnLine(const Vertex *v, const LINE *l) {
if(l->v1.getX() == l->v2.getX() && l->v1.getY() == l->v2.getY()) {
if(l->v1.getX() == v->getX() && l->v1.getY() == v->getY()) return 1;
@ -70,166 +37,6 @@ int vertexInRect(const Vertex *v, const RECTANGLE *rect) {
return ret;
}
static int quadrant(Vertex *v) {
if(v->getX() > 0 && v->getY() >= 0) return 1;
if(v->getX() >= 0 && v->getY() < 0) return 2;
if(v->getX() < 0 && v->getY() <= 0) return 3;
if(v->getX() <= 0 && v->getY() > 0) return 4;
return 0;
}
gboolean vertexInPolygon(const Vertex *v, const POLYGON *p) {
int d = 0, i, li;
int q, ql, q2;
LINE d1 = {Vertex(-1, -1), Vertex(1, 1)};
LINE d2 = {Vertex(-1, 1), Vertex(1, -1)};
LINE l;
Vertex v2;
if(p->nVertices == 0) return FALSE;
v2 = p->vertices[p->nVertices-1] - *v;
q = quadrant(&v2);
if(q == 0) return TRUE;
for(i = 0; i < p->nVertices; i++) {
ql = q;
v2 = p->vertices[i] - *v;
if(q == 0) return TRUE;
switch(q-ql) {
case 0:
break;
case 1:
case -3:
d++;
break;
case 3:
case -1:
d--;
break;
default:
l.v1 = p->vertices[(i>0)?i-1:p->nVertices-1] - *v;
l.v2 = v2;
if(q == 1 || q == 3) {
if(!(lineIntersection(&l, &d2, &v2) & INTERSECTION_LINE)) return FALSE;
q2 = quadrant(&v2);
if(q2 == 0) return TRUE;
if((q == 1 && q2 == 2) || (q == 3 && q2 == 4)) d -= 2;
else d += 2;
}
else {
if(!(lineIntersection(&l, &d1, &v2) & INTERSECTION_LINE)) return FALSE;
q2 = quadrant(&v2);
if(q2 == 0) return TRUE;
if((q == 2 && q2 == 3) || (q == 4 && q2 == 1)) d -= 2;
else d += 2;
}
}
}
return (d == 0) ? FALSE : TRUE;
}
double polygonPerimeter(const POLYGON *p) {
int i;
double d = 0.0;
for(i = 0; i < p->nVertices; i++)
d += p->vertices[i].distance(p->vertices[(i+1)%p->nVertices]);
return d;
}
double polygonArea(const POLYGON *p) {
int i;
double d = 0.0;
for(i = 0; i < p->nVertices; i++)
d += (p->vertices[(i+1)%p->nVertices].getX()+p->vertices[i].getX())*(p->vertices[(i+1)%p->nVertices].getY()-p->vertices[i].getY());
return fabs(d/2);
}
int lineIntersection(const LINE *la, const LINE *lb, Vertex *v) {
double xa1 = la->v1.getX(), ya1 = la->v1.getY();
double xa2 = la->v2.getX(), ya2 = la->v2.getY();
double xb1 = lb->v1.getX(), yb1 = lb->v1.getY();
double xb2 = lb->v2.getX(), yb2 = lb->v2.getY();
double temp;
int switched = 0;
Vertex v2;
if(v == NULL) v = &v2;
if(xa1 == xa2 && ya1 == ya2) return INTERSECTION_ERROR;
if(xb1 == xb2 && yb1 == yb2) return INTERSECTION_ERROR;
if(xa1 == xa2 || xb1 == xb2) {
temp = xa1; xa1 = ya1; ya1 = temp;
temp = xa2; xa2 = ya2; ya2 = temp;
temp = xb1; xb1 = yb1; yb1 = temp;
temp = xb2; xb2 = yb2; yb2 = temp;
switched = 1;
}
if(xa1 == xa2 && xb1 == xb2)
return (xa1 == xb1) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
if(xa1 == xa2) {
v->setX(xa1);
v->setY(yb1);
}
else if(xb1 == xb2) {
v->setX(xb1);
v->setY(ya1);
}
else {
double ma = (ya2-ya1)/(xa2-xa1);
double mb = (yb2-yb1)/(xb2-xb1);
double ba = ya1 - ma*xa1;
double bb = yb1 - mb*xb1;
if(ma == mb) return (ba == bb) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
v->setX((bb-ba)/(ma-mb));
v->setY(ma*v->getX() + ba);
}
if(switched) {
temp = v->getX(); v->setX(v->getY()); v->setY(temp);
//switch back everything for segment tests
temp = xa1; xa1 = ya1; ya1 = temp;
temp = xa2; xa2 = ya2; ya2 = temp;
temp = xb1; xb1 = yb1; yb1 = temp;
temp = xb2; xb2 = yb2; yb2 = temp;
}
if(v->getX() < MIN(xa1,xa2) || v->getX() > MAX(xa1, xa2) || v->getY() < MIN(ya1,ya2) || v->getY() > MAX(ya1, ya2)) {
if(v->getX() < MIN(xb1,xb2) || v->getX() > MAX(xb1, xb2) || v->getY() < MIN(yb1,yb2) || v->getY() > MAX(yb1, yb2))
return INTERSECTION_LINE_LINE;
else
return INTERSECTION_LINE_SEGMENT;
}
else if(v->getX() < MIN(xb1,xb2) || v->getX() > MAX(xb1, xb2) || v->getY() < MIN(yb1,yb2) || v->getY() > MAX(yb1, yb2))
return INTERSECTION_SEGMENT_LINE;
else
return INTERSECTION_SEGMENT_SEGMENT;
}
int lineRectIntersection(const LINE *l, const RECTANGLE *rect, int edge, Vertex *v) {
const double minX = rect->x, maxX = rect->x+rect->width;
@ -262,21 +69,6 @@ int lineRectIntersections(const LINE *line, const RECTANGLE *rect, int edge, Ver
return ret;
}
gboolean linePolygonIntersection(const LINE *l, const POLYGON *p) {
int i;
LINE line;
for(i = 0; i < p->nVertices; i++) {
line.v1 = p->vertices[i];
line.v2 = p->vertices[(i+1)%p->nVertices];
if(lineIntersection(l, &line, NULL) == INTERSECTION_SEGMENT_SEGMENT)
return TRUE;
}
return FALSE;
}
static void edgeVertex(Vertex *v, int edge, const RECTANGLE *rect) {
if(edge == EDGE_NONE)
@ -306,7 +98,7 @@ static int simplifyVertex(Vertex *v, const Vertex *to, const RECTANGLE *rect) {
static void addSimplifiedLine(const Vertex *v1, const Vertex *v2, const RECTANGLE *rect, int last, POLYGON *out) {
static void addSimplifiedLine(const Vertex *v1, const Vertex *v2, const RECTANGLE *rect, int last, Polygon *out) {
const LINE d1 = {Vertex(rect->x, rect->y), Vertex(rect->x+rect->width, rect->y+rect->height)};
const LINE d2 = {Vertex(rect->x, rect->y+rect->height), Vertex(rect->x+rect->width, rect->y)};
@ -317,7 +109,7 @@ static void addSimplifiedLine(const Vertex *v1, const Vertex *v2, const RECTANGL
v = *v1;
if((edge1 = simplifyVertex(&v, v2, rect)) != EDGE_NONE)
addVertex(out, &v);
out->push_back(v);
v = *v2;
edge2 = simplifyVertex(&v, v1, rect);
@ -325,33 +117,35 @@ static void addSimplifiedLine(const Vertex *v1, const Vertex *v2, const RECTANGL
if(edge1 != EDGE_NONE && edge2 != EDGE_NONE && !(edge1 & edge2)) {
if(lineIntersection(&l, &d1, &vi) == INTERSECTION_SEGMENT_LINE) {
edgeVertex(&vi, 0, rect);
addVertex(out, &vi);
out->push_back(vi);
}
else if(lineIntersection(&l, &d2, &vi) == INTERSECTION_SEGMENT_LINE) {
edgeVertex(&vi, 0, rect);
addVertex(out, &vi);
out->push_back(vi);
}
}
if(!last)
addVertex(out, &v);
out->push_back(v);
}
void simplifyPolygon(const POLYGON *in, const RECTANGLE *rect, POLYGON *out) {
void simplifyPolygon(const Polygon *in, const RECTANGLE *rect, Polygon *out) {
Vertex v;
int i;
if(in->nVertices == 0) return;
else if(in->nVertices == 1) {
addVertex(out, &in->vertices[0]);
if(in->empty()) return;
else if(in->size() == 1) {
out->push_back(in->front());
return;
}
v = in->vertices[0];
simplifyVertex(&v, &in->vertices[in->nVertices-1], rect);
addVertex(out, &v);
v = in->front();
simplifyVertex(&v, &in->back(), rect);
out->push_back(v);
for(i = 0; i < in->nVertices; i++) {
addSimplifiedLine(&in->vertices[i], &in->vertices[(i+1)%in->nVertices], rect, (i == in->nVertices-1), out);
for(Polygon::const_iterator it = in->begin(); it != in->end(); it++) {
Polygon::const_iterator it2 = it+1;
if(it2 == in->end()) it2 = in->begin();
addSimplifiedLine(&*it, &*it2, rect, (it2 == in->begin()), out);
}
}

View file

@ -3,6 +3,8 @@
#include "Vertex.h"
#include "Polygon.h"
#include "Line.h"
#include <glib.h>
#define EDGE_NONE 0
@ -12,45 +14,21 @@
#define EDGE_BOTTOM (1<<3)
#define EDGE_ALL (EDGE_LEFT|EDGE_RIGHT|EDGE_TOP|EDGE_BOTTOM)
#define INTERSECTION_ERROR -1
#define INTERSECTION_NONE 0
#define INTERSECTION_IDENTICAL 1
#define INTERSECTION_LINE 2
#define INTERSECTION_LINE_LINE 2
#define INTERSECTION_LINE_SEGMENT 3
#define INTERSECTION_SEGMENT_LINE 6
#define INTERSECTION_SEGMENT_SEGMENT 7
typedef struct _RECTANGLE {
double x, y, width, height;
} RECTANGLE;
typedef struct _LINE {
Vertex v1, v2;
} LINE;
typedef struct _VERTEX_LIST {
unsigned int nVertices;
Vertex *vertices;
} VERTEX_LIST, POLYGON;
void addVertex(VERTEX_LIST *list, const Vertex *v);
void insertVertex(VERTEX_LIST *list, const Vertex *v, unsigned int n);
void deleteVertex(VERTEX_LIST *list, unsigned int n);
int vertexOnLine(const Vertex *v, const LINE *l);
int vertexInRect(const Vertex *v, const RECTANGLE *rect);
gboolean vertexInPolygon(const Vertex *v, const POLYGON *p);
double polygonPerimeter(const POLYGON *p);
double polygonArea(const POLYGON *p);
int lineIntersection(const LINE *la, const LINE *lb, Vertex *v);
int lineRectIntersection(const LINE *l, const RECTANGLE *rect, int edge, Vertex *v);
int lineRectIntersections(const LINE *line, const RECTANGLE *rect, int edge, Vertex *v1, Vertex *v2);
gboolean linePolygonIntersection(const LINE *l, const POLYGON *p);
void simplifyPolygon(const POLYGON *in, const RECTANGLE *rect, POLYGON *out);
//gboolean linePolygonIntersection(const LINE *l, const POLYGON *p);
void simplifyPolygon(const Polygon *in, const RECTANGLE *rect, Polygon *out);
#endif /*GEOMETRY_H_*/

View file

@ -15,7 +15,10 @@ void setLevel(LEVEL *l) {
void addRoom(LEVEL *lvl, const ROOM *room) {
lvl->nRooms++;
if(lvl->nRooms > 1)
lvl->rooms = (ROOM*)realloc(lvl->rooms, lvl->nRooms*sizeof(ROOM));
else
lvl->rooms = (ROOM*)calloc(1, sizeof(ROOM));
lvl->rooms[lvl->nRooms-1] = *room;
}
@ -36,9 +39,6 @@ void freeLevel(LEVEL *lvl) {
if(lvl) {
if(lvl->rooms) {
for(i = 0; i < lvl->nRooms; i++) {
if(lvl->rooms[i].polygon.vertices)
free(lvl->rooms[i].polygon.vertices);
if(lvl->rooms[i].name)
free(lvl->rooms[i].name);
}

View file

@ -2,9 +2,10 @@
#define LEVEL_H_
#include "geometry.h"
#include "Polygon.h"
typedef struct _ROOM {
POLYGON polygon;
Polygon polygon;
char *name;
} ROOM;

View file

@ -52,7 +52,7 @@ static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer u
viewToImage(&v);
if(isVertexOk(&v)) {
addVertex(&getActiveRoom()->polygon, &v);
getActiveRoom()->polygon.push_back(v);
updateSidebar();
}
}
@ -68,6 +68,7 @@ gboolean crossingNotifyEvent(GtkWidget *widget, GdkEventCrossing *event, gpointe
Vertex v(event->x, event->y);
switch(event->type) {
case GDK_ENTER_NOTIFY:
viewToImage(&v);
@ -87,7 +88,6 @@ gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer us
Vertex v(event->x, event->y);
ROOM *last = getHoveredRoom();
viewToImage(&v);
setHoveredVertex(&v);
@ -165,7 +165,7 @@ static void sidebarButtonClicked(GtkButton *button, gpointer user_data) {
gtk_widget_queue_draw(drawingArea);
}
else if(button == GTK_BUTTON(buttonAddDo)) {
if(getActiveRoom() &&getActiveRoom()->polygon.nVertices > 2 && isPolygonOk(&getActiveRoom()->polygon)) {
if(getActiveRoom() && getActiveRoom()->polygon.size() > 2 && isPolygonOk(&getActiveRoom()->polygon)) {
addRoom(getLevel(), getActiveRoom());
setActiveRoom(&getLevel()->rooms[getLevel()->nRooms-1]);
}
@ -313,11 +313,11 @@ void updateSidebar() {
gtk_entry_set_text(GTK_ENTRY(entryName), getActiveRoom()->name);
gtk_widget_set_sensitive(entryName, TRUE);
string = g_strdup_printf("%.2f", polygonArea(&getActiveRoom()->polygon));
string = g_strdup_printf("%.2f", getActiveRoom()->polygon.area());
gtk_label_set_text(GTK_LABEL(labelArea), string);
g_free(string);
string = g_strdup_printf("%.2f", polygonPerimeter(&getActiveRoom()->polygon));
string = g_strdup_printf("%.2f", getActiveRoom()->polygon.perimeter());
gtk_label_set_text(GTK_LABEL(labelPerimeter), string);
g_free(string);
}
@ -335,7 +335,7 @@ void updateSidebar() {
gtk_widget_show(sidebarAdd);
if(getActiveRoom()) {
if(getActiveRoom()->polygon.nVertices > 2 && isPolygonOk(&getActiveRoom()->polygon))
if(getActiveRoom()->polygon.size() > 2 && isPolygonOk(&getActiveRoom()->polygon))
gtk_widget_set_sensitive(buttonAddDo, TRUE);
else
gtk_widget_set_sensitive(buttonAddDo, FALSE);