diff options
-rw-r--r-- | draw.c | 63 | ||||
-rw-r--r-- | edit.c | 2 | ||||
-rw-r--r-- | geometry.c | 21 | ||||
-rw-r--r-- | geometry.h | 6 | ||||
-rw-r--r-- | level.c | 7 | ||||
-rw-r--r-- | level.h | 5 | ||||
-rw-r--r-- | window.c | 103 | ||||
-rw-r--r-- | window.h | 2 | ||||
-rw-r--r-- | zoomedit.c | 7 |
9 files changed, 167 insertions, 49 deletions
@@ -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); } } } @@ -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; } @@ -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; @@ -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); @@ -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); @@ -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; @@ -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); @@ -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); @@ -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; } |