zoomedit: Einige Rauminformationen werden jetzt angezeigt & Name kann ge?ndert werden.

This commit is contained in:
neoraider 2007-08-29 19:54:05 +00:00
parent 22da7179ac
commit 4d035c6455
9 changed files with 167 additions and 49 deletions

63
draw.c
View file

@ -4,7 +4,6 @@
#include "geometry.h" #include "geometry.h"
#include <math.h> #include <math.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <cairo/cairo.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 step = pow(0.1, depth2);
double d; double d;
int i; int i;
gchar buffer[20]; gchar *string;
cairo_set_font_size(cr, 10.0/scale); 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_move_to(cr, d, rect->y);
cairo_line_to(cr, d, rect->y+rect->height); cairo_line_to(cr, d, rect->y+rect->height);
if(step > 0.2) if(step > 0.5)
g_snprintf(buffer, sizeof(buffer), "%i", (int)rint(d)); string = g_strdup_printf("%i", (int)rint(d));
else else
g_snprintf(buffer, sizeof(buffer), "%.*f", -(int)floor(log10(step*1.1)), d+step/10); string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
buffer[sizeof(buffer)-1] = '\0';
cairo_move_to(cr, d+1/scale, rect->y+11/scale); 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) { 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); cairo_line_to(cr, rect->x+rect->width, d);
if(step > 0.5) if(step > 0.5)
g_snprintf(buffer, sizeof(buffer), "%i", (int)rint(d)); string = g_strdup_printf("%i", (int)rint(d));
else else
g_snprintf(buffer, sizeof(buffer), "%.*f", -(int)floor(log10(step*1.1)), d+step/10); string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
buffer[sizeof(buffer)-1] = '\0';
cairo_move_to(cr, rect->x+3/scale, d+11/scale); 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); 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; int i;
ROOM room2 = {0, NULL}; POLYGON polygon2 = {0, NULL};
// no vertices // no vertices
if(room->nVertices == 0) return; if(polygon->nVertices == 0) return;
if(rect) if(rect)
simplifyPolygon(room, rect, &room2); simplifyPolygon(polygon, rect, &polygon2);
else else
room2 = *room; polygon2 = *polygon;
if(room2.nVertices == 0) return; if(polygon2.nVertices == 0) return;
cairo_new_sub_path(cr); cairo_new_sub_path(cr);
for(i = 0; i < room2.nVertices; i++) { for(i = 0; i < polygon2.nVertices; i++) {
cairo_line_to(cr, room2.vertices[i].x, room2.vertices[i].y); cairo_line_to(cr, polygon2.vertices[i].x, polygon2.vertices[i].y);
} }
cairo_close_path(cr); cairo_close_path(cr);
if(rect && room2.vertices) if(rect && polygon2.vertices)
free(room2.vertices); free(polygon2.vertices);
} }
gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { 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++) { for(i = 0; i < getLevel()->nRooms; i++) {
if(&getLevel()->rooms[i] != getActiveRoom()) 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); 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); cairo_stroke(cr);
if(getEditMode() == EDIT_MODE_SELECTED) { 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_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2);
cairo_fill_preserve(cr); 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_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); 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_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr); cairo_stroke(cr);
@ -209,9 +212,9 @@ double getImageWidth() {
if(level) { if(level) {
for(i = 0; i < level->nRooms; i++) { for(i = 0; i < level->nRooms; i++) {
for(j = 0; j < level->rooms[i].nVertices; j++) { for(j = 0; j < level->rooms[i].polygon.nVertices; j++) {
min = MIN(min, level->rooms[i].vertices[j].x); min = MIN(min, level->rooms[i].polygon.vertices[j].x);
max = MAX(max, level->rooms[i].vertices[j].x); max = MAX(max, level->rooms[i].polygon.vertices[j].x);
} }
} }
} }
@ -226,9 +229,9 @@ double getImageHeight() {
if(level) { if(level) {
for(i = 0; i < level->nRooms; i++) { for(i = 0; i < level->nRooms; i++) {
for(j = 0; j < level->rooms[i].nVertices; j++) { for(j = 0; j < level->rooms[i].polygon.nVertices; j++) {
min = MIN(min, level->rooms[i].vertices[j].y); min = MIN(min, level->rooms[i].polygon.vertices[j].y);
max = MAX(max, level->rooms[i].vertices[j].y); max = MAX(max, level->rooms[i].polygon.vertices[j].y);
} }
} }
} }

2
edit.c
View file

@ -6,11 +6,11 @@ static int editMode = EDIT_MODE_VIEW;
static ROOM *activeRoom = NULL; static ROOM *activeRoom = NULL;
static ROOM *hoveredRoom = NULL; static ROOM *hoveredRoom = NULL;
int getEditMode() { int getEditMode() {
return editMode; return editMode;
} }
ROOM *getActiveRoom() { ROOM *getActiveRoom() {
return activeRoom; return activeRoom;
} }

View file

@ -44,7 +44,6 @@ double vertexDistance(const VERTEX *v1, const VERTEX *v2) {
return sqrt(vertexDistanceSquare(v1, v2)); return sqrt(vertexDistanceSquare(v1, v2));
} }
int vertexInRect(const VERTEX *v, const RECTANGLE *rect) { int vertexInRect(const VERTEX *v, const RECTANGLE *rect) {
int ret = EDGE_NONE; int ret = EDGE_NONE;
@ -133,6 +132,26 @@ gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p) {
return (d == 0) ? FALSE : TRUE; 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) { int lineIntersection(const LINE *la, const LINE *lb, VERTEX *v) {
double xa1 = la->v1.x, ya1 = la->v1.y; double xa1 = la->v1.x, ya1 = la->v1.y;
double xa2 = la->v2.x, ya2 = la->v2.y; double xa2 = la->v2.x, ya2 = la->v2.y;

View file

@ -43,9 +43,15 @@ void addVertex(VERTEX_LIST *list, VERTEX *v);
void insertVertex(VERTEX_LIST *list, VERTEX *v, unsigned int n); void insertVertex(VERTEX_LIST *list, VERTEX *v, unsigned int n);
void deleteVertex(VERTEX_LIST *list, 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); int vertexInRect(const VERTEX *v, const RECTANGLE *rect);
gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p); 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 lineIntersection(const LINE *la, const LINE *lb, VERTEX *v);
int lineRectIntersection(const LINE *l, const RECTANGLE *rect, int edge, 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); int lineRectIntersections(const LINE *line, const RECTANGLE *rect, int edge, VERTEX *v1, VERTEX *v2);

View file

@ -36,8 +36,11 @@ void freeLevel(LEVEL *lvl) {
if(lvl) { if(lvl) {
if(lvl->rooms) { if(lvl->rooms) {
for(i = 0; i < lvl->nRooms; i++) { for(i = 0; i < lvl->nRooms; i++) {
if(lvl->rooms[i].vertices) if(lvl->rooms[i].polygon.vertices)
free(lvl->rooms[i].vertices); free(lvl->rooms[i].polygon.vertices);
if(lvl->rooms[i].name)
free(lvl->rooms[i].name);
} }
free(lvl->rooms); free(lvl->rooms);

View file

@ -3,7 +3,10 @@
#include "geometry.h" #include "geometry.h"
typedef POLYGON ROOM; typedef struct _ROOM {
POLYGON polygon;
unsigned char *name;
} ROOM;
typedef struct _LEVEL { typedef struct _LEVEL {
unsigned int nRooms; unsigned int nRooms;

103
window.c
View file

@ -5,11 +5,14 @@
#include "geometry.h" #include "geometry.h"
#include "level.h" #include "level.h"
#include <gtk/gtk.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 GtkAdjustment *hAdjustment = NULL, *vAdjustment = NULL;
static GtkWidget *entryName, *labelArea = NULL, *labelPerimeter = NULL;
static gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data) { static gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data) {
return FALSE; return FALSE;
@ -40,13 +43,15 @@ static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer u
setActiveRoom(NULL); setActiveRoom(NULL);
for(i = 0; i < getLevel()->nRooms; i++) { for(i = 0; i < getLevel()->nRooms; i++) {
if(vertexInPolygon(&v, &getLevel()->rooms[i])) { if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setActiveRoom(&getLevel()->rooms[i]); setActiveRoom(&getLevel()->rooms[i]);
break; break;
} }
} }
updateSidebar();
redraw(); redraw();
gtk_widget_queue_draw(drawingArea); gtk_widget_queue_draw(drawingArea);
} }
@ -70,7 +75,7 @@ gboolean crossingNotifyEvent(GtkWidget *widget, GdkEventCrossing *event, gpointe
for(i = 0; i < getLevel()->nRooms; i++) { for(i = 0; i < getLevel()->nRooms; i++) {
if(vertexInPolygon(&v, &getLevel()->rooms[i])) { if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setHoveredRoom(&getLevel()->rooms[i]); setHoveredRoom(&getLevel()->rooms[i]);
break; break;
@ -96,8 +101,8 @@ gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer us
line.v2 = v; line.v2 = v;
for(i = 0; i < getLevel()->nRooms; i++) { for(i = 0; i < getLevel()->nRooms; i++) {
if(linePolygonIntersection(&line, &getLevel()->rooms[i])) { if(linePolygonIntersection(&line, &getLevel()->rooms[i].polygon)) {
if(vertexInPolygon(&v, &getLevel()->rooms[i])) { if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setHoveredRoom(&getLevel()->rooms[i]); setHoveredRoom(&getLevel()->rooms[i]);
changed = TRUE; changed = TRUE;
@ -170,8 +175,60 @@ static void updateScrollbarsCentered() {
updateScrollbars(0.5, 0.5); 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* createMainWindow() {
GtkWidget *window, *vbox, *menubar, *toolbar, *hPaned, *table, *vScroll, *hScroll, *sidebar; GtkWidget *window, *vbox, *hPaned, *table, *vScroll, *hScroll;
GdkColor color = {0, 0, 0, 0}; GdkColor color = {0, 0, 0, 0};
@ -183,11 +240,8 @@ GtkWidget* createMainWindow() {
vbox = gtk_vbox_new(FALSE, 0); vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox); gtk_container_add(GTK_CONTAINER(window), vbox);
menubar = getMenu(); gtk_box_pack_start(GTK_BOX(vbox), getMenu(), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), getToolbar(), FALSE, FALSE, 0);
toolbar = getToolbar();
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
gtk_window_add_accel_group(GTK_WINDOW(window), getAccels()); 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); 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); 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_paned_pack2(GTK_PANED(hPaned), sidebar, FALSE, TRUE);
gtk_widget_show_all(vbox); gtk_widget_show_all(vbox);
@ -229,6 +283,31 @@ GtkWidget* createMainWindow() {
return window; 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) { void zoomIn(double factor, double x, double y) {
setScale(getScale()*factor); setScale(getScale()*factor);
updateScrollbars(x, y); updateScrollbars(x, y);

View file

@ -6,6 +6,8 @@
GtkWidget* createMainWindow(); GtkWidget* createMainWindow();
void updateSidebar();
void zoomIn(double factor, double x, double y); void zoomIn(double factor, double x, double y);
void zoomOut(double factor, double x, double y); void zoomOut(double factor, double x, double y);
void zoomInCentered(double factor); void zoomInCentered(double factor);

View file

@ -1,11 +1,12 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <stdlib.h>
#include "level.h" #include "level.h"
#include "window.h" #include "window.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
VERTEX vertices[4] = {{-1.1,-1}, {-1,-1.1}, {1.1,1}, {1,1.1}}; VERTEX vertices[4] = {{0,-1}, {1,0}, {0,1}, {-1,0}};
ROOM room = {sizeof(vertices)/sizeof(vertices[0]), vertices}; ROOM room = {{sizeof(vertices)/sizeof(vertices[0]), vertices}, calloc(1, sizeof(unsigned char))};
LEVEL lvl = {1, &room}; LEVEL lvl = {1, &room};
GtkWidget *window; GtkWidget *window;
@ -19,5 +20,7 @@ int main(int argc, char *argv[]) {
gtk_main(); gtk_main();
free(room.name);
return 0; return 0;
} }