Output renderers: Move existing renderers to common folder
This commit is contained in:
341
output-renderers/cairo-output.c
Normal file
341
output-renderers/cairo-output.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* GDSII-Converter
|
||||
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of GDSII-Converter.
|
||||
*
|
||||
* GDSII-Converter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* GDSII-Converter is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file cairo-output.c
|
||||
* @brief Output renderer for Cairo PDF export
|
||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||
*/
|
||||
|
||||
/** @addtogroup Cairo-Renderer
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <cairo.h>
|
||||
#include <cairo-pdf.h>
|
||||
#include <cairo-svg.h>
|
||||
|
||||
#include <gds-render/output-renderers/cairo-output.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* @brief The cairo_layer struct
|
||||
* Each rendered layer is represented by this struct.
|
||||
*/
|
||||
struct cairo_layer {
|
||||
cairo_t *cr; /**< @brief cairo context for layer*/
|
||||
cairo_surface_t *rec; /**< @brief Recording surface to hold the layer */
|
||||
struct layer_info *linfo; /**< @brief Reference to layer information */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Revert the last transformation on all layers
|
||||
* @param layers Pointer to #cairo_layer structures
|
||||
*/
|
||||
static void revert_inherited_transform(struct cairo_layer *layers)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_LAYERS; i++) {
|
||||
if (layers[i].cr == NULL)
|
||||
continue;
|
||||
cairo_restore(layers[i].cr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Applies transformation to all layers
|
||||
* @param layers Array of layers
|
||||
* @param origin Origin translation
|
||||
* @param magnification Scaling
|
||||
* @param flipping Mirror image on x-axis before rotating
|
||||
* @param rotation Rotattion in degrees
|
||||
* @param scale Scale the image down by. Only used for sclaing origin coordinates. Not applied to layer.
|
||||
*/
|
||||
static void apply_inherited_transform_to_all_layers(struct cairo_layer *layers,
|
||||
const struct gds_point *origin,
|
||||
double magnification,
|
||||
gboolean flipping,
|
||||
double rotation,
|
||||
double scale)
|
||||
{
|
||||
int i;
|
||||
cairo_t *temp_layer_cr;
|
||||
|
||||
for (i = 0; i < MAX_LAYERS; i++) {
|
||||
temp_layer_cr = layers[i].cr;
|
||||
if (temp_layer_cr == NULL)
|
||||
continue;
|
||||
|
||||
/* Save the state and apply transformation */
|
||||
cairo_save(temp_layer_cr);
|
||||
cairo_translate(temp_layer_cr, (double)origin->x/scale, (double)origin->y/scale);
|
||||
cairo_rotate(temp_layer_cr, M_PI*rotation/180.0);
|
||||
cairo_scale(temp_layer_cr, magnification,
|
||||
(flipping == TRUE ? -magnification : magnification));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief render_cell Render a cell with its sub-cells
|
||||
* @param cell Cell to render
|
||||
* @param layers Cell will be rendered into these layers
|
||||
* @param scale sclae image down by this factor
|
||||
*/
|
||||
static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, double scale)
|
||||
{
|
||||
GList *instance_list;
|
||||
struct gds_cell *temp_cell;
|
||||
struct gds_cell_instance *cell_instance;
|
||||
GList *gfx_list;
|
||||
struct gds_graphics *gfx;
|
||||
GList *vertex_list;
|
||||
struct gds_point *vertex;
|
||||
cairo_t *cr;
|
||||
|
||||
/* Render child cells */
|
||||
for (instance_list = cell->child_cells; instance_list != NULL; instance_list = instance_list->next) {
|
||||
cell_instance = (struct gds_cell_instance *)instance_list->data;
|
||||
if ((temp_cell = cell_instance->cell_ref) != NULL) {
|
||||
apply_inherited_transform_to_all_layers(layers,
|
||||
&cell_instance->origin,
|
||||
cell_instance->magnification,
|
||||
cell_instance->flipped,
|
||||
cell_instance->angle,
|
||||
scale);
|
||||
render_cell(temp_cell, layers, scale);
|
||||
revert_inherited_transform(layers);
|
||||
}
|
||||
}
|
||||
|
||||
/* Render graphics */
|
||||
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
|
||||
gfx = (struct gds_graphics *)gfx_list->data;
|
||||
|
||||
/* Get layer renderer */
|
||||
if (gfx->layer >= MAX_LAYERS)
|
||||
continue;
|
||||
if ((cr = layers[gfx->layer].cr) == NULL)
|
||||
continue;
|
||||
|
||||
/* Apply settings */
|
||||
cairo_set_line_width(cr, (gfx->width_absolute ? gfx->width_absolute/scale : 1));
|
||||
|
||||
switch (gfx->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;
|
||||
}
|
||||
|
||||
/* Add vertices */
|
||||
for (vertex_list = gfx->vertices; vertex_list != NULL; vertex_list = vertex_list->next) {
|
||||
vertex = (struct gds_point *)vertex_list->data;
|
||||
|
||||
/* If first point -> move to, else line to */
|
||||
if (vertex_list->prev == NULL)
|
||||
cairo_move_to(cr, vertex->x/scale, vertex->y/scale);
|
||||
else
|
||||
cairo_line_to(cr, vertex->x/scale, vertex->y/scale);
|
||||
|
||||
}
|
||||
|
||||
/* Create graphics object */
|
||||
switch (gfx->gfx_type) {
|
||||
case GRAPHIC_PATH:
|
||||
cairo_stroke(cr);
|
||||
break;
|
||||
case GRAPHIC_BOX:
|
||||
case GRAPHIC_POLYGON:
|
||||
cairo_set_line_width(cr, 0.1/scale);
|
||||
cairo_close_path(cr);
|
||||
cairo_stroke_preserve(cr); // Prevent graphic glitches
|
||||
cairo_fill(cr);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, char *pdf_file, char *svg_file, double scale)
|
||||
{
|
||||
cairo_surface_t *pdf_surface = NULL, *svg_surface = NULL;
|
||||
cairo_t *pdf_cr = NULL, *svg_cr = NULL;
|
||||
struct layer_info *linfo;
|
||||
struct cairo_layer *layers;
|
||||
struct cairo_layer *lay;
|
||||
GList *info_list;
|
||||
int i;
|
||||
double rec_x0, rec_y0, rec_width, rec_height;
|
||||
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
|
||||
pid_t process_id;
|
||||
|
||||
if (pdf_file == NULL && svg_file == NULL) {
|
||||
/* No output specified */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't
|
||||
* brick everything.
|
||||
*
|
||||
* And by the way: This now bricks all Windows compatibility. Deal with it.
|
||||
*/
|
||||
process_id = fork();
|
||||
if (process_id < 0) {
|
||||
/* Well... shit... We have to run it in our process. */
|
||||
} else if (process_id > 0) {
|
||||
/* Woohoo... Successfully dumped the shitty code to an unknowing victim */
|
||||
goto ret_parent;
|
||||
}
|
||||
|
||||
layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
|
||||
|
||||
/* Clear layers */
|
||||
for (i = 0; i < MAX_LAYERS; i++) {
|
||||
layers[i].cr = NULL;
|
||||
layers[i].rec = NULL;
|
||||
}
|
||||
|
||||
/* Create recording surface for each layer */
|
||||
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
||||
linfo = (struct layer_info *)info_list->data;
|
||||
if (linfo->layer < MAX_LAYERS) {
|
||||
lay = &(layers[(unsigned int)linfo->layer]);
|
||||
lay->linfo = linfo;
|
||||
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
|
||||
NULL);
|
||||
lay->cr = cairo_create(layers[(unsigned int)linfo->layer].rec);
|
||||
cairo_scale(lay->cr, 1, -1); // Fix coordinate system
|
||||
cairo_set_source_rgb(lay->cr, linfo->color.red, linfo->color.green, linfo->color.blue);
|
||||
} else {
|
||||
printf("Layer number (%d) too high!\n", linfo->layer);
|
||||
goto ret_clear_layers;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render_cell(cell, layers, scale);
|
||||
|
||||
/* get size of image and top left coordinate */
|
||||
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
||||
linfo = (struct layer_info *)info_list->data;
|
||||
|
||||
if (linfo->layer >= MAX_LAYERS) {
|
||||
printf("Layer outside of Spec.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Print size */
|
||||
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
|
||||
&rec_width, &rec_height);
|
||||
printf("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n",
|
||||
linfo->layer,
|
||||
(linfo->name && linfo->name[0] ? " (" : ""),
|
||||
(linfo->name && linfo->name[0] ? linfo->name : ""),
|
||||
(linfo->name && linfo->name[0] ? ")" : ""),
|
||||
rec_width, rec_height, rec_x0, rec_y0);
|
||||
|
||||
/* update bounding box */
|
||||
xmin = MIN(xmin, rec_x0);
|
||||
xmax = MAX(xmax, rec_x0);
|
||||
ymin = MIN(ymin, rec_y0);
|
||||
ymax = MAX(ymax, rec_y0);
|
||||
xmin = MIN(xmin, rec_x0+rec_width);
|
||||
xmax = MAX(xmax, rec_x0+rec_width);
|
||||
ymin = MIN(ymin, rec_y0+rec_height);
|
||||
ymax = MAX(ymax, rec_y0+rec_height);
|
||||
|
||||
}
|
||||
|
||||
printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax);
|
||||
|
||||
if (pdf_file) {
|
||||
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
|
||||
pdf_cr = cairo_create(pdf_surface);
|
||||
}
|
||||
|
||||
if (svg_file) {
|
||||
svg_surface = cairo_svg_surface_create(svg_file, xmax-xmin, ymax-ymin);
|
||||
svg_cr = cairo_create(svg_surface);
|
||||
}
|
||||
|
||||
/* Write layers to PDF */
|
||||
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
||||
linfo = (struct layer_info *)info_list->data;
|
||||
|
||||
if (linfo->layer >= MAX_LAYERS) {
|
||||
printf("Layer outside of Spec.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdf_file && pdf_cr) {
|
||||
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
||||
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
|
||||
}
|
||||
|
||||
if (svg_file && svg_cr) {
|
||||
cairo_set_source_surface(svg_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
||||
cairo_paint_with_alpha(svg_cr, linfo->color.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
if (pdf_file) {
|
||||
cairo_show_page(pdf_cr);
|
||||
cairo_destroy(pdf_cr);
|
||||
cairo_surface_destroy(pdf_surface);
|
||||
}
|
||||
|
||||
if (svg_file) {
|
||||
cairo_show_page(svg_cr);
|
||||
cairo_destroy(svg_cr);
|
||||
cairo_surface_destroy(svg_surface);
|
||||
}
|
||||
|
||||
ret_clear_layers:
|
||||
for (i = 0; i < MAX_LAYERS; i++) {
|
||||
lay = &layers[i];
|
||||
if(lay->cr) {
|
||||
cairo_destroy(lay->cr);
|
||||
cairo_surface_destroy(lay->rec);
|
||||
}
|
||||
}
|
||||
free(layers);
|
||||
|
||||
printf("Cairo export finished. It might still be buggy!\n");
|
||||
|
||||
/* If forked, suspend process */
|
||||
if (process_id == 0)
|
||||
exit(0);
|
||||
|
||||
/* Fork didn't work. Just return here */
|
||||
return;
|
||||
ret_parent:
|
||||
waitpid(process_id, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/** @} */
|
72
output-renderers/external-renderer.c
Normal file
72
output-renderers/external-renderer.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* GDSII-Converter
|
||||
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of GDSII-Converter.
|
||||
*
|
||||
* GDSII-Converter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* GDSII-Converter is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file external-renderer.c
|
||||
* @brief This file implements the dynamic library loading for the external rendering feature
|
||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup external-renderer
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gds-render/output-renderers/external-renderer.h>
|
||||
|
||||
int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list,
|
||||
char *output_file, char *so_path)
|
||||
{
|
||||
int (*so_render_func)(struct gds_cell *, GList *, char *) = NULL;
|
||||
void *so_handle = NULL;
|
||||
char *error_msg;
|
||||
int ret = 0;
|
||||
|
||||
/* Check parameter sanity */
|
||||
if (!output_file || !so_path || !toplevel_cell || !layer_info_list)
|
||||
return -3000;
|
||||
|
||||
/* Load shared object */
|
||||
so_handle = dlopen(so_path, RTLD_LAZY);
|
||||
if (!so_handle) {
|
||||
printf("Could not load external library '%s'\nDetailed error is:\n%s\n", so_path, dlerror());
|
||||
return -2000;
|
||||
}
|
||||
|
||||
/* Load symbol from library */
|
||||
so_render_func = (int (*)(struct gds_cell *, GList *, char *))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION);
|
||||
error_msg = dlerror();
|
||||
if (error_msg != NULL) {
|
||||
printf("Rendering function not found in library:\n%s\n", error_msg);
|
||||
goto ret_close_so_handle;
|
||||
}
|
||||
|
||||
/* Execute */
|
||||
if (so_render_func)
|
||||
so_render_func(toplevel_cell, layer_info_list, output_file);
|
||||
|
||||
ret_close_so_handle:
|
||||
dlclose(so_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @} */
|
303
output-renderers/latex-output.c
Normal file
303
output-renderers/latex-output.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* GDSII-Converter
|
||||
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
|
||||
*
|
||||
* This file is part of GDSII-Converter.
|
||||
*
|
||||
* GDSII-Converter is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* GDSII-Converter is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file latex-output.c
|
||||
* @brief LaTeX output renderer
|
||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <gds-render/output-renderers/latex-output.h>
|
||||
|
||||
/**
|
||||
* @addtogroup LaTeX-Renderer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Writes a GString \p buffer to the fixed file tex_file */
|
||||
#define WRITEOUT_BUFFER(buff) fwrite((buff)->str, sizeof(char), (buff)->len, tex_file)
|
||||
|
||||
/**
|
||||
* @brief Write the layer declarration to TeX file
|
||||
*
|
||||
* This writes the declaration of the layers and the mapping in which order
|
||||
* the layers shall be rendered by TikZ. Layers are written in the order they are
|
||||
* positioned inside the \p layer_infos list.
|
||||
*
|
||||
* @param tex_file TeX-File to write to
|
||||
* @param layer_infos List containing layer_info structs.
|
||||
* @param buffer
|
||||
* @note The field layer_info::stacked_position is ignored. Stack depends on list order.
|
||||
*/
|
||||
static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString *buffer)
|
||||
{
|
||||
GList *list;
|
||||
struct layer_info *lifo;
|
||||
char *end_str;
|
||||
|
||||
for (list = layer_infos; list != NULL; list = list->next) {
|
||||
lifo = (struct layer_info *)list->data;
|
||||
g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
|
||||
lifo->layer, lifo->layer,
|
||||
lifo->color.red, lifo->color.green, lifo->color.blue);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
|
||||
g_string_printf(buffer, "\\pgfsetlayers{");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
for (list = layer_infos; list != NULL; list = list->next) {
|
||||
lifo = (struct layer_info *)list->data;
|
||||
|
||||
if (list->next == NULL)
|
||||
end_str = ",main}";
|
||||
else
|
||||
end_str = ",";
|
||||
g_string_printf(buffer, "l%d%s", lifo->layer, end_str);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
fwrite("\n", sizeof(char), 1, tex_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write layer Envirmonment
|
||||
*
|
||||
* If the requested layer shall be rendered, this code writes the necessary code
|
||||
* to open the layer. It also returns the color the layer shall be rendered in.
|
||||
*
|
||||
* The followingenvironments are generated:
|
||||
*
|
||||
* @code{.tex}
|
||||
* \begin{pgfonlayer}{<layer>}
|
||||
* % If pdf layers shall be used also this is enabled:
|
||||
* \begin{scope}[ocg={ref=<layer>, status=visible,name={<Layer Name>}}]
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* If the layer shall not be rendered, FALSE is returned and the color is not filled in and
|
||||
* the cod eis not written to the file.
|
||||
*
|
||||
* @param tex_file TeX file to write to
|
||||
* @param color Return of the layer's color
|
||||
* @param layer Requested layer number
|
||||
* @param linfo Layer information list containing layer_info structs
|
||||
* @param buffer Some working buffer
|
||||
* @return TRUE, if the layer shall be rendered.
|
||||
* @note The opened environments have to be closed afterwards
|
||||
*/
|
||||
static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList *linfo, GString *buffer)
|
||||
{
|
||||
GList *temp;
|
||||
struct layer_info *inf;
|
||||
|
||||
for (temp = linfo; temp != NULL; temp = temp->next) {
|
||||
inf = (struct layer_info *)temp->data;
|
||||
if (inf->layer == layer) {
|
||||
color->alpha = inf->color.alpha;
|
||||
color->red = inf->color.red;
|
||||
color->green = inf->color.green;
|
||||
color->blue = inf->color.blue;
|
||||
g_string_printf(buffer, "\\begin{pgfonlayer}{l%d}\n\\ifcreatepdflayers\n\\begin{scope}[ocg={ref=%d, status=visible,name={%s}}]\n\\fi\n",
|
||||
layer, layer, inf->name);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a graphics object to the specified tex_file
|
||||
*
|
||||
* This function opens the layer, writes a graphics object and closes the layer
|
||||
*
|
||||
* @param tex_file File to write to
|
||||
* @param graphics Object to render
|
||||
* @param linfo Layer information
|
||||
* @param buffer Working buffer
|
||||
* @param scale Scale abject down by this value
|
||||
*/
|
||||
static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GString *buffer, double scale)
|
||||
{
|
||||
GList *temp;
|
||||
GList *temp_vertex;
|
||||
struct gds_graphics *gfx;
|
||||
struct gds_point *pt;
|
||||
GdkRGBA color;
|
||||
static const char *line_caps[] = {"butt", "round", "rect"};
|
||||
|
||||
for (temp = graphics; temp != NULL; temp = temp->next) {
|
||||
gfx = (struct gds_graphics *)temp->data;
|
||||
if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) {
|
||||
|
||||
/* Layer is defined => create graphics */
|
||||
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);
|
||||
/* Append vertices */
|
||||
for (temp_vertex = gfx->vertices; temp_vertex != NULL; temp_vertex = temp_vertex->next) {
|
||||
pt = (struct gds_point *)temp_vertex->data;
|
||||
g_string_printf(buffer, "(%lf pt, %lf pt) -- ", ((double)pt->x)/scale, ((double)pt->y)/scale);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
g_string_printf(buffer, "cycle;\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
} else if (gfx->gfx_type == GRAPHIC_PATH) {
|
||||
|
||||
if (g_list_length(gfx->vertices) < 2) {
|
||||
printf("Cannot write path with less than 2 points\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (gfx->path_render_type < 0 || gfx->path_render_type > 2) {
|
||||
printf("Path type unrecognized. Setting to 'flushed'\n");
|
||||
gfx->path_render_type = PATH_FLUSH;
|
||||
}
|
||||
|
||||
g_string_printf(buffer, "\\draw[line width=%lf pt, draw={c%d}, opacity={%lf}, cap=%s] ",
|
||||
gfx->width_absolute/scale, gfx->layer, color.alpha,
|
||||
line_caps[gfx->path_render_type]);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
/* Append vertices */
|
||||
for (temp_vertex = gfx->vertices; temp_vertex != NULL; temp_vertex = temp_vertex->next) {
|
||||
pt = (struct gds_point *)temp_vertex->data;
|
||||
g_string_printf(buffer, "(%lf pt, %lf pt)%s",
|
||||
((double)pt->x)/scale,
|
||||
((double)pt->y)/scale,
|
||||
(temp_vertex->next ? " -- " : ""));
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
g_string_printf(buffer, ";\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
|
||||
g_string_printf(buffer, "\\ifcreatepdflayers\n\\end{scope}\n\\fi\n\\end{pgfonlayer}\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
|
||||
} /* For graphics */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Render cell to file
|
||||
* @param cell Cell to render
|
||||
* @param layer_infos Layer information
|
||||
* @param tex_file File to write to
|
||||
* @param buffer Working buffer
|
||||
* @param scale Scale output down by this value
|
||||
*/
|
||||
static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale)
|
||||
{
|
||||
|
||||
GList *list_child;
|
||||
struct gds_cell_instance *inst;
|
||||
|
||||
/* Draw polygons of current cell */
|
||||
generate_graphics(tex_file, cell->graphic_objs, layer_infos, buffer, scale);
|
||||
|
||||
/* 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)/scale,((double)inst->origin.y)/scale);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n", (inst->flipped ? -1*inst->magnification : inst->magnification),
|
||||
inst->magnification);
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
render_cell(inst->cell_ref, layer_infos, tex_file, buffer, scale);
|
||||
|
||||
g_string_printf(buffer, "\\end{scope}\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
g_string_printf(buffer, "\\end{scope}\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
|
||||
g_string_printf(buffer, "\\end{scope}\n");
|
||||
WRITEOUT_BUFFER(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
|
||||
gboolean create_pdf_layers, gboolean standalone_document)
|
||||
{
|
||||
GString *working_line;
|
||||
|
||||
|
||||
if (!tex_file || !layer_infos || !cell)
|
||||
return;
|
||||
|
||||
/* 10 kB Line working buffer should be enough */
|
||||
working_line = g_string_new_len(NULL, LATEX_LINE_BUFFER_KB*1024);
|
||||
|
||||
/* standalone foo */
|
||||
g_string_printf(working_line, "\\newif\\iftestmode\n\\testmode%s\n",
|
||||
(standalone_document ? "true" : "false"));
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
g_string_printf(working_line, "\\newif\\ifcreatepdflayers\n\\createpdflayers%s\n",
|
||||
(create_pdf_layers ? "true" : "false"));
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
g_string_printf(working_line, "\\iftestmode\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
g_string_printf(working_line, "\\documentclass[tikz]{standalone}\n\\usepackage{xcolor}\n\\usetikzlibrary{ocgx}\n\\begin{document}\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
g_string_printf(working_line, "\\fi\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
|
||||
/* Write layer definitions */
|
||||
write_layer_definitions(tex_file, layer_infos, working_line);
|
||||
|
||||
/* Open tikz Pictute */
|
||||
g_string_printf(working_line, "\\begin{tikzpicture}\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
|
||||
/* Generate graphics output */
|
||||
render_cell(cell, layer_infos, tex_file, working_line, scale);
|
||||
|
||||
|
||||
g_string_printf(working_line, "\\end{tikzpicture}\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
|
||||
g_string_printf(working_line, "\\iftestmode\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
g_string_printf(working_line, "\\end{document}\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
g_string_printf(working_line, "\\fi\n");
|
||||
WRITEOUT_BUFFER(working_line);
|
||||
|
||||
fflush(tex_file);
|
||||
g_string_free(working_line, TRUE);
|
||||
}
|
||||
|
||||
/** @} */
|
Reference in New Issue
Block a user