GDS-Render v1.2.1
latex-renderer.c
Go to the documentation of this file.
1/*
2 * GDSII-Converter
3 * Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
4 *
5 * This file is part of GDSII-Converter.
6 *
7 * GDSII-Converter is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * GDSII-Converter is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
18 */
19
26#include <math.h>
27#include <stdio.h>
29#include <gdk/gdk.h>
30#include <glib/gi18n.h>
31
43 GdsOutputRenderer parent;
45 gboolean pdf_layers;
46};
47
48G_DEFINE_TYPE(LatexRenderer, latex_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
49
50enum {
54};
55
60#define WRITEOUT_BUFFER(buff) fwrite((buff)->str, sizeof(char), (buff)->len, tex_file)
61
74static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString *buffer)
75{
76 GList *list;
77 struct layer_info *lifo;
78
79 for (list = layer_infos; list != NULL; list = list->next) {
80 lifo = (struct layer_info *)list->data;
81
82 if (!lifo->render)
83 continue;
84
85 g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
86 lifo->layer, lifo->layer,
87 lifo->color.red, lifo->color.green, lifo->color.blue);
88 WRITEOUT_BUFFER(buffer);
89 }
90
91 g_string_printf(buffer, "\\pgfsetlayers{");
92 WRITEOUT_BUFFER(buffer);
93
94 for (list = layer_infos; list != NULL; list = list->next) {
95 lifo = (struct layer_info *)list->data;
96
97 if (!lifo->render)
98 continue;
99
100 g_string_printf(buffer, "l%d,", lifo->layer);
101 WRITEOUT_BUFFER(buffer);
102 }
103 g_string_printf(buffer, "main}\n");
104 WRITEOUT_BUFFER(buffer);
105}
106
133static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList *linfo, GString *buffer)
134{
135 GList *temp;
136 struct layer_info *inf;
137
138 for (temp = linfo; temp != NULL; temp = temp->next) {
139 inf = (struct layer_info *)temp->data;
140 if (inf->layer == layer && inf->render) {
141 color->alpha = inf->color.alpha;
142 color->red = inf->color.red;
143 color->green = inf->color.green;
144 color->blue = inf->color.blue;
145 g_string_printf(buffer,
146 "\\begin{pgfonlayer}{l%d}\n\\ifcreatepdflayers\n\\begin{scope}[ocg={ref=%d, status=visible,name={%s}}]\n\\fi\n",
147 layer, layer, inf->name);
148 WRITEOUT_BUFFER(buffer);
149 return TRUE;
150 }
151 }
152 return FALSE;
153}
154
166static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GString *buffer, double scale)
167{
168 GList *temp;
169 GList *temp_vertex;
170 struct gds_graphics *gfx;
171 struct gds_point *pt;
172 GdkRGBA color;
173 static const char * const line_caps[] = {"butt", "round", "rect"};
174
175 for (temp = graphics; temp != NULL; temp = temp->next) {
176 gfx = (struct gds_graphics *)temp->data;
177 if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) {
178
179 /* Layer is defined => create graphics */
180 if (gfx->gfx_type == GRAPHIC_POLYGON || gfx->gfx_type == GRAPHIC_BOX) {
181 g_string_printf(buffer,
182 "\\draw[line width=0.00001 pt, draw={c%d}, fill={c%d}, fill opacity={%lf}] ",
183 gfx->layer, gfx->layer, color.alpha);
184 WRITEOUT_BUFFER(buffer);
185 /* Append vertices */
186 for (temp_vertex = gfx->vertices;
187 temp_vertex != NULL;
188 temp_vertex = temp_vertex->next) {
189 pt = (struct gds_point *)temp_vertex->data;
190 g_string_printf(buffer, "(%lf pt, %lf pt) -- ",
191 ((double)pt->x)/scale,
192 ((double)pt->y)/scale);
193 WRITEOUT_BUFFER(buffer);
194 }
195 g_string_printf(buffer, "cycle;\n");
196 WRITEOUT_BUFFER(buffer);
197 } else if (gfx->gfx_type == GRAPHIC_PATH) {
198
199 if (g_list_length(gfx->vertices) < 2) {
200 printf("Cannot write path with less than 2 points\n");
201 break;
202 }
203
204 if (gfx->path_render_type < 0 || gfx->path_render_type > 2) {
205 printf("Path type unrecognized. Setting to 'flushed'\n");
207 }
208
209 g_string_printf(buffer, "\\draw[line width=%lf pt, draw={c%d}, opacity={%lf}, cap=%s] ",
210 gfx->width_absolute/scale, gfx->layer, color.alpha,
211 line_caps[gfx->path_render_type]);
212 WRITEOUT_BUFFER(buffer);
213
214 /* Append vertices */
215 for (temp_vertex = gfx->vertices;
216 temp_vertex != NULL;
217 temp_vertex = temp_vertex->next) {
218 pt = (struct gds_point *)temp_vertex->data;
219 g_string_printf(buffer, "(%lf pt, %lf pt)%s",
220 ((double)pt->x)/scale,
221 ((double)pt->y)/scale,
222 (temp_vertex->next ? " -- " : ""));
223 WRITEOUT_BUFFER(buffer);
224 }
225 g_string_printf(buffer, ";\n");
226 WRITEOUT_BUFFER(buffer);
227 }
228
229 g_string_printf(buffer, "\\ifcreatepdflayers\n\\end{scope}\n\\fi\n\\end{pgfonlayer}\n");
230 WRITEOUT_BUFFER(buffer);
231 }
232
233 } /* For graphics */
234}
235
245static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale,
246 GdsOutputRenderer *renderer)
247{
248 GString *status;
249 GList *list_child;
250 struct gds_cell_instance *inst;
251
252 status = g_string_new(NULL);
253 g_string_printf(status, _("Generating cell %s"), cell->name);
254 gds_output_renderer_update_async_progress(renderer, status->str);
255 g_string_free(status, TRUE);
256
257 /* Draw polygons of current cell */
258 generate_graphics(tex_file, cell->graphic_objs, layer_infos, buffer, scale);
259
260 /* Draw polygons of childs */
261 for (list_child = cell->child_cells; list_child != NULL; list_child = list_child->next) {
262 inst = (struct gds_cell_instance *)list_child->data;
263
264 /* Abort if cell has no reference */
265 if (!inst->cell_ref)
266 continue;
267
268 /* generate translation scope */
269 g_string_printf(buffer, "\\begin{scope}[shift={(%lf pt,%lf pt)}]\n",
270 ((double)inst->origin.x) / scale, ((double)inst->origin.y) / scale);
271 WRITEOUT_BUFFER(buffer);
272
273 g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle);
274 WRITEOUT_BUFFER(buffer);
275
276 g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n",
277 (inst->flipped ? -1*inst->magnification : inst->magnification),
278 inst->magnification);
279 WRITEOUT_BUFFER(buffer);
280
281 render_cell(inst->cell_ref, layer_infos, tex_file, buffer, scale, renderer);
282
283 g_string_printf(buffer, "\\end{scope}\n");
284 WRITEOUT_BUFFER(buffer);
285
286 g_string_printf(buffer, "\\end{scope}\n");
287 WRITEOUT_BUFFER(buffer);
288
289 g_string_printf(buffer, "\\end{scope}\n");
290 WRITEOUT_BUFFER(buffer);
291 }
292
293}
294
295static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
296 gboolean create_pdf_layers, gboolean standalone_document, GdsOutputRenderer *renderer)
297{
298 GString *working_line;
299
300
301 if (!tex_file || !layer_infos || !cell)
302 return -1;
303
304 /* 10 kB Line working buffer should be enough */
305 working_line = g_string_new_len(NULL, LATEX_LINE_BUFFER_KB*1024);
306
307 /* standalone foo */
308 g_string_printf(working_line, "\\newif\\iftestmode\n\\testmode%s\n",
309 (standalone_document ? "true" : "false"));
310 WRITEOUT_BUFFER(working_line);
311 g_string_printf(working_line, "\\newif\\ifcreatepdflayers\n\\createpdflayers%s\n",
312 (create_pdf_layers ? "true" : "false"));
313 WRITEOUT_BUFFER(working_line);
314 g_string_printf(working_line, "\\iftestmode\n");
315 WRITEOUT_BUFFER(working_line);
316 g_string_printf(working_line,
317 "\\documentclass[tikz]{standalone}\n\\usepackage{xcolor}\n\\usetikzlibrary{ocgx}\n\\begin{document}\n");
318 WRITEOUT_BUFFER(working_line);
319 g_string_printf(working_line, "\\fi\n");
320 WRITEOUT_BUFFER(working_line);
321
322 /* Write layer definitions */
323 write_layer_definitions(tex_file, layer_infos, working_line);
324
325 /* Open tikz Pictute */
326 g_string_printf(working_line, "\\begin{tikzpicture}\n");
327 WRITEOUT_BUFFER(working_line);
328
329 /* Generate graphics output */
330 render_cell(cell, layer_infos, tex_file, working_line, scale, renderer);
331
332
333 g_string_printf(working_line, "\\end{tikzpicture}\n");
334 WRITEOUT_BUFFER(working_line);
335
336 g_string_printf(working_line, "\\iftestmode\n");
337 WRITEOUT_BUFFER(working_line);
338 g_string_printf(working_line, "\\end{document}\n");
339 WRITEOUT_BUFFER(working_line);
340 g_string_printf(working_line, "\\fi\n");
341 WRITEOUT_BUFFER(working_line);
342
343 fflush(tex_file);
344 g_string_free(working_line, TRUE);
345
346 return 0;
347}
348
349static int latex_renderer_render_output(GdsOutputRenderer *renderer,
350 struct gds_cell *cell,
351 double scale)
352{
353 LatexRenderer *l_renderer = GDS_RENDER_LATEX_RENDERER(renderer);
354 FILE *tex_file;
355 int ret = -2;
356 LayerSettings *settings;
357 GList *layer_infos = NULL;
358 const char *output_file;
359
360 output_file = gds_output_renderer_get_output_file(renderer);
362
363 /* Set layer info list. In case of failure it remains NULL */
364 if (settings)
365 layer_infos = layer_settings_get_layer_info_list(settings);
366
367 tex_file = fopen(output_file, "w");
368 if (tex_file) {
369 ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale,
370 l_renderer->pdf_layers, l_renderer->tex_standalone, renderer);
371 fclose(tex_file);
372 } else {
373 g_warning(_("Could not open LaTeX output file"));
374 }
375
376 if (settings)
377 g_object_unref(settings);
378
379 return ret;
380}
381
382static void latex_renderer_init(LatexRenderer *self)
383{
384 self->pdf_layers = FALSE;
385 self->tex_standalone = FALSE;
386}
387
388static void latex_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
389{
390 LatexRenderer *self = GDS_RENDER_LATEX_RENDERER(obj);
391
392 switch (property_id) {
393 case PROP_STANDALONE:
394 g_value_set_boolean(value, self->tex_standalone);
395 break;
396 case PROP_PDF_LAYERS:
397 g_value_set_boolean(value, self->pdf_layers);
398 break;
399 default:
400 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
401 break;
402 }
403}
404
405static void latex_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
406{
407 LatexRenderer *self = GDS_RENDER_LATEX_RENDERER(obj);
408
409 switch (property_id) {
410 case PROP_STANDALONE:
411 self->tex_standalone = g_value_get_boolean(value);
412 break;
413 case PROP_PDF_LAYERS:
414 self->pdf_layers = g_value_get_boolean(value);
415 break;
416 default:
417 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
418 break;
419 }
420}
421
422static GParamSpec *latex_renderer_properties[N_PROPERTIES] = {NULL};
423
424static void latex_renderer_class_init(LatexRendererClass *klass)
425{
426 GdsOutputRendererClass *render_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
427 GObjectClass *oclass = G_OBJECT_CLASS(klass);
428
429 /* Overwrite virtual function */
430 render_class->render_output = latex_renderer_render_output;
431
432 /* Property stuff */
433 oclass->get_property = latex_renderer_get_property;
434 oclass->set_property = latex_renderer_set_property;
435
437 g_param_spec_boolean("standalone",
438 N_("Standalone TeX file"),
439 N_("Generate a standalone LaTeX file."),
440 FALSE,
441 G_PARAM_READWRITE);
443 g_param_spec_boolean("pdf-layers",
444 N_("PDF OCR layers"),
445 N_("Generate OCR layers"),
446 FALSE,
447 G_PARAM_READWRITE);
448
449 g_object_class_install_properties(oclass, N_PROPERTIES, latex_renderer_properties);
450}
451
452LatexRenderer *latex_renderer_new()
453{
454 return GDS_RENDER_LATEX_RENDERER(g_object_new(GDS_RENDER_TYPE_LATEX_RENDERER, NULL));
455}
456
457LatexRenderer *latex_renderer_new_with_options(gboolean pdf_layers, gboolean standalone)
458{
459 GObject *obj;
460
461 obj = g_object_new(GDS_RENDER_TYPE_LATEX_RENDERER, "standalone", standalone, "pdf-layers", pdf_layers, NULL);
462 return GDS_RENDER_LATEX_RENDERER(obj);
463}
464
@ GRAPHIC_POLYGON
An arbitrary polygon.
Definition: gds-types.h:51
@ GRAPHIC_PATH
Path. Esentially a line.
Definition: gds-types.h:50
@ GRAPHIC_BOX
A rectangle.
Definition: gds-types.h:52
@ PATH_FLUSH
Definition: gds-types.h:58
const char * gds_output_renderer_get_output_file(GdsOutputRenderer *renderer)
Convenience function for getting the "output-file" property.
void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status)
This function emits the 'progress-changed' in the thread/context that triggered an asynchronous rende...
LayerSettings * gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer *renderer)
Get layer settings.
#define GDS_RENDER_TYPE_OUTPUT_RENDERER
static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString *buffer)
Write the layer declarration to TeX file.
static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale, gboolean create_pdf_layers, gboolean standalone_document, GdsOutputRenderer *renderer)
static void latex_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
static GParamSpec * latex_renderer_properties[N_PROPERTIES]
static int latex_renderer_render_output(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList *linfo, GString *buffer)
Write layer Envirmonment.
LatexRenderer * latex_renderer_new_with_options(gboolean pdf_layers, gboolean standalone)
Create new LatexRenderer object.
#define LATEX_LINE_BUFFER_KB
Buffer for LaTeX Code line in KiB.
static void latex_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
#define WRITEOUT_BUFFER(buff)
Writes a GString buffer to the fixed file tex_file.
LatexRenderer * latex_renderer_new()
Create new LatexRenderer object.
static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale, GdsOutputRenderer *renderer)
Render cell to file.
static void latex_renderer_class_init(LatexRendererClass *klass)
static void latex_renderer_init(LatexRenderer *self)
#define GDS_RENDER_TYPE_LATEX_RENDERER
static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GString *buffer, double scale)
Writes a graphics object to the specified tex_file.
@ N_PROPERTIES
@ PROP_PDF_LAYERS
@ PROP_STANDALONE
LaTeX output renderer.
GList * layer_settings_get_layer_info_list(LayerSettings *settings)
Get a GList with layer_info structs.
Struct representing the LaTeX-Renderer object.
GdsOutputRenderer parent
gboolean tex_standalone
gboolean pdf_layers
This represents an instanc of a cell inside another cell.
Definition: gds-types.h:110
int flipped
Mirrored on x-axis before rotation.
Definition: gds-types.h:114
double angle
Angle of rotation (counter clockwise) in degrees.
Definition: gds-types.h:115
double magnification
magnification
Definition: gds-types.h:116
struct gds_cell * cell_ref
Referenced gds_cell structure.
Definition: gds-types.h:112
struct gds_point origin
Origin.
Definition: gds-types.h:113
A Cell inside a gds_library.
Definition: gds-types.h:122
char name[CELL_NAME_MAX]
Definition: gds-types.h:123
GList * child_cells
List of gds_cell_instance elements.
Definition: gds-types.h:126
GList * graphic_objs
List of gds_graphics.
Definition: gds-types.h:127
A GDS graphics object.
Definition: gds-types.h:98
enum graphics_type gfx_type
Type of graphic.
Definition: gds-types.h:99
enum path_type path_render_type
Line cap.
Definition: gds-types.h:101
int width_absolute
Width. Not used for objects other than paths.
Definition: gds-types.h:102
int16_t layer
Layer the graphic object is on.
Definition: gds-types.h:103
GList * vertices
List of gds_point.
Definition: gds-types.h:100
A point in the 2D plane. Sometimes referred to as vertex.
Definition: gds-types.h:63
Layer information.
int render
true: Render to output
char * name
Layer name.
GdkRGBA color
RGBA color used to render this layer.
int layer
Layer number.