/* * chart.c: high level chart graphics generator * * Copyright (C) 1997-2005 John Coppens (john@jcoppens.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "support.h" #include "types.h" #include "element.h" #include "printer.h" #include "global.h" #include "load.h" #include "log.h" #include "aux.h" #include "main.h" #include "chart_def.h" #include "chart.h" // Note that the initial_bg is relative to PACKAGE_DATA_DIR #define initial_bg "/pixmaps/linsmith/smithent.png" gdouble chartw, charth, z0 = 50.0, last_lw = 0.1; gboolean logomode = TRUE, imp_mode = TRUE, printchart = FALSE; complex act_imp; int load_nr, el_nr, nr_els, last_color = 0, zoom_factor = 0; GnomeCanvas *chart_canvas = NULL; GnomeCanvasItem *chart_bg = NULL, *swr_circle = NULL; GnomeCanvasGroup *bg_group = NULL, *point_group = NULL, *line_group = NULL; struct { char *name; double factor; } zoom_table[] = { {"x0.1", 0.1}, {"x0.15", 0.15}, {"x0.2", 0.2}, {"x0.3", 0.3}, {"x0.5", 0.5}, {"x0.7", 0.7}, {"x1", 1.0}, {"x1.5", 1.5}, {"x2", 2.0}, {"x3", 3.0}, {"x5", 5.0}, {"x7", 7.0}, {"x10", 10.0} }; #define ZOOM_MIN -6 #define ZOOM_MAX 6 void make_group(GnomeCanvasGroup **grp) { GnomeCanvasItem *item; if (!(*grp)) { item = gnome_canvas_item_new(gnome_canvas_root(chart_canvas), gnome_canvas_group_get_type(), "x", 0.0, "y", 0.0, NULL); *grp = GNOME_CANVAS_GROUP(item); } } void update_chart_z0(void) { GtkWidget *w = lookup_widget(MainWindow, "z0_cbbox"); char *p; double z0 = atof(p = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w))); g_free(p); if (z0 == 0) { ok_dialog(_("Value"), _("Invalid value for Zo")); return; } pref.chart_z0 = z0; } void set_chart_background_bitmap(char *bgf) { GnomeCanvasGroup *grp = gnome_canvas_root(chart_canvas); GdkPixbuf *chart_pxm; if (debug & DBG_GRAPHICS) fprintf(stderr, "%s\n", bgf); chart_pxm = gdk_pixbuf_new_from_file(bgf, NULL); if (!chart_pxm) printf(_("Can't load the chart background\n")); chartw = gdk_pixbuf_get_width(chart_pxm); charth = gdk_pixbuf_get_height(chart_pxm); if (chart_bg) gtk_object_destroy(GTK_OBJECT(chart_bg)); chart_bg = gnome_canvas_item_new(grp, gnome_canvas_pixbuf_get_type(), "pixbuf", chart_pxm, "x", 0.0, "y", -charth/2, "width", chartw, "height", charth, NULL); gdk_pixbuf_unref(chart_pxm); gnome_canvas_set_scroll_region(chart_canvas, 0.0, -charth/2, chartw, charth/2); } void set_chart_background_vector(void) { GnomeCanvasGroup *grp = gnome_canvas_root(chart_canvas); int def; if (chart_bg) gtk_object_destroy(GTK_OBJECT(chart_bg)); gnome_canvas_item_new(grp, gnome_canvas_ellipse_get_type(), "x1", 0.0, "y1", (double) -pref.vec_bg_radius, "x2", (double) pref.vec_bg_radius * 2, "y2", (double) pref.vec_bg_radius, "fill_color_rgba", pref.vec_background, NULL); for (def = 0; def < nrpldefs; def++) { switch (pldef[def].type) { case 'R': setlinestyle(&grp, 1, pldef[def].bold ? pref.arc_color[RB_ARC] : pref.arc_color[R_ARC]); rg_arc(&grp, pldef[def].val + pldef[def].a_max * I, pldef[def].val + pldef[def].a_min * I, 1.0, TRUE); break; case 'X': setlinestyle(&grp, 1, pldef[def].bold ? pref.arc_color[XB_ARC] : pref.arc_color[X_ARC]); x_arc(&grp, pldef[def].a_max + pldef[def].val * I, pldef[def].a_min + pldef[def].val * I, 1.0); x_arc(&grp, pldef[def].a_max - pldef[def].val * I, pldef[def].a_min - pldef[def].val * I, 1.0); break; } } gnome_canvas_set_scroll_region(chart_canvas, 0.0, -pref.vec_bg_radius, pref.vec_bg_radius * 2, pref.vec_bg_radius); } void set_chart_background(void) { if (pref.use_bitmap) set_chart_background_bitmap(pref.chart); else set_chart_background_vector(); } void draw_swr_circle(double swr) { if (swr_circle) gtk_object_destroy(GTK_OBJECT(swr_circle)); setlinestyle(&bg_group, 1, pref.swr_color); swr_circle = k_arc(&bg_group, z0/swr - 0.001*I, z0/swr + 0.001*I, z0); } void draw_extras(void) { double z0 = pref.chart_z0; if (pref.show_swr) draw_swr_circle(pref.swr_circle); if (pref.show_g1) { setlinestyle(&bg_group, 1, pref.g1_color); rg_arc(&bg_group, 50 - 1e5*I, 50 + 1e5*I, pref.chart_z0, FALSE); } } void stop_logomode(void) { if (logomode) { set_chart_background(); make_group(&bg_group); make_group(&line_group); make_group(&point_group); draw_extras(); logomode = FALSE; } } void chart_initialize(void) { char *p = g_strconcat(PACKAGE_DATA_DIR, initial_bg, NULL); chart_canvas = GNOME_CANVAS(lookup_widget(MainWindow, "chart_canvas")); set_chart_background_bitmap(p); if (debug & DBG_GRAPHICS) fprintf(stderr, "[chart_init] %s\n", p); g_free(p); } void pos2impedance(complex *c, gdouble x, gdouble y) { gdouble tX, tY, M, radius = pref.use_bitmap ? pref.chartradius : pref.vec_bg_radius, x_offs = pref.use_bitmap ? pref.x_offs : 0, y_offs = pref.use_bitmap ? pref.y_offs : 0; tX = (x - x_offs - radius) / radius; tY = y / radius; M = (pow(1.0 - tX, 2.0) + pow(tY, 2.0)); *c = pref.chart_z0 * (1.0 - pow(tX, 2.0) - pow(tY, 2.0)) / M - pref.chart_z0 * 2.0 * tY / M * I; } complex reflection_coef(complex z, complex z0) { complex k = (z - z0)/(z + z0); if (debug & DBG_MATH) fprintf(stderr, "[refl_c] z: (%f %+fj), z0: (%f %+fj)\n", creal(z), cimag(z), creal(z0), cimag(z0)); return k; } void update_cursor_values(int x, int y) { GtkWidget *w; double m, swr, q, wx, wy, radius = pref.use_bitmap ? pref.chartradius : pref.vec_bg_radius, x_offs = pref.use_bitmap ? pref.x_offs : 0, y_offs = pref.use_bitmap ? pref.y_offs : 0; complex imp, k; char *bff; gnome_canvas_window_to_world(chart_canvas, x, y, &wx, &wy); m = sqrt(pow(wx - x_offs - radius, 2.0) + pow(wy - y_offs, 2.0)); if (m > radius) return; stop_logomode(); pos2impedance(&imp, wx, wy); k = reflection_coef(imp, z0); if (cabs(k) == 1.0) { swr = 9999.9; } else { swr = -(cabs(k) + 1.0)/(cabs(k) - 1.0); } if (swr > 10000.0) swr = 9999.9; // Quality factor if (creal(imp) != 0.0) { q = cimag(imp) / creal(imp); } else { q = 999.9; } if (q > 1000.0) q = 999.9; else if (q < -1000.0) q = -999.9; w = lookup_widget(MainWindow, "stat_z_lbl"); bff = g_strdup_printf("%8.2lf %+8.2lfj", pref.cursor_font, creal(imp), cimag(imp)); gtk_label_set_markup(GTK_LABEL(w), bff); g_free(bff); w = lookup_widget(MainWindow, "stat_zpol_lbl"); bff = g_strdup_printf("%.2lf <%.2lf°", pref.cursor_font, cabs(imp), carg(imp)*57.29578); gtk_label_set_markup(GTK_LABEL(w), bff); g_free(bff); w = lookup_widget(MainWindow, "stat_swr_lbl"); bff = g_strdup_printf("%.2lf", pref.cursor_font, swr); gtk_label_set_markup(GTK_LABEL(w), bff); g_free(bff); w = lookup_widget(MainWindow, "stat_q_lbl"); bff = g_strdup_printf("%.2lf", pref.cursor_font, q); gtk_label_set_markup(GTK_LABEL(w), bff); g_free(bff); } //--------------------------------------------------------------------- // chart_point routines //--------------------------------------------------------------------- static gint point_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) { static double x, y; double new_x, new_y; GdkCursor *fleur; static int dragging; double item_x, item_y; item_x = event->button.x; item_y = event->button.y; gnome_canvas_item_w2i(item->parent, &item_x, &item_y); switch (event->type) { case GDK_BUTTON_PRESS: switch(event->button.button) { case 1: x = item_x; y = item_y; fleur = gdk_cursor_new(GDK_FLEUR); gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, fleur, event->button.time); gdk_cursor_destroy(fleur); dragging = TRUE; break; default: break; } break; case GDK_MOTION_NOTIFY: if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) { // CHANGE chartradius for vector too // move_rotation_cursor(data, atan2(pref.chartradius - item_x, // item_y)); } break; case GDK_BUTTON_RELEASE: gnome_canvas_item_ungrab(item, event->button.time); dragging = FALSE; break; default: break; } return FALSE; } chart_pt create_load_point(void) { chart_pt pt = malloc(sizeof(chart_point)); if (debug & DBG_GRAPHICS) fprintf(stderr, "[create_ld]\n"); stop_logomode(); pt->group = point_group; pt->point = gnome_canvas_item_new(point_group, gnome_canvas_ellipse_get_type(), "width_pixels", 1, NULL); pt->handler = g_signal_connect(GTK_OBJECT(pt->point), "event", GTK_SIGNAL_FUNC(point_event), pt); set_point_fixed(pt, TRUE); return pt; } chart_pt create_element_point(void) { chart_pt pt = malloc(sizeof(chart_point)); if (debug & DBG_GRAPHICS) fprintf(stderr, "[create_el_pt]\n"); stop_logomode(); pt->group = point_group; pt->point = gnome_canvas_item_new(point_group, gnome_canvas_ellipse_get_type(), "width_pixels", 1, NULL); pt->handler = g_signal_connect(GTK_OBJECT(pt->point), "event", GTK_SIGNAL_FUNC(point_event), pt); set_point_fixed(pt, TRUE); return pt; } chart_ln create_element_line(void) { chart_ln ln = malloc(sizeof(chart_line)); if (debug & DBG_GRAPHICS) fprintf(stderr, "[create_el_ln]\n"); stop_logomode(); ln->group = line_group; ln->line = gnome_canvas_item_new(line_group, gnome_canvas_line_get_type(), "width_pixels", 1, NULL); return ln; } void show_point(chart_pt pt) { double x, y, s2, radius = pref.use_bitmap ? pref.chartradius : pref.vec_bg_radius, x_offs = pref.use_bitmap ? pref.x_offs : 0, y_offs = pref.use_bitmap ? pref.y_offs : 0; guint32 color; complex k = reflection_coef(pt->value, pref.chart_z0); x = 1 + creal(k); y = cimag(k); if (printchart) print_point(x, y, pt->style); s2 = pref.point_size[pt->style]/2; color = pref.point_color[pt->style]; if (debug & DBG_GRAPHICS) fprintf(stderr, "[show_pt] re:%f im:%f size:%f color:%08x\n", creal(pt->value), cimag(pt->value), s2, color); gnome_canvas_item_set(pt->point, "x1", x * radius + x_offs - s2, "y1", -y * radius + y_offs + s2, "x2", x * radius + x_offs + s2, "y2", -y * radius + y_offs - s2, "fill_color_rgba", color, "outline_color_rgba", pt->fixed ? 0x000000ff : color, NULL); } void set_point(chart_pt pt, complex val, int ptype) { pt->value = val; pt->line = FALSE; pt->fixed = TRUE; pt->style = ptype; show_point(pt); } void set_point_fixed(chart_point *pt, gboolean fixed) { int color; if (fixed) { if (pt->fixed) return; pt->fixed = TRUE; g_signal_handler_block(GTK_OBJECT(pt->point), pt->handler); gnome_canvas_item_set(pt->point, "outline-color", "black", NULL); } else { if (!pt->fixed) return; pt->fixed = FALSE; color = pref.point_color[pt->style]; g_signal_handler_unblock(GTK_OBJECT(pt->point), pt->handler); gnome_canvas_item_set(pt->point, "outline-color-rgba", color, NULL); } } gboolean foreach_load(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { load_definition load; char bff[30]; gtk_tree_model_get(model, iter, LD_FREQ_VAL, &load.f, LD_REAL_VAL, &load.r, LD_REACT_VAL, &load.x, LD_POINT, &load.pt, -1); set_point(load.pt, load.r + I*load.x, ZPT_LOAD); gtk_list_store_set(GTK_LIST_STORE(model), iter, LD_POINT, load.pt, -1); sprintf(bff, "%.1f MHz", load.f); load_nr++; return FALSE; } void recalculate_loads(void) { GtkWidget *loads = lookup_widget(MainWindow, "load_treeview"); GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(loads)); update_chart_z0(); if (store) { load_nr = 0; gtk_tree_model_foreach(store, foreach_load, NULL); } } complex reciprocal(complex z) { return pref.chart_z0 * pref.chart_z0 / z; } //--------------------------------------------------------------------- // Recalculate the circuit: // for each element // for each frequency // calculate component value // calculate the resulting impedance //--------------------------------------------------------------------- void combine_impedance(el_definition *el, double f) { complex res, el_imp; double wl, z0 = pref.chart_z0; switch (el->typ) { case ELT_CAP: case ELT_IND: case ELT_PARLC: case ELT_SERLC: case ELT_OSTUB: case ELT_SSTUB: switch (el->conn) { case ELC_SERIES: el_imp = calc_el_impedance(el, f); act_imp = act_imp + el_imp; break; case ELC_PARALLEL: el_imp = calc_el_impedance(el, f); act_imp = (act_imp * el_imp)/(act_imp + el_imp); break; } break; case ELT_LINE: wl = el->val1 / (el->vf * 300000 / f); el_imp = el->val1 / wl; act_imp = calc_line_impedance(act_imp, el->z0, wl, f); break; case ELT_XFORM: el_imp = el->val1; act_imp = el->val1 * act_imp; break; case ELT_ZY: el_imp = 0.0; break; } if (debug & DBG_ELEMENTS) fprintf(stderr, "[combined] %f %fj\n", creal(act_imp), cimag(act_imp)); loglist_set_impedance(load_nr, el_nr, el_imp, act_imp, el->typ); } void add_point_to_list(chart_ptlist *ptlst, gboolean islast) { chart_pt pt; if (load_nr == 0) clear_element_ptlist(ptlst); pt = create_element_point(); *ptlst = g_list_append(*ptlst, pt); set_point(pt, imp_mode ? act_imp : reciprocal(act_imp), islast ? ZPT_FINAL : ZPT_INT); } void add_line_to_list(el_definition *el, complex prev_imp, double f) { chart_ln ln; int arctype; gboolean prev_first; complex imp1, imp2; double wl; if (load_nr == 0) clear_element_lnlist(&el->lnlst); ln = create_element_line(); el->lnlst = g_list_append(el->lnlst, ln); switch (el->typ) { case ELT_OSTUB: case ELT_SSTUB: case ELT_LINE: wl = 300000 * el->vf / f; // milimeters } switch (el->typ) { case ELT_CAP: // R is constant here. case ELT_IND: case ELT_PARLC: case ELT_SERLC: case ELT_OSTUB: case ELT_SSTUB: switch (el->conn) { case ELC_SERIES: arctype = Z_ARC; break; case ELC_PARALLEL: arctype = Y_ARC; break; } if (cimag(prev_imp) < cimag(act_imp)) { // Inductive imp2 = prev_imp; imp1 = act_imp; } else { // Capacitive imp1 = prev_imp; imp2 = act_imp; } switch (el->conn) { case ELC_SERIES: setlinestyle(&ln->group, 1, pref.arc_color[Z_ARC]); ln->line = rg_arc(&ln->group, imp1, imp2, pref.chart_z0, imp_mode); if (printchart) { print_setlinestyle(pref.prt_arc_size[Z_ARC], pref.prt_arc_color[Z_ARC]); ln->line = rg_arc(NULL, imp1, imp2, pref.chart_z0, imp_mode); } break; case ELC_PARALLEL: setlinestyle(&ln->group, 1, pref.arc_color[Y_ARC]); ln->line = rg_arc(&ln->group, reciprocal(imp2), reciprocal(imp1), pref.chart_z0, !imp_mode); if (printchart) { print_setlinestyle(pref.prt_arc_size[Y_ARC], pref.prt_arc_color[Y_ARC]); ln->line = rg_arc(NULL, reciprocal(imp2), reciprocal(imp1), pref.chart_z0, !imp_mode); } break; } break; case ELT_LINE: setlinestyle(&ln->group, 1, pref.arc_color[K_ARC]); if (imp_mode) ln->line = k_arc(&ln->group, act_imp, prev_imp, el->z0); else ln->line = k_arc(&ln->group, reciprocal(act_imp), reciprocal(prev_imp), el->z0); if (printchart) { print_setlinestyle(pref.prt_arc_size[K_ARC], pref.prt_arc_color[K_ARC]); if (imp_mode) ln->line = k_arc(NULL, act_imp, prev_imp, el->z0); else ln->line = k_arc(&ln->group, reciprocal(act_imp), reciprocal(prev_imp), el->z0); } break; case ELT_ZY: setlinestyle(&ln->group, 1, pref.arc_color[ZY_LINE]); ln->line = zy_line(&ln->group, act_imp); if (printchart) { print_setlinestyle(pref.prt_arc_size[ZY_LINE], pref.prt_arc_color[ZY_LINE]); ln->line = zy_line(NULL, act_imp); } imp_mode = !imp_mode; break; } } gboolean recalc_each_element(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { GtkTreeSelection *sel; el_definition el; chart_pt pt; complex prev_imp; double f; char bff[30]; gboolean haveselection; f = ((load_definition *)user_data)->f; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(el_view)); if (gtk_tree_selection_iter_is_selected(sel, iter)) { el = act_el; } else { gtk_tree_model_get(model, iter, EL_CONN_VAL, &el.conn, EL_TYPE_VAL, &el.typ, EL_VAL_VAL1, &el.val1, EL_VAL_VAL2, &el.val2, EL_Z0_VAL, &el.z0, EL_VF_VAL, &el.vf, EL_USE_LOSS, &el.useloss, EL_LOSS1_VAL, &el.loss1, EL_MHZ1_VAL, &el.mhz1, EL_LOSS2_VAL, &el.loss2, EL_MHZ2_VAL, &el.mhz2, -1); } gtk_tree_model_get(model, iter, EL_POINTLIST, &el.ptlst, EL_LINELIST, &el.lnlst, -1); if (debug & DBG_ELEMENTS) fprintf(stderr, "[each elem] %d, %d, %f, %f\n", el.conn, el.typ, el.val1, el.val2); prev_imp = act_imp; combine_impedance(&el, f); sprintf(bff, "Z%d", load_nr); add_line_to_list(&el, prev_imp, f); add_point_to_list(&el.ptlst, el_nr == nr_els-1); gtk_list_store_set(GTK_LIST_STORE(model), iter, EL_POINTLIST, el.ptlst, EL_LINELIST, el.lnlst, -1); el_nr++; return FALSE; } gboolean recalc_each_load(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { GtkTreeModel *elstore = user_data; load_definition load; complex imp; gtk_tree_model_get(model, iter, LD_FREQ_VAL, &load.f, LD_REAL_VAL, &load.r, LD_REACT_VAL, &load.x, LD_POINT, &load.pt, -1); act_imp = load.r + I * load.x; imp_mode = TRUE; loglist_set_load(load_nr, load.f, act_imp); if (debug & DBG_LOADS) fprintf(stderr, "[each load] At %f: %f %fj\n", load.f, load.r, load.x); el_nr = 0; nr_els = gtk_tree_model_iter_n_children(elstore, NULL); gtk_tree_model_foreach(elstore, recalc_each_element, &load); load_nr++; return FALSE; } void recalculate_elements(void) { GtkWidget *els = lookup_widget(MainWindow, "circ_treeview"); GtkTreeModel *elstore = gtk_tree_view_get_model(GTK_TREE_VIEW(els)); GtkWidget *loads = lookup_widget(MainWindow, "load_treeview"); GtkTreeModel *ldstore = gtk_tree_view_get_model(GTK_TREE_VIEW(loads)); load_nr = 0; gtk_tree_model_foreach(ldstore, recalc_each_load, elstore); } void recalculate_all(void) { update_chart_z0(); loglist_create(number_loads(), number_elements()); recalculate_loads(); recalculate_elements(); loglist_show(); } void recalculate_all_export(void) { if (run_filedialog(_("Postscript filename:"), pref.last_ps_file, "*.ps")) { if (g_file_test(pref.last_ps_file, G_FILE_TEST_EXISTS)) { if (ok_cancel_dialog(_("Confirmation"), _("This file already exists.\n" "Pressing Ok will overwrite it.")) == 1) return; } create_printer_chart(); } else return; printchart = TRUE; recalculate_all(); printchart = FALSE; close_printer_chart(); } //--------------------------------------------------------------------- // Chart element generation // arcs are in radians! //--------------------------------------------------------------------- void setlinestyle(GnomeCanvasGroup **grp, double lw, int color) { if (!grp) { print_setlinestyle(lw, color); return; } last_lw = lw; last_color = color; } void setfontstyle(GnomeCanvasGroup **grp, char *font, double size, int color) { if (!grp) { print_setfontstyle(font, size, color); return; } } GnomeCanvasItem * do_arc(GnomeCanvasGroup **grp, double x, double y, double arcb, double arce, double rad) { GnomeCanvasItem *item; GnomeCanvasPoints *points; int nr, a; guint32 color; double px, py, arc, arclen, darc, x_offs = pref.use_bitmap ? pref.x_offs : 0, y_offs = pref.use_bitmap ? pref.y_offs : 0, radius = pref.use_bitmap ? pref.chartradius : pref.vec_bg_radius; if (!grp) { print_do_arc(x, y, arcb, arce, rad); return NULL; } arc = arce - arcb; if (arc < 0) arc = arc + 2 * M_PI; arclen = arc * radius; nr = arclen / 3 + 1; if (nr < 10) nr = 10; darc = arc / (nr-1); points = gnome_canvas_points_new(nr); for (a = 0; a < nr; a++) { px = radius *( x + rad * cos(arcb + a*darc)) + x_offs; py = radius *(-y - rad * sin(arcb + a*darc)) + y_offs; if (debug & DBG_MATH) fprintf(stderr, "[do_arc] %f %f\n", px, py); points->coords[a*2 + 0] = px; points->coords[a*2 + 1] = py; } item = gnome_canvas_item_new(*grp, gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", last_color, "width_pixels", 1, NULL); gnome_canvas_points_unref(points); return item; } GnomeCanvasItem * do_line(GnomeCanvasGroup **grp, double x1, double y1, double x2, double y2) { GnomeCanvasItem *item; GnomeCanvasPoints *points; double radius = pref.use_bitmap ? pref.chartradius : pref.vec_bg_radius, x_offs = pref.use_bitmap ? pref.x_offs : 0, y_offs = pref.use_bitmap ? pref.y_offs : 0; if (!grp) { print_do_line(x1, y1, x2, y2); return NULL; } points = gnome_canvas_points_new(2); points->coords[0] = x1 * radius + x_offs; points->coords[1] = -y1 * radius + y_offs; points->coords[2] = x2 * radius + x_offs; points->coords[3] = -y2 * radius + y_offs; item = gnome_canvas_item_new(*grp, gnome_canvas_line_get_type(), "points", points, "fill_color_rgba", last_color, "width_pixels", 1, NULL); gnome_canvas_points_unref(points); return item; } GnomeCanvasItem * do_string(GnomeCanvasGroup **grp, char *lbl, double x, double y, double size, double angle) { if (!grp) { print_do_string(lbl, x, y, size, angle); return NULL; } return NULL; } GnomeCanvasItem * rg_arc(GnomeCanvasGroup **grp, complex zb, complex ze, double z0, gboolean imp_mode) { double radius; complex rcb, rce; radius = (1.0 - reflection_coef(creal(zb), z0)) / 2.0; rcb = reflection_coef(zb, z0); rce = reflection_coef(ze, z0); rcb = rcb - (1 - radius); rce = rce - (1 - radius); if (cimag(zb) > cimag(ze)) { if (imp_mode) return do_arc(grp, 2.0 - radius, 0.0, carg(rcb), carg(rce), radius); else return do_arc(grp, radius, 0.0, carg(rcb) + M_PI, carg(rce) + M_PI, radius); } else { if (imp_mode) return do_arc(grp, 2.0 - radius, 0.0, carg(rce), carg(rcb), radius); else return do_arc(grp, radius, 0.0, carg(rce) + M_PI, carg(rcb) + M_PI, radius); } } GnomeCanvasItem * x_arc(GnomeCanvasGroup **grp, complex zb, complex ze, double z0) { double radius; complex rcb, rce; rcb = reflection_coef(zb, z0); rce = reflection_coef(ze, z0); if (cimag(zb) == 0) { return do_line(grp, creal(rcb) + 1, 0.0, creal(rce) + 1, 0.0); } else { radius = z0 / cimag(zb); rcb = rcb - radius * I - 1.0; rce = rce - radius * I - 1.0; if (cimag(zb) > 0) return do_arc(grp, 2.0, radius, carg(rce), carg(rcb), fabs(radius)); else return do_arc(grp, 2.0, radius, carg(rcb), carg(rce), fabs(radius)); } } GnomeCanvasItem * k_arc(GnomeCanvasGroup **grp, complex zbeg, complex zend, double z0) { double b_ang, e_ang, ch_z0 = pref.chart_z0, swr1, swr2, rcabs, rcrad, rc1, rc2; complex rc, b_rc, e_rc, test; // Calculate the circle's center point rc = reflection_coef(zbeg, z0); rcabs = cabs(rc); swr1 = (1 + rcabs)/(1 - rcabs) * z0 / ch_z0; swr2 = (1 - rcabs)/(1 + rcabs) * z0 / ch_z0; rc1 = (swr1 - 1)/(swr1 + 1); rc2 = (swr2 - 1)/(swr2 + 1); rcrad = (rc1 - rc2)/2; b_rc = reflection_coef(zbeg, ch_z0); e_rc = reflection_coef(zend, ch_z0); b_ang = carg(b_rc - (rc1 - rcrad)); e_ang = carg(e_rc - (rc1 - rcrad)); switch (pref.rotation) { case TO_GENERATOR: return do_arc(grp, 1 + rc1 - rcrad, 0.0, b_ang, e_ang, rcrad); case TO_LOAD: return do_arc(grp, 1 + rc1 - rcrad, 0.0, e_ang, b_ang, rcrad); } } GnomeCanvasItem * zy_line(GnomeCanvasGroup **grp, complex z) { double ch_z0 = pref.chart_z0; complex rc; rc = reflection_coef(z, ch_z0); return do_line(grp, creal(rc) + 1.0, cimag(rc), -creal(rc) + 1.0, -cimag(rc)); } GnomeCanvasItem * r_label(GnomeCanvasGroup **grp, double r, double x, char where) { complex rc = reflection_coef(r + x*I, 1.0); double radius, x1, x2, y2, alpha; char bff[10]; radius = (1.0 - reflection_coef(r, 1.0)) / 2.0, x1 = 1.0 - radius; x2 = creal(rc); y2 = cimag(rc); sprintf(bff, "%.*f", (r > 5) ? 0 : 1, r); return do_string(grp, bff, creal(rc) + 1, cimag(rc), 2.0, atan2(y2, x2-x1) - M_PI/2); } GnomeCanvasItem * x_label(GnomeCanvasGroup **grp, double r, double x, char where) { complex rc = reflection_coef(r + x*I, 1.0); double radius, x1, x2, y2, alpha; char bff[10]; radius = (1.0 - reflection_coef(r, 1.0)) / 2.0, x1 = 1.0 - radius; x2 = creal(rc); y2 = cimag(rc); sprintf(bff, "%.*f", (fabs(x) > 5) ? 0 : 1, fabs(x)); return do_string(grp, bff, creal(rc) + 1, cimag(rc), 2.0, atan2(y2, x2-x1) + M_PI); } void create_printer_chart(void) { int el; complex cmin, cmax; print_new_page(pref.last_ps_file); for (el = 0; el < nrpldefs; el++) { switch (pldef[el].type) { case 'R': cmin = (pldef[el].val + pldef[el].a_min * I) * pref.chart_z0, cmax = (pldef[el].val + pldef[el].a_max * I) * pref.chart_z0; setlinestyle(NULL, pldef[el].bold ? pref.prt_arc_size[RB_ARC] : pref.prt_arc_size[R_ARC], pldef[el].bold ? pref.prt_arc_color[RB_ARC] : pref.prt_arc_color[R_ARC]); rg_arc(NULL, cmax, cmin, pref.chart_z0, TRUE); break; case 'X': cmin = (pldef[el].a_min + pldef[el].val * I) * pref.chart_z0, cmax = (pldef[el].a_max + pldef[el].val * I) * pref.chart_z0; setlinestyle(NULL, pldef[el].bold ? pref.prt_arc_size[XB_ARC] : pref.prt_arc_size[X_ARC], pldef[el].bold ? pref.prt_arc_color[XB_ARC] : pref.prt_arc_color[X_ARC]); x_arc(NULL, cmax, cmin, pref.chart_z0); x_arc(NULL, conj(cmax), conj(cmin), pref.chart_z0); break; } } for (el = 0; el < nrlbldefs; el++) { setfontstyle(NULL, pref.prt_font_name, pref.prt_font_size, pref.prt_font_color); switch (lbldef[el].type) { case 'R': r_label(NULL, lbldef[el].re, lbldef[el].im, lbldef[el].pos); break; case 'X': x_label(NULL, lbldef[el].re, lbldef[el].im, lbldef[el].pos); break; } } if (pref.show_swr) { setlinestyle(NULL, pref.prt_swr_size, pref.prt_swr_color); k_arc(NULL, z0/pref.swr_circle - 1e-5*I, z0/pref.swr_circle + 1e-5*I, z0); } if (pref.show_g1) { setlinestyle(NULL, pref.prt_g1_size, pref.prt_g1_color); rg_arc(NULL, 1.0 - 1e-5*I, 1.0 + 1e-5*I, 1.0, TRUE); } } void close_printer_chart() { print_close_page(); } void test_routine(void) { printf("Testing\n"); setlinestyle(&line_group, 1, pref.arc_color[Z_ARC]); do_arc(&line_group, 1, 0, 0, M_PI/2, 0.2); } void change_zoom(int how) { GtkWidget *w; switch (how) { case ZOOM_IN: if (zoom_factor == ZOOM_MAX) return; zoom_factor++; break; case ZOOM_OUT: if (zoom_factor == ZOOM_MIN) return; zoom_factor--; } w = lookup_widget(MainWindow, "zoom_in_btn"); gtk_widget_set_sensitive(w, zoom_factor != ZOOM_MAX); w = lookup_widget(MainWindow, "zoom_out_btn"); gtk_widget_set_sensitive(w, zoom_factor != ZOOM_MIN); gnome_canvas_set_pixels_per_unit(chart_canvas, zoom_table[zoom_factor-ZOOM_MIN].factor); w = lookup_widget(MainWindow, "zoom_lbl"); gtk_label_set_text(GTK_LABEL(w), zoom_table[zoom_factor - ZOOM_MIN].name); } void comp_discr_val_scale_value_changed(GtkRange *range) { }