Compare commits
6 Commits
v1.0-rc1
...
dac834aef2
Author | SHA1 | Date | |
---|---|---|---|
dac834aef2 | |||
f8cbf7e066 | |||
bbd731401d | |||
7734467ea9 | |||
7d66ca1280 | |||
542737622f |
@@ -2,13 +2,14 @@ cmake_minimum_required(VERSION 2.8)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(GLIB REQUIRED glib-2.0)
|
||||
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
|
||||
pkg_check_modules(CAIRO REQUIRED cairo)
|
||||
|
||||
project(gds-render)
|
||||
|
||||
add_subdirectory(glade)
|
||||
|
||||
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS})
|
||||
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS})
|
||||
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS})
|
||||
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${CAIRO_LINK_DIRS})
|
||||
add_definitions(${GLIB2_CFLAGS_OTHER})
|
||||
|
||||
|
||||
@@ -32,5 +33,5 @@ add_compile_options(-Wall)
|
||||
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c)
|
||||
add_dependencies(${PROJECT_NAME} glib-resources)
|
||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c PROPERTIES GENERATED 1)
|
||||
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} m)
|
||||
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m)
|
||||
|
||||
|
@@ -33,9 +33,12 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n", ##__VA_ARGS__)
|
||||
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__)
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
enum record {
|
||||
INVALID = 0x0000,
|
||||
@@ -223,6 +226,7 @@ static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr)
|
||||
cell->child_cells = NULL;
|
||||
cell->graphic_objs = NULL;
|
||||
cell->name[0] = 0;
|
||||
cell->bounding_box.scanned = FALSE;
|
||||
} else
|
||||
return NULL;
|
||||
/* return cell */
|
||||
@@ -347,6 +351,221 @@ void scan_library_references(gpointer library_list_item, gpointer user)
|
||||
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
|
||||
}
|
||||
|
||||
static void apply_transforms_on_bounding_box(struct gds_cell_instance *cell_inst, struct gds_bounding_box *result)
|
||||
{
|
||||
struct gds_dpoint vertices[4];
|
||||
int i;
|
||||
double xmin= INT_MAX, xmax=INT_MIN, ymin=INT_MAX, ymax= INT_MIN;
|
||||
double temp;
|
||||
|
||||
double phi = M_PI * cell_inst->angle / 180;
|
||||
|
||||
if (cell_inst->cell_ref->bounding_box.scanned == FALSE)
|
||||
return;
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
/* Calculate all 4 bounding box points */
|
||||
vertices[0].x = cell_inst->cell_ref->bounding_box.coords[0].x;
|
||||
vertices[0].y = cell_inst->cell_ref->bounding_box.coords[0].y;
|
||||
vertices[1].x = cell_inst->cell_ref->bounding_box.coords[0].x;
|
||||
vertices[1].y = cell_inst->cell_ref->bounding_box.coords[1].y;
|
||||
vertices[2].x = cell_inst->cell_ref->bounding_box.coords[1].x;
|
||||
vertices[2].y = cell_inst->cell_ref->bounding_box.coords[1].y;
|
||||
vertices[3].x = cell_inst->cell_ref->bounding_box.coords[1].x;
|
||||
vertices[3].y = cell_inst->cell_ref->bounding_box.coords[0].y;
|
||||
|
||||
/* Apply flipping and magnification */
|
||||
for (i = 0; i < 4; i++) {
|
||||
vertices[i].x = (vertices[i].x * cell_inst->magnification);
|
||||
vertices[i].y = (vertices[i].y * cell_inst->magnification * (cell_inst->flipped ? -1 : 1));
|
||||
}
|
||||
/* Apply rotation */
|
||||
for (i = 0; i < 4; i++) {
|
||||
temp =(cos(phi) * vertices[i].x - sin(phi) * vertices[i].y);
|
||||
vertices[i].y =(sin(phi) * vertices[i].x + cos(phi) * vertices[i].y);
|
||||
vertices[i].x = temp;
|
||||
}
|
||||
|
||||
/* Translate origin */
|
||||
for (i = 0; i < 4; i++) {
|
||||
vertices[i].x += (double)cell_inst->origin.x;
|
||||
vertices[i].y += (double)cell_inst->origin.y;
|
||||
}
|
||||
|
||||
/* Calculate new bounding box */
|
||||
for (i = 0; i < 4; i++) {
|
||||
xmin = MIN(xmin, vertices[i].x);
|
||||
ymin = MIN(ymin, vertices[i].y);
|
||||
ymax = MAX(ymax, vertices[i].y);
|
||||
xmax = MAX(xmax, vertices[i].x);
|
||||
}
|
||||
|
||||
result->scanned = TRUE;
|
||||
result->coords[0].x = xmin;
|
||||
result->coords[0].y = ymin;
|
||||
result->coords[1].x = xmax;
|
||||
result->coords[1].y = ymax;
|
||||
}
|
||||
|
||||
static void calculate_bounding_path_box(struct gds_graphics *path, struct gds_bounding_box *box)
|
||||
{
|
||||
cairo_surface_t *surf;
|
||||
cairo_t *cr;
|
||||
GList *vertex_list;
|
||||
struct gds_point *vertex;
|
||||
|
||||
double x0, y0, width, height;
|
||||
|
||||
if (path == NULL || box == NULL)
|
||||
return;
|
||||
if (path->vertices == NULL)
|
||||
return;
|
||||
if (path->vertices->data == NULL)
|
||||
return;
|
||||
|
||||
box->scanned = FALSE;
|
||||
|
||||
/* Check path length */
|
||||
if (g_list_length(path->vertices) < 2)
|
||||
return;
|
||||
|
||||
surf = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||
cr = cairo_create(surf);
|
||||
|
||||
/* Prepare line properties */
|
||||
switch (path->path_render_type) {
|
||||
case PATH_FLUSH:
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
|
||||
break;
|
||||
case PATH_ROUNDED:
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
break;
|
||||
case PATH_SQUARED:
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
|
||||
break;
|
||||
default:
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_set_line_width(cr, path->width_absolute);
|
||||
cairo_set_source_rgba(cr, 1, 1 , 0, 0.5);
|
||||
|
||||
/* Start at first point */
|
||||
vertex = (struct gds_point *)path->vertices->data;
|
||||
cairo_move_to(cr, (double)vertex->x, (double)vertex->y);
|
||||
|
||||
/* Remaining points */
|
||||
for (vertex_list = path->vertices->next; vertex_list != NULL; vertex_list = vertex_list->next) {
|
||||
vertex = (struct gds_point *)vertex_list->data;
|
||||
cairo_line_to(cr, (double)vertex->x, (double)vertex->y);
|
||||
}
|
||||
cairo_stroke(cr);
|
||||
|
||||
cairo_recording_surface_ink_extents(surf, &x0, &y0, &width, &height);
|
||||
box->coords[0].x = x0;
|
||||
box->coords[0].y = y0;
|
||||
box->coords[1].x = (x0+width);
|
||||
box->coords[1].y = (y0+height);
|
||||
box->scanned = TRUE;
|
||||
cairo_destroy(cr);
|
||||
cairo_surface_destroy(surf);
|
||||
|
||||
}
|
||||
|
||||
static void update_bounding_box_with_gfx(struct gds_graphics *gfx, double *xlow,
|
||||
double *ylow, double *xhigh, double *yhigh)
|
||||
{
|
||||
GList *vertex_list;
|
||||
struct gds_point *vertex;
|
||||
struct gds_bounding_box path_box;
|
||||
|
||||
path_box.scanned = FALSE;
|
||||
|
||||
if (gfx->gfx_type == GRAPHIC_POLYGON) {
|
||||
for (vertex_list = gfx->vertices; vertex_list != NULL; vertex_list = vertex_list->next) {
|
||||
vertex = (struct gds_point *)vertex_list->data;
|
||||
|
||||
*xlow = MIN(*xlow, (double)vertex->x);
|
||||
*ylow = MIN(*ylow, (double)vertex->y);
|
||||
*xhigh = MAX(*xhigh, (double)vertex->x);
|
||||
*yhigh = MAX(*yhigh, (double)vertex->y);
|
||||
}
|
||||
} else if (gfx->gfx_type == GRAPHIC_PATH) {
|
||||
calculate_bounding_path_box(gfx, &path_box);
|
||||
if (path_box.scanned == TRUE) {
|
||||
*xlow = MIN(*xlow, path_box.coords[0].x);
|
||||
*ylow = MIN(*ylow, path_box.coords[0].y);
|
||||
*xhigh = MAX(*xhigh, path_box.coords[1].x);
|
||||
*yhigh = MAX(*yhigh, path_box.coords[1].y);
|
||||
} else
|
||||
GDS_WARN("Bounding box of path not calculated");
|
||||
}
|
||||
}
|
||||
|
||||
static void cell_create_bounding_box(struct gds_cell *cell)
|
||||
{
|
||||
GList *ref;
|
||||
GList *gfx_list;
|
||||
|
||||
struct gds_bounding_box box_transform;
|
||||
struct gds_cell_instance *cell_inst;
|
||||
struct gds_graphics *gfx;
|
||||
|
||||
double xlow=INT_MAX, xhigh=INT_MIN, ylow=INT_MAX, yhigh=INT_MIN;
|
||||
|
||||
if (cell->bounding_box.scanned == TRUE)
|
||||
return;
|
||||
|
||||
/* Generate bounding boxes of child cells and update current box*/
|
||||
for (ref = cell->child_cells; ref != NULL; ref = ref->next) {
|
||||
cell_inst = (struct gds_cell_instance *)ref->data;
|
||||
if (cell_inst->cell_ref) {
|
||||
if (cell_inst->cell_ref->bounding_box.scanned == FALSE)
|
||||
cell_create_bounding_box(cell_inst->cell_ref);
|
||||
|
||||
/* Apply transforms of cell in current cell to calculate the box of the specific instance */
|
||||
if (cell_inst->cell_ref->bounding_box.scanned == TRUE) {
|
||||
apply_transforms_on_bounding_box(cell_inst, &box_transform);
|
||||
xlow = MIN(xlow, box_transform.coords[0].x);
|
||||
ylow = MIN(ylow, box_transform.coords[0].y);
|
||||
xhigh = MAX(xhigh, box_transform.coords[1].x);
|
||||
yhigh = MAX(yhigh, box_transform.coords[1].y);
|
||||
} else
|
||||
GDS_WARN("Unscanned cells present: %s. This should not happen", cell_inst->ref_name);
|
||||
} else
|
||||
GDS_WARN("Cell referenced that does not exist: %s. Bounding box might be incorrect.",
|
||||
cell_inst->ref_name);
|
||||
}
|
||||
|
||||
/* Generate update box using graphic objects*/
|
||||
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
|
||||
gfx = (struct gds_graphics *)gfx_list->data;
|
||||
|
||||
update_bounding_box_with_gfx(gfx, &xlow, &ylow, &xhigh, &yhigh);
|
||||
}
|
||||
|
||||
printf("Cell '%s' has size: %lf / %lf\n", cell->name, xhigh - xlow, yhigh - ylow);
|
||||
cell->bounding_box.coords[0].x = xlow;
|
||||
cell->bounding_box.coords[0].y = ylow;
|
||||
cell->bounding_box.coords[1].x = xhigh;
|
||||
cell->bounding_box.coords[1].y = yhigh;
|
||||
cell->bounding_box.scanned = TRUE;
|
||||
}
|
||||
|
||||
static void library_create_bounding_boxes(gpointer library_list_item, gpointer user)
|
||||
{
|
||||
GList *cell_list;
|
||||
struct gds_library *lib = (struct gds_library *)library_list_item;
|
||||
if (!lib)
|
||||
return;
|
||||
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
|
||||
cell_create_bounding_box((struct gds_cell *)cell_list->data);
|
||||
}
|
||||
}
|
||||
|
||||
void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_date, struct gds_time_field *access_date)
|
||||
{
|
||||
|
||||
@@ -507,21 +726,22 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
||||
current_cell = NULL;
|
||||
printf("Leaving Cell\n");
|
||||
break;
|
||||
//case BOX:
|
||||
case BOX:
|
||||
case BOUNDARY:
|
||||
if (current_cell == NULL) {
|
||||
GDS_ERROR("Boundary outside of cell");
|
||||
GDS_ERROR("Boundary/Box outside of cell");
|
||||
run = -3;
|
||||
break;
|
||||
}
|
||||
current_cell->graphic_objs = append_graphics(current_cell->graphic_objs,
|
||||
GRAPHIC_POLYGON, ¤t_graphics);
|
||||
(rec_type == BOUNDARY ? GRAPHIC_POLYGON : GRAPHIC_BOX),
|
||||
¤t_graphics);
|
||||
if (current_cell->graphic_objs == NULL) {
|
||||
GDS_ERROR("Memory allocation failed");
|
||||
run = -4;
|
||||
break;
|
||||
}
|
||||
printf("\tEntering boundary\n");
|
||||
printf("\tEntering boundary/Box\n");
|
||||
break;
|
||||
case SREF:
|
||||
if (current_cell == NULL) {
|
||||
@@ -575,6 +795,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MAG:
|
||||
break;
|
||||
case ANGLE:
|
||||
@@ -727,8 +948,13 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
||||
if (!run) {
|
||||
/* Iterate and find references to cells */
|
||||
g_list_foreach(lib_list, scan_library_references, NULL);
|
||||
/* Create bounding boxes */
|
||||
g_list_foreach(lib_list, library_create_bounding_boxes, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
*library_list = lib_list;
|
||||
|
||||
free(workbuff);
|
||||
|
@@ -6,56 +6,67 @@
|
||||
|
||||
#define CELL_NAME_MAX (100)
|
||||
|
||||
enum graphics_type {GRAPHIC_PATH = 0, GRAPHIC_POLYGON = 1};
|
||||
enum graphics_type {GRAPHIC_PATH = 0, GRAPHIC_POLYGON = 1, GRAPHIC_BOX};
|
||||
enum path_type {PATH_FLUSH = 0, PATH_ROUNDED = 1, PATH_SQUARED = 2};
|
||||
|
||||
struct gds_time_field {
|
||||
uint16_t year;
|
||||
uint16_t month;
|
||||
uint16_t day;
|
||||
uint16_t hour;
|
||||
uint16_t minute;
|
||||
uint16_t second;
|
||||
struct gds_point {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct gds_point {
|
||||
int x;
|
||||
int y;
|
||||
struct gds_dpoint {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct gds_bounding_box {
|
||||
gboolean scanned;
|
||||
struct gds_dpoint coords[2];
|
||||
};
|
||||
|
||||
struct gds_time_field {
|
||||
uint16_t year;
|
||||
uint16_t month;
|
||||
uint16_t day;
|
||||
uint16_t hour;
|
||||
uint16_t minute;
|
||||
uint16_t second;
|
||||
};
|
||||
|
||||
struct gds_graphics {
|
||||
enum graphics_type gfx_type;
|
||||
GList *vertices;
|
||||
enum path_type path_render_type;
|
||||
int width_absolute;
|
||||
int16_t layer;
|
||||
uint16_t datatype;
|
||||
enum graphics_type gfx_type;
|
||||
GList *vertices;
|
||||
enum path_type path_render_type;
|
||||
int width_absolute;
|
||||
int16_t layer;
|
||||
uint16_t datatype;
|
||||
};
|
||||
|
||||
struct gds_cell_instance {
|
||||
char ref_name[CELL_NAME_MAX];
|
||||
struct gds_cell *cell_ref;
|
||||
struct gds_point origin;
|
||||
int flipped;
|
||||
double angle;
|
||||
double magnification;
|
||||
char ref_name[CELL_NAME_MAX];
|
||||
struct gds_cell *cell_ref;
|
||||
struct gds_point origin;
|
||||
int flipped;
|
||||
double angle;
|
||||
double magnification;
|
||||
};
|
||||
|
||||
struct gds_cell {
|
||||
char name[CELL_NAME_MAX];
|
||||
struct gds_time_field mod_time;
|
||||
struct gds_time_field access_time;
|
||||
GList *child_cells;
|
||||
GList *graphic_objs;
|
||||
char name[CELL_NAME_MAX];
|
||||
struct gds_time_field mod_time;
|
||||
struct gds_time_field access_time;
|
||||
GList *child_cells;
|
||||
GList *graphic_objs;
|
||||
struct gds_bounding_box bounding_box;
|
||||
};
|
||||
|
||||
struct gds_library {
|
||||
char name[CELL_NAME_MAX];
|
||||
struct gds_time_field mod_time;
|
||||
struct gds_time_field access_time;
|
||||
double unit_to_meters;
|
||||
GList *cells;
|
||||
GList *cell_names;
|
||||
char name[CELL_NAME_MAX];
|
||||
struct gds_time_field mod_time;
|
||||
struct gds_time_field access_time;
|
||||
double unit_to_meters;
|
||||
GList *cells;
|
||||
GList *cell_names;
|
||||
};
|
||||
|
||||
#endif /* __GDS_TYPES_H__ */
|
||||
|
@@ -1,8 +1,6 @@
|
||||
add_custom_target(glib-resources DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resources.c)
|
||||
add_custom_command(DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.glade
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/layer-widget.glade
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.glade
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_BINARY_DIR}/resources.c
|
||||
COMMAND
|
||||
|
@@ -95,7 +95,7 @@ static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GSt
|
||||
if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) {
|
||||
|
||||
/* Layer is defined => create graphics */
|
||||
if (gfx->gfx_type == GRAPHIC_POLYGON) {
|
||||
if (gfx->gfx_type == GRAPHIC_POLYGON || gfx->gfx_type == GRAPHIC_BOX ) {
|
||||
g_string_printf(buffer, "\\draw[line width=0.00001 pt, draw={c%d}, fill={c%d}, fill opacity={%lf}] ",
|
||||
gfx->layer, gfx->layer, color.alpha);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
@@ -107,7 +107,7 @@ static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GSt
|
||||
}
|
||||
g_string_printf(buffer, "cycle;\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
} else if(gfx->gfx_type == GRAPHIC_PATH) {
|
||||
} else if (gfx->gfx_type == GRAPHIC_PATH) {
|
||||
|
||||
if (g_list_length(gfx->vertices) < 2) {
|
||||
printf("Cannot write path with less than 2 points\n");
|
||||
@@ -116,7 +116,7 @@ static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GSt
|
||||
|
||||
if (gfx->path_render_type < 0 || gfx->path_render_type > 2) {
|
||||
printf("Path type unrecognized. Setting to 'flushed'\n");
|
||||
gfx->path_render_type = 0;
|
||||
gfx->path_render_type = PATH_FLUSH;
|
||||
}
|
||||
|
||||
g_string_printf(buffer, "\\draw[line width=%lf pt, draw={c%d}, opacity={%lf}, cap=%s] ",
|
||||
@@ -157,6 +157,11 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
|
||||
/* Draw polygons of childs */
|
||||
for (list_child = cell->child_cells; list_child != NULL; list_child = list_child->next) {
|
||||
inst = (struct gds_cell_instance *)list_child->data;
|
||||
|
||||
/* Abort if cell has no reference */
|
||||
if (!inst->cell_ref)
|
||||
continue;
|
||||
|
||||
/* generate translation scope */
|
||||
g_string_printf(buffer, "\\begin{scope}[shift={(%lf pt,%lf pt)}]\n",
|
||||
((double)inst->origin.x)/1000.0,((double)inst->origin.y)/1000.0);
|
||||
@@ -165,11 +170,11 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
|
||||
g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
g_string_printf(buffer, "\\begin{scope}[yscale=%s]\n", (inst->flipped ? "-1" : "1"));
|
||||
g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n", (inst->flipped ? -1*inst->magnification : inst->magnification),
|
||||
inst->magnification);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
if (inst->cell_ref)
|
||||
render_cell(inst->cell_ref, layer_infos, tex_file, buffer);
|
||||
render_cell(inst->cell_ref, layer_infos, tex_file, buffer);
|
||||
|
||||
g_string_printf(buffer, "\\end{scope}\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
Reference in New Issue
Block a user