/* * element.c: Element related routines * * 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 "support.h" #include "callbacks.h" #include "main.h" #include "global.h" #include "chart.h" #include "aux.h" #include "element.h" typedef struct { char *hdr; int w, rendertype; } circuitdef_entry; circuitdef_entry circuitdef[] = { {N_("Conx"), 30, 0}, {N_("El"), 30, 0}, {N_("Value"), 130, 1}, {N_("Description"), 300, 1} }; #define cdef_len sizeof(circuitdef)/sizeof(circuitdef_entry) typedef struct { char *xml; int offs; GType type; } circ_filedef_entry; circ_filedef_entry circ_filedef[] = { {"element", offsetof(el_definition, typ), G_TYPE_INT}, {"connection", offsetof(el_definition, conn), G_TYPE_INT}, {"useloss", offsetof(el_definition, useloss), G_TYPE_INT}, {"val1", offsetof(el_definition, val1), G_TYPE_DOUBLE}, {"val2", offsetof(el_definition, val2), G_TYPE_DOUBLE}, {"z0", offsetof(el_definition, z0), G_TYPE_DOUBLE}, {"vf", offsetof(el_definition, vf), G_TYPE_DOUBLE}, {"loss1", offsetof(el_definition, loss1), G_TYPE_DOUBLE}, {"mhz1", offsetof(el_definition, mhz1), G_TYPE_DOUBLE}, {"loss2", offsetof(el_definition, loss2), G_TYPE_DOUBLE}, {"mhz2", offsetof(el_definition, mhz2), G_TYPE_DOUBLE} }; #define cfiledef_len sizeof(circ_filedef)/sizeof(circ_filedef_entry) enum {FMT_DBL_ENTRY, FMT_INT_CBTN, FMT_SE_PAIR}; typedef struct { char *wname, nrdec, type; int offs; } element_format; element_format stub_els[] = { {"", SEP_STUB_VAL, FMT_SE_PAIR, offsetof(el_definition, val1)}, {"", SEP_STUB_Z0, FMT_SE_PAIR, offsetof(el_definition, z0)}, {"comp_stub_vf_entry", 3, FMT_DBL_ENTRY, offsetof(el_definition, vf)}, {"comp_stub_l1_entry", 2, FMT_DBL_ENTRY, offsetof(el_definition, loss1)}, {"comp_stub_f1_entry", 3, FMT_DBL_ENTRY, offsetof(el_definition, mhz1)}, {"comp_stub_l2_entry", 2, FMT_DBL_ENTRY, offsetof(el_definition, loss2)}, {"comp_stub_f2_entry", 3, FMT_DBL_ENTRY, offsetof(el_definition, mhz2)}, {"comp_stub_useloss_cbtn", 0, FMT_INT_CBTN, offsetof(el_definition, useloss)} }; #define stub_els_len (sizeof(stub_els)/sizeof(element_format)) element_format line_els[] = { {"", SEP_LINE_VAL, FMT_SE_PAIR, offsetof(el_definition, val1)}, {"", SEP_LINE_Z0, FMT_SE_PAIR, offsetof(el_definition, z0)}, {"comp_line_vf_entry", 3, FMT_DBL_ENTRY, offsetof(el_definition, vf)}, {"comp_line_l1_entry", 2, FMT_DBL_ENTRY, offsetof(el_definition, loss1)}, {"comp_line_f1_entry", 3, FMT_DBL_ENTRY, offsetof(el_definition, mhz1)}, {"comp_line_l2_entry", 2, FMT_DBL_ENTRY, offsetof(el_definition, loss2)}, {"comp_line_f2_entry", 3, FMT_DBL_ENTRY, offsetof(el_definition, mhz2)}, {"comp_line_useloss_cbtn", 0, FMT_INT_CBTN, offsetof(el_definition, useloss)} }; #define line_els_len (sizeof(line_els)/sizeof(element_format)) GtkWidget *el_view; GtkTreeIter active_el_iter; gboolean elements_changed = FALSE; el_definition act_el = {-1, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; void initialize_elementtable(void) { GtkListStore *els; GtkCellRenderer *renderer; GtkTreeViewColumn *col; int def; els = gtk_list_store_new(EL_COLS, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, // conn, type G_TYPE_STRING, // value G_TYPE_STRING, // descr G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, // useloss, conn, type G_TYPE_DOUBLE, G_TYPE_DOUBLE, // val1, val2 G_TYPE_DOUBLE, G_TYPE_DOUBLE, // z0, vf G_TYPE_DOUBLE, G_TYPE_DOUBLE, // loss1, mhz1 G_TYPE_DOUBLE, G_TYPE_DOUBLE, // loss2, mhz2 G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER); // ptlist, linlist,act el_view = lookup_widget(MainWindow, "circ_treeview"); gtk_tree_view_set_model(GTK_TREE_VIEW(el_view), GTK_TREE_MODEL(els)); g_object_unref(G_OBJECT(els)); for (def = 0; def < cdef_len; def++) { switch (circuitdef[def].rendertype) { case 0: renderer = gtk_cell_renderer_pixbuf_new(); col = gtk_tree_view_column_new_with_attributes( _(circuitdef[def].hdr), renderer, "pixbuf", def, NULL); break; case 1: renderer = gtk_cell_renderer_text_new(); gtk_object_set(GTK_OBJECT(renderer), "height", 14, "ypad", 0, "xalign", 1.0, "xalign", 0.0, NULL); col = gtk_tree_view_column_new_with_attributes( _(circuitdef[def].hdr), renderer, "text", def, NULL); break; } gtk_tree_view_append_column(GTK_TREE_VIEW(el_view), col); gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(col), GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(col), circuitdef[def].w); } } void enable_circ_buttons(int action) { GtkWidget *wdel, *wclr, *wup, *wdown, *wupd, *wnew; static int selected = FALSE; wdel = lookup_widget(MainWindow, "circ_delete_btn"); wclr = lookup_widget(MainWindow, "circ_clear_btn"); wup = lookup_widget(MainWindow, "circ_up_btn"); wdown = lookup_widget(MainWindow, "circ_down_btn"); wupd = lookup_widget(MainWindow, "circ_upd_el_btn"); wnew = lookup_widget(MainWindow, "circ_newel_btn"); switch (action) { case CIRCLIST_SELECT: gtk_widget_set_sensitive(wdel, TRUE); gtk_widget_set_sensitive(wup, TRUE); gtk_widget_set_sensitive(wdown, TRUE); gtk_widget_set_sensitive(wupd, FALSE); gtk_widget_set_sensitive(wnew, TRUE); selected = TRUE; break; case CIRCLIST_UNSELECT: gtk_widget_set_sensitive(wdel, FALSE); gtk_widget_set_sensitive(wup, FALSE); gtk_widget_set_sensitive(wdown, FALSE); gtk_widget_set_sensitive(wupd, FALSE); gtk_widget_set_sensitive(wnew, TRUE); selected = FALSE; break; case CIRCLIST_ENTRYSET: gtk_widget_set_sensitive(wupd, TRUE); break; case CIRCLIST_ENTRYVALID: if (selected) gtk_widget_set_sensitive(wupd, TRUE); gtk_widget_set_sensitive(wnew, TRUE); break; case CIRCLIST_ENTRYINVALID: if (selected) gtk_widget_set_sensitive(wupd, FALSE); gtk_widget_set_sensitive(wnew, FALSE); break; case CIRCLIST_CONNCHANGED: if (selected) gtk_widget_set_sensitive(wupd, TRUE); gtk_widget_set_sensitive(wnew, TRUE); break; case CIRCLIST_TYPECHANGED: if (selected) gtk_widget_set_sensitive(wupd, TRUE); gtk_widget_set_sensitive(wnew, TRUE); break; case CIRCLIST_UPDATED: gtk_widget_set_sensitive(wupd, FALSE); break; } gtk_widget_set_sensitive(wclr, action != CIRCLIST_EMPTY); } //--------------------------------------------------------------------- // Element list maintenance //--------------------------------------------------------------------- void clear_element_ptlist(chart_ptlist *ptlst) { GList *l; chart_pt pt; if (!*ptlst) return; if (debug) fprintf(stderr, "[clr ptlst] Deleting %d points\n", g_list_length(*ptlst)); for (l = g_list_first(*ptlst); l; l = l->next) { pt = l->data; if (pt) gtk_object_destroy(GTK_OBJECT(pt->point)); g_free(pt); } g_list_free(*ptlst); *ptlst = NULL; } clear_element_lnlist(chart_lnlist *lnlst) { GList *l; chart_ln ln; if (!*lnlst) return; if (debug) fprintf(stderr, "[clr lnlst] Deleting %d lines\n", g_list_length(*lnlst)); for (l = g_list_first(*lnlst); l; l = l->next) { ln = l->data; if (ln) gtk_object_destroy(GTK_OBJECT(ln->line)); g_free(ln); } g_list_free(*lnlst); *lnlst = NULL; } void format_elements(element_format *fmt, int fmtlen, char *el) { GtkWidget *w; char bff[30]; int f; for (f = 0; f < fmtlen; f++) { switch (fmt[f].type) { case FMT_DBL_ENTRY: sprintf(bff, "%.*f", fmt[f].nrdec, *(double *)&el[fmt[f].offs]); w = lookup_widget(MainWindow, fmt[f].wname); gtk_entry_set_text(GTK_ENTRY(w), bff); break; case FMT_INT_CBTN: w = lookup_widget(MainWindow, fmt[f].wname); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), *(int *)&el[fmt[f].offs]); break; case FMT_SE_PAIR: scale_entry_pair_set(fmt[f].nrdec, *(double *)&el[fmt[f].offs]); break; } } } void set_discr_mode(int mode) { GtkWidget *w; w = lookup_widget(MainWindow, "comp_cap_table"); gtk_widget_set_sensitive(w, (mode == ELT_CAP) || (mode == ELT_PARLC) || (mode == ELT_SERLC)); w = lookup_widget(MainWindow, "comp_ind_table"); gtk_widget_set_sensitive(w, (mode == ELT_IND) || (mode == ELT_PARLC) || (mode == ELT_SERLC)); } void parse_elements(element_format *fmt, int fmtlen, char *el) { GtkWidget *w; const char *p; double tval; int f; for (f = 0; f < fmtlen; f++) { switch (fmt[f].type) { case FMT_DBL_ENTRY: w = lookup_widget(MainWindow, fmt[f].wname); p = gtk_entry_get_text(GTK_ENTRY(w)); if (strlen(p) == 0) break; // don't change val if empty *(double *)&el[fmt[f].offs] = atof(p); break; case FMT_INT_CBTN: w = lookup_widget(MainWindow, fmt[f].wname); *(int *)&el[fmt[f].offs] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); break; case FMT_SE_PAIR: tval = scale_entry_pair_get(fmt[f].nrdec); if (tval != 0.0) *(double *)&el[fmt[f].offs] = tval; break; } } } int fetch_selected_element(GtkTreeView *treeview, el_definition *el) { GtkTreeModel *store; GtkTreeSelection *sel; gboolean havesel; sel = gtk_tree_view_get_selection(treeview); havesel = gtk_tree_selection_get_selected(sel, &store, &active_el_iter); if (havesel) { memset(el, 0, sizeof(el_definition)); gtk_tree_model_get(store, &active_el_iter, EL_CONN_VAL, &el->conn, EL_TYPE_VAL, &el->typ, EL_USE_LOSS, &el->useloss, EL_VAL_VAL1, &el->val1, EL_VAL_VAL2, &el->val2, EL_Z0_VAL, &el->z0, EL_VF_VAL, &el->vf, EL_LOSS1_VAL, &el->loss1, EL_MHZ1_VAL, &el->mhz1, EL_LOSS2_VAL, &el->loss2, EL_MHZ2_VAL, &el->mhz2, EL_POINTLIST, &el->ptlst, EL_LINELIST, &el->lnlst, -1); set_element_type(el->typ); set_element_conn(el->conn); switch (el->typ) { case ELT_CAP: scale_entry_pair_set(SEP_CAP_VAL, el->val2); break; case ELT_IND: scale_entry_pair_set(SEP_IND_VAL, el->val1); break; case ELT_PARLC: case ELT_SERLC: scale_entry_pair_set(SEP_IND_VAL, el->val1); scale_entry_pair_set(SEP_CAP_VAL, el->val2); break; case ELT_OSTUB: case ELT_SSTUB: format_elements(stub_els, stub_els_len, (char *)el); break; case ELT_LINE: format_elements(line_els, line_els_len, (char *)el); break; } enable_circ_buttons(CIRCLIST_SELECT); return TRUE; } else return FALSE; } void valid_double(char *wdg, double *val) { GtkWidget *w = lookup_widget(MainWindow, wdg); double tval; const char *begp; char *endp; begp = gtk_entry_get_text(GTK_ENTRY(w)); if (endp == begp) tval = 0.0; else tval = strtod(begp, &endp); *val = tval; return; } int element_valid(el_definition *el) { GtkWidget *w; double tval; const char *begp; char *endp; if (act_el.typ == -1 || act_el.conn == -1) { return FALSE; } memset(el, 0, sizeof(el_definition)); el->typ = act_el.typ; el->conn = act_el.conn; switch (el->typ) { case ELT_CAP: valid_double("comp_cap_val_entry", &el->val2); break; case ELT_IND: valid_double("comp_ind_val_entry", &el->val1); break; case ELT_PARLC: case ELT_SERLC: valid_double("comp_cap_val_entry", &el->val2); valid_double("comp_ind_val_entry", &el->val1); break; case ELT_LINE: parse_elements(line_els, line_els_len, (char *)el); break; case ELT_OSTUB: case ELT_SSTUB: parse_elements(stub_els, stub_els_len, (char *)el); break; case ELT_XFORM: w = lookup_widget(MainWindow, "comp_xform_entry"); el->val1 = atof(gtk_entry_get_text(GTK_ENTRY(w))); break; } return TRUE; } void element_update(el_definition el) { char bff[30], descr[80], *p1, *p2; GtkTreeSelection *sel; GtkListStore *store; GtkTreeIter *actiter; chart_ptlist ptlst; chart_lnlist lnlst; if (active_el_iter.stamp == 0) return; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(el_view)); store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(el_view))); gtk_tree_model_get(GTK_TREE_MODEL(store), &active_el_iter, EL_POINTLIST, &ptlst, EL_LINELIST, &lnlst, EL_ACT_ITER, &actiter, -1); clear_element_ptlist(&ptlst); clear_element_lnlist(&lnlst); g_free(actiter); descr[0] = '\0'; bff[0] = '\0'; switch (el.typ) { case ELT_OSTUB: case ELT_SSTUB: case ELT_LINE: sprintf(bff, "%.1fmm @ %.1fΩ", el.val1, el.z0); // if (el.useloss) { sprintf(descr, "Vf = %.2f (%.2fdB @ %.1f MHz, %.2fdB @ %.1f MHz)", el.vf, el.loss1, el.mhz1, el.loss2, el.mhz2); } else { sprintf(descr, "Vf = %.2f (no loss)", el.vf); } break; case ELT_CAP: sprintf(bff, "%.2fpF", el.val2); break; case ELT_IND: sprintf(bff, "%.1fnH", el.val1); break; case ELT_PARLC: case ELT_SERLC: sprintf(bff, "%.2fpF, %.1fnH", el.val2, el.val1); break; } gtk_list_store_set(store, &active_el_iter, EL_CONN, connection_glyph(el.conn, el.typ), EL_TYPE, type_glyph(el.conn, el.typ), EL_VAL1, bff, EL_DESCR, p2 = g_locale_to_utf8(descr, -1, NULL, NULL, NULL), EL_USE_LOSS, el.useloss, 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_LOSS1_VAL, el.loss1, EL_LOSS2_VAL, el.loss2, EL_MHZ1_VAL, el.mhz1, EL_MHZ2_VAL, el.mhz2, EL_POINTLIST, NULL, EL_LINELIST, NULL, EL_ACT_ITER, NULL, -1); g_free(p2); elements_changed = TRUE; gtk_tree_selection_select_iter(sel, &active_el_iter); act_el = el; recalculate_all(); enable_circ_buttons(CIRCLIST_UPDATED); } void element_append(el_definition el) { GtkListStore *store; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(el_view))); gtk_list_store_append(store, &active_el_iter); // add a row element_update(el); } void active_element_remove(void) { GtkListStore *store; GtkTreeSelection *sel; chart_ptlist ptlst; chart_lnlist lnlst; if (active_el_iter.stamp == 0) return; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(el_view))); gtk_tree_model_get(GTK_TREE_MODEL(store), &active_el_iter, EL_POINTLIST, &ptlst, EL_LINELIST, &lnlst, -1); clear_element_ptlist(&ptlst); clear_element_lnlist(&lnlst); if (gtk_list_store_remove(store, &active_el_iter)) { sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(el_view)); gtk_tree_selection_select_iter(sel, &active_el_iter); } if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL) == 0) enable_circ_buttons(CIRCLIST_EMPTY); elements_changed = TRUE; } void circlist_clear(void) { GtkTreeModel *model; GtkTreeIter iter; chart_ptlist ptlst; chart_lnlist lnlst; gboolean more; model = gtk_tree_view_get_model(GTK_TREE_VIEW(el_view)); more = gtk_tree_model_get_iter_first(model, &iter); while (more) { gtk_tree_model_get(model, &iter, EL_POINTLIST, &ptlst, EL_LINELIST, &lnlst, -1); clear_element_ptlist(&ptlst); clear_element_lnlist(&lnlst); more = gtk_tree_model_iter_next(model, &iter); } gtk_list_store_clear(GTK_LIST_STORE(model)); enable_circ_buttons(CIRCLIST_UNSELECT); elements_changed = TRUE; } void circ_move_up(void) { if (active_el_iter.stamp == 0) return; GtkTreeIter csr, prev; GtkListStore *store; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(el_view))); if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &csr)) return; } void circ_move_down(void) { if (active_el_iter.stamp == 0) return; GtkTreeIter *next; GtkListStore *store; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(el_view))); next = gtk_tree_iter_copy(&active_el_iter); if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), next)) { gtk_list_store_swap(store, &active_el_iter, next); } g_free(next); } //--------------------------------------------------------------------- // File routines //--------------------------------------------------------------------- gboolean save_each_element(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { el_definition el; FILE *xmlf = user_data; char bff[50]; int e; 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); fprintf(xmlf, " \n"); for (e = 0; e < cfiledef_len; e++) { switch (circ_filedef[e].type) { case G_TYPE_INT: sprintf(bff, "%d", *(int *)((char *)&el + circ_filedef[e].offs)); break; case G_TYPE_CHAR: sprintf(bff, "%d", ((char *)&el)[circ_filedef[e].offs]); break; case G_TYPE_DOUBLE: sprintf(bff, "%f", *(double *)((char *)&el + circ_filedef[e].offs)); break; } fprintf(xmlf, " <%s>%s\n", circ_filedef[e].xml, bff, circ_filedef[e].xml); } fprintf(xmlf, " \n"); return FALSE; } void save_circuit(char *fn) { GtkWidget *els = lookup_widget(MainWindow, "circ_treeview"); GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(els)); FILE *xmlf; if ((xmlf = fopen(fn, "r"))) { fclose(xmlf); if (ok_cancel_dialog(_("Confirmation"), _("File exists - want to overwrite?")) == 1) { return; } } if (!(xmlf = fopen(fn, "w"))) { ok_dialog(_("Error"), _("Cannot open destination file")); return; } fprintf(xmlf, "\n"); fprintf(xmlf, "\n"); fprintf(xmlf, " \n", prog_version); gtk_tree_model_foreach(store, save_each_element, xmlf); fprintf(xmlf, "\n"); fclose(xmlf); elements_changed = FALSE; } void parse_element(el_definition *el, xmlDocPtr doc, xmlNodePtr cur) { xmlChar *key; int e; cur = cur->xmlChildrenNode; while (cur != NULL) { for (e = 0; e < cfiledef_len; e++) { if ((!xmlStrcmp(cur->name, (const xmlChar *) circ_filedef[e].xml))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); switch (circ_filedef[e].type) { case G_TYPE_INT: *(int *)((char *)el + circ_filedef[e].offs) = atol(key); break; case G_TYPE_CHAR: ((char *)el)[circ_filedef[e].offs] = atol(key); break; case G_TYPE_DOUBLE: *(double *)((char *)el + circ_filedef[e].offs) = atof(key); break; } xmlFree(key); } } cur = cur->next; } } void load_circuit(char *fn) { el_definition el; xmlDocPtr doc; xmlNodePtr cur; printf("[Circuit] Load circuit: %s\n", fn); if (!xml_file_loaded(&doc, fn, "circuit")) return; cur = xmlDocGetRootElement(doc); cur = cur->xmlChildrenNode; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar *) "element"))) { parse_element(&el, doc, cur); element_append(el); } cur = cur->next; } g_signal_emit_by_name(G_OBJECT(el_view), "cursor-changed", NULL); xmlFreeDoc(doc); } complex calc_line_impedance(complex zl, double z0, double len, double f) { double arg = tan(2 * M_PI * len); complex stub; switch (pref.rotation) { case TO_GENERATOR: stub = zl * (1 + I * z0 / zl * arg) / (1 + I * zl / z0 * arg); break; case TO_LOAD: stub = zl * (1 - I * z0 / zl * arg) / (1 - I * zl / z0 * arg); break; } if (debug) fprintf(stderr, "[line imp] %f %fj\n", creal(stub), cimag(stub)); return stub; } complex calc_el_impedance(el_definition *el, double f) { complex res, tc, tl; double wl = el->vf * 300000 / f, twopif = 2 * M_PI * f; switch (el->typ) { case ELT_CAP: res = 0.0 - (1000000/(twopif * el->val2)) * I; break; case ELT_IND: res = 0.0 + (twopif * el->val1 / 1000) * I; break; case ELT_PARLC: tc = 0.0 - (1000000/(twopif * el->val2)) * I; tl = 0.0 + (twopif * el->val1 / 1000) * I; res = (tc * tl)/(tc + tl); break; case ELT_SERLC: tc = 0.0 - (1000000/(twopif * el->val2)) * I; tl = 0.0 + (twopif * el->val1 / 1000) * I; res = tc + tl; break; case ELT_OSTUB: res = calc_line_impedance(1e30, el->z0, el->val1 / wl, f); break; case ELT_SSTUB: res = calc_line_impedance(1e-30, el->z0, el->val1 / wl, f); break; case ELT_LINE: res = 0.0 - 0.0 * I; break; case ELT_ZY: break; } if (debug) printf("[elem imp] %f %fj\n", creal(res), cimag(res)); return res; } int number_elements(void) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(el_view)); return gtk_tree_model_iter_n_children(model, NULL); }