summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--draw.c63
-rw-r--r--edit.c2
-rw-r--r--geometry.c21
-rw-r--r--geometry.h6
-rw-r--r--level.c7
-rw-r--r--level.h5
-rw-r--r--window.c103
-rw-r--r--window.h2
-rw-r--r--zoomedit.c7
9 files changed, 167 insertions, 49 deletions
diff --git a/draw.c b/draw.c
index d91449c..7ce0d7f 100644
--- a/draw.c
+++ b/draw.c
@@ -4,7 +4,6 @@
#include "geometry.h"
#include <math.h>
#include <gtk/gtk.h>
-#include <glib/gprintf.h>
#include <cairo/cairo.h>
@@ -19,7 +18,7 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
double step = pow(0.1, depth2);
double d;
int i;
- gchar buffer[20];
+ gchar *string;
cairo_set_font_size(cr, 10.0/scale);
@@ -32,13 +31,15 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
cairo_move_to(cr, d, rect->y);
cairo_line_to(cr, d, rect->y+rect->height);
- if(step > 0.2)
- g_snprintf(buffer, sizeof(buffer), "%i", (int)rint(d));
+ if(step > 0.5)
+ string = g_strdup_printf("%i", (int)rint(d));
else
- g_snprintf(buffer, sizeof(buffer), "%.*f", -(int)floor(log10(step*1.1)), d+step/10);
- buffer[sizeof(buffer)-1] = '\0';
+ string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
+
cairo_move_to(cr, d+1/scale, rect->y+11/scale);
- cairo_show_text(cr, buffer);
+ cairo_show_text(cr, string);
+
+ g_free(string);
}
for(d = rect->y - fmod(rect->y, step) - step; d <= rect->y+rect->height; d+=step) {
@@ -46,12 +47,14 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
cairo_line_to(cr, rect->x+rect->width, d);
if(step > 0.5)
- g_snprintf(buffer, sizeof(buffer), "%i", (int)rint(d));
+ string = g_strdup_printf("%i", (int)rint(d));
else
- g_snprintf(buffer, sizeof(buffer), "%.*f", -(int)floor(log10(step*1.1)), d+step/10);
- buffer[sizeof(buffer)-1] = '\0';
+ string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
+
cairo_move_to(cr, rect->x+3/scale, d+11/scale);
- cairo_show_text(cr, buffer);
+ cairo_show_text(cr, string);
+
+ g_free(string);
}
cairo_stroke(cr);
@@ -60,30 +63,30 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
}
}
-static void room2path(cairo_t *cr, const ROOM *room, const RECTANGLE *rect) {
+static void polygon2path(cairo_t *cr, const POLYGON *polygon, const RECTANGLE *rect) {
int i;
- ROOM room2 = {0, NULL};
+ POLYGON polygon2 = {0, NULL};
// no vertices
- if(room->nVertices == 0) return;
+ if(polygon->nVertices == 0) return;
if(rect)
- simplifyPolygon(room, rect, &room2);
+ simplifyPolygon(polygon, rect, &polygon2);
else
- room2 = *room;
+ polygon2 = *polygon;
- if(room2.nVertices == 0) return;
+ if(polygon2.nVertices == 0) return;
cairo_new_sub_path(cr);
- for(i = 0; i < room2.nVertices; i++) {
- cairo_line_to(cr, room2.vertices[i].x, room2.vertices[i].y);
+ for(i = 0; i < polygon2.nVertices; i++) {
+ cairo_line_to(cr, polygon2.vertices[i].x, polygon2.vertices[i].y);
}
cairo_close_path(cr);
- if(rect && room2.vertices)
- free(room2.vertices);
+ if(rect && polygon2.vertices)
+ free(polygon2.vertices);
}
gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
@@ -135,7 +138,7 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
for(i = 0; i < getLevel()->nRooms; i++) {
if(&getLevel()->rooms[i] != getActiveRoom())
- room2path(cr, &getLevel()->rooms[i], &rect);
+ polygon2path(cr, &getLevel()->rooms[i].polygon, &rect);
}
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.3);
@@ -145,7 +148,7 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_stroke(cr);
if(getEditMode() == EDIT_MODE_SELECTED) {
- room2path(cr, getActiveRoom(), &rect);
+ polygon2path(cr, &getActiveRoom()->polygon, &rect);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2);
cairo_fill_preserve(cr);
@@ -171,7 +174,7 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_set_line_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
- room2path(cr, getHoveredRoom(), &rect);
+ polygon2path(cr, &getHoveredRoom()->polygon, &rect);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr);
@@ -209,9 +212,9 @@ double getImageWidth() {
if(level) {
for(i = 0; i < level->nRooms; i++) {
- for(j = 0; j < level->rooms[i].nVertices; j++) {
- min = MIN(min, level->rooms[i].vertices[j].x);
- max = MAX(max, level->rooms[i].vertices[j].x);
+ for(j = 0; j < level->rooms[i].polygon.nVertices; j++) {
+ min = MIN(min, level->rooms[i].polygon.vertices[j].x);
+ max = MAX(max, level->rooms[i].polygon.vertices[j].x);
}
}
}
@@ -226,9 +229,9 @@ double getImageHeight() {
if(level) {
for(i = 0; i < level->nRooms; i++) {
- for(j = 0; j < level->rooms[i].nVertices; j++) {
- min = MIN(min, level->rooms[i].vertices[j].y);
- max = MAX(max, level->rooms[i].vertices[j].y);
+ for(j = 0; j < level->rooms[i].polygon.nVertices; j++) {
+ min = MIN(min, level->rooms[i].polygon.vertices[j].y);
+ max = MAX(max, level->rooms[i].polygon.vertices[j].y);
}
}
}
diff --git a/edit.c b/edit.c
index c234364..bb20d89 100644
--- a/edit.c
+++ b/edit.c
@@ -6,11 +6,11 @@ static int editMode = EDIT_MODE_VIEW;
static ROOM *activeRoom = NULL;
static ROOM *hoveredRoom = NULL;
+
int getEditMode() {
return editMode;
}
-
ROOM *getActiveRoom() {
return activeRoom;
}
diff --git a/geometry.c b/geometry.c
index 057fea0..248f354 100644
--- a/geometry.c
+++ b/geometry.c
@@ -44,7 +44,6 @@ double vertexDistance(const VERTEX *v1, const VERTEX *v2) {
return sqrt(vertexDistanceSquare(v1, v2));
}
-
int vertexInRect(const VERTEX *v, const RECTANGLE *rect) {
int ret = EDGE_NONE;
@@ -133,6 +132,26 @@ gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p) {
return (d == 0) ? FALSE : TRUE;
}
+double polygonPerimeter(const POLYGON *p) {
+ int i;
+ double d = 0.0;
+
+ for(i = 0; i < p->nVertices; i++)
+ d += vertexDistance(&p->vertices[i], &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].x+p->vertices[i].x)*(p->vertices[(i+1)%p->nVertices].y-p->vertices[i].y);
+
+ return d/2;
+}
+
int lineIntersection(const LINE *la, const LINE *lb, VERTEX *v) {
double xa1 = la->v1.x, ya1 = la->v1.y;
double xa2 = la->v2.x, ya2 = la->v2.y;
diff --git a/geometry.h b/geometry.h
index 2978ef4..c32b3ea 100644
--- a/geometry.h
+++ b/geometry.h
@@ -43,9 +43,15 @@ void addVertex(VERTEX_LIST *list, VERTEX *v);
void insertVertex(VERTEX_LIST *list, VERTEX *v, unsigned int n);
void deleteVertex(VERTEX_LIST *list, unsigned int n);
+double vertexDistanceSquare(const VERTEX *v1, const VERTEX *v2);
+double vertexDistance(const VERTEX *v1, const VERTEX *v2);
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);
diff --git a/level.c b/level.c
index 4253746..7c6aaa9 100644
--- a/level.c
+++ b/level.c
@@ -36,8 +36,11 @@ void freeLevel(LEVEL *lvl) {
if(lvl) {
if(lvl->rooms) {
for(i = 0; i < lvl->nRooms; i++) {
- if(lvl->rooms[i].vertices)
- free(lvl->rooms[i].vertices);
+ if(lvl->rooms[i].polygon.vertices)
+ free(lvl->rooms[i].polygon.vertices);
+
+ if(lvl->rooms[i].name)
+ free(lvl->rooms[i].name);
}
free(lvl->rooms);
diff --git a/level.h b/level.h
index 735076a..aa51ea1 100644
--- a/level.h
+++ b/level.h
@@ -3,7 +3,10 @@
#include "geometry.h"
-typedef POLYGON ROOM;
+typedef struct _ROOM {
+ POLYGON polygon;
+ unsigned char *name;
+} ROOM;
typedef struct _LEVEL {
unsigned int nRooms;
diff --git a/window.c b/window.c
index c2e1c55..d0cb531 100644
--- a/window.c
+++ b/window.c
@@ -5,11 +5,14 @@
#include "geometry.h"
#include "level.h"
#include <gtk/gtk.h>
+#include <string.h>
-static GtkWidget *drawingArea = NULL;
+static GtkWidget *drawingArea = NULL, *sidebar = NULL;
static GtkAdjustment *hAdjustment = NULL, *vAdjustment = NULL;
+static GtkWidget *entryName, *labelArea = NULL, *labelPerimeter = NULL;
+
static gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data) {
return FALSE;
@@ -40,13 +43,15 @@ static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer u
setActiveRoom(NULL);
for(i = 0; i < getLevel()->nRooms; i++) {
- if(vertexInPolygon(&v, &getLevel()->rooms[i])) {
+ if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setActiveRoom(&getLevel()->rooms[i]);
break;
}
}
+ updateSidebar();
+
redraw();
gtk_widget_queue_draw(drawingArea);
}
@@ -70,7 +75,7 @@ gboolean crossingNotifyEvent(GtkWidget *widget, GdkEventCrossing *event, gpointe
for(i = 0; i < getLevel()->nRooms; i++) {
- if(vertexInPolygon(&v, &getLevel()->rooms[i])) {
+ if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setHoveredRoom(&getLevel()->rooms[i]);
break;
@@ -96,8 +101,8 @@ gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer us
line.v2 = v;
for(i = 0; i < getLevel()->nRooms; i++) {
- if(linePolygonIntersection(&line, &getLevel()->rooms[i])) {
- if(vertexInPolygon(&v, &getLevel()->rooms[i])) {
+ if(linePolygonIntersection(&line, &getLevel()->rooms[i].polygon)) {
+ if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setHoveredRoom(&getLevel()->rooms[i]);
changed = TRUE;
@@ -170,8 +175,60 @@ static void updateScrollbarsCentered() {
updateScrollbars(0.5, 0.5);
}
+static void sidebarNameChanged(GtkEditable *editable, gpointer user_data) {
+ if(getActiveRoom() == NULL) return;
+
+ free(getActiveRoom()->name);
+ getActiveRoom()->name = strdup(gtk_entry_get_text(GTK_ENTRY(entryName)));
+}
+
+static GtkWidget* createSidebar() {
+ GtkWidget *widget, *labelRoomInfo, *labelName, *tableRoomData, *labelAreaLabel, *labelPerimeterLabel;
+
+ widget = gtk_vbox_new(FALSE, 0);
+
+ labelRoomInfo = gtk_label_new(NULL);
+ gtk_label_set_markup(GTK_LABEL(labelRoomInfo), "<b>Room info:</b>");
+ gtk_misc_set_alignment(GTK_MISC(labelRoomInfo), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(widget), labelRoomInfo, FALSE, FALSE, 5);
+
+ gtk_box_pack_start(GTK_BOX(widget), gtk_hseparator_new(), FALSE, FALSE, 5);
+
+ labelName = gtk_label_new("Name:");
+ gtk_misc_set_alignment(GTK_MISC(labelName), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(widget), labelName, FALSE, FALSE, 0);
+
+ entryName = gtk_entry_new();
+ gtk_widget_set_sensitive(entryName, FALSE);
+ g_signal_connect(G_OBJECT(entryName), "changed", G_CALLBACK(sidebarNameChanged), NULL);
+ gtk_box_pack_start(GTK_BOX(widget), entryName, FALSE, FALSE, 0);
+
+ tableRoomData = gtk_table_new(2, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(tableRoomData), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(tableRoomData), 10);
+ gtk_box_pack_start(GTK_BOX(widget), tableRoomData, FALSE, FALSE, 5);
+
+ labelAreaLabel = gtk_label_new("Room area:");
+ gtk_misc_set_alignment(GTK_MISC(labelAreaLabel), 0.0, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelAreaLabel, 0, 1, 0, 1);
+
+ labelArea = gtk_label_new(NULL);
+ gtk_misc_set_alignment(GTK_MISC(labelArea), 1.0, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelArea, 1, 2, 0, 1);
+
+ labelPerimeterLabel = gtk_label_new("Room perimeter:");
+ gtk_misc_set_alignment(GTK_MISC(labelPerimeterLabel), 0.0, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelPerimeterLabel, 0, 1, 1, 2);
+
+ labelPerimeter = gtk_label_new(NULL);
+ gtk_misc_set_alignment(GTK_MISC(labelPerimeter), 1.0, 0.5);
+ gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelPerimeter, 1, 2, 1, 2);
+
+ return widget;
+}
+
GtkWidget* createMainWindow() {
- GtkWidget *window, *vbox, *menubar, *toolbar, *hPaned, *table, *vScroll, *hScroll, *sidebar;
+ GtkWidget *window, *vbox, *hPaned, *table, *vScroll, *hScroll;
GdkColor color = {0, 0, 0, 0};
@@ -183,11 +240,8 @@ GtkWidget* createMainWindow() {
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
- menubar = getMenu();
- gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
-
- toolbar = getToolbar();
- gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), getMenu(), FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), getToolbar(), FALSE, FALSE, 0);
gtk_window_add_accel_group(GTK_WINDOW(window), getAccels());
@@ -221,7 +275,7 @@ GtkWidget* createMainWindow() {
g_signal_connect(G_OBJECT(vScroll), "value-changed", G_CALLBACK(refreshScrolling), NULL);
gtk_table_attach(GTK_TABLE(table), vScroll, 1, 2, 0, 1, 0, GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0, 0);
- sidebar = gtk_vbox_new(FALSE, 0);
+ sidebar = createSidebar();
gtk_paned_pack2(GTK_PANED(hPaned), sidebar, FALSE, TRUE);
gtk_widget_show_all(vbox);
@@ -229,6 +283,31 @@ GtkWidget* createMainWindow() {
return window;
}
+void updateSidebar() {
+ gchar *string;
+
+
+ if(getActiveRoom()) {
+ gtk_entry_set_text(GTK_ENTRY(entryName), getActiveRoom()->name);
+ gtk_widget_set_sensitive(entryName, TRUE);
+
+ string = g_strdup_printf("%.2f", polygonArea(&getActiveRoom()->polygon));
+ gtk_label_set_text(GTK_LABEL(labelArea), string);
+ g_free(string);
+
+ string = g_strdup_printf("%.2f", polygonPerimeter(&getActiveRoom()->polygon));
+ gtk_label_set_text(GTK_LABEL(labelPerimeter), string);
+ g_free(string);
+ }
+ else {
+ gtk_entry_set_text(GTK_ENTRY(entryName), "");
+ gtk_widget_set_sensitive(entryName, FALSE);
+
+ gtk_label_set_text(GTK_LABEL(labelArea), NULL);
+ gtk_label_set_text(GTK_LABEL(labelPerimeter), NULL);
+ }
+}
+
void zoomIn(double factor, double x, double y) {
setScale(getScale()*factor);
updateScrollbars(x, y);
diff --git a/window.h b/window.h
index 01c377d..396c014 100644
--- a/window.h
+++ b/window.h
@@ -6,6 +6,8 @@
GtkWidget* createMainWindow();
+void updateSidebar();
+
void zoomIn(double factor, double x, double y);
void zoomOut(double factor, double x, double y);
void zoomInCentered(double factor);
diff --git a/zoomedit.c b/zoomedit.c
index bedee53..0d90aa3 100644
--- a/zoomedit.c
+++ b/zoomedit.c
@@ -1,11 +1,12 @@
#include <gtk/gtk.h>
+#include <stdlib.h>
#include "level.h"
#include "window.h"
int main(int argc, char *argv[]) {
- VERTEX vertices[4] = {{-1.1,-1}, {-1,-1.1}, {1.1,1}, {1,1.1}};
- ROOM room = {sizeof(vertices)/sizeof(vertices[0]), vertices};
+ VERTEX vertices[4] = {{0,-1}, {1,0}, {0,1}, {-1,0}};
+ ROOM room = {{sizeof(vertices)/sizeof(vertices[0]), vertices}, calloc(1, sizeof(unsigned char))};
LEVEL lvl = {1, &room};
GtkWidget *window;
@@ -19,5 +20,7 @@ int main(int argc, char *argv[]) {
gtk_main();
+ free(room.name);
+
return 0;
}