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 <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);
}
}
}

2
edit.c
View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

103
window.c
View file

@ -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);

View file

@ -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);

View file

@ -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;
}